mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-19 10:51:34 +08:00
Merge branch 'release_23.1' into dev
This commit is contained in:
@@ -66,6 +66,7 @@ describe("FormSelect", () => {
|
||||
|
||||
it("multiple values", async () => {
|
||||
const wrapper = createTarget({
|
||||
optional: true,
|
||||
multiple: true,
|
||||
optional: true,
|
||||
options: defaultOptions,
|
||||
|
||||
@@ -13,13 +13,14 @@ import HistoryView from "./HistoryView";
|
||||
const localVue = getLocalVue();
|
||||
jest.mock("stores/services/history.services");
|
||||
|
||||
function create_history(historyId, userId, purged = false) {
|
||||
function create_history(historyId, userId, purged = false, archived = false) {
|
||||
const historyName = `${userId}'s History ${historyId}`;
|
||||
return {
|
||||
model_class: "History",
|
||||
id: historyId,
|
||||
name: historyName,
|
||||
purged: purged,
|
||||
archived: archived,
|
||||
count: 10,
|
||||
annotation: "This is a history",
|
||||
tags: ["tag_1", "tag_2"],
|
||||
@@ -164,13 +165,43 @@ describe("History center panel View", () => {
|
||||
const wrapper = await createWrapper(localVue, "user_1", history);
|
||||
expect(wrapper.vm.history).toEqual(history);
|
||||
|
||||
// switch/import buttons: purged they don't exist
|
||||
// history purged, not switchable and not importable
|
||||
const switchButton = wrapper.find("[data-description='switch to history button']");
|
||||
const importButton = wrapper.find("[data-description='import history button']");
|
||||
expect(switchButton.exists()).toBe(false);
|
||||
expect(switchButton.attributes("disabled")).toBeTruthy();
|
||||
expect(importButton.exists()).toBe(false);
|
||||
|
||||
// instead we have an alert
|
||||
expect(wrapper.find("[data-description='history state info']").text()).toBe("This history has been purged.");
|
||||
});
|
||||
|
||||
it("should not display archived message and should be importable when user is not owner and history is archived", async () => {
|
||||
const history = create_history("history_2", "user_2", false, true);
|
||||
const wrapper = await createWrapper(localVue, "user_1", history);
|
||||
expect(wrapper.vm.history).toEqual(history);
|
||||
|
||||
const switchButton = wrapper.find("[data-description='switch to history button']");
|
||||
const importButton = wrapper.find("[data-description='import history button']");
|
||||
expect(switchButton.exists()).toBe(false);
|
||||
expect(importButton.exists()).toBe(true);
|
||||
expect(importButton.attributes("disabled")).toBeFalsy();
|
||||
|
||||
expectCorrectLayout(wrapper);
|
||||
expect(wrapper.find("[data-description='history state info']").exists()).toBe(false);
|
||||
});
|
||||
|
||||
it("should display archived message and should not be importable when user is owner and history is archived", async () => {
|
||||
const history = create_history("history_2", "user_1", false, true);
|
||||
const wrapper = await createWrapper(localVue, "user_1", history);
|
||||
expect(wrapper.vm.history).toEqual(history);
|
||||
|
||||
const switchButton = wrapper.find("[data-description='switch to history button']");
|
||||
const importButton = wrapper.find("[data-description='import history button']");
|
||||
expect(switchButton.exists()).toBe(true);
|
||||
expect(switchButton.attributes("disabled")).toBeTruthy();
|
||||
expect(importButton.exists()).toBe(false);
|
||||
|
||||
expectCorrectLayout(wrapper);
|
||||
expect(wrapper.find("[data-description='history state info']").text()).toBe("This history has been archived.");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,19 +3,19 @@
|
||||
<b-alert v-if="showHistoryStateInfo" variant="info" show data-description="history state info">
|
||||
{{ historyStateInfoMessage }}
|
||||
</b-alert>
|
||||
<div v-else class="flex-row flex-grow-0 pb-3">
|
||||
<div class="flex-row flex-grow-0 pb-3">
|
||||
<b-button
|
||||
v-if="userOwnsHistory"
|
||||
size="sm"
|
||||
variant="outline-info"
|
||||
title="Switch to this history"
|
||||
:title="setAsCurrentTitle"
|
||||
:disabled="isSetAsCurrentDisabled"
|
||||
data-description="switch to history button"
|
||||
@click="setCurrentHistory(history.id)">
|
||||
Switch to this history
|
||||
</b-button>
|
||||
<b-button
|
||||
v-else
|
||||
v-if="canImportHistory"
|
||||
v-b-modal:copy-history-modal
|
||||
size="sm"
|
||||
variant="outline-info"
|
||||
@@ -77,25 +77,46 @@ export default {
|
||||
userOwnsHistory() {
|
||||
return this.currentUser.id == this.history.user_id;
|
||||
},
|
||||
isCurrentHistory() {
|
||||
return this.currentHistory?.id == this.history?.id;
|
||||
},
|
||||
isSetAsCurrentDisabled() {
|
||||
return this.currentHistory?.id == this.history?.id || this.history.archived || this.history.purged;
|
||||
return this.isCurrentHistory || this.history.archived || this.history.purged;
|
||||
},
|
||||
setAsCurrentTitle() {
|
||||
if (this.isCurrentHistory) {
|
||||
return "This history is already your current history.";
|
||||
}
|
||||
if (this.history.archived) {
|
||||
return "This history has been archived and cannot be set as your current history. Unarchive it first.";
|
||||
}
|
||||
if (this.history.purged) {
|
||||
return "This history has been purged and cannot be set as your current history.";
|
||||
}
|
||||
return "Switch to this history";
|
||||
},
|
||||
canEditHistory() {
|
||||
return this.userOwnsHistory && !this.history.archived && !this.history.purged;
|
||||
},
|
||||
showHistoryArchived() {
|
||||
return this.history.archived && this.userOwnsHistory;
|
||||
},
|
||||
showHistoryStateInfo() {
|
||||
return this.history.archived || this.history.purged;
|
||||
return this.showHistoryArchived || this.history.purged;
|
||||
},
|
||||
historyStateInfoMessage() {
|
||||
if (this.history.archived && this.history.purged) {
|
||||
if (this.showHistoryArchived && this.history.purged) {
|
||||
return "This history has been archived and purged.";
|
||||
} else if (this.history.archived) {
|
||||
} else if (this.showHistoryArchived) {
|
||||
return "This history has been archived.";
|
||||
} else if (this.history.purged) {
|
||||
return "This history has been purged.";
|
||||
}
|
||||
return "";
|
||||
},
|
||||
canImportHistory() {
|
||||
return !this.userOwnsHistory && !this.history.purged;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.loadHistoryById(this.id);
|
||||
|
||||
@@ -62,7 +62,7 @@ export default {
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(useUserStore, ["isAnonymous"]),
|
||||
...mapState(useUserStore, ["currentUser", "isAnonymous"]),
|
||||
title() {
|
||||
return `Copying History: ${this.history.name}`;
|
||||
},
|
||||
@@ -72,9 +72,12 @@ export default {
|
||||
saveVariant() {
|
||||
return this.loading ? "info" : this.formValid ? "primary" : "secondary";
|
||||
},
|
||||
userOwnsHistory() {
|
||||
return this.currentUser.id == this.history.user_id;
|
||||
},
|
||||
newNameValid() {
|
||||
if (this.name == this.history.name) {
|
||||
return null;
|
||||
if (this.userOwnsHistory && this.name == this.history.name) {
|
||||
return false;
|
||||
}
|
||||
return this.name.length > 0;
|
||||
},
|
||||
|
||||
@@ -149,6 +149,9 @@ const infoString = computed(() => {
|
||||
invocationMessage.workflow_step_id + 1
|
||||
} is a conditional step and the result of the when expression is not a boolean type.`;
|
||||
} else if (reason === "unexpected_failure") {
|
||||
if (invocationMessage.details) {
|
||||
return `${failFragment} an unexpected failure occurred: '${invocationMessage.details}'`;
|
||||
}
|
||||
return `${failFragment} an unexpected failure occurred.`;
|
||||
} else if (reason === "workflow_output_not_found") {
|
||||
return `Defined workflow output '${invocationMessage.output_name}' was not found in step ${
|
||||
|
||||
@@ -47,7 +47,7 @@ for _tag in reversed(tags):
|
||||
if Version(_ver) >= MIN_DOC_VERSION:
|
||||
simpleversioning_versions.append({"id": f"release_{_ver}", "name": _ver})
|
||||
|
||||
if re.fullmatch(r"release_\d{2}\.\d{2}", TARGET_GIT_BRANCH):
|
||||
if re.fullmatch(r"release_\d{2}\.\d{1,2}", TARGET_GIT_BRANCH):
|
||||
if _stable:
|
||||
# The current stable release will go here but fail the next conditional, avoiding either banner.
|
||||
if TARGET_GIT_BRANCH != f"release_{_stable}":
|
||||
|
||||
@@ -498,7 +498,7 @@ class RemoveTagDatasetAction(TagDatasetAction):
|
||||
|
||||
@classmethod
|
||||
def _execute(cls, tag_handler, user, output, tags):
|
||||
tag_handler.remove_tags_from_list(user, output, tags)
|
||||
tag_handler.remove_tags_from_list(user, output, tags, flush=False)
|
||||
|
||||
|
||||
class ActionBox:
|
||||
|
||||
@@ -95,7 +95,8 @@ class ToolBoxRegistryImpl(ToolBoxRegistry):
|
||||
self.__toolbox = toolbox
|
||||
|
||||
def has_tool(self, tool_id: str) -> bool:
|
||||
return tool_id in self.__toolbox._tools_by_id
|
||||
toolbox = self.__toolbox
|
||||
return tool_id in toolbox._tools_by_id or tool_id in toolbox._tools_by_old_id
|
||||
|
||||
def get_tool(self, tool_id: str):
|
||||
return self.__toolbox.get_tool(tool_id)
|
||||
@@ -161,6 +162,7 @@ class AbstractToolBox(Dictifiable, ManagesIntegratedToolPanelMixin):
|
||||
# so each will be present once in the above dictionary. The following
|
||||
# dictionary can instead hold multiple tools with different versions.
|
||||
self._tool_versions_by_id = {}
|
||||
self._tools_by_old_id = {}
|
||||
self._workflows_by_id = {}
|
||||
# Cache for tool's to_dict calls specific to toolbox. Invalidates on toolbox reload.
|
||||
self._tool_to_dict_cache = {}
|
||||
@@ -718,9 +720,8 @@ class AbstractToolBox(Dictifiable, ManagesIntegratedToolPanelMixin):
|
||||
rval.append(lineage_tool)
|
||||
if not rval:
|
||||
# still no tool, do a deeper search and try to match by old ids
|
||||
for tool in self._tools_by_id.values():
|
||||
if tool.old_id == tool_id:
|
||||
rval.append(tool)
|
||||
if tool_id in self._tools_by_old_id:
|
||||
rval.extend(self._tools_by_old_id[tool_id])
|
||||
if get_all_versions and tool_id in self._tool_versions_by_id:
|
||||
for tool in self._tool_versions_by_id[tool_id].values():
|
||||
if tool not in rval:
|
||||
@@ -1160,6 +1161,10 @@ class AbstractToolBox(Dictifiable, ManagesIntegratedToolPanelMixin):
|
||||
self._tools_by_id[tool_id] = tool
|
||||
else:
|
||||
self._tools_by_id[tool_id] = tool
|
||||
old_id = tool.old_id
|
||||
if old_id not in self._tools_by_old_id:
|
||||
self._tools_by_old_id[old_id] = []
|
||||
self._tools_by_old_id[old_id].append(tool)
|
||||
|
||||
def package_tool(self, trans, tool_id):
|
||||
"""
|
||||
@@ -1219,6 +1224,7 @@ class AbstractToolBox(Dictifiable, ManagesIntegratedToolPanelMixin):
|
||||
else:
|
||||
tool = self._tools_by_id[tool_id]
|
||||
del self._tools_by_id[tool_id]
|
||||
self._tools_by_old_id[tool.old_id].remove(tool)
|
||||
tool_cache = getattr(self.app, "tool_cache", None)
|
||||
if tool_cache:
|
||||
tool_cache.expire_tool(tool_id)
|
||||
|
||||
@@ -2,7 +2,7 @@ name: Custom Panel in a New Section
|
||||
type: generic
|
||||
items:
|
||||
- type: section
|
||||
name: My Completely New Sectin
|
||||
name: My Completely New Section
|
||||
items:
|
||||
- type: label
|
||||
text: The Start
|
||||
|
||||
@@ -125,9 +125,7 @@ class TestRepositoryInstallIntegrationTestCase(integration_util.IntegrationTestC
|
||||
assert tool["version"] == "0.0.2"
|
||||
self.uninstall_repository(REPO.owner, REPO.name, REPO.changeset)
|
||||
response = self.get_tool(assert_ok=False)
|
||||
assert (
|
||||
"err_msg" in response
|
||||
), f"Expected an error message after tool install but response was {response.content}"
|
||||
assert "err_msg" in response, f"Expected an error message after tool install but response was {response}"
|
||||
assert response["err_msg"]
|
||||
assert self.get_installed_repository_for(REPO.owner, REPO.name, REPO.changeset) is None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user