@@ -4,7 +4,16 @@ import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
44import { BAlert , BFormCheckbox } from " bootstrap-vue" ;
55import { computed , onMounted , type Ref , ref , watch } from " vue" ;
66
7- import { isDatasetElement , isDCE } from " @/api" ;
7+ import {
8+ type DCESummary ,
9+ type HDAObject ,
10+ type HistoryItemSummary ,
11+ isDatasetElement ,
12+ isDCE ,
13+ isHDCA ,
14+ isHistoryItem ,
15+ } from " @/api" ;
16+ import type { HistoryContentType } from " @/api/datasets" ;
817import { getGalaxyInstance } from " @/app" ;
918import type { CollectionType } from " @/components/History/adapters/buildCollectionModal" ;
1019import { useDatatypesMapper } from " @/composables/datatypesMapper" ;
@@ -27,6 +36,8 @@ type SelectOption = {
2736 value: DataOption | null ;
2837};
2938
39+ type HistoryOrCollectionItem = HistoryItemSummary | DCESummary ;
40+
3041const props = withDefaults (
3142 defineProps <{
3243 loading? : boolean ;
@@ -51,7 +62,7 @@ const props = withDefaults(
5162 value: undefined ,
5263 extensions : () => [],
5364 type: " data" ,
54- collectionTypes: undefined ,
65+ collectionTypes : () => [] ,
5566 flavor: undefined ,
5667 tag: undefined ,
5768 userDefinedTitle: undefined ,
@@ -73,7 +84,7 @@ const currentField = ref(0);
7384const currentHighlighting: Ref <string | null > = ref (null );
7485
7586// Drag/Drop related values
76- const dragData: Ref <EventData | null > = ref (null );
87+ const dragData: Ref <EventData [] > = ref ([] );
7788const dragTarget: Ref <EventTarget | null > = ref (null );
7889
7990const workflowTab = ref (" " );
@@ -339,35 +350,50 @@ function getSourceType(val: DataOption) {
339350}
340351
341352/** Add values from drag/drop or data dialog sources */
342- function handleIncoming(incoming : Record <string , unknown >, partial = true ) {
353+ function handleIncoming(incoming : Record <string , unknown > | Record < string , unknown >[] , partial = true ) {
343354 if (incoming ) {
344355 const values = Array .isArray (incoming ) ? incoming : [incoming ];
345- const extensions = values .map ((v ) => v .extension || v .elements_datatypes ).filter ((v ) => (v ? true : false ));
356+
357+ // ensure all incoming values are isHistoryOrCollectionItem
358+ if (! values .every (isHistoryOrCollectionItem )) {
359+ return false ;
360+ }
361+
362+ const extensions = Array .from (
363+ new Set (
364+ values
365+ .map (getExtensionsForItem )
366+ .flat ()
367+ .filter ((v ) => v !== null && v !== undefined )
368+ )
369+ ) as string [];
370+
346371 if (! canAcceptDatatype (extensions )) {
347372 return false ;
348373 }
349- if (values .some ((v ) => ! canAcceptSrc (v .history_content_type , v .collection_type ))) {
374+ if (
375+ values .some ((v ) => {
376+ const { historyContentType } = getSrcAndContentType (v );
377+ const collectionType = " collection_type" in v && v .collection_type ? v .collection_type : undefined ;
378+ return ! canAcceptSrc (historyContentType , collectionType );
379+ })
380+ ) {
350381 return false ;
351382 }
352383 if (values .length > 0 ) {
353384 const incomingValues: Array <DataOption > = [];
354- values .forEach ((v ) => {
385+ values .forEach ((currVal ) => {
355386 // Map incoming objects to data option values
356- let newSrc;
357- if (isDCE (v )) {
358- if (isDatasetElement (v )) {
359- newSrc = SOURCE .DATASET ;
360- v = v .object ;
361- } else {
362- newSrc = SOURCE .COLLECTION_ELEMENT ;
363- }
387+ const { newSrc, datasetCollectionDataset } = getSrcAndContentType (currVal );
388+ let v: HistoryOrCollectionItem | HDAObject ;
389+ if (datasetCollectionDataset ) {
390+ v = datasetCollectionDataset ;
364391 } else {
365- newSrc =
366- v .src || (v .history_content_type === " dataset_collection" ? SOURCE .COLLECTION : SOURCE .DATASET );
392+ v = currVal ;
367393 }
368- const newHid = v .hid ;
394+ const newHid = isHistoryItem ( v ) ? v .hid : undefined ;
369395 const newId = v .id ;
370- const newName = v .name ? v .name : newId ;
396+ const newName = isHistoryItem ( v ) && v .name ? v .name : newId ;
371397 const newValue: DataOption = {
372398 id: newId ,
373399 src: newSrc ,
@@ -378,10 +404,11 @@ function handleIncoming(incoming: Record<string, unknown>, partial = true) {
378404 keep: true ,
379405 tags: [],
380406 };
381- if (v .collection_type && props .collectionTypes ?.length > 0 ) {
382- if (! props .collectionTypes .includes (v .collection_type )) {
407+ if (isHistoryItem (v ) && isHDCA (v ) && props .collectionTypes ?.length > 0 ) {
408+ const itemCollectionType = v .collection_type ;
409+ if (! props .collectionTypes .includes (itemCollectionType as CollectionType )) {
383410 const mapOverType = props .collectionTypes .find ((collectionType ) =>
384- v . collection_type .endsWith (collectionType )
411+ itemCollectionType .endsWith (collectionType )
385412 );
386413 if (! mapOverType ) {
387414 return false ;
@@ -445,6 +472,9 @@ function onBrowse() {
445472}
446473
447474function canAcceptDatatype(itemDatatypes : string | Array <string >) {
475+ // TODO: Shouldn't we enforce a datatype (at least "data") because of the case:
476+ // What if the drop item is a `DCESummary`, then it has no extension (?) and we
477+ // pass it as a valid item regardless of its elements' datatypes.
448478 if (! (props .extensions ?.length > 0 ) || props .extensions .includes (" data" )) {
449479 return true ;
450480 }
@@ -463,7 +493,40 @@ function canAcceptDatatype(itemDatatypes: string | Array<string>) {
463493 return true ;
464494}
465495
466- function canAcceptSrc(historyContentType : " dataset" | " dataset_collection" , collectionType ? : CollectionType ) {
496+ /**
497+ * Given an element, determine the source and content type.
498+ * Also returns the collection element dataset object if it exists.
499+ */
500+ function getSrcAndContentType(element : HistoryOrCollectionItem ): {
501+ historyContentType: HistoryContentType ;
502+ newSrc: string ;
503+ datasetCollectionDataset: HDAObject | undefined ;
504+ } {
505+ let historyContentType: HistoryContentType ;
506+ let newSrc: string ;
507+ let datasetCollectionDataset: HDAObject | undefined ;
508+ if (isDCE (element )) {
509+ if (isDatasetElement (element )) {
510+ historyContentType = " dataset" ;
511+ newSrc = SOURCE .DATASET ;
512+ datasetCollectionDataset = element .object ;
513+ } else {
514+ historyContentType = " dataset_collection" ;
515+ newSrc = SOURCE .COLLECTION_ELEMENT ;
516+ }
517+ } else {
518+ historyContentType = element .history_content_type ;
519+ newSrc =
520+ " src" in element && typeof element .src === " string"
521+ ? element .src
522+ : historyContentType === " dataset_collection"
523+ ? SOURCE .COLLECTION
524+ : SOURCE .DATASET ;
525+ }
526+ return { historyContentType , newSrc , datasetCollectionDataset };
527+ }
528+
529+ function canAcceptSrc(historyContentType : " dataset" | " dataset_collection" , collectionType ? : string ) {
467530 if (historyContentType === " dataset" ) {
468531 // HDA can only be fed into data parameters, not collection parameters
469532 if (props .type === " data" ) {
@@ -485,7 +548,7 @@ function canAcceptSrc(historyContentType: "dataset" | "dataset_collection", coll
485548 // if no collection_type is set all collections are valid
486549 return true ;
487550 } else {
488- if (props .collectionTypes .includes (collectionType )) {
551+ if (props .collectionTypes .includes (collectionType as CollectionType )) {
489552 return true ;
490553 }
491554 if (props .collectionTypes .some ((element ) => collectionType .endsWith (element ))) {
@@ -511,31 +574,37 @@ const effectiveCollectionTypes = props.collectionTypes?.filter((collectionType)
511574);
512575const currentCollectionTypeTab = ref (effectiveCollectionTypes ?.[0 ]);
513576
577+ /**
578+ * Get the extension(s) for a given item
579+ */
580+ function getExtensionsForItem(item : HistoryOrCollectionItem ): string | string [] | null {
581+ return " extension" in item ? item .extension : " elements_datatypes" in item ? item .elements_datatypes : null ;
582+ }
583+
584+ function isHistoryOrCollectionItem(item : EventData ): item is HistoryOrCollectionItem {
585+ return isHistoryItem (item ) || isDCE (item );
586+ }
587+
514588// Drag/Drop event handlers
515589function onDragEnter(evt : DragEvent ) {
516- const eventData = eventStore .getDragData ();
517- if (eventData ) {
518- let eventFiles: any [];
519- if (eventStore .multipleDragData ) {
520- eventFiles = Object .values (eventData );
521- } else {
522- eventFiles = [eventData ];
523- }
590+ const eventData = eventStore .getDragItems ();
524591
592+ if (eventData ?.length ) {
525593 let highlightingState = " success" ;
526- for (const eventFile of eventFiles ) {
527- const extensions = (eventFile .extension as string ) || (eventFile .elements_datatypes as Array <string >);
528- if (! canAcceptDatatype (extensions )) {
529- highlightingState = " warning" ;
530- $emit (" alert" , ` ${extensions } is not an acceptable format for this parameter. ` );
531- } else if (
532- ! canAcceptSrc (
533- eventFile .history_content_type as " dataset" | " dataset_collection" ,
534- eventFile .collection_type as CollectionType
535- )
536- ) {
537- highlightingState = " warning" ;
538- $emit (" alert" , ` ${eventFile .history_content_type } is not an acceptable input type for this parameter. ` );
594+ for (const item of eventData ) {
595+ if (isHistoryOrCollectionItem (item )) {
596+ const extensions = getExtensionsForItem (item );
597+ const { historyContentType } = getSrcAndContentType (item );
598+ const collectionType =
599+ " collection_type" in item && item .collection_type ? item .collection_type : undefined ;
600+
601+ if (extensions && ! canAcceptDatatype (extensions )) {
602+ highlightingState = " warning" ;
603+ $emit (" alert" , ` ${extensions } is not an acceptable format for this parameter. ` );
604+ } else if (! canAcceptSrc (historyContentType , collectionType )) {
605+ highlightingState = " warning" ;
606+ $emit (" alert" , ` ${historyContentType } is not an acceptable input type for this parameter. ` );
607+ }
539608 }
540609 }
541610 currentHighlighting .value = highlightingState ;
@@ -568,14 +637,8 @@ function onDragLeave(evt: DragEvent) {
568637}
569638
570639function onDrop(e : DragEvent ) {
571- if (dragData .value ) {
572- let accept = false ;
573- if (eventStore .multipleDragData ) {
574- accept = handleIncoming (Object .values (dragData .value ) as any , false );
575- } else {
576- accept = handleIncoming (dragData .value );
577- }
578- if (accept ) {
640+ if (dragData .value .length ) {
641+ if (handleIncoming (dragData .value , dragData .value .length === 1 )) {
579642 currentHighlighting .value = " success" ;
580643 if (props .workflowRun ) {
581644 workflowTab .value = " view" ;
@@ -584,11 +647,11 @@ function onDrop(e: DragEvent) {
584647 currentHighlighting .value = " warning" ;
585648 }
586649 $emit (" alert" , undefined );
587- dragData .value = null ;
650+ dragData .value = [] ;
588651 clearHighlighting ();
589652 } else if (props .workflowRun && e .dataTransfer ?.files ?.length ) {
590653 $emit (" alert" , undefined );
591- dragData .value = null ;
654+ dragData .value = [] ;
592655 clearHighlighting ();
593656 }
594657}
0 commit comments