diff --git a/client/src/components/Markdown/LabelSelector.vue b/client/src/components/Markdown/LabelSelector.vue
index 682389c6fd15..2527704f28c6 100644
--- a/client/src/components/Markdown/LabelSelector.vue
+++ b/client/src/components/Markdown/LabelSelector.vue
@@ -1,8 +1,10 @@
@@ -31,7 +33,7 @@ function update(index: number) {
name="labels"
:value="index"
@change="update">
- {{ label }}
+ {{ label.label }}
No labels found. Please specify labels in the Workflow Editor.
diff --git a/client/src/components/Markdown/MarkdownDialog.vue b/client/src/components/Markdown/MarkdownDialog.vue
index 4076696f47ee..7dd49fd8bf75 100644
--- a/client/src/components/Markdown/MarkdownDialog.vue
+++ b/client/src/components/Markdown/MarkdownDialog.vue
@@ -9,6 +9,8 @@ import { jobsFetcher } from "@/api/jobs";
import { workflowsFetcher } from "@/api/workflows";
import { useHistoryStore } from "@/stores/historyStore";
+import { WorkflowLabel, WorkflowLabels } from "./labels";
+
import MarkdownSelector from "./MarkdownSelector.vue";
import MarkdownVisualization from "./MarkdownVisualization.vue";
import DataDialog from "@/components/DataDialog/DataDialog.vue";
@@ -21,7 +23,7 @@ interface MarkdownDialogProps {
argumentName?: string;
argumentType?: string;
argumentPayload?: object;
- labels?: string[];
+ labels?: WorkflowLabels;
useLabels: boolean;
}
@@ -42,6 +44,22 @@ interface SelectTitles {
type SelectType = "job_id" | "invocation_id" | "history_dataset_id" | "history_dataset_collection_id";
+const effectiveLabels = computed(() => {
+ if (!props.labels) {
+ return [] as WorkflowLabels;
+ }
+ const selectSteps = props.argumentType == "job_id";
+ const filteredLabels: WorkflowLabels = [];
+ for (const label of props.labels) {
+ if (selectSteps && label.type == "step") {
+ filteredLabels.push(label);
+ } else if (!selectSteps && label.type != "step") {
+ filteredLabels.push(label);
+ }
+ }
+ return filteredLabels;
+});
+
const selectorConfig = {
job_id: {
labelTitle: "Step",
@@ -50,10 +68,10 @@ const selectorConfig = {
labelTitle: "Step",
},
history_dataset_id: {
- labelTitle: "Output",
+ labelTitle: "Dataset (Input/Output)",
},
history_dataset_collection_id: {
- labelTitle: "Output",
+ labelTitle: "Dataset Collection (Input/Output)",
},
};
@@ -127,30 +145,33 @@ function onVisualization(response: string) {
emit("onInsert", response);
}
-function onOk(selectedLabel: string) {
- selectedLabel = selectedLabel || "";
+function onOk(selectedLabel: WorkflowLabel | undefined) {
+ const defaultLabelType: string =
+ ["history_dataset_id", "history_dataset_collection_id"].indexOf(props.argumentType) >= 0 ? "output" : "step";
+ const labelText: string = selectedLabel ? selectedLabel.label : "";
+ const labelType: string = selectedLabel ? selectedLabel.type : defaultLabelType;
selectedShow.value = false;
if (props.argumentType == "history_dataset_id") {
if (props.useLabels) {
- emit("onInsert", `${props.argumentName}(output="${selectedLabel}")`);
+ emit("onInsert", `${props.argumentName}(${labelType}="${labelText}")`);
} else {
dataShow.value = true;
}
} else if (props.argumentType == "history_dataset_collection_id") {
if (props.useLabels) {
- emit("onInsert", `${props.argumentName}(output="${selectedLabel}")`);
+ emit("onInsert", `${props.argumentName}(${labelType}="${labelText}")`);
} else {
dataCollectionShow.value = true;
}
} else if (props.argumentType == "job_id") {
if (props.useLabels) {
- emit("onInsert", `${props.argumentName}(step="${selectedLabel}")`);
+ emit("onInsert", `${props.argumentName}(${labelType}="${labelText}")`);
} else {
jobShow.value = true;
}
} else if (props.argumentType == "invocation_id") {
if (props.useLabels) {
- emit("onInsert", `${props.argumentName}(step="${selectedLabel}")`);
+ emit("onInsert", `${props.argumentName}(${labelType}="${labelText}")`);
} else {
invocationShow.value = true;
}
@@ -207,7 +228,7 @@ if (props.argumentType == "workflow_id") {
v-if="selectedShow"
:initial-value="argumentType"
:argument-name="argumentName"
- :labels="labels"
+ :labels="effectiveLabels"
:label-title="selectedLabelTitle"
@onOk="onOk"
@onCancel="onCancel" />
@@ -215,7 +236,7 @@ if (props.argumentType == "workflow_id") {
v-else-if="visualizationShow"
:argument-name="argumentName"
:argument-payload="argumentPayload"
- :labels="labels"
+ :labels="effectiveLabels"
:use-labels="useLabels"
:history="currentHistoryId"
@onOk="onVisualization"
diff --git a/client/src/components/Markdown/MarkdownSelector.vue b/client/src/components/Markdown/MarkdownSelector.vue
index 75b95f474e6e..c41f9c4109f7 100644
--- a/client/src/components/Markdown/MarkdownSelector.vue
+++ b/client/src/components/Markdown/MarkdownSelector.vue
@@ -2,16 +2,18 @@
import BootstrapVue from "bootstrap-vue";
import Vue, { computed, ref } from "vue";
+import { WorkflowLabel } from "./labels";
+
import LabelSelector from "./LabelSelector.vue";
interface MarkdownSelectorProps {
labelTitle?: string;
- labels: string[];
+ labels: WorkflowLabel[];
argumentName?: string;
}
const props = defineProps();
-const selectedValue = ref(undefined);
+const selectedValue = ref(undefined);
const modalShow = ref(true);
const title = computed(() => {
@@ -22,7 +24,7 @@ const hasLabels = computed(() => {
});
const emit = defineEmits<{
- (e: "onOk", value: string | undefined): void;
+ (e: "onOk", value: WorkflowLabel | undefined): void;
(e: "onCancel"): void;
}>();
diff --git a/client/src/components/Markdown/MarkdownToolBox.vue b/client/src/components/Markdown/MarkdownToolBox.vue
index c8f7341f6fed..02d6a513e3bc 100644
--- a/client/src/components/Markdown/MarkdownToolBox.vue
+++ b/client/src/components/Markdown/MarkdownToolBox.vue
@@ -33,7 +33,7 @@
:argument-type="selectedType"
:argument-name="selectedArgumentName"
:argument-payload="selectedPayload"
- :labels="selectedLabels"
+ :labels="workflowLabels"
:use-labels="isWorkflow"
@onInsert="onInsert"
@onCancel="onCancel" />
@@ -48,6 +48,7 @@ import { getAppRoot } from "onload/loadConfig";
import Vue from "vue";
import { directiveEntry } from "./directives.ts";
+import { fromSteps } from "./labels.ts";
import MarkdownDialog from "./MarkdownDialog";
Vue.use(BootstrapVue);
@@ -105,7 +106,6 @@ export default {
return {
selectedArgumentName: null,
selectedType: null,
- selectedLabels: undefined,
selectedShow: false,
selectedPayload: null,
visualizationIndex: {},
@@ -244,33 +244,14 @@ export default {
],
};
},
+ workflowLabels() {
+ return fromSteps(this.steps);
+ },
},
created() {
this.getVisualizations();
},
methods: {
- getSteps() {
- const steps = [];
- this.steps &&
- Object.values(this.steps).forEach((step) => {
- if (step.label) {
- steps.push(step.label);
- }
- });
- return steps;
- },
- getOutputs() {
- const outputLabels = [];
- this.steps &&
- Object.values(this.steps).forEach((step) => {
- step.workflow_outputs.forEach((workflowOutput) => {
- if (workflowOutput.label) {
- outputLabels.push(workflowOutput.label);
- }
- });
- });
- return outputLabels;
- },
getArgumentTitle(argumentName) {
return (
argumentName[0].toUpperCase() +
@@ -320,7 +301,6 @@ export default {
this.selectedArgumentName = argumentName;
this.selectedType = "visualization_id";
this.selectedPayload = this.visualizationIndex[argumentName];
- this.selectedLabels = this.getOutputs();
this.selectedShow = true;
},
onHistoryId(argumentName) {
@@ -331,13 +311,11 @@ export default {
onHistoryDatasetId(argumentName) {
this.selectedArgumentName = argumentName;
this.selectedType = "history_dataset_id";
- this.selectedLabels = this.getOutputs();
this.selectedShow = true;
},
onHistoryCollectionId(argumentName) {
this.selectedArgumentName = argumentName;
this.selectedType = "history_dataset_collection_id";
- this.selectedLabels = this.getOutputs();
this.selectedShow = true;
},
onWorkflowId(argumentName) {
@@ -348,13 +326,11 @@ export default {
onJobId(argumentName) {
this.selectedArgumentName = argumentName;
this.selectedType = "job_id";
- this.selectedLabels = this.getSteps();
this.selectedShow = true;
},
onInvocationId(argumentName) {
this.selectedArgumentName = argumentName;
this.selectedType = "invocation_id";
- this.selectedLabels = this.getSteps();
this.selectedShow = true;
},
async getVisualizations() {
diff --git a/client/src/components/Markdown/labels.ts b/client/src/components/Markdown/labels.ts
new file mode 100644
index 000000000000..10048e834573
--- /dev/null
+++ b/client/src/components/Markdown/labels.ts
@@ -0,0 +1,48 @@
+// abstractions for dealing with workflows labels and
+// connecting them to the Markdown editor
+
+type WorkflowLabelKind = "input" | "output" | "step";
+
+export interface WorkflowLabel {
+ label: string;
+ type: WorkflowLabelKind;
+}
+
+interface StepOutput {
+ label?: string;
+}
+
+interface Step {
+ label?: string;
+ type: string;
+ workflow_outputs: StepOutput[];
+}
+
+export type WorkflowLabels = WorkflowLabel[];
+
+export function fromSteps(steps?: Step[]): WorkflowLabels {
+ const labels: WorkflowLabels = [];
+
+ if (!steps) {
+ return labels;
+ }
+
+ Object.values(steps).forEach((step) => {
+ const stepType = step.type;
+ if (step.label) {
+ const isInput = ["data_input", "data_collection_input", "parameter_input"].indexOf(stepType) >= 0;
+ if (isInput) {
+ labels.push({ type: "input", label: step.label });
+ } else {
+ labels.push({ type: "step", label: step.label });
+ }
+ }
+ step.workflow_outputs.forEach((workflowOutput) => {
+ if (workflowOutput.label) {
+ labels.push({ type: "output", label: workflowOutput.label });
+ }
+ });
+ });
+
+ return labels;
+}