From f7932e2742a33bc4d24d9b9ab957e2aef057bc4d Mon Sep 17 00:00:00 2001 From: John Chilton Date: Thu, 2 Jan 2025 12:52:10 -0500 Subject: [PATCH] Activity for rule builder imports. --- .../Collections/BuildFileSetWizard.vue | 59 +++++++++++++++++-- .../src/components/Collections/ListWizard.vue | 35 +++-------- .../Collections/RulesStandalone.vue | 35 +++++++++++ .../common/useCollectionCreator.ts | 22 ++++++- .../Common/Wizard/GenericWizard.vue | 11 +++- .../src/components/Common/Wizard/useWizard.ts | 6 ++ .../src/components/RuleCollectionBuilder.vue | 24 +++++--- .../src/components/Upload/UploadContainer.vue | 14 ----- client/src/entry/analysis/router.js | 11 ++++ client/src/stores/activitySetup.ts | 14 +++++ lib/galaxy/webapps/galaxy/buildapp.py | 1 + 11 files changed, 176 insertions(+), 56 deletions(-) create mode 100644 client/src/components/Collections/RulesStandalone.vue diff --git a/client/src/components/Collections/BuildFileSetWizard.vue b/client/src/components/Collections/BuildFileSetWizard.vue index 9d659ce1e528..c74a53202c37 100644 --- a/client/src/components/Collections/BuildFileSetWizard.vue +++ b/client/src/components/Collections/BuildFileSetWizard.vue @@ -3,6 +3,8 @@ import { BCardGroup } from "bootstrap-vue"; import { computed, ref } from "vue"; import { getGalaxyInstance } from "@/app"; +import { attemptCreate, type CollectionCreatorComponent } from "@/components/Collections/common/useCollectionCreator"; +import { rawToTable } from "@/components/Collections/tables"; import { useWizard } from "@/components/Common/Wizard/useWizard"; import { useToolRouting } from "@/composables/route"; @@ -18,6 +20,7 @@ import SourceFromDatasetAsTable from "./wizard/SourceFromDatasetAsTable.vue"; import SourceFromPastedData from "./wizard/SourceFromPastedData.vue"; import SourceFromRemoteFiles from "./wizard/SourceFromRemoteFiles.vue"; import GenericWizard from "@/components/Common/Wizard/GenericWizard.vue"; +import RuleCollectionBuilder from "@/components/RuleCollectionBuilder.vue"; const isBusy = ref(false); const { pasteData, tabularDatasetContents, uris, setRemoteFilesFolder, onFtp, setDatasetContents, setPasteTable } = @@ -26,10 +29,12 @@ const { pasteData, tabularDatasetContents, uris, setRemoteFilesFolder, onFtp, se interface Props { fileSourcesConfigured: boolean; ftpUploadSite?: string; + mode: "uploadModal" | "standalone"; } const props = defineProps(); +const ruleState = ref(false); const creatingWhat = ref("datasets"); const creatingWhatTitle = computed(() => { return creatingWhat.value == "datasets" ? "Datasets" : "Collections"; @@ -37,6 +42,7 @@ const creatingWhatTitle = computed(() => { const sourceInstructions = computed(() => { return `${creatingWhatTitle.value} can be created from a set or files, URIs, or existing datasets.`; }); +const collectionCreator = ref(); const sourceFrom = ref("remote_files"); @@ -65,7 +71,7 @@ const wizard = useWizard({ }, "paste-data": { label: "Paste data", - instructions: "Paste data containing URIs and optional extra metadata.", + instructions: "Paste data (or drop file) containing URIs and optional extra metadata.", isValid: () => sourceFrom.value === "pasted_table" && pasteData.value.length > 0, isSkippable: () => sourceFrom.value !== "pasted_table", }, @@ -75,6 +81,13 @@ const wizard = useWizard({ isValid: () => sourceFrom.value === "dataset_as_table" && tabularDatasetContents.value.length > 0, isSkippable: () => sourceFrom.value !== "dataset_as_table", }, + "rule-builder": { + label: "Specify Rules", + instructions: "Use this form to describe rules for importing", + isValid: () => ruleState.value, + isSkippable: () => props.mode == "uploadModal", + width: "100%", + }, }); const importButtonLabel = computed(() => { @@ -85,7 +98,7 @@ const importButtonLabel = computed(() => { } }); -const emit = defineEmits(["dismiss"]); +const emit = defineEmits(["dismiss", "created"]); type SelectionType = "raw" | "remote_files"; type ElementsType = RemoteFile[] | string[][]; @@ -101,8 +114,7 @@ interface Entry { selectionType: SelectionType; } -function launchRuleBuilder() { - const Galaxy = getGalaxyInstance(); +const ruleBuilderModalEntryProps = computed(() => { let elements: ElementsType | undefined = undefined; let selectionType: SelectionType = "raw"; if (sourceFrom.value == "remote_files") { @@ -119,12 +131,31 @@ function launchRuleBuilder() { selectionType: selectionType, elements: elements, }; + return entry; +}); + +const ruleBuilderElements = computed(() => { + const builderProps = ruleBuilderModalEntryProps.value; + let elements; + if (builderProps.elements) { + elements = builderProps.elements; + } else { + elements = rawToTable(builderProps.content || ""); + } + return elements; +}); + +function launchRuleBuilder() { + const Galaxy = getGalaxyInstance(); + const entry = ruleBuilderModalEntryProps.value; Galaxy.currHistoryPanel.buildCollectionFromRules(entry, null, true); } function submit() { if (sourceFrom.value == "collection") { routeToTool("__APPLY_RULES__"); + } else if (props.mode == "standalone") { + attemptCreate(collectionCreator); } else { launchRuleBuilder(); } @@ -138,6 +169,15 @@ function setCreatingWhat(what: RulesCreatingWhat) { function setSourceForm(newValue: RulesSourceFrom) { sourceFrom.value = newValue; } + +function onRuleState(newRuleState: boolean) { + ruleState.value = newRuleState; +} + +function onRuleCreate() { + // axios response data for job currently sent, not really used but wanted to document what is available. + emit("created"); +} diff --git a/client/src/components/Collections/ListWizard.vue b/client/src/components/Collections/ListWizard.vue index d584f818db52..2f493c06ee22 100644 --- a/client/src/components/Collections/ListWizard.vue +++ b/client/src/components/Collections/ListWizard.vue @@ -13,7 +13,11 @@ import { useCollectionBuilderItemSelection } from "@/stores/collectionBuilderIte import { errorMessageAsString } from "@/utils/simple-error"; import { useCollectionCreation } from "./common/useCollectionCreation"; -import { type SupportedPairedOrPairedBuilderCollectionTypes } from "./common/useCollectionCreator"; +import { + attemptCreate, + type CollectionCreatorComponent, + type SupportedPairedOrPairedBuilderCollectionTypes, +} from "./common/useCollectionCreator"; import { type WhichListBuilder } from "./ListWizard/types"; import { autoPairWithCommonFilters } from "./pairing"; @@ -40,9 +44,6 @@ const creationError = ref(null); const collectionCreated = ref(false); type InferrableBuilder = "list" | "list:paired"; -type CollectionCreatorComponent = - | InstanceType - | InstanceType; const collectionCreator = ref(); const { selectedItems } = storeToRefs(store); @@ -155,26 +156,15 @@ const pairedListType = computed(() => { return whichBuilder.value == "list:paired_or_unpaired" ? "list:paired_or_unpaired" : "list:paired"; }); -async function attemptCreate(creator: CollectionCreatorComponent) { - // fight typing to workaround https://github.com/vuejs/core/issues/10077 - interface HasAttemptCreate { - attemptCreate: () => Promise; - } - - (creator as unknown as HasAttemptCreate).attemptCreate(); -} - async function submit() { if (collectionCreator.value) { - attemptCreate(collectionCreator.value); + attemptCreate(collectionCreator); } } async function onCreate(payload: CreateNewCollectionPayload) { try { - const data = await createHistoryDatasetCollectionInstanceFull(payload); - console.log(data); - console.log("collection created!"); + await createHistoryDatasetCollectionInstanceFull(payload); collectionCreated.value = true; } catch (e) { creationError.value = errorMessageAsString(e); @@ -213,18 +203,9 @@ function goToAutoPairing() { wizard.goTo("auto-pairing"); } -function onRuleCreate() { - return 3; -} - -function onRuleCancel() { - return 3; -} - const ruleState = ref(false); function onRuleState(newRuleState: boolean) { - console.log("in on Rule state..."); ruleState.value = newRuleState; } @@ -288,8 +269,6 @@ function onRuleState(newRuleState: boolean) { elements-type="datasets" :initial-elements="selectedItems || []" mode="wizard" - :oncreate="onRuleCreate" - :oncancel="onRuleCancel" @onAttemptCreate="ruleOnAttemptCreate" @validInput="onRuleState" /> diff --git a/client/src/components/Collections/RulesStandalone.vue b/client/src/components/Collections/RulesStandalone.vue new file mode 100644 index 000000000000..fa06e7a4f158 --- /dev/null +++ b/client/src/components/Collections/RulesStandalone.vue @@ -0,0 +1,35 @@ + + + diff --git a/client/src/components/Collections/common/useCollectionCreator.ts b/client/src/components/Collections/common/useCollectionCreator.ts index d2f76d0f932e..46bce28ff5bf 100644 --- a/client/src/components/Collections/common/useCollectionCreator.ts +++ b/client/src/components/Collections/common/useCollectionCreator.ts @@ -1,10 +1,13 @@ -import { computed, ref, watch } from "vue"; +import { computed, type Ref, ref, unref, watch } from "vue"; import { type HistoryItemSummary } from "@/api"; import { type CollectionElementIdentifiers, type CreateNewCollectionPayload } from "@/api/datasetCollections"; +import type RuleCollectionBuilder from "@/components/RuleCollectionBuilder.vue"; import STATES from "@/mvc/dataset/states"; import localize from "@/utils/localization"; +import type ListCollectionCreator from "./ListCollectionCreator.vue"; +import type PairedOrUnpairedListCollectionCreator from "./PairedOrUnpairedListCollectionCreator.vue"; import { useCollectionCreation } from "./useCollectionCreation"; import { useExtensionFiltering } from "./useExtensionFilter"; @@ -28,6 +31,23 @@ export type SupportedPairedOrPairedBuilderCollectionTypes = | "list:list" | "list:list:paired"; +export type CollectionCreatorComponent = + | InstanceType + | InstanceType + | InstanceType; + +export async function attemptCreate(creator: CollectionCreatorComponent | Ref) { + const creatorValue: CollectionCreatorComponent | undefined = unref(creator); + // fight typing to workaround https://github.com/vuejs/core/issues/10077 + interface HasAttemptCreate { + attemptCreate: () => Promise; + } + + if (creatorValue) { + (creatorValue as unknown as HasAttemptCreate).attemptCreate(); + } +} + export function useCollectionCreator(props: CommonCollectionBuilderProps, emit?: EmitsName) { const removeExtensions = ref(true); const hideSourceItems = ref(props.defaultHideSourceItems || false); diff --git a/client/src/components/Common/Wizard/GenericWizard.vue b/client/src/components/Common/Wizard/GenericWizard.vue index b51e60df43ae..dc75454e5f0f 100644 --- a/client/src/components/Common/Wizard/GenericWizard.vue +++ b/client/src/components/Common/Wizard/GenericWizard.vue @@ -125,6 +125,15 @@ const stepsGridColumnsTemplate = computed(() => { .join(" ") + " max-content" ); }); + +const bodyStyle = computed(() => { + const width = props.use.current.value.width; + if (width) { + return { width: width }; + } else { + return {}; + } +});