Skip to content

Commit 768f197

Browse files
committed
Merge branch 'release_25.1' into forward_merge_10_11_25
2 parents d703a3d + 04c8242 commit 768f197

8 files changed

Lines changed: 113 additions & 34 deletions

File tree

client/src/components/History/useHistoryCardActions.ts

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -247,25 +247,6 @@ export function useHistoryCardActions(
247247
handler: onRestore,
248248
visible: history.value.deleted && !history.value.purged && isMyHistory(history.value),
249249
},
250-
{
251-
id: "switch",
252-
title: localize("Set as current history"),
253-
label: localize("Set as Current"),
254-
variant: "outline-primary",
255-
icon: faExchangeAlt,
256-
handler: () => historyStore.setCurrentHistory(String(history.value.id)),
257-
visible:
258-
(isMyHistory(history.value) || archivedView) && historyStore.currentHistoryId !== history.value.id,
259-
},
260-
{
261-
title: "current history",
262-
id: "current",
263-
label: "Current",
264-
variant: "outline-primary",
265-
disabled: true,
266-
visible:
267-
(isMyHistory(history.value) || archivedView) && historyStore.currentHistoryId === history.value.id,
268-
},
269250
{
270251
id: "import-copy",
271252
label: localize("Import Copy"),
@@ -291,9 +272,28 @@ export function useHistoryCardActions(
291272
label: localize("View"),
292273
title: localize("View this history"),
293274
icon: faEye,
294-
variant: "primary",
275+
variant: "outline-primary",
295276
to: `/histories/view?id=${history.value.id}`,
296277
},
278+
{
279+
id: "switch",
280+
title: localize("Set as current history"),
281+
label: localize("Set as Current"),
282+
variant: "primary",
283+
icon: faExchangeAlt,
284+
handler: () => historyStore.setCurrentHistory(String(history.value.id)),
285+
visible:
286+
(isMyHistory(history.value) || archivedView) && historyStore.currentHistoryId !== history.value.id,
287+
},
288+
{
289+
title: "current history",
290+
id: "current",
291+
label: "Current",
292+
variant: "outline-primary",
293+
disabled: true,
294+
visible:
295+
(isMyHistory(history.value) || archivedView) && historyStore.currentHistoryId === history.value.id,
296+
},
297297
];
298298
});
299299

client/src/components/Panels/Common/Tool.test.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { createTestingPinia } from "@pinia/testing";
12
import { mount } from "@vue/test-utils";
23
import { getLocalVue } from "tests/jest/helpers";
34

@@ -7,11 +8,15 @@ const localVue = getLocalVue();
78

89
describe("Tool", () => {
910
test("test tool", () => {
11+
const pinia = createTestingPinia();
1012
const wrapper = mount(Tool, {
1113
propsData: {
12-
tool: {},
14+
tool: {
15+
id: "test_tool",
16+
},
1317
},
1418
localVue,
19+
pinia,
1520
});
1621
const nameElement = wrapper.findAll(".name");
1722
expect(nameElement.at(0).text()).toBe("");
@@ -25,15 +30,18 @@ describe("Tool", () => {
2530
expect(wrapper.emitted().onOperation).toBeDefined();
2631
});
2732
test("test tool operation", () => {
33+
const pinia = createTestingPinia();
2834
const wrapper = mount(Tool, {
2935
propsData: {
3036
tool: {
37+
id: "test_tool",
3138
name: "name",
3239
},
3340
operationIcon: "operationIconClass",
3441
operationTitle: "operationTitle",
3542
},
3643
localVue,
44+
pinia,
3745
});
3846
const nameElement = wrapper.findAll(".name");
3947
expect(nameElement.at(0).text()).toBe("name");
@@ -43,15 +51,18 @@ describe("Tool", () => {
4351
expect(title).toBe("operationTitle");
4452
});
4553
test("test tool hide name, test description", () => {
54+
const pinia = createTestingPinia();
4655
const wrapper = mount(Tool, {
4756
propsData: {
4857
tool: {
58+
id: "test_tool",
4959
name: "name",
5060
description: "description",
5161
},
5262
hideName: true,
5363
},
5464
localVue,
65+
pinia,
5566
});
5667
const nameElement = wrapper.findAll(".name");
5768
expect(nameElement.length).toBe(0);

client/src/components/Panels/Common/Tool.vue

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
v-else
99
:class="targetClass"
1010
:data-tool-id="tool.id"
11-
:href="tool.link"
12-
:target="tool.target"
11+
:href="toolLink"
12+
:target="toolTarget"
1313
:title="tool.help"
1414
@click="onClick">
1515
<span class="labels">
@@ -35,6 +35,7 @@
3535
import BootstrapVue from "bootstrap-vue";
3636
import Vue from "vue";
3737
38+
import { useToolStore } from "@/stores/toolStore";
3839
import ariaAlert from "@/utils/ariaAlert";
3940
4041
Vue.use(BootstrapVue);
@@ -67,7 +68,20 @@ export default {
6768
default: false,
6869
},
6970
},
71+
setup() {
72+
const toolStore = useToolStore();
73+
return {
74+
getLinkById: toolStore.getLinkById,
75+
getTargetById: toolStore.getTargetById,
76+
};
77+
},
7078
computed: {
79+
toolLink() {
80+
return this.getLinkById(this.tool.id);
81+
},
82+
toolTarget() {
83+
return this.getTargetById(this.tool.id);
84+
},
7185
targetClass() {
7286
if (this.toolKey) {
7387
return `tool-menu-item-${this.tool[this.toolKey]} title-link cursor-pointer`;

client/src/stores/toolStore.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,28 @@ export const useToolStore = defineStore("toolStore", () => {
103103
return toolSections.value[effectiveView] || {};
104104
});
105105

106+
const getLinkById = computed(() => {
107+
return (toolId: string) => {
108+
const tool = toolsById.value[toolId];
109+
const appRoot = getAppRoot();
110+
if (tool && tool.model_class === "DataSourceTool") {
111+
return `${appRoot}tool_runner/data_source_redirect?tool_id=${encodeURIComponent(toolId)}`;
112+
} else if (tool?.model_class) {
113+
return `${appRoot}?tool_id=${encodeURIComponent(toolId)}&version=latest`;
114+
} else {
115+
// accommodates hacky toolbox markdown directive overload
116+
return undefined;
117+
}
118+
};
119+
});
120+
121+
const getTargetById = computed(() => {
122+
return (toolId: string) => {
123+
const tool = toolsById.value[toolId];
124+
return tool?.model_class === "DataSourceTool" ? "_top" : "galaxy_main";
125+
};
126+
});
127+
106128
const getToolsById = computed(() => {
107129
return (q?: string) => {
108130
if (!q?.trim()) {
@@ -299,6 +321,8 @@ export const useToolStore = defineStore("toolStore", () => {
299321
fetchPanels,
300322
fetchToolForId,
301323
fetchTools,
324+
getLinkById,
325+
getTargetById,
302326
helpDataCached,
303327
initializePanel,
304328
isPanelPopulated,

client/src/utils/navigation/navigation.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,8 +408,8 @@ tool_panel:
408408
selectors:
409409
edam_link: 'a[href^="https://edamontology.github.io/edam-browser"]'
410410
tool_box: '[data-description="panel toolbox"]'
411-
tool_link: 'a[href$$="tool_runner?tool_id=${tool_id}"]'
412-
outer_tool_link: '.toolTitle a[href$$="tool_runner?tool_id=${tool_id}"]'
411+
tool_link: 'a[href$$="/?tool_id=${tool_id}&version=latest"]'
412+
outer_tool_link: '.toolTitle a[href$$="/?tool_id=${tool_id}&version=latest"]'
413413
data_source_tool_link: 'a[href$$="tool_runner/data_source_redirect?tool_id=${tool_id}"]'
414414
search: '.search-query'
415415
toolbox: '[data-description="panel toolbox"]'

lib/galaxy/model/__init__.py

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1664,7 +1664,17 @@ class Job(Base, JobLike, UsesCreateAndUpdateTime, Dictifiable, Serializable):
16641664
back_populates="job"
16651665
)
16661666

1667-
dict_collection_visible_keys = ["id", "state", "exit_code", "update_time", "create_time", "galaxy_version"]
1667+
dict_collection_visible_keys = [
1668+
"id",
1669+
"state",
1670+
"exit_code",
1671+
"update_time",
1672+
"create_time",
1673+
"galaxy_version",
1674+
"tool_id",
1675+
"tool_version",
1676+
"history_id",
1677+
]
16681678
dict_element_visible_keys = [
16691679
"id",
16701680
"state",
@@ -1675,6 +1685,9 @@ class Job(Base, JobLike, UsesCreateAndUpdateTime, Dictifiable, Serializable):
16751685
"command_version",
16761686
"copied_from_job_id",
16771687
"user_id",
1688+
"tool_id",
1689+
"tool_version",
1690+
"history_id",
16781691
]
16791692

16801693
_numeric_metric = JobMetricNumeric
@@ -2210,9 +2223,6 @@ def to_dict(self, view="collection", system_details=False):
22102223
rval = super().to_dict(view="collection")
22112224
else:
22122225
rval = super().to_dict(view=view)
2213-
rval["tool_id"] = self.tool_id
2214-
rval["tool_version"] = self.tool_version
2215-
rval["history_id"] = self.history_id
22162226
if system_details or view == "admin_job_list":
22172227
# System level details that only admins should have.
22182228
rval["external_id"] = self.job_runner_external_id
@@ -2848,6 +2858,17 @@ def job_list(self):
28482858
.all()
28492859
)
28502860

2861+
def get_job_attributes(self, attributes: list[str]):
2862+
session = required_object_session(self)
2863+
targets = [getattr(Job.table.columns, attr) for attr in attributes]
2864+
stmt = (
2865+
select(*targets)
2866+
.select_from(Job)
2867+
.join(ImplicitCollectionJobsJobAssociation, Job.id == ImplicitCollectionJobsJobAssociation.job_id)
2868+
.where(ImplicitCollectionJobsJobAssociation.implicit_collection_jobs_id == self.id)
2869+
)
2870+
return session.execute(stmt)
2871+
28512872
def _serialize(self, id_encoder, serialization_options):
28522873
rval = dict_for(
28532874
self,
@@ -10169,6 +10190,15 @@ def _serialize(self, id_encoder, serialization_options):
1016910190

1017010191
return step_attrs
1017110192

10193+
def get_jobs_dict(self):
10194+
if self.implicit_collection_jobs:
10195+
result = self.implicit_collection_jobs.get_job_attributes(Job.dict_collection_visible_keys)
10196+
return [{"model_class": "Job", **row._mapping} for row in result]
10197+
elif self.job:
10198+
return [self.job.to_dict()]
10199+
else:
10200+
return []
10201+
1017210202
def to_dict(self, view="collection", value_mapper=None):
1017310203
rval = super().to_dict(view=view, value_mapper=value_mapper)
1017410204
rval["order_index"] = self.workflow_step.order_index
@@ -10177,9 +10207,7 @@ def to_dict(self, view="collection", value_mapper=None):
1017710207
# Following no longer makes sense...
1017810208
# rval['state'] = self.job.state if self.job is not None else None
1017910209
if view == "element":
10180-
jobs = []
10181-
for job in self.jobs:
10182-
jobs.append(job.to_dict())
10210+
jobs = self.get_jobs_dict()
1018310211

1018410212
outputs = {}
1018510213
for output_assoc in self.output_datasets:

lib/galaxy/tool_util/verify/interactor.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,6 @@ def verify_output(self, history_id, jobs, output_data, output_testdef, tool_id,
332332
attributes = output_testdef.attributes
333333
name = output_testdef.name
334334
expected_count = attributes.get("count")
335-
self.wait_for_jobs(history_id, jobs, maxseconds)
336335
hid = self.__output_id(output_data)
337336
# TODO: Twill version verifies dataset is 'ok' in here.
338337
try:

lib/galaxy/tools/execute.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,10 @@ def finalize_dataset_collections(self, trans):
659659
# We mark this here so that the job cache query in subsequent
660660
# jobs considers this to be a valid cached input.
661661
completed_job_ids = {job.id for job in self.completed_jobs.values() if job}
662-
if all(job.copied_from_job_id in completed_job_ids for job in self.implicit_collection_jobs.job_list):
662+
completed_implicit_jobs_copied_from = set(
663+
self.implicit_collection_jobs.get_job_attributes(["copied_from_job_id"]).all()
664+
)
665+
if completed_implicit_jobs_copied_from <= completed_job_ids:
663666
completed_collections = {
664667
jtodca.name: jtodca.dataset_collection_instance
665668
for jtodca in self.completed_jobs[0].output_dataset_collection_instances

0 commit comments

Comments
 (0)