Skip to content

Commit

Permalink
Remove "Create Workflow" form and allow workflow creation in editor
Browse files Browse the repository at this point in the history
Skip the step of Creating a workflow, and instead go straight into an
empty editor, add nodes, tags, connections...; workflow will only
be created once you Save and provide the worfklow a name and annotation.
Fixes galaxyproject#16912
  • Loading branch information
ahmedhamidawan committed Oct 27, 2023
1 parent 4fcf3b5 commit e78625e
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 46 deletions.
2 changes: 1 addition & 1 deletion client/src/components/Panels/WorkflowBox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ function userTitle(title: string) {
variant="link"
:title="userTitle('Create new workflow')"
:disabled="isAnonymous"
@click="$router.push('/workflows/create')">
@click="$router.push('/workflows/edit')">
<Icon fixed-width icon="plus" />
</b-button>
<b-button
Expand Down
17 changes: 12 additions & 5 deletions client/src/components/Workflow/Editor/Attributes.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
<div id="workflow-name-area">
<b>Name</b>
<meta itemprop="name" :content="name" />
<b-input id="workflow-name" v-model="nameCurrent" @keyup="$emit('update:nameCurrent', nameCurrent)" />
<b-input
id="workflow-name"
v-model="nameCurrent"
:state="!nameCurrent ? false : null"
@keyup="$emit('update:nameCurrent', nameCurrent)" />
</div>
<div id="workflow-version-area" class="mt-2">
<b>Version</b>
Expand All @@ -30,6 +34,7 @@
<b-textarea
id="workflow-annotation"
v-model="annotationCurrent"
:state="!annotationCurrent ? false : null"
@keyup="$emit('update:annotationCurrent', annotationCurrent)" />
<div class="form-text text-muted">These notes will be visible when this workflow is viewed.</div>
</div>
Expand Down Expand Up @@ -184,7 +189,7 @@ export default {
onTags(tags) {
this.tagsCurrent = tags;
this.onAttributes({ tags });
this.$emit("input", this.tagsCurrent);
this.$emit("onTags", this.tagsCurrent);
},
onVersion() {
this.$emit("onVersion", this.versionCurrent);
Expand All @@ -200,9 +205,11 @@ export default {
this.messageVariant = "danger";
},
onAttributes(data) {
this.services.updateWorkflow(this.id, data).catch((error) => {
this.onError(error);
});
if (this.id !== "new_temp_workflow") {
this.services.updateWorkflow(this.id, data).catch((error) => {
this.onError(error);
});
}
},
},
};
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/Workflow/Editor/Index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ describe("Index", () => {
});
wrapper = shallowMount(Index, {
propsData: {
id: "workflow_id",
workflowId: "workflow_id",
initialVersion: 1,
tags: ["moo", "cow"],
workflowTags: ["moo", "cow"],
moduleSections: [],
dataManagers: [],
workflows: [],
Expand Down
71 changes: 62 additions & 9 deletions client/src/components/Workflow/Editor/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
<div class="unified-panel-header" unselectable="on">
<div class="unified-panel-header-inner">
<span class="sr-only">Workflow Editor</span>
{{ name }}
<span v-if="!isNewTempWorkflow || name">{{ name }}</span>
<i v-else>Create New Workflow</i>
</div>
</div>
<WorkflowGraph
Expand All @@ -68,9 +69,11 @@
<div class="unified-panel-header" unselectable="on">
<div class="unified-panel-header-inner">
<WorkflowOptions
:is-new-temp-workflow="isNewTempWorkflow"
:has-changes="hasChanges"
:has-invalid-connections="hasInvalidConnections"
@onSave="onSave"
@onCreate="onCreate"
@onSaveAs="onSaveAs"
@onRun="onRun"
@onDownload="onDownload"
Expand Down Expand Up @@ -118,6 +121,7 @@
:license="license"
:creator="creator"
@onVersion="onVersion"
@onTags="onTags"
@onLicense="onLicense"
@onCreator="onCreator" />
<WorkflowLint
Expand Down Expand Up @@ -171,6 +175,7 @@ import { provideScopedWorkflowStores } from "@/composables/workflowStores";
import { hide_modal } from "@/layout/modal";
import { getAppRoot } from "@/onload/loadConfig";
import { LastQueue } from "@/utils/promise-queue";
import { withPrefix } from "@/utils/redirect";
import { defaultPosition } from "./composables/useDefaultStepPosition";
import { fromSimple, toSimple } from "./modules/model";
Expand All @@ -191,6 +196,8 @@ import ToolPanel from "@/components/Panels/ToolPanel.vue";
import FormDefault from "@/components/Workflow/Editor/Forms/FormDefault.vue";
import FormTool from "@/components/Workflow/Editor/Forms/FormTool.vue";
const NEW_TEMP_ID = "new_temp_workflow";
export default {
components: {
MarkdownEditor,
Expand All @@ -207,17 +214,17 @@ export default {
WorkflowGraph,
},
props: {
id: {
workflowId: {
type: String,
required: true,
default: NEW_TEMP_ID,
},
initialVersion: {
type: Number,
required: true,
default: 0,
},
tags: {
workflowTags: {
type: Array,
required: true,
default: () => [],
},
moduleSections: {
type: Array,
Expand All @@ -235,7 +242,7 @@ export default {
setup(props, { emit }) {
const { datatypes, datatypesMapper, datatypesMapperLoading } = useDatatypesMapper();
const { connectionStore, stepStore, stateStore } = provideScopedWorkflowStores(props.id);
const { connectionStore, stepStore, stateStore } = provideScopedWorkflowStores(props.workflowId);
const { getStepIndex, steps } = storeToRefs(stepStore);
const { activeNodeId } = storeToRefs(stateStore);
Expand Down Expand Up @@ -280,6 +287,7 @@ export default {
},
data() {
return {
id: this.workflowId,
isCanvas: true,
markdownConfig: null,
markdownText: null,
Expand All @@ -291,6 +299,7 @@ export default {
creator: null,
annotation: null,
name: null,
tags: this.workflowTags,
stateMessages: [],
insertedStateMessages: [],
refactorActions: [],
Expand Down Expand Up @@ -324,10 +333,13 @@ export default {
hasActiveNodeTool() {
return this.activeStep?.type == "tool";
},
isNewTempWorkflow() {
return this.id === NEW_TEMP_ID;
},
},
watch: {
id(newId, oldId) {
if (oldId) {
if (oldId && oldId !== NEW_TEMP_ID) {
this._loadCurrent(newId);
}
},
Expand All @@ -347,7 +359,9 @@ export default {
},
created() {
this.lastQueue = new LastQueue();
this._loadCurrent(this.id, this.version);
if (!this.isNewTempWorkflow) {
this._loadCurrent(this.id, this.version);
}
hide_modal();
},
methods: {
Expand Down Expand Up @@ -541,6 +555,40 @@ export default {
const step = { ...this.steps[nodeId], annotation: newAnnotation };
this.onUpdateStep(step);
},
async onCreate() {
if (!this.name || !this.annotation) {
const response = "Must provide name and annotation before creation...";
this.onWorkflowError("Creating workflow failed...", response, {
Ok: () => {
this.hideModal();
},
});
this.onAttributes();
return;
}
const payload = {
workflow_name: this.name,
workflow_annotation: this.annotation,
workflow_tags: this.tags,
};
try {
const { data } = await axios.put(withPrefix("/workflow/create"), payload);
const { id, message } = data;
this.id = id;
this.onWorkflowMessage("Success", message);
const editUrl = `/workflows/edit?id=${id}`;
this.onNavigate(editUrl);
} catch (e) {
this.onWorkflowError("Couldn't create workflow..."),
e,
{
Ok: () => {
this.hideModal();
},
};
}
},
onSetData(stepId, newData) {
this.lastQueue
.enqueue(() => getModule(newData, stepId, this.stateStore.setLoadingState))
Expand Down Expand Up @@ -699,6 +747,11 @@ export default {
this.onWorkflowError("Loading workflow failed...", response);
});
},
onTags(tags) {
if (this.tags != tags) {
this.tags = tags;
}
},
onLicense(license) {
if (this.license != license) {
this.hasChanges = true;
Expand Down
31 changes: 23 additions & 8 deletions client/src/components/Workflow/Editor/Options.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useConfirmDialog } from "@/composables/confirmDialog";
const emit = defineEmits<{
(e: "onAttributes"): void;
(e: "onSave"): void;
(e: "onCreate"): void;
(e: "onReport"): void;
(e: "onSaveAs"): void;
(e: "onLayout"): void;
Expand All @@ -17,6 +18,7 @@ const emit = defineEmits<{
}>();
const props = defineProps<{
isNewTempWorkflow?: boolean;
hasChanges?: boolean;
hasInvalidConnections?: boolean;
requiredReindex?: boolean;
Expand All @@ -25,7 +27,9 @@ const props = defineProps<{
const { confirm } = useConfirmDialog();
const saveHover = computed(() => {
if (!props.hasChanges) {
if (props.isNewTempWorkflow) {
return "Create a new workflow";
} else if (!props.hasChanges) {
return "Workflow has no changes";
} else if (props.hasInvalidConnections) {
return "Workflow has invalid connections, review and remove invalid connections";
Expand All @@ -34,6 +38,14 @@ const saveHover = computed(() => {
}
});
function emitSaveOrCreate() {
if (props.isNewTempWorkflow) {
emit("onCreate");
} else {
emit("onSave");
}
}
async function onSave() {
if (props.hasInvalidConnections) {
console.log("getting confirmation");
Expand All @@ -45,18 +57,18 @@ async function onSave() {
}
);
if (confirmed) {
emit("onSave");
emitSaveOrCreate();
}
} else {
emit("onSave");
emitSaveOrCreate();
}
}
</script>
<template>
<div class="panel-header-buttons">
<BButton
id="workflow-home-button"
v-b-tooltip.hover
v-b-tooltip.hover.noninteractive
role="button"
title="Edit Attributes"
variant="link"
Expand All @@ -79,25 +91,27 @@ async function onSave() {
</b-button-group>
<BButton
id="workflow-report-button"
v-b-tooltip.hover
v-b-tooltip.hover.noninteractive
role="button"
title="Edit Report"
variant="link"
aria-label="Edit Report"
class="editor-button-report"
:disabled="isNewTempWorkflow"
@click="$emit('onReport')">
<span class="fa fa-edit" />
</BButton>
<BDropdown
id="workflow-options-button"
v-b-tooltip.hover
v-b-tooltip.hover.noninteractive
no-caret
right
role="button"
title="Workflow Options"
variant="link"
aria-label="Workflow Options"
class="editor-button-options">
class="editor-button-options"
:disabled="isNewTempWorkflow">
<template v-slot:button-content>
<span class="fa fa-cog" />
</template>
Expand All @@ -113,12 +127,13 @@ async function onSave() {
</BDropdown>
<BButton
id="workflow-run-button"
v-b-tooltip.hover
v-b-tooltip.hover.noninteractive
role="button"
title="Run Workflow"
variant="link"
aria-label="Run Workflow"
class="editor-button-run"
:disabled="isNewTempWorkflow"
@click="$emit('onRun')">
<span class="fa fa-play" />
</BButton>
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/Workflow/Editor/modules/services.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export async function loadWorkflow({ id, version = null }) {
export async function saveWorkflow(workflow) {
if (workflow.hasChanges) {
try {
const requestData = { workflow: toSimple(workflow), from_tool_form: true };
const requestData = { workflow: toSimple(workflow), from_tool_form: true, tags: workflow.tags };
const { data } = await axios.put(`${getAppRoot()}api/workflows/${workflow.id}`, requestData);
workflow.name = data.name;
workflow.hasChanges = false;
Expand Down
Loading

0 comments on commit e78625e

Please sign in to comment.