fix: added sidebar to show workflow data
This commit is contained in:
parent
13e5031c3c
commit
bcfd07be73
6 changed files with 185 additions and 29 deletions
|
|
@ -5,6 +5,7 @@ import TransitionEdge from "./components/TransitionEdge.vue";
|
|||
import StateNode from "./components/StateNode.vue";
|
||||
import ActionNode from "./components/ActionNode.vue";
|
||||
import ConnectionLine from "./components/ConnectionLine.vue";
|
||||
import Sidebar from "./components/Sidebar.vue";
|
||||
import { useStore } from "./store";
|
||||
import { nextTick, onMounted, watch } from "vue";
|
||||
import { useMagicKeys, whenever } from "@vueuse/core";
|
||||
|
|
@ -185,36 +186,39 @@ onMounted(() => store.fetch());
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="workflow-container" @drop="onDrop">
|
||||
<VueFlow v-model="store.workflow.elements" connection-mode="loose" @dragover="onDragOver">
|
||||
<Background pattern-color="#aaa" gap="10" />
|
||||
<Panel :position="PanelPosition.TopRight">
|
||||
<div class="empty-state">
|
||||
<div class="btn btn-md drag-handle" :draggable="true" @dragstart="onDragStart">
|
||||
Drag to add state
|
||||
<div class="main">
|
||||
<Sidebar />
|
||||
<div class="workflow-container" @drop="onDrop">
|
||||
<VueFlow v-model="store.workflow.elements" connection-mode="loose" @dragover="onDragOver">
|
||||
<Background pattern-color="#aaa" gap="10" />
|
||||
<Panel :position="PanelPosition.TopRight">
|
||||
<div class="empty-state">
|
||||
<div class="btn btn-md drag-handle" :draggable="true" @dragstart="onDragStart">
|
||||
Drag to add state
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
<Panel :position="PanelPosition.BottomLeft">
|
||||
<button class="btn btn-sm btn-default mr-2" @click="zoomIn">+</button>
|
||||
<button class="btn btn-sm btn-default mr-2" @click="zoomOut">-</button>
|
||||
<button class="btn btn-sm btn-default" @click="fitView({ padding: 0.4 })">
|
||||
Fit
|
||||
</button>
|
||||
</Panel>
|
||||
<template #node-state="node">
|
||||
<StateNode :node="node" />
|
||||
</template>
|
||||
<template #node-action="node">
|
||||
<ActionNode :node="node" />
|
||||
</template>
|
||||
<template #edge-transition="props">
|
||||
<TransitionEdge v-bind="props" />
|
||||
</template>
|
||||
<template #connection-line="props">
|
||||
<ConnectionLine v-bind="props" />
|
||||
</template>
|
||||
</VueFlow>
|
||||
</Panel>
|
||||
<Panel :position="PanelPosition.BottomLeft">
|
||||
<button class="btn btn-sm btn-default mr-2" @click="zoomIn">+</button>
|
||||
<button class="btn btn-sm btn-default mr-2" @click="zoomOut">-</button>
|
||||
<button class="btn btn-sm btn-default" @click="fitView({ padding: 0.4 })">
|
||||
Fit
|
||||
</button>
|
||||
</Panel>
|
||||
<template #node-state="node">
|
||||
<StateNode :node="node" />
|
||||
</template>
|
||||
<template #node-action="node">
|
||||
<ActionNode :node="node" />
|
||||
</template>
|
||||
<template #edge-transition="props">
|
||||
<TransitionEdge v-bind="props" />
|
||||
</template>
|
||||
<template #connection-line="props">
|
||||
<ConnectionLine v-bind="props" />
|
||||
</template>
|
||||
</VueFlow>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -222,6 +226,11 @@ onMounted(() => store.fetch());
|
|||
@import "@vue-flow/core/dist/style.css";
|
||||
@import "@vue-flow/core/dist/theme-default.css";
|
||||
|
||||
.main {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: calc(100vh - var(--navbar-height) - var(--page-head-height) - 65px);
|
||||
}
|
||||
.workflow-container {
|
||||
width: 100%;
|
||||
height: calc(100vh - var(--navbar-height) - var(--page-head-height) - 65px);
|
||||
|
|
|
|||
58
frappe/public/js/workflow_builder/components/Properties.vue
Normal file
58
frappe/public/js/workflow_builder/components/Properties.vue
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<script setup>
|
||||
import { computed } from "vue";
|
||||
import { useStore } from "../store";
|
||||
|
||||
let store = useStore();
|
||||
|
||||
let properties = computed(() => {
|
||||
return store.workflowfields.filter(df => {
|
||||
if (in_list(["states", "transitions", "workflow_data", "workflow_name"], df.fieldname)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="properties">
|
||||
<div class="control-data">
|
||||
<div v-if="store.workflow_doc">
|
||||
<div class="field" v-for="df in properties" :key="df.name">
|
||||
<component
|
||||
:is="df.fieldtype.replace(' ', '') + 'Control'"
|
||||
:df="df"
|
||||
:value="store.workflow_doc[df.fieldname]"
|
||||
v-model="store.workflow_doc[df.fieldname]"
|
||||
:data-fieldname="df.fieldname"
|
||||
:data-fieldtype="df.fieldtype"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.control-data {
|
||||
height: calc(100vh - 210px);
|
||||
overflow-y: auto;
|
||||
padding: 8px;
|
||||
|
||||
.field {
|
||||
margin: 5px;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
:deep(.form-control:disabled) {
|
||||
color: var(--disabled-text-color);
|
||||
background-color: var(--disabled-control-bg);
|
||||
cursor: default;
|
||||
}
|
||||
:deep(.description) {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--text-muted);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
21
frappe/public/js/workflow_builder/components/Sidebar.vue
Normal file
21
frappe/public/js/workflow_builder/components/Sidebar.vue
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<script setup>
|
||||
import Properties from "./Properties.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="sidebar-container">
|
||||
<Properties />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.sidebar-container {
|
||||
position: relative;
|
||||
width: 300px;
|
||||
height: 100%;
|
||||
margin-right: 10px;
|
||||
border-radius: var(--border-radius-lg);
|
||||
border: 1px solid var(--border-color);
|
||||
background-color: var(--fg-color);
|
||||
}
|
||||
</style>
|
||||
56
frappe/public/js/workflow_builder/globals.js
Normal file
56
frappe/public/js/workflow_builder/globals.js
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import AttachControl from "../form_builder/components/controls/AttachControl.vue";
|
||||
import ButtonControl from "../form_builder/components/controls/ButtonControl.vue";
|
||||
import CheckControl from "../form_builder/components/controls/CheckControl.vue";
|
||||
import CodeControl from "../form_builder/components/controls/CodeControl.vue";
|
||||
import DataControl from "../form_builder/components/controls/DataControl.vue";
|
||||
import GeolocationControl from "../form_builder/components/controls/GeolocationControl.vue";
|
||||
import ImageControl from "../form_builder/components/controls/ImageControl.vue";
|
||||
import LinkControl from "../form_builder/components/controls/LinkControl.vue";
|
||||
import RatingControl from "../form_builder/components/controls/RatingControl.vue";
|
||||
import SelectControl from "../form_builder/components/controls/SelectControl.vue";
|
||||
import SignatureControl from "../form_builder/components/controls/SignatureControl.vue";
|
||||
import TableControl from "../form_builder/components/controls/TableControl.vue";
|
||||
import TextControl from "../form_builder/components/controls/TextControl.vue";
|
||||
import TextEditorControl from "../form_builder/components/controls/TextEditorControl.vue";
|
||||
|
||||
export function registerGlobalComponents(app) {
|
||||
app.component("AttachControl", AttachControl)
|
||||
.component("AttachImageControl", AttachControl)
|
||||
.component("AutocompleteControl", DataControl)
|
||||
.component("BarcodeControl", DataControl)
|
||||
.component("ButtonControl", ButtonControl)
|
||||
.component("CheckControl", CheckControl)
|
||||
.component("CodeControl", CodeControl)
|
||||
.component("ColorControl", DataControl)
|
||||
.component("CurrencyControl", DataControl)
|
||||
.component("DataControl", DataControl)
|
||||
.component("DateControl", DataControl)
|
||||
.component("DatetimeControl", DataControl)
|
||||
.component("DurationControl", DataControl)
|
||||
.component("DynamicLinkControl", DataControl)
|
||||
.component("FloatControl", DataControl)
|
||||
.component("GeolocationControl", GeolocationControl)
|
||||
.component("HeadingControl", ButtonControl)
|
||||
.component("HTMLControl", DataControl)
|
||||
.component("HTMLEditorControl", CodeControl)
|
||||
.component("IconControl", DataControl)
|
||||
.component("ImageControl", ImageControl)
|
||||
.component("IntControl", DataControl)
|
||||
.component("JSONControl", CodeControl)
|
||||
.component("LinkControl", LinkControl)
|
||||
.component("LongTextControl", TextControl)
|
||||
.component("MarkdownEditorControl", CodeControl)
|
||||
.component("PasswordControl", DataControl)
|
||||
.component("PercentControl", DataControl)
|
||||
.component("PhoneControl", DataControl)
|
||||
.component("ReadOnlyControl", DataControl)
|
||||
.component("RatingControl", RatingControl)
|
||||
.component("SelectControl", SelectControl)
|
||||
.component("SignatureControl", SignatureControl)
|
||||
.component("SmallTextControl", TextControl)
|
||||
.component("TableControl", TableControl)
|
||||
.component("TableMultiSelectControl", DataControl)
|
||||
.component("TextControl", TextControl)
|
||||
.component("TextEditorControl", TextEditorControl)
|
||||
.component("TimeControl", DataControl);
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ export const useStore = defineStore("workflow-builder-store", () => {
|
|||
let workflow = ref({
|
||||
elements: [],
|
||||
});
|
||||
let workflowfields = ref([]);
|
||||
let ref_history = ref(null);
|
||||
|
||||
async function fetch() {
|
||||
|
|
@ -18,6 +19,11 @@ export const useStore = defineStore("workflow-builder-store", () => {
|
|||
workflow_doc.value = frappe.get_doc("Workflow", workflow_name.value);
|
||||
await frappe.model.with_doctype(workflow_doc.value.document_type);
|
||||
|
||||
if (!workflowfields.value.length) {
|
||||
await frappe.model.with_doctype("Workflow");
|
||||
workflowfields.value = frappe.get_meta("Workflow").fields;
|
||||
}
|
||||
|
||||
if (
|
||||
workflow_doc.value.workflow_data &&
|
||||
JSON.parse(workflow_doc.value.workflow_data).length &&
|
||||
|
|
@ -75,7 +81,9 @@ export const useStore = defineStore("workflow-builder-store", () => {
|
|||
|
||||
return {
|
||||
workflow_name,
|
||||
workflow_doc,
|
||||
workflow,
|
||||
workflowfields,
|
||||
ref_history,
|
||||
fetch,
|
||||
reset_changes,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { createApp } from "vue";
|
|||
import { createPinia } from "pinia";
|
||||
import { useStore } from "./store";
|
||||
import WorkflowBuilderComponent from "./WorkflowBuilder.vue";
|
||||
import { registerGlobalComponents } from "./globals.js";
|
||||
|
||||
class WorkflowBuilder {
|
||||
constructor({ wrapper, page, workflow }) {
|
||||
|
|
@ -53,6 +54,9 @@ class WorkflowBuilder {
|
|||
this.store = useStore();
|
||||
this.store.workflow_name = this.workflow;
|
||||
|
||||
// register global components
|
||||
registerGlobalComponents(app);
|
||||
|
||||
// mount the app
|
||||
this.$workflow_builder = app.mount(this.$wrapper.get(0));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue