From d5e86bb2c56abc0ef921715fa4922a86420d6516 Mon Sep 17 00:00:00 2001 From: Ahmed Awan Date: Thu, 5 Dec 2024 10:24:41 -0600 Subject: [PATCH 1/2] draft for simplified workflow run just syncs the active node id with the graph for now --- client/src/components/Form/FormDisplay.vue | 7 +- client/src/components/Form/FormInputs.vue | 15 +- .../Workflow/Editor/WorkflowGraph.vue | 3 +- .../Invocation/Graph/InvocationGraph.vue | 1 + .../components/Workflow/Run/WorkflowRun.vue | 2 +- .../Workflow/Run/WorkflowRunFormSimple.vue | 414 +++++++++--------- .../Workflow/Run/WorkflowRunInfo.vue | 74 ++++ 7 files changed, 311 insertions(+), 205 deletions(-) create mode 100644 client/src/components/Workflow/Run/WorkflowRunInfo.vue diff --git a/client/src/components/Form/FormDisplay.vue b/client/src/components/Form/FormDisplay.vue index e51dfe7e39b1..5975714adfcf 100644 --- a/client/src/components/Form/FormDisplay.vue +++ b/client/src/components/Form/FormDisplay.vue @@ -12,7 +12,8 @@ :collapsed-disable-icon="collapsedDisableIcon" :on-change="onChange" :on-change-form="onChangeForm" - :workflow-building-mode="workflowBuildingMode" /> + :workflow-building-mode="workflowBuildingMode" + :active-node-id="activeNodeId" /> + + diff --git a/client/src/components/Workflow/Editor/WorkflowGraph.vue b/client/src/components/Workflow/Editor/WorkflowGraph.vue index b0a27f1b6235..d5801e74a652 100644 --- a/client/src/components/Workflow/Editor/WorkflowGraph.vue +++ b/client/src/components/Workflow/Editor/WorkflowGraph.vue @@ -11,7 +11,7 @@ id="canvas-container" ref="canvas" class="canvas-content" - :class="props.isInvocation ? 'fixed-window-height' : 'h-100'" + :class="props.fixedHeight ? 'fixed-window-height' : 'h-100'" @drop.prevent @dragover.prevent> diff --git a/client/src/components/Workflow/Run/WorkflowRun.vue b/client/src/components/Workflow/Run/WorkflowRun.vue index dea37e56adc0..6012ad2a8cb6 100644 --- a/client/src/components/Workflow/Run/WorkflowRun.vue +++ b/client/src/components/Workflow/Run/WorkflowRun.vue @@ -179,7 +179,7 @@ defineExpose({ v-else-if="invocations.length > 0" :invocations="invocations" :workflow-name="workflowName" /> -
+
+import { BAlert, BDropdown, BDropdownForm, BFormCheckbox } from "bootstrap-vue"; +import { storeToRefs } from "pinia"; +import { computed, ref, set } from "vue"; + +import { allowCachedJobs } from "@/components/Tool/utilities"; +import { isWorkflowInput } from "@/components/Workflow/constants"; +import { useConfig } from "@/composables/config"; +import { provideScopedWorkflowStores } from "@/composables/workflowStores"; +import { useUserStore } from "@/stores/userStore"; +import { useWorkflowStateStore } from "@/stores/workflowEditorStateStore"; +import { errorMessageAsString } from "@/utils/simple-error"; + +import { invokeWorkflow } from "./services"; + +import WorkflowAnnotation from "../WorkflowAnnotation.vue"; +import WorkflowNavigationTitle from "../WorkflowNavigationTitle.vue"; +import WorkflowRunInfo from "./WorkflowRunInfo.vue"; +import WorkflowStorageConfiguration from "./WorkflowStorageConfiguration.vue"; +import FormDisplay from "@/components/Form/FormDisplay.vue"; +import FlexPanel from "@/components/Panels/FlexPanel.vue"; + +interface Props { + model: Record; + targetHistory?: string; + useJobCache?: boolean; + canMutateCurrentHistory: boolean; + requestState?: Record; +} + +const props = withDefaults(defineProps(), { + targetHistory: "current", + useJobCache: false, + requestState: undefined, +}); + +const emit = defineEmits<{ + (e: "showAdvanced"): void; + (e: "submissionSuccess", invocations: any): void; + (e: "submissionError", error: string): void; +}>(); + +provideScopedWorkflowStores(props.model.workflowId); + +const { activeNodeId } = storeToRefs(useWorkflowStateStore(props.model.workflowId)); + +const { config, isConfigLoaded } = useConfig(true); +const { currentUser } = storeToRefs(useUserStore()); + +const formData = ref>({}); +const inputTypes = ref>({}); +const stepValidations = ref>({}); +const sendToNewHistory = ref(props.targetHistory === "new" || props.targetHistory === "prefer_new"); +const useCachedJobs = ref(props.useJobCache); +const splitObjectStore = ref(false); +const preferredObjectStoreId = ref(null); +const preferredIntermediateObjectStoreId = ref(null); +const waitingForRequest = ref(false); + +const formInputs = computed(() => { + const inputs = [] as any[]; + // Add workflow parameters. + Object.values(props.model.wpInputs).forEach((input) => { + const inputCopy = Object.assign({}, input) as any; + // do we want to keep the color if we're not showing steps? + inputCopy.color = undefined; + inputs.push(inputCopy); + inputTypes.value[inputCopy.name] = "replacement_parameter"; + }); + // Add actual input modules. + props.model.steps.forEach((step: any, i: number) => { + if (isWorkflowInput(step.step_type)) { + const stepName = new String(step.step_index) as any; + const stepLabel = step.step_label || new String(step.step_index + 1); + const stepType = step.step_type; + const help = step.annotation; + const longFormInput = step.inputs[0]; + const stepAsInput = Object.assign({}, longFormInput, { + name: stepName, + help: help, + label: stepLabel, + }); + if (props.requestState && props.requestState[stepLabel]) { + const value = props.requestState[stepLabel]; + stepAsInput.value = value; + } + // disable collection mapping... + stepAsInput.flavor = "module"; + inputs.push(stepAsInput); + inputTypes.value[stepName] = stepType; + } + }); + return inputs; +}); + +const hasValidationErrors = computed(() => { + return Boolean(Object.values(stepValidations.value).find((value) => value !== null && value !== undefined)); +}); + +const canRunOnHistory = computed(() => props.canMutateCurrentHistory || sendToNewHistory.value); + +function onValidation(validation: any) { + if (validation) { + set(stepValidations.value, validation[0], validation[1]); + } else { + stepValidations.value = {}; + } +} + +function reuseAllowed(user: any) { + return user && allowCachedJobs(user.preferences); +} + +function showRuntimeSettings(user: any) { + return props.targetHistory && (props.targetHistory.indexOf("prefer") >= 0 || (user && reuseAllowed(user))); +} + +function onChange(data: any) { + formData.value = data; +} + +function onStorageUpdate(objectStoreId: string, intermediate: boolean) { + if (intermediate) { + preferredIntermediateObjectStoreId.value = objectStoreId; + } else { + preferredObjectStoreId.value = objectStoreId; + } +} + +async function onExecute() { + waitingForRequest.value = true; + + const replacementParams: Record = {}; + const inputs: Record = {}; + for (const inputName in formData.value) { + const value = formData.value[inputName]; + const inputType = inputTypes.value[inputName]; + if (inputType == "replacement_parameter") { + replacementParams[inputName] = value; + } else if (inputType && isWorkflowInput(inputType)) { + inputs[inputName] = value; + } + } + const data: Record = { + replacement_dict: replacementParams, + inputs: inputs, + inputs_by: "step_index", + batch: true, + use_cached_job: useCachedJobs.value, + require_exact_tool_versions: false, + version: props.model.runData.version, + }; + if (sendToNewHistory.value) { + data.new_history_name = props.model.name; + } else { + data.history_id = props.model.historyId; + } + if (splitObjectStore.value) { + if (preferredObjectStoreId.value != null) { + data.preferred_outputs_object_store_id = preferredObjectStoreId.value; + } + if (preferredIntermediateObjectStoreId.value != null && splitObjectStore.value) { + data.preferred_intermediate_object_store_id = preferredIntermediateObjectStoreId.value; + } + } else { + if (preferredObjectStoreId.value != null) { + data.preferred_object_store_id = preferredObjectStoreId.value; + } + } + + try { + const invocations = await invokeWorkflow(props.model.workflowId, data); + emit("submissionSuccess", invocations); + } catch (error) { + emit("submissionError", errorMessageAsString(error)); + } finally { + waitingForRequest.value = false; + } +} + +
- - - Expand to full workflow form. + +
- - diff --git a/client/src/components/Workflow/Run/WorkflowRunInfo.vue b/client/src/components/Workflow/Run/WorkflowRunInfo.vue new file mode 100644 index 000000000000..01d8f784d9a9 --- /dev/null +++ b/client/src/components/Workflow/Run/WorkflowRunInfo.vue @@ -0,0 +1,74 @@ + + + From 1554aa1aed07e7d35da4266c8f2c04b939ead657 Mon Sep 17 00:00:00 2001 From: Ahmed Awan Date: Mon, 9 Dec 2024 14:49:31 -0600 Subject: [PATCH 2/2] have a functioning side by side inputs w/graph run form The input values are synced with the graph --- client/src/components/Form/FormDisplay.vue | 8 +- client/src/components/Form/FormInputs.vue | 34 ++++- .../src/components/Workflow/Editor/Node.vue | 24 +++- .../Workflow/Editor/WorkflowGraph.vue | 2 + .../Workflow/Run/WorkflowRunFormSimple.vue | 37 +++-- .../Workflow/Run/WorkflowRunGraph.vue | 130 ++++++++++++++++++ .../Workflow/Run/WorkflowRunInfo.vue | 74 ---------- 7 files changed, 213 insertions(+), 96 deletions(-) create mode 100644 client/src/components/Workflow/Run/WorkflowRunGraph.vue delete mode 100644 client/src/components/Workflow/Run/WorkflowRunInfo.vue diff --git a/client/src/components/Form/FormDisplay.vue b/client/src/components/Form/FormDisplay.vue index 5975714adfcf..b0d447512844 100644 --- a/client/src/components/Form/FormDisplay.vue +++ b/client/src/components/Form/FormDisplay.vue @@ -13,7 +13,9 @@ :on-change="onChange" :on-change-form="onChangeForm" :workflow-building-mode="workflowBuildingMode" - :active-node-id="activeNodeId" /> + :active-node-id="activeNodeId" + :sync-with-graph="syncWithGraph" + @update:active-node-id="($event) => $emit('update:active-node-id', $event)" /> + + diff --git a/client/src/components/Workflow/Run/WorkflowRunInfo.vue b/client/src/components/Workflow/Run/WorkflowRunInfo.vue deleted file mode 100644 index 01d8f784d9a9..000000000000 --- a/client/src/components/Workflow/Run/WorkflowRunInfo.vue +++ /dev/null @@ -1,74 +0,0 @@ - - -