fix: added sidebar to show workflow data

This commit is contained in:
Shariq Ansari 2023-05-02 19:00:34 +05:30
parent 13e5031c3c
commit bcfd07be73
6 changed files with 185 additions and 29 deletions

View file

@ -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);

View 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>

View 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>

View 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);
}

View file

@ -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,

View file

@ -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));
}