fix: render states & transition by fetching workflow data
This commit is contained in:
parent
b004a28a15
commit
f258ca09ac
7 changed files with 132 additions and 38 deletions
|
|
@ -52,8 +52,13 @@ onConnect(edge => {
|
|||
const action_node = {
|
||||
id: "action-" + frappe.utils.get_random(5),
|
||||
type: "action",
|
||||
label: "Approve",
|
||||
position: { x: center_x, y: center_y }
|
||||
position: { x: center_x, y: center_y },
|
||||
data: {
|
||||
action: "",
|
||||
allowed: "All",
|
||||
from: source_node.data.state,
|
||||
to: target_node.data.state
|
||||
},
|
||||
};
|
||||
addNodes([action_node]);
|
||||
|
||||
|
|
@ -130,8 +135,12 @@ function onDrop(event) {
|
|||
const new_state = {
|
||||
id: state_id,
|
||||
type: "state",
|
||||
label: "Open",
|
||||
position,
|
||||
data: {
|
||||
state: "",
|
||||
doc_status: "0",
|
||||
allow_edit: "All"
|
||||
}
|
||||
};
|
||||
|
||||
addNodes([new_state]);
|
||||
|
|
@ -162,11 +171,7 @@ function onDragStart(event) {
|
|||
}
|
||||
|
||||
onPaneReady(() => fitView({ padding: 0.4 }));
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
store.setup_undo_redo();
|
||||
}, 1000);
|
||||
});
|
||||
onMounted(() => store.fetch());
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ const isValidConnection = ({ source, target }) => {
|
|||
|
||||
<template>
|
||||
<div class="node" tabindex="0">
|
||||
<div v-if="node.label" class="node-label">{{ node.label }}</div>
|
||||
<div v-if="node.data.action" class="node-label">{{ node.data.action }}</div>
|
||||
<div v-else class="node-placeholder text-muted">{{ __("No Label") }}</div>
|
||||
<Handle
|
||||
v-for="handle in ['top', 'right', 'bottom', 'left']"
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ const isValidConnection = ({ source, target }) => {
|
|||
|
||||
<template>
|
||||
<div class="node" tabindex="0">
|
||||
<div v-if="node.label" class="node-label">{{ node.label }}</div>
|
||||
<div v-if="node.data.state" class="node-label">{{ node.data.state }}</div>
|
||||
<div v-else class="node-placeholder text-muted">{{ __("No Label") }}</div>
|
||||
<Handle
|
||||
v-for="handle in ['top', 'right', 'bottom', 'left']"
|
||||
|
|
|
|||
|
|
@ -1,37 +1,32 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { ref } from "vue";
|
||||
import { get_workflow_elements } from "./utils";
|
||||
import { useManualRefHistory, onKeyDown } from "@vueuse/core";
|
||||
|
||||
export const useStore = defineStore("workflow-builder-store", () => {
|
||||
let workflow_name = ref(null);
|
||||
let workflow_doc = ref(null);
|
||||
let workflow = ref({
|
||||
elements: [
|
||||
{ id: "1", label: "Open", type: "state", position: { x: 300, y: 150 } },
|
||||
{ id: "2", label: "Approved", type: "state", position: { x: 700, y: 150 } },
|
||||
{ id: "action-1", label: "Approve", type: "action", position: { x: 500, y: 170 } },
|
||||
{
|
||||
id: "edge-1-action-1",
|
||||
source: "1",
|
||||
target: "action-1",
|
||||
type: "transition",
|
||||
sourceHandle: "right",
|
||||
targetHandle: "left",
|
||||
updatable: true,
|
||||
animated: true,
|
||||
},
|
||||
{
|
||||
id: "edge-action-1-2",
|
||||
source: "action-1",
|
||||
target: "2",
|
||||
type: "transition",
|
||||
sourceHandle: "right",
|
||||
targetHandle: "left",
|
||||
updatable: true,
|
||||
animated: true,
|
||||
},
|
||||
],
|
||||
elements: [],
|
||||
});
|
||||
let ref_history = ref(null);
|
||||
|
||||
async function fetch() {
|
||||
await frappe.model.clear_doc("Workflow", workflow_name.value);
|
||||
await frappe.model.with_doc("Workflow", workflow_name.value);
|
||||
|
||||
workflow_doc.value = frappe.get_doc("Workflow", workflow_name.value);
|
||||
await frappe.model.with_doctype(workflow_doc.value.document_type);
|
||||
|
||||
workflow.value.elements = get_workflow_elements(workflow_doc.value);
|
||||
|
||||
setup_undo_redo();
|
||||
}
|
||||
|
||||
function reset_changes() {
|
||||
fetch();
|
||||
}
|
||||
|
||||
let undo_redo_keyboard_event = onKeyDown(true, (e) => {
|
||||
if (!ref_history.value) return;
|
||||
if (e.ctrlKey || e.metaKey) {
|
||||
|
|
@ -50,8 +45,11 @@ export const useStore = defineStore("workflow-builder-store", () => {
|
|||
}
|
||||
|
||||
return {
|
||||
workflow_name,
|
||||
workflow,
|
||||
ref_history,
|
||||
fetch,
|
||||
reset_changes,
|
||||
setup_undo_redo,
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
export function get_workflow_elements(workflow) {
|
||||
let elements = [];
|
||||
let states = {};
|
||||
let x = 150;
|
||||
let y = 100;
|
||||
|
||||
function state_obj(id, data) {
|
||||
let state = {
|
||||
id: id.toString(),
|
||||
type: "state",
|
||||
position: { x: x, y: y },
|
||||
data: data,
|
||||
};
|
||||
if (!states[data.state]) {
|
||||
states[data.state] = [id, { x: x, y: y }];
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
function action_obj(id, data, position) {
|
||||
return {
|
||||
id: "action-" + id,
|
||||
type: "action",
|
||||
position: position,
|
||||
data: data,
|
||||
};
|
||||
}
|
||||
|
||||
function transition_obj(id, source, target) {
|
||||
return {
|
||||
id: "edge-" + id,
|
||||
type: "transition",
|
||||
source: source.toString(),
|
||||
target: target.toString(),
|
||||
sourceHandle: "right",
|
||||
targetHandle: "left",
|
||||
updatable: true,
|
||||
animated: true,
|
||||
};
|
||||
}
|
||||
|
||||
workflow.states.forEach((state, i) => {
|
||||
x += 400;
|
||||
elements.push(
|
||||
state_obj(i + 1, {
|
||||
state: state.state,
|
||||
doc_status: state.doc_status,
|
||||
allow_edit: state.allow_edit,
|
||||
update_field: state.update_field,
|
||||
update_value: state.update_value,
|
||||
is_optional_state: state.is_optional_state,
|
||||
next_action_email_template: state.next_action_email_template,
|
||||
message: state.message,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
workflow.transitions.forEach((transition, i) => {
|
||||
let source = states[transition.state];
|
||||
let target = states[transition.next_state];
|
||||
let position = { x: source[1].x + 250, y: y + 20 };
|
||||
let data = {
|
||||
from: transition.state,
|
||||
to: transition.next_state,
|
||||
action: transition.action,
|
||||
allowed: transition.allowed,
|
||||
allow_self_approval: transition.allow_self_approval,
|
||||
condition: transition.condition,
|
||||
};
|
||||
|
||||
let action = "action-" + (i + 1);
|
||||
|
||||
elements.push(action_obj(i + 1, data, position));
|
||||
elements.push(transition_obj(source[0] + "-" + action, source[0], action));
|
||||
elements.push(transition_obj(action + "-" + target[0], action, target[0]));
|
||||
});
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
|
@ -28,6 +28,10 @@ class WorkflowBuilder {
|
|||
SetVueGlobals(app);
|
||||
app.use(pinia);
|
||||
|
||||
// create a store
|
||||
this.store = useStore();
|
||||
this.store.workflow_name = this.workflow;
|
||||
|
||||
// mount the app
|
||||
this.$workflow_builder = app.mount(this.$wrapper.get(0));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@
|
|||
"states",
|
||||
"transition_rules",
|
||||
"transitions",
|
||||
"workflow_state_field"
|
||||
"workflow_state_field",
|
||||
"workflow_data"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
|
|
@ -92,12 +93,18 @@
|
|||
"fieldtype": "Data",
|
||||
"label": "Workflow State Field",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "workflow_data",
|
||||
"fieldtype": "JSON",
|
||||
"hidden": 1,
|
||||
"label": "Workflow Data"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-random",
|
||||
"idx": 1,
|
||||
"links": [],
|
||||
"modified": "2023-05-01 13:21:30.951859",
|
||||
"modified": "2023-05-02 16:56:28.704844",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Workflow",
|
||||
"name": "Workflow",
|
||||
|
|
@ -117,5 +124,6 @@
|
|||
"show_name_in_global_search": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "ASC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue