diff --git a/client/src/components/DragGhost.vue b/client/src/components/DragGhost.vue index 9f3219cba1b2..ae4dbfc6eaa4 100644 --- a/client/src/components/DragGhost.vue +++ b/client/src/components/DragGhost.vue @@ -2,6 +2,7 @@ import { library } from "@fortawesome/fontawesome-svg-core"; import { faPaperPlane } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; +import { storeToRefs } from "pinia"; import { useEventStore } from "stores/eventStore"; import { computed } from "vue"; @@ -10,9 +11,14 @@ import TextShort from "@/components/Common/TextShort.vue"; library.add(faPaperPlane); const eventStore = useEventStore(); +const { multipleDragData } = storeToRefs(eventStore); const name = computed(() => { const dragData = eventStore.getDragData(); + if (multipleDragData.value) { + const count = Object.keys(dragData).length; + return `${count} items`; + } return dragData?.name ?? "Draggable"; }); diff --git a/client/src/components/History/Content/ContentItem.vue b/client/src/components/History/Content/ContentItem.vue index a603f209c07b..580fee7866c3 100644 --- a/client/src/components/History/Content/ContentItem.vue +++ b/client/src/components/History/Content/ContentItem.vue @@ -113,7 +113,7 @@ import { updateContentFields } from "components/History/model/queries"; import StatelessTags from "components/TagsMultiselect/StatelessTags"; import { useEntryPointStore } from "stores/entryPointStore"; -import { clearDrag, setDrag } from "@/utils/setDrag.js"; +import { clearDrag } from "@/utils/setDrag.js"; import CollectionDescription from "./Collection/CollectionDescription"; import { JobStateSummary } from "./Collection/JobStateSummary"; @@ -287,9 +287,9 @@ export default { this.$emit("delete", this.item, recursive); }, onDragStart(evt) { - setDrag(evt, this.item); + this.$emit("drag-start", evt); }, - onDragEnd: function () { + onDragEnd() { clearDrag(); }, onEdit() { diff --git a/client/src/components/History/CurrentHistory/HistoryPanel.vue b/client/src/components/History/CurrentHistory/HistoryPanel.vue index a9b69c72d4ff..ea521be916e2 100644 --- a/client/src/components/History/CurrentHistory/HistoryPanel.vue +++ b/client/src/components/History/CurrentHistory/HistoryPanel.vue @@ -10,9 +10,11 @@ import { HistoryFilters } from "@/components/History/HistoryFilters"; import { deleteContent, updateContentFields } from "@/components/History/model/queries"; import { Toast } from "@/composables/toast"; import { startWatchingHistory } from "@/store/historyStore/model/watchHistory"; +import { useEventStore } from "@/stores/eventStore"; import { type HistoryItem, useHistoryItemsStore } from "@/stores/historyItemsStore"; import { useHistoryStore } from "@/stores/historyStore"; import { type Alias, getOperatorForAlias } from "@/utils/filtering"; +import { setDrag } from "@/utils/setDrag"; import HistoryCounter from "./HistoryCounter.vue"; import HistoryDetails from "./HistoryDetails.vue"; @@ -312,26 +314,45 @@ function onDragLeave(e: DragEvent) { } async function onDrop(evt: any) { + const eventStore = useEventStore(); showDropZone.value = false; - let data; + let data: HistoryItem[] | undefined; + let historyId: string | undefined; + const multiple = eventStore.multipleDragData; try { - data = JSON.parse(evt.dataTransfer.getData("text"))[0]; + if (multiple) { + const dragData = eventStore.getDragData() as Record; + // set historyId to the first history_id in the multiple drag data + const firstItem = Object.values(dragData)[0]; + if (firstItem) { + historyId = firstItem.history_id; + } + data = Object.values(dragData); + } else { + data = [eventStore.getDragData() as HistoryItem]; + if (data[0]) { + historyId = data[0].history_id; + } + } } catch (error) { // this was not a valid object for this dropzone, ignore } - if (!data || data.history_id === props.history.id) { + if (!data || historyId === props.history.id) { return; } try { - const dataSource = data.history_content_type === "dataset" ? "hda" : "hdca"; - await copyDataset(data.id, props.history.id, data.history_content_type, dataSource); - - if (data.history_content_type === "dataset") { - Toast.info("Dataset copied to history"); - } else { - Toast.info("Collection copied to history"); + // iterate over the data array and copy each item to the current history + for (const item of data) { + const dataSource = item.history_content_type === "dataset" ? "hda" : "hdca"; + await copyDataset(item.id, props.history.id, item.history_content_type, dataSource); + + if (item.history_content_type === "dataset") { + Toast.info("Dataset copied to history"); + } else { + Toast.info("Collection copied to history"); + } } historyStore.loadHistoryById(props.history.id); @@ -378,6 +399,24 @@ function arrowNavigate(item: HistoryItem, eventKey: string) { } return nextItem; } + +function setItemDragstart( + item: HistoryItem, + showSelection: boolean, + selectedItems: Map, + selectionSize: number, + event: DragEvent +) { + if (showSelection && selectionSize > 1) { + const selectedItemsObj: any = {}; + for (const [key, value] of selectedItems) { + selectedItemsObj[key] = value; + } + setDrag(event, selectedItemsObj, true); + } else { + setDrag(event, item as any); + } +}