import { computed, type Ref, ref, unref } from "vue"; import { type DCEDataset, type DCESummary, type HistoryItemSummary, isDatasetElement, isHistoryItem } from "@/api"; import { copyDataset, type HistoryContentSource, type HistoryContentType } from "@/api/datasets"; import { Toast } from "@/composables/toast"; import { useEventStore } from "@/stores/eventStore"; import { useHistoryStore } from "@/stores/historyStore"; type DraggableHistoryItem = HistoryItemSummary | DCEDataset; // TODO: DCESummary instead of DCEDataset interface HistoryItemCopyData { dataSource: HistoryContentSource; type: HistoryContentType; id: string; } export function useHistoryDragDrop(targetHistoryId?: Ref | string, createNew = false, pinHistories = false) { // convert destinationHistoryId to a ref if it's not already const destinationHistoryId = computed(() => { if (typeof targetHistoryId === "string") { return targetHistoryId; } return unref(targetHistoryId); }); const eventStore = useEventStore(); const historyStore = useHistoryStore(); const fromHistoryId = computed(() => { const dragItems = getDragItems(); return dragItems[0] ? isHistoryItem(dragItems[0]) ? dragItems[0].history_id : dragItems[0].object?.history_id : null; }); const showDropZone = ref(false); const dragTarget = ref(null); const processingDrop = ref(false); const operationDisabled = computed( () => !fromHistoryId.value || (destinationHistoryId.value && fromHistoryId.value === destinationHistoryId.value) || (!createNew && !destinationHistoryId.value) || !getDragItems().length || processingDrop.value, ); function getDragItems() { const storeItems = eventStore.getDragItems(); // Filter out any non-history or `DatasetCollectionElement` items return storeItems?.filter( (item) => isHistoryItem(item) || isDatasetElement(item as DCESummary), ) as DraggableHistoryItem[]; } function onDragEnter(e: DragEvent) { if (operationDisabled.value) { return; } dragTarget.value = e.target; showDropZone.value = true; } function onDragOver(e: DragEvent) { if (operationDisabled.value) { return; } e.preventDefault(); } function onDragLeave(e: DragEvent) { if (operationDisabled.value) { return; } if (dragTarget.value === e.target) { showDropZone.value = false; } } async function onDrop() { showDropZone.value = false; if (operationDisabled.value) { return; } processingDrop.value = true; let datasetCount = 0; let collectionCount = 0; try { const dragItems = getDragItems(); const multiple = dragItems.length > 1; const originalHistoryId = fromHistoryId.value as string; let historyId; if (destinationHistoryId.value) { historyId = destinationHistoryId.value; } else if (createNew) { await historyStore.createNewHistory(); historyId = historyStore.currentHistoryId; } else { historyId = null; } if (!historyId) { throw new Error("Destination history not found or created"); } const copyableItems: HistoryItemCopyData[] = []; // iterate over the data array and get valid copyable items for (const item of dragItems) { let copyableItem: HistoryItemCopyData; if (isHistoryItem(item)) { copyableItem = { dataSource: item.history_content_type === "dataset" ? "hda" : "hdca", type: item.history_content_type, id: item.id, }; } // For DCEs, only `DCEDataset`s are droppable, `DCEDatasetCollection`s are not else if (isDatasetElement(item) && item.object) { copyableItem = { dataSource: "hda", type: "dataset", id: item.object.id, }; } else { throw new Error(`Invalid item type${item.element_type ? `: ${item.element_type}` : ""}`); } copyableItems.push(copyableItem); } // iterate over the data array and copy each item to the current history for (const item of copyableItems) { const { dataSource, type, id } = item; await copyDataset(id, historyId, type, dataSource); if (dataSource === "hda") { datasetCount++; if (!multiple) { Toast.info(`Dataset copied to ${createNew ? "new" : ""} history`); } } else { collectionCount++; if (!multiple) { Toast.info(`Collection copied to ${createNew ? "new" : ""} history`); } } } if (multiple && datasetCount > 0) { Toast.info( `${datasetCount} dataset${datasetCount > 1 ? "s" : ""} copied to ${createNew ? "new" : ""} history`, ); } if (multiple && collectionCount > 0) { Toast.info( `${collectionCount} collection${collectionCount > 1 ? "s" : ""} copied to ${ createNew ? "new" : "" } history`, ); } // if items were copied if (datasetCount > 0 && collectionCount > 0) { if (pinHistories && historyStore.pinnedHistories.length > 0) { // pin the target history historyStore.pinHistory(historyId); // also pin the original history where the item came from historyStore.pinHistory(originalHistoryId); } else { historyStore.loadHistoryById(historyId); } } } catch (error) { Toast.error(`${error}`); } finally { processingDrop.value = false; } } return { showDropZone, onDragEnter, onDragOver, onDragLeave, onDrop, }; }