From e40d3787ef4674f08ff7a8258b6d98bc84a3ce7e Mon Sep 17 00:00:00 2001 From: Ahmed Awan Date: Mon, 4 Mar 2024 10:14:26 -0600 Subject: [PATCH 01/46] tab navigates to `ContentOptions` instead of next item Users can use arrows keys to go to the next/prev item. Tab key will instead help navigate through the `ContentOptions` (and other item actions if expanded) --- .../src/components/History/Content/ContentItem.vue | 1 - .../components/History/Content/ContentOptions.vue | 13 +++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/client/src/components/History/Content/ContentItem.vue b/client/src/components/History/Content/ContentItem.vue index 1e56b0a0d451..609f5d60a900 100644 --- a/client/src/components/History/Content/ContentItem.vue +++ b/client/src/components/History/Content/ContentItem.vue @@ -66,7 +66,6 @@ :is-visible="item.visible" :state="state" :item-urls="itemUrls" - :keyboard-selectable="isCollection || expandDataset" @delete="onDelete" @display="onDisplay" @showCollectionInfo="onShowCollectionInfo" diff --git a/client/src/components/History/Content/ContentOptions.vue b/client/src/components/History/Content/ContentOptions.vue index 4cc1fe03fdea..d3f55ba2b275 100644 --- a/client/src/components/History/Content/ContentOptions.vue +++ b/client/src/components/History/Content/ContentOptions.vue @@ -12,7 +12,6 @@ const props = defineProps({ isVisible: { type: Boolean, default: true }, state: { type: String, default: "" }, itemUrls: { type: Object, required: true }, - keyboardSelectable: { type: Boolean, default: true }, }); const emit = defineEmits<{ @@ -46,8 +45,6 @@ const canShowCollectionDetails = computed(() => props.itemUrls.showDetails); const showCollectionDetailsUrl = computed(() => prependPath(props.itemUrls.showDetails)); -const tabindex = computed(() => (props.keyboardSelectable ? "0" : "-1")); - function onDelete($event: MouseEvent) { if (isCollection.value) { deleteCollectionMenu.value?.show(); @@ -94,7 +91,7 @@ function onDisplay($event: MouseEvent) { v-if="isDataset" :disabled="displayDisabled" :title="displayButtonTitle" - :tabindex="tabindex" + tabindex="0" class="display-btn px-1" size="sm" variant="link" @@ -106,7 +103,7 @@ function onDisplay($event: MouseEvent) { v-if="writable && isHistoryItem" :disabled="editDisabled" :title="editButtonTitle" - :tabindex="tabindex" + tabindex="0" class="edit-btn px-1" size="sm" variant="link" @@ -116,7 +113,7 @@ function onDisplay($event: MouseEvent) { Date: Mon, 4 Mar 2024 10:31:43 -0600 Subject: [PATCH 02/46] make ctrl/command(meta) keydown events cross platform (mac) --- client/src/components/History/Content/ContentItem.vue | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/client/src/components/History/Content/ContentItem.vue b/client/src/components/History/Content/ContentItem.vue index 609f5d60a900..c085546afbec 100644 --- a/client/src/components/History/Content/ContentItem.vue +++ b/client/src/components/History/Content/ContentItem.vue @@ -229,6 +229,10 @@ export default { }, }, methods: { + isCtrlKey(event) { + const isMac = navigator.userAgent.indexOf("Mac") >= 0; + return isMac ? event.metaKey : event.ctrlKey; + }, onKeyDown(event) { if (!event.target.classList.contains("content-item")) { return; @@ -248,13 +252,13 @@ export default { } else if (event.key === "Escape") { event.preventDefault(); this.$emit("hide-selection"); - } else if (event.key === "a" && event.ctrlKey) { + } else if (event.key === "a" && this.isCtrlKey(event)) { event.preventDefault(); this.$emit("select-all"); } }, onClick(event) { - if (event && event.ctrlKey) { + if (event && this.isCtrlKey(event)) { this.$emit("update:selected", !this.selected); } else if (this.isPlaceholder) { return; From af0921989b92922a8af31b00769705c09196676f Mon Sep 17 00:00:00 2001 From: Ahmed Awan Date: Mon, 4 Mar 2024 10:32:47 -0600 Subject: [PATCH 03/46] toggle select all on/off if user uses ctrl-a --- client/src/components/History/Content/SelectedItems.js | 7 ++++++- .../src/components/History/CurrentHistory/HistoryPanel.vue | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/client/src/components/History/Content/SelectedItems.js b/client/src/components/History/Content/SelectedItems.js index c79d63080741..8185b3cd71c3 100644 --- a/client/src/components/History/Content/SelectedItems.js +++ b/client/src/components/History/Content/SelectedItems.js @@ -36,7 +36,12 @@ export default { setShowSelection(val) { this.showSelection = val; }, - selectAllInCurrentQuery(loadedItems = []) { + selectAllInCurrentQuery(loadedItems = [], force = true) { + // if we are not forcing selectAll, and all items are already selected; deselect them + if (!force && this.allSelected) { + this.setShowSelection(false); + return; + } this.selectItems(loadedItems); this.allSelected = true; }, diff --git a/client/src/components/History/CurrentHistory/HistoryPanel.vue b/client/src/components/History/CurrentHistory/HistoryPanel.vue index 9fcb25c3e14a..554321cf4254 100644 --- a/client/src/components/History/CurrentHistory/HistoryPanel.vue +++ b/client/src/components/History/CurrentHistory/HistoryPanel.vue @@ -589,7 +589,7 @@ function setItemDragstart( " @hide-selection="setShowSelection(false)" @shift-select="(eventKey) => shiftSelect(nextSelections(item, eventKey))" - @select-all="selectAllInCurrentQuery(historyItems)" + @select-all="selectAllInCurrentQuery(historyItems, false)" @tag-click="updateFilterValue('tag', $event)" @tag-change="onTagChange" @toggleHighlights="updateFilterValue('related', item.hid)" From eff893b46f04b1c36578184a1c3ec977ffdc07d7 Mon Sep 17 00:00:00 2001 From: Ahmed Awan Date: Mon, 4 Mar 2024 10:48:34 -0600 Subject: [PATCH 04/46] fix `HistoryPanel` multi item drop text --- client/src/components/History/CurrentHistory/HistoryPanel.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/components/History/CurrentHistory/HistoryPanel.vue b/client/src/components/History/CurrentHistory/HistoryPanel.vue index 554321cf4254..bb4f90ac80d2 100644 --- a/client/src/components/History/CurrentHistory/HistoryPanel.vue +++ b/client/src/components/History/CurrentHistory/HistoryPanel.vue @@ -361,10 +361,10 @@ async function onDrop(evt: any) { } if (multiple && datasetCount > 0) { - Toast.info(`${datasetCount} datasets copied to history`); + Toast.info(`${datasetCount} dataset${datasetCount > 1 ? "s" : ""} copied to new history`); } if (multiple && collectionCount > 0) { - Toast.info(`${collectionCount} collections copied to history`); + Toast.info(`${collectionCount} collection${collectionCount > 1 ? "s" : ""} copied to new history`); } historyStore.loadHistoryById(props.history.id); } catch (error) { From f57504b6b38a583cd2c51cf64856eafe7672d391 Mon Sep 17 00:00:00 2001 From: Ahmed Awan Date: Mon, 4 Mar 2024 13:53:27 -0600 Subject: [PATCH 05/46] unselect a `ContentItem` when deleted/undeleted --- client/src/components/History/Content/ContentItem.vue | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/src/components/History/Content/ContentItem.vue b/client/src/components/History/Content/ContentItem.vue index c085546afbec..6d5a548b3f30 100644 --- a/client/src/components/History/Content/ContentItem.vue +++ b/client/src/components/History/Content/ContentItem.vue @@ -70,7 +70,7 @@ @display="onDisplay" @showCollectionInfo="onShowCollectionInfo" @edit="onEdit" - @undelete="$emit('undelete')" + @undelete="onUndelete" @unhide="$emit('unhide')" /> @@ -288,6 +288,11 @@ export default { }, onDelete(recursive = false) { this.$emit("delete", this.item, recursive); + this.$emit("update:selected", false); + }, + onUndelete() { + this.$emit("undelete"); + this.$emit("update:selected", false); }, onDragStart(evt) { this.$emit("drag-start", evt); From 2331e4d8c3b868f4a6356101fd3236b865065672 Mon Sep 17 00:00:00 2001 From: Ahmed Awan Date: Mon, 4 Mar 2024 14:24:47 -0600 Subject: [PATCH 06/46] add `Shift+Click` (and `Shift+Ctrl+Click`) selection Users can select a batch of items starting from one focused item, until the next `Shift+Click` item. If the user uses a combination of `Shift+Ctrl+Click`, the remainder of the selection persists and is not reset. --- .../History/Content/ContentItem.vue | 18 ++++++-- .../History/Content/SelectedItems.js | 45 ++++++++++++++++--- .../History/CurrentHistory/HistoryPanel.vue | 37 +++++++++------ 3 files changed, 78 insertions(+), 22 deletions(-) diff --git a/client/src/components/History/Content/ContentItem.vue b/client/src/components/History/Content/ContentItem.vue index 6d5a548b3f30..a17182251a19 100644 --- a/client/src/components/History/Content/ContentItem.vue +++ b/client/src/components/History/Content/ContentItem.vue @@ -6,7 +6,8 @@ :data-state="dataState" tabindex="0" role="button" - @keydown="onKeyDown"> + @keydown="onKeyDown" + @focus="$emit('update:item-focused')">
@@ -245,7 +246,10 @@ export default { this.$emit("shift-select", event.key); } else if (event.key === "ArrowUp" || event.key === "ArrowDown") { event.preventDefault(); + this.$emit("init-key-selection"); this.$emit("arrow-navigate", event.key); + } else if (event.key === "Tab") { + this.$emit("init-key-selection"); } else if (event.key === "Delete" && !this.selected && !this.item.deleted) { event.preventDefault(); this.onDelete(event.shiftKey); @@ -258,11 +262,17 @@ export default { } }, onClick(event) { - if (event && this.isCtrlKey(event)) { + if (event && event.shiftKey && this.isCtrlKey(event)) { + this.$emit("selected-to", false); + } else if (event && this.isCtrlKey(event)) { + this.$emit("init-key-selection"); this.$emit("update:selected", !this.selected); + } else if (event && event.shiftKey) { + this.$emit("selected-to", true); } else if (this.isPlaceholder) { - return; + this.$emit("init-key-selection"); } else if (this.isDataset) { + this.$emit("init-key-selection"); this.$emit("update:expand-dataset", !this.expandDataset); } else { this.$emit("view-collection", this.item, this.name); @@ -289,10 +299,12 @@ export default { onDelete(recursive = false) { this.$emit("delete", this.item, recursive); this.$emit("update:selected", false); + this.$emit("init-key-selection"); }, onUndelete() { this.$emit("undelete"); this.$emit("update:selected", false); + this.$emit("init-key-selection"); }, onDragStart(evt) { this.$emit("drag-start", evt); diff --git a/client/src/components/History/Content/SelectedItems.js b/client/src/components/History/Content/SelectedItems.js index 8185b3cd71c3..7a0d3a24196f 100644 --- a/client/src/components/History/Content/SelectedItems.js +++ b/client/src/components/History/Content/SelectedItems.js @@ -17,7 +17,7 @@ export default { items: new Map(), showSelection: false, allSelected: false, - initSelectedKey: null, + initSelectedItem: null, initDirection: null, }; }, @@ -31,6 +31,9 @@ export default { currentFilters() { return HistoryFilters.getFiltersForText(this.filterText); }, + initSelectedKey() { + return this.initSelectedItem ? this.getItemKey(this.initSelectedItem) : null; + }, }, methods: { setShowSelection(val) { @@ -59,10 +62,10 @@ export default { this.items = newSelected; this.breakQuerySelection(); }, - shiftSelect({ item, nextItem, eventKey }) { + shiftSelect(item, nextItem, eventKey) { const currentItemKey = this.getItemKey(item); - if (!this.initDirection) { - this.initSelectedKey = currentItemKey; + if (!this.initSelectedKey) { + this.initSelectedItem = item; this.initDirection = eventKey; this.setSelected(item, true); } @@ -82,8 +85,39 @@ export default { this.setSelected(nextItem, true); } }, + selectTo(item, prevItem, allItems, reset = true) { + if (prevItem && item) { + // we are staring a new shift+click selectTo from `prevItem` + if (!this.initSelectedKey) { + this.initSelectedItem = prevItem; + } + + // `reset = false` in the case user is holding shift+ctrl key + if (reset) { + // clear this.items of any other selections + this.items = new Map(); + } + this.setSelected(this.initSelectedItem, true); + + const initItemIndex = allItems.indexOf(this.initSelectedItem); + const currentItemIndex = allItems.indexOf(item); + + let selections = []; + // from allItems, get the items between the init item and the current item + if (initItemIndex < currentItemIndex) { + this.initDirection = "ArrowDown"; + selections = allItems.slice(initItemIndex + 1, currentItemIndex + 1); + } else if (initItemIndex > currentItemIndex) { + this.initDirection = "ArrowUp"; + selections = allItems.slice(currentItemIndex, initItemIndex); + } + this.selectItems(selections); + } else { + this.setSelected(item, true); + } + }, initKeySelection() { - this.initSelectedKey = null; + this.initSelectedItem = null; this.initDirection = null; }, selectItems(items = []) { @@ -142,6 +176,7 @@ export default { setShowSelection: this.setShowSelection, selectAllInCurrentQuery: this.selectAllInCurrentQuery, selectItems: this.selectItems, + selectTo: this.selectTo, isSelected: this.isSelected, setSelected: this.setSelected, resetSelection: this.reset, diff --git a/client/src/components/History/CurrentHistory/HistoryPanel.vue b/client/src/components/History/CurrentHistory/HistoryPanel.vue index bb4f90ac80d2..6f863bdb4deb 100644 --- a/client/src/components/History/CurrentHistory/HistoryPanel.vue +++ b/client/src/components/History/CurrentHistory/HistoryPanel.vue @@ -82,6 +82,8 @@ const contentItemRefs = computed(() => { return acc; }, {}); }); +const currItemFocused = ref(null); +const lastItemFocused = ref(null); const { currentFilterText, currentHistoryId } = storeToRefs(useHistoryStore()); const { lastCheckedTime, totalMatchesCount, isWatching } = storeToRefs(useHistoryItemsStore()); @@ -149,6 +151,8 @@ watch( invisibleHistoryItems.value = {}; offsetQueryParam.value = 0; loadHistoryItems(); + currItemFocused.value = null; + lastItemFocused.value = null; } ); @@ -176,6 +180,8 @@ watch( (newValue, currentValue) => { if (newValue !== currentValue) { operationRunning.value = null; + currItemFocused.value = null; + lastItemFocused.value = null; } } ); @@ -193,6 +199,15 @@ watch(historyItems, (newHistoryItems) => { } }); +watch( + () => currItemFocused.value, + (newItem, oldItem) => { + if (newItem) { + lastItemFocused.value = oldItem; + } + } +); + function getHighlight(item: HistoryItem) { if (unref(isLoading)) { return undefined; @@ -389,15 +404,6 @@ onMounted(async () => { await loadHistoryItems(); }); -function nextSelections(item: HistoryItem, eventKey: string) { - const nextItem = arrowNavigate(item, eventKey); - return { - item, - nextItem, - eventKey, - }; -} - function arrowNavigate(item: HistoryItem, eventKey: string) { let nextItem = null; if (eventKey === "ArrowDown") { @@ -444,6 +450,7 @@ function setItemDragstart( setShowSelection, selectAllInCurrentQuery, isSelected, + selectTo, setSelected, shiftSelect, initKeySelection, @@ -574,10 +581,7 @@ function setItemDragstart( :selected="isSelected(item)" :selectable="showSelection" :filterable="filterable" - @arrow-navigate=" - arrowNavigate(item, $event); - initKeySelection(); - " + @arrow-navigate="arrowNavigate(item, $event)" @drag-start=" setItemDragstart( item, @@ -588,12 +592,17 @@ function setItemDragstart( ) " @hide-selection="setShowSelection(false)" - @shift-select="(eventKey) => shiftSelect(nextSelections(item, eventKey))" + @init-key-selection="initKeySelection" + @shift-select=" + (eventKey) => shiftSelect(item, arrowNavigate(item, eventKey), eventKey) + " @select-all="selectAllInCurrentQuery(historyItems, false)" + @selected-to="(reset) => selectTo(item, lastItemFocused, historyItems, reset)" @tag-click="updateFilterValue('tag', $event)" @tag-change="onTagChange" @toggleHighlights="updateFilterValue('related', item.hid)" @update:expand-dataset="setExpanded(item, $event)" + @update:item-focused="currItemFocused = item" @update:selected="setSelected(item, $event)" @view-collection="$emit('view-collection', item, currentOffset)" @delete="onDelete" From 0dbc86ccba2f7d2ead83d1ab400da06e1d47e840 Mon Sep 17 00:00:00 2001 From: Ahmed Awan Date: Tue, 5 Mar 2024 13:24:35 -0600 Subject: [PATCH 07/46] convert `ContentItem` to composition api+ts --- .../History/Content/ContentItem.test.js | 24 +- .../History/Content/ContentItem.vue | 560 ++++++++++-------- .../Content/Dataset/DatasetActions.vue | 14 +- .../History/Content/Dataset/index.ts | 10 +- .../History/Content/model/states.ts | 2 +- 5 files changed, 343 insertions(+), 267 deletions(-) diff --git a/client/src/components/History/Content/ContentItem.test.js b/client/src/components/History/Content/ContentItem.test.js index fba74e873824..269df341756c 100644 --- a/client/src/components/History/Content/ContentItem.test.js +++ b/client/src/components/History/Content/ContentItem.test.js @@ -5,6 +5,8 @@ import { PiniaVuePlugin } from "pinia"; import { getLocalVue } from "tests/jest/helpers"; import VueRouter from "vue-router"; +import { mockFetcher } from "@/api/schema/__mocks__"; + import ContentItem from "./ContentItem"; jest.mock("components/History/model/queries"); @@ -14,23 +16,31 @@ localVue.use(VueRouter); localVue.use(PiniaVuePlugin); const router = new VueRouter(); +jest.mock("vue-router/composables", () => ({ + useRoute: jest.fn(() => ({})), + useRouter: jest.fn(() => ({})), +})); + // mock queries updateContentFields.mockImplementation(async () => {}); +const item = { + id: "item_id", + some_data: "some_data", + tags: ["tag1", "tag2", "tag3"], + deleted: false, + visible: true, +}; + describe("ContentItem", () => { let wrapper; beforeEach(() => { + mockFetcher.path("/api/datasets/{dataset_id}").method("get").mock({ data: item }); wrapper = mount(ContentItem, { propsData: { expandDataset: true, - item: { - id: "item_id", - some_data: "some_data", - tags: ["tag1", "tag2", "tag3"], - deleted: false, - visible: true, - }, + item, id: 1, isDataset: true, isHistoryItem: true, diff --git a/client/src/components/History/Content/ContentItem.vue b/client/src/components/History/Content/ContentItem.vue index a17182251a19..744aef7130fc 100644 --- a/client/src/components/History/Content/ContentItem.vue +++ b/client/src/components/History/Content/ContentItem.vue @@ -1,3 +1,295 @@ + + - - From da8e1e1579eb17a26e8c0bb0c61680ecc679c9e8 Mon Sep 17 00:00:00 2001 From: Ahmed Awan Date: Thu, 7 Mar 2024 11:59:43 -0600 Subject: [PATCH 25/46] remove `UploadButton` from workflow `ToolBox` --- client/src/components/Panels/ToolBox.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/Panels/ToolBox.vue b/client/src/components/Panels/ToolBox.vue index 7296116bc834..29698f105af4 100644 --- a/client/src/components/Panels/ToolBox.vue +++ b/client/src/components/Panels/ToolBox.vue @@ -253,7 +253,7 @@ function setButtonText() { @onQuery="(q) => (query = q)" @onResults="onResults" />
- +
From b20a52b4c62a3387ac434dcb51e7ea5b2be6559f Mon Sep 17 00:00:00 2001 From: Ahmed Awan Date: Thu, 7 Mar 2024 12:00:11 -0600 Subject: [PATCH 26/46] fetch panel view in case the view string changes but panel isn't stored This can happen if the user has Galaxy open on 2 windows, and they changed the panel view, it will show up on one, and would keep loading on the other since the panel isn't populated (panel string is stored in `localStorage` and panel views in the pinia store; both don't get updated simultaneously. --- client/src/components/Panels/ToolPanel.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/components/Panels/ToolPanel.vue b/client/src/components/Panels/ToolPanel.vue index b95fbaf2ebe1..fa7f599df5ae 100644 --- a/client/src/components/Panels/ToolPanel.vue +++ b/client/src/components/Panels/ToolPanel.vue @@ -34,7 +34,7 @@ const emit = defineEmits<{ const arePanelsFetched = ref(false); const toolStore = useToolStore(); -const { currentPanelView, defaultPanelView, isPanelPopulated, loading, panelViews } = storeToRefs(toolStore); +const { currentPanelView, defaultPanelView, isPanelPopulated, loading, panel, panelViews } = storeToRefs(toolStore); const loadingView = ref(undefined); const query = ref(""); @@ -62,7 +62,7 @@ watch( watch( () => currentPanelView.value, async (newVal) => { - if (!newVal && arePanelsFetched.value) { + if ((!newVal || !panel.value[newVal]) && arePanelsFetched.value) { await initializeTools(); } } From 8bc5c7a88646bd3646050029504319453384fc3e Mon Sep 17 00:00:00 2001 From: Ahmed Awan Date: Thu, 7 Mar 2024 12:21:38 -0600 Subject: [PATCH 27/46] convert `FavoritesButton` to composition+ts... ... as this also fixes the "could not find icon" error. --- .../Panels/Buttons/FavoritesButton.vue | 114 +++++++++--------- 1 file changed, 59 insertions(+), 55 deletions(-) diff --git a/client/src/components/Panels/Buttons/FavoritesButton.vue b/client/src/components/Panels/Buttons/FavoritesButton.vue index 6c375eb30100..c7d285bb4253 100644 --- a/client/src/components/Panels/Buttons/FavoritesButton.vue +++ b/client/src/components/Panels/Buttons/FavoritesButton.vue @@ -1,5 +1,61 @@ + + - - From 4a57547e84ea1c2100cd8c18e8c649a183349414 Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Thu, 7 Mar 2024 20:05:45 +0100 Subject: [PATCH 28/46] Fix job manager unit tests --- test/unit/app/managers/test_JobConnectionsManager.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/unit/app/managers/test_JobConnectionsManager.py b/test/unit/app/managers/test_JobConnectionsManager.py index a9d482d2b916..5ec06f388fd7 100644 --- a/test/unit/app/managers/test_JobConnectionsManager.py +++ b/test/unit/app/managers/test_JobConnectionsManager.py @@ -25,10 +25,10 @@ def job_connections_manager(sa_session) -> JobConnectionsManager: # ============================================================================= def setup_connected_dataset(sa_session: galaxy_scoped_session): - center_hda = HistoryDatasetAssociation(sa_session=sa_session) - input_hda = HistoryDatasetAssociation(sa_session=sa_session) + center_hda = HistoryDatasetAssociation(sa_session=sa_session, create_dataset=True) + input_hda = HistoryDatasetAssociation(sa_session=sa_session, create_dataset=True) input_hdca = HistoryDatasetCollectionAssociation() - output_hda = HistoryDatasetAssociation(sa_session=sa_session) + output_hda = HistoryDatasetAssociation(sa_session=sa_session, create_dataset=True) output_hdca = HistoryDatasetCollectionAssociation() input_job = Job() output_job = Job() @@ -56,10 +56,10 @@ def setup_connected_dataset(sa_session: galaxy_scoped_session): def setup_connected_dataset_collection(sa_session: galaxy_scoped_session): center_hdca = HistoryDatasetCollectionAssociation() - input_hda1 = HistoryDatasetAssociation(sa_session=sa_session) - input_hda2 = HistoryDatasetAssociation(sa_session=sa_session) + input_hda1 = HistoryDatasetAssociation(sa_session=sa_session, create_dataset=True) + input_hda2 = HistoryDatasetAssociation(sa_session=sa_session, create_dataset=True) input_hdca = HistoryDatasetCollectionAssociation() - output_hda = HistoryDatasetAssociation(sa_session=sa_session) + output_hda = HistoryDatasetAssociation(sa_session=sa_session, create_dataset=True) output_hdca = HistoryDatasetCollectionAssociation() input_job = Job() output_job = Job() From 2896c3a18b7959469814658c5351913d6e9ffb1d Mon Sep 17 00:00:00 2001 From: Martin Cech Date: Thu, 7 Mar 2024 11:31:38 -0800 Subject: [PATCH 29/46] default sort all grid histories the same --- client/src/components/Grid/configs/historiesShared.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/Grid/configs/historiesShared.ts b/client/src/components/Grid/configs/historiesShared.ts index e3be64ff3f07..65a65e8a54ac 100644 --- a/client/src/components/Grid/configs/historiesShared.ts +++ b/client/src/components/Grid/configs/historiesShared.ts @@ -112,7 +112,7 @@ const gridConfig: GridConfig = { filtering: new Filtering(validFilters, undefined, false, false), getData: getData, plural: "Histories", - sortBy: "name", + sortBy: "update_time", sortDesc: true, sortKeys: ["create_time", "name", "update_time", "username"], title: "Shared Histories", From b8df73d58273e2056e05203c7bb2873530039ec5 Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Thu, 7 Mar 2024 21:09:27 +0100 Subject: [PATCH 30/46] Only set dataset.job if not set --- lib/galaxy/model/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/galaxy/model/__init__.py b/lib/galaxy/model/__init__.py index 69be939b521e..9495b3a82401 100644 --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -1633,7 +1633,10 @@ def add_input_dataset(self, name, dataset=None, dataset_id=None): def add_output_dataset(self, name, dataset): joda = JobToOutputDatasetAssociation(name, dataset) - dataset.dataset.job = self + if dataset.dataset.job is None: + # Only set job if dataset doesn't already have associated job. + # database operation tools that make copies should not modify the job here. + dataset.dataset.job = self add_object_to_object_session(self, joda) self.output_datasets.append(joda) From 8d95f36011a08a9def9378f8541656c6c2a4b586 Mon Sep 17 00:00:00 2001 From: Martin Cech Date: Thu, 7 Mar 2024 12:20:14 -0800 Subject: [PATCH 31/46] unify invocation icons --- .../components/History/CurrentHistory/HistoryNavigation.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/components/History/CurrentHistory/HistoryNavigation.vue b/client/src/components/History/CurrentHistory/HistoryNavigation.vue index 2db131d6ac52..79e730bd4faa 100644 --- a/client/src/components/History/CurrentHistory/HistoryNavigation.vue +++ b/client/src/components/History/CurrentHistory/HistoryNavigation.vue @@ -7,11 +7,11 @@ import { faExchangeAlt, faFileArchive, faFileExport, + faList, faLock, faPlay, faPlus, faShareAlt, - faSitemap, faStream, faTrash, faUserLock, @@ -50,7 +50,7 @@ library.add( faPlay, faPlus, faShareAlt, - faSitemap, + faList, faStream, faTrash, faUserLock @@ -204,7 +204,7 @@ function userTitle(title: string) { :disabled="isAnonymous" :title="userTitle('Display Workflow Invocations')" @click="$router.push(`/histories/${history.id}/invocations`)"> - + Show Invocations From 26b18c2cc187de10344849401b5d61f5f7692ec2 Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Thu, 7 Mar 2024 18:42:52 -0500 Subject: [PATCH 32/46] Fix workflow creator validation -- name can actually be empty if you specify givenName/family_name, etc. --- client/src/api/schema/schema.ts | 4 ++-- lib/galaxy/schema/schema.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index 9ba1ae1d2d83..b8ec4fbdce1e 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -9752,7 +9752,7 @@ export interface components { * Name * @description The name of the creator. */ - name: string; + name?: string | null; /** Telephone */ telephone?: string | null; /** URL */ @@ -12474,7 +12474,7 @@ export interface components { * Name * @description The name of the creator. */ - name: string; + name?: string | null; /** Telephone */ telephone?: string | null; /** URL */ diff --git a/lib/galaxy/schema/schema.py b/lib/galaxy/schema/schema.py index 1cf0729dd020..9391c03efd33 100644 --- a/lib/galaxy/schema/schema.py +++ b/lib/galaxy/schema/schema.py @@ -2275,7 +2275,7 @@ class SubworkflowStep(WorkflowStepBase): class Creator(Model): class_: str = Field(..., alias="class", title="Class", description="The class representing this creator.") - name: str = Field(..., title="Name", description="The name of the creator.") + name: Optional[str] = Field(None, title="Name", description="The name of the creator.") address: Optional[str] = Field( None, title="Address", From 07deeffc0c33f701c4c520f428ba8f694e7a20b4 Mon Sep 17 00:00:00 2001 From: Ahmed Awan Date: Thu, 7 Mar 2024 18:14:43 -0600 Subject: [PATCH 33/46] sync tool panel `filterText` to favorited tool(s) Fixes part 1 of https://github.com/galaxyproject/galaxy/issues/17150 --- .../components/Panels/Common/ToolSearch.vue | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/client/src/components/Panels/Common/ToolSearch.vue b/client/src/components/Panels/Common/ToolSearch.vue index 4f4e326c12ec..2b94c93a53ae 100644 --- a/client/src/components/Panels/Common/ToolSearch.vue +++ b/client/src/components/Panels/Common/ToolSearch.vue @@ -1,9 +1,10 @@