フロー保存の実装
This commit is contained in:
Binary file not shown.
@@ -1,11 +1,5 @@
|
||||
<template>
|
||||
<div
|
||||
class="row"
|
||||
style="
|
||||
border-radius: 2px;
|
||||
box-shadow: rgba(255, 255, 255, 0.1) 0px 0px 0px 1px inset,
|
||||
rgba(0, 0, 0, 0.3) 0px 0px 0px 1px;
|
||||
">
|
||||
<div class="row app-box">
|
||||
<q-icon
|
||||
class="self-center q-ma-sm"
|
||||
name="widgets"
|
||||
@@ -13,7 +7,7 @@
|
||||
style="font-size: 2em"
|
||||
/>
|
||||
<div class="col-7 self-center ellipsis">
|
||||
{{ selectedApp.name }}
|
||||
{{ store.appInfo?.name }}
|
||||
</div>
|
||||
<div class="self-center">
|
||||
<q-btn
|
||||
@@ -51,22 +45,19 @@ export default defineComponent({
|
||||
const store = useFlowEditorStore();
|
||||
const appDg = ref();
|
||||
const showSelectApp=ref(false);
|
||||
const selectedApp =ref<AppInfo>({
|
||||
appId:"",
|
||||
name:"",
|
||||
});
|
||||
|
||||
const closeDg=(val :any)=>{
|
||||
showSelectApp.value=false;
|
||||
console.log("Dialog closed->",val);
|
||||
if (val == 'OK') {
|
||||
const data = appDg.value.selected[0];
|
||||
console.log(data);
|
||||
selectedApp.value={
|
||||
const appInfo={
|
||||
appId:data.id ,
|
||||
name:data.name
|
||||
};
|
||||
store.setApp(selectedApp.value);
|
||||
store.setFlow();
|
||||
store.setApp(appInfo);
|
||||
store.loadFlow();
|
||||
}
|
||||
}
|
||||
const showAppDialog=()=>{
|
||||
@@ -74,7 +65,6 @@ export default defineComponent({
|
||||
}
|
||||
return {
|
||||
store,
|
||||
selectedApp,
|
||||
showSelectApp,
|
||||
showAppDialog,
|
||||
closeDg,
|
||||
@@ -83,3 +73,9 @@ export default defineComponent({
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.app-box{
|
||||
border-radius: 2px;
|
||||
box-shadow: rgba(255, 255, 255, 0.1) 0px 0px 0px 1px inset,rgba(0, 0, 0, 0.3) 0px 0px 0px 1px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="q-pa-md q-gutter-sm">
|
||||
<!-- <div class="q-pa-md q-gutter-sm"> -->
|
||||
<q-tree
|
||||
:nodes="store.eventTree.screens"
|
||||
node-key="label"
|
||||
children-key="events"
|
||||
no-connectors
|
||||
v-model:expanded="expanded"
|
||||
v-model:expanded="store.expandedScreen"
|
||||
:dense="true"
|
||||
>
|
||||
<template v-slot:default-header="prop">
|
||||
@@ -19,7 +19,7 @@
|
||||
</div>
|
||||
</template>
|
||||
</q-tree>
|
||||
</div>
|
||||
<!-- </div> -->
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -36,9 +36,7 @@ export default defineComponent({
|
||||
// const eventTree=ref(kintoneEvents);
|
||||
// const selectedFlow = store.currentFlow;
|
||||
|
||||
const expanded=ref([
|
||||
store.currentFlow?.getRoot()?.title
|
||||
]);
|
||||
// const expanded=ref();
|
||||
const selectedEvent = ref<IKintoneEvent|null>(null);
|
||||
const onSelected=(node:IKintoneEvent)=>{
|
||||
if(!node.eventId){
|
||||
@@ -63,7 +61,7 @@ export default defineComponent({
|
||||
}
|
||||
return {
|
||||
// eventTree,
|
||||
expanded,
|
||||
// expanded,
|
||||
onSelected,
|
||||
selectedEvent,
|
||||
store
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
|
||||
<q-input v-model="selectedDate" :label="placeholder" mask="date" :rules="['date']">
|
||||
<q-input v-model="selectedDate" :label="displayName" :placeholder="placeholder" mask="date" :rules="['date']">
|
||||
<template v-slot:append>
|
||||
<q-icon name="event" class="cursor-pointer">
|
||||
<q-popup-proxy cover transition-show="scale" transition-hide="scale">
|
||||
@@ -21,6 +21,10 @@ import { defineComponent, ref ,watchEffect} from 'vue';
|
||||
export default defineComponent({
|
||||
name: 'DatePicker',
|
||||
props: {
|
||||
displayName:{
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<q-input v-model="selectedField" :label="placeholder">
|
||||
<q-input v-model="selectedField" :label="displayName" :placeholder="placeholder" >
|
||||
<template v-slot:append>
|
||||
<q-icon name="search" class="cursor-pointer" @click="showDg"/>
|
||||
</template>
|
||||
@@ -21,6 +21,10 @@ export default defineComponent({
|
||||
FieldSelect,
|
||||
},
|
||||
props: {
|
||||
displayName:{
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<q-input :label="placeholder" v-model="inputValue"/>
|
||||
<q-input :label="displayName" :placeholder="placeholder" v-model="inputValue"/>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -8,6 +8,10 @@ import { defineComponent,ref,watchEffect } from 'vue';
|
||||
export default defineComponent({
|
||||
name: 'InputText',
|
||||
props: {
|
||||
displayName:{
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<q-select v-model="selectedValue" :label="placeholder" :options="options"/>
|
||||
<q-select v-model="selectedValue" :label="displayName" :options="options"/>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -8,6 +8,10 @@ import { defineComponent,ref,watchEffect } from 'vue';
|
||||
export default defineComponent({
|
||||
name: 'SelectBox',
|
||||
props: {
|
||||
displayName:{
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
|
||||
@@ -6,16 +6,22 @@ export class FlowCtrl
|
||||
|
||||
async getFlows(appId:string):Promise<ActionFlow[]>
|
||||
{
|
||||
const flows:ActionFlow[]=[];
|
||||
try{
|
||||
const result = await api.get(`http://127.0.0.1:8000/api/flows/${appId}`);
|
||||
//console.info(result.data);
|
||||
if(!result.data || !Array.isArray(result.data)){
|
||||
return [];
|
||||
}
|
||||
const flows:ActionFlow[]=[];
|
||||
|
||||
for(const flow of result.data){
|
||||
flows.push(ActionFlow.fromJSON(flow.content));
|
||||
}
|
||||
return flows;
|
||||
}catch(error){
|
||||
console.error(error);
|
||||
return flows;
|
||||
}
|
||||
}
|
||||
|
||||
async SaveFlow(jsonData:any):Promise<boolean>
|
||||
|
||||
@@ -8,21 +8,23 @@
|
||||
:show-if-above="false"
|
||||
elevated
|
||||
>
|
||||
<!-- <q-card class="column full-height" style="width: 300px">
|
||||
<q-card-section> -->
|
||||
|
||||
<div class="flex-center fixd-top" >
|
||||
<q-card class="column full-height" >
|
||||
<q-card-section>
|
||||
<div class="flex-center " >
|
||||
<AppSelector />
|
||||
</div>
|
||||
|
||||
<!-- </q-card-section> -->
|
||||
<q-separator />
|
||||
<!-- <q-card-section> -->
|
||||
<!-- </q-card-section>
|
||||
<q-card-section> -->
|
||||
<div class="flex-center">
|
||||
<EventTree />
|
||||
</div>
|
||||
<!-- </q-card-section> -->
|
||||
<!-- </q-card> -->
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
<div class="flex-center fixed-bottom bg-grey-3 q-pa-md row ">
|
||||
<q-btn color="deep-orange" glossy label="デプロイ" @click="onDeploy" icon="sync"/>
|
||||
<q-space></q-space>
|
||||
<q-btn color="primary" label="保存" @click="onSaveFlow" icon="save" />
|
||||
</div>
|
||||
</q-drawer>
|
||||
</div>
|
||||
|
||||
@@ -59,8 +61,9 @@ import PropertyPanel from 'components/right/PropertyPanel.vue';
|
||||
import AppSelector from 'components/left/AppSelector.vue';
|
||||
import EventTree from 'components/left/EventTree.vue';
|
||||
import {FlowCtrl } from '../control/flowctrl';
|
||||
import { useQuasar } from 'quasar';
|
||||
const drawerLeft = ref(true);
|
||||
|
||||
const $q=useQuasar();
|
||||
const store = useFlowEditorStore();
|
||||
// ref関数を使ってtemplateとバインド
|
||||
const state=reactive({
|
||||
@@ -73,7 +76,7 @@ const prevNodeIfo=ref({
|
||||
prevNode:{} as IActionNode,
|
||||
inputPoint:""
|
||||
});
|
||||
const refFlow = ref<ActionFlow|null>(null);
|
||||
// const refFlow = ref<ActionFlow|null>(null);
|
||||
const showAddAction=ref(false);
|
||||
const drawerRight=ref(false);
|
||||
const model=ref("");
|
||||
@@ -120,6 +123,37 @@ const closeDg=(val :any)=>{
|
||||
}
|
||||
}
|
||||
|
||||
const onDeploy=()=>{
|
||||
return;
|
||||
}
|
||||
|
||||
const onSaveFlow = async ()=>{
|
||||
const targetFlow = store.selectedFlow;
|
||||
if(targetFlow===undefined){
|
||||
$q.notify({
|
||||
type: 'negative',
|
||||
caption:"エラー",
|
||||
message: `編集中のフローがありません。`
|
||||
});
|
||||
return;
|
||||
}
|
||||
try{
|
||||
await store.saveFlow(targetFlow);
|
||||
$q.notify({
|
||||
type: 'positive',
|
||||
caption:"通知",
|
||||
message: `${targetFlow.getRoot()?.subTitle}のフロー設定を保存しました。`
|
||||
});
|
||||
}catch(error){
|
||||
$q.notify({
|
||||
type: 'negative',
|
||||
caption:"エラー",
|
||||
message: `${targetFlow.getRoot()?.subTitle}のフローの設定の保存が失敗しました。`
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const fetchData = async ()=>{
|
||||
const flowCtrl = new FlowCtrl();
|
||||
if(store.appInfo===undefined) return;
|
||||
@@ -130,8 +164,7 @@ const fetchData= async ()=>{
|
||||
if(actionFlows && actionFlows.length==1){
|
||||
store.selectFlow(actionFlows[0]);
|
||||
}
|
||||
refFlow.value=actionFlows[0];
|
||||
const root =refFlow.value.getRoot();
|
||||
const root =actionFlows[0].getRoot();
|
||||
if(root){
|
||||
state.activeNode=root;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ export interface FlowEditorState{
|
||||
selectedFlow?:IActionFlow|undefined;
|
||||
eventTree:KintoneEventManager;
|
||||
selectedEvent:IKintoneEvent|undefined;
|
||||
expandedScreen:any[];
|
||||
}
|
||||
const flowCtrl=new FlowCtrl();
|
||||
export const useFlowEditorStore = defineStore("flowEditor",{
|
||||
@@ -19,7 +20,8 @@ export const useFlowEditorStore = defineStore("flowEditor",{
|
||||
flows:[],
|
||||
selectedFlow:undefined,
|
||||
eventTree:kintoneEvents,
|
||||
selectedEvent:undefined
|
||||
selectedEvent:undefined,
|
||||
expandedScreen:[]
|
||||
}),
|
||||
getters: {
|
||||
/**
|
||||
@@ -54,17 +56,46 @@ export const useFlowEditorStore = defineStore("flowEditor",{
|
||||
setApp(app:AppInfo){
|
||||
this.appInfo=app;
|
||||
},
|
||||
async setFlow(){
|
||||
/**
|
||||
* DBからフルーを保存する
|
||||
* @returns
|
||||
*/
|
||||
async loadFlow(){
|
||||
if(this.appInfo===undefined) return;
|
||||
const actionFlows = await flowCtrl.getFlows(this.appInfo?.appId);
|
||||
//eventTreeにバンドする
|
||||
this.eventTree.bindFlows(actionFlows);
|
||||
if(actionFlows && actionFlows.length>0){
|
||||
this.setFlows(actionFlows);
|
||||
if(actionFlows===undefined || actionFlows.length===0){
|
||||
this.flows=[];
|
||||
this.selectedFlow=undefined;
|
||||
return;
|
||||
}
|
||||
if(actionFlows && actionFlows.length==1){
|
||||
this.setFlows(actionFlows);
|
||||
if(actionFlows && actionFlows.length>0){
|
||||
this.selectFlow(actionFlows[0]);
|
||||
}
|
||||
const expandName =actionFlows[0].getRoot()?.title;
|
||||
this.expandedScreen=[expandName];
|
||||
},
|
||||
/**
|
||||
* フローをDBに保存及び更新する
|
||||
*/
|
||||
async saveFlow(flow:IActionFlow){
|
||||
const root=flow.getRoot();
|
||||
const isNew = flow.id==='';
|
||||
const jsonData={
|
||||
flowid: isNew ? flow.createNewId():flow.id,
|
||||
appid: this.appInfo?.appId,
|
||||
eventid: root?.name,
|
||||
name: root?.subTitle,
|
||||
content: JSON.stringify(flow)
|
||||
}
|
||||
|
||||
if(isNew){
|
||||
return await flowCtrl.SaveFlow(jsonData);
|
||||
}else{
|
||||
return await flowCtrl.UpdateFlow(jsonData);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ export interface IActionFlow {
|
||||
id: string;
|
||||
actionNodes: Array<IActionNode>;
|
||||
getRoot(): IActionNode | undefined;
|
||||
createNewId():string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,7 +98,10 @@ class ActionProperty implements IActionProperty {
|
||||
export class ActionNode implements IActionNode {
|
||||
id: string;
|
||||
name: string;
|
||||
title:string;
|
||||
get title(): string {
|
||||
const prop = this.actionProps.find((prop) => prop.props.name === "displayName");
|
||||
return prop?.props.modelValue;
|
||||
};
|
||||
get subTitle(): string {
|
||||
return this.name;
|
||||
};
|
||||
@@ -126,11 +130,10 @@ export class ActionNode implements IActionNode {
|
||||
) {
|
||||
this.id = uuidv4();
|
||||
this.name = name;
|
||||
this.title=title;
|
||||
this.inputPoint = inputPoint;
|
||||
this.outputPoints = outputPoint;
|
||||
const defProp = ActionProperty.defaultProperty();
|
||||
defProp.props.displayName=title;
|
||||
defProp.props.modelValue = title;
|
||||
this.actionProps = actionProps;
|
||||
const prop = this.actionProps.find((prop) => prop.props.name === defProp.props.name);
|
||||
if (prop === undefined) {
|
||||
@@ -186,7 +189,8 @@ export class ActionFlow implements IActionFlow {
|
||||
} else {
|
||||
this.actionNodes = [actionNodes];
|
||||
}
|
||||
this.id=uuidv4();
|
||||
this.id = '';
|
||||
//this.id = uuidv4();
|
||||
}
|
||||
/**
|
||||
* ノードを追加する
|
||||
@@ -200,8 +204,7 @@ export class ActionFlow implements IActionFlow {
|
||||
addNode(
|
||||
newNode: IActionNode,
|
||||
prevNode?: IActionNode,
|
||||
inputPoint?:string):IActionNode
|
||||
{
|
||||
inputPoint?: string): IActionNode {
|
||||
if (inputPoint !== undefined) {
|
||||
newNode.inputPoint = inputPoint;
|
||||
}
|
||||
@@ -270,7 +273,7 @@ disconnectFromPrevNode(targetNode: IActionNode): void {
|
||||
}
|
||||
}
|
||||
|
||||
// 从 actionNodes 数组中移除节点
|
||||
// actionNodes からノードを削除する
|
||||
private removeFromActionNodes(targetNodeId: string): void {
|
||||
const index = this.actionNodes.findIndex(node => node.id === targetNodeId);
|
||||
if (index > -1) {
|
||||
@@ -333,14 +336,18 @@ reconnectOrRemoveNextNodes(targetNode: IActionNode): void {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param prevNode ノードの接続をリセットする
|
||||
* @param newNode
|
||||
* @param inputPoint
|
||||
*/
|
||||
resetNodeRelation(prevNode: IActionNode, newNode: IActionNode, inputPoint?: string) {
|
||||
// 设置新节点和前节点的关联
|
||||
//
|
||||
prevNode.nextNodeIds.set(inputPoint || '', newNode.id);
|
||||
newNode.prevNodeId = prevNode.id;
|
||||
// 保存前节点原有的后节点ID
|
||||
const originalNextNodeId = prevNode.nextNodeIds.get(inputPoint || '');
|
||||
this.setNewNodeNextId(newNode, originalNextNodeId, inputPoint);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -350,13 +357,13 @@ reconnectOrRemoveNextNodes(targetNode: IActionNode): void {
|
||||
* @param inputPoint
|
||||
*/
|
||||
private setNewNodeNextId(newNode: IActionNode, originalNextNodeId: string | undefined, inputPoint?: string) {
|
||||
// 如果原先的后节点存在
|
||||
// 元の接続ノードが存在する
|
||||
if (originalNextNodeId) {
|
||||
// 检查新节点的 outputPoints 是否包含该 inputPoint
|
||||
// 新しいノードの outputPoints に該当 inputPointが存在するか場合をチェックする
|
||||
if (newNode.outputPoints.includes(inputPoint || '')) {
|
||||
newNode.nextNodeIds.set(inputPoint || '', originalNextNodeId);
|
||||
} else {
|
||||
// 如果不包含,选择新节点的一个 outputPoint
|
||||
// inputPointが存在しない場合、outputPointのポイントの任意ポートを選択する
|
||||
const alternativeOutputPoint = newNode.outputPoints.length > 0 ? newNode.outputPoints[0] : '';
|
||||
newNode.nextNodeIds.set(alternativeOutputPoint, originalNextNodeId);
|
||||
}
|
||||
@@ -387,6 +394,11 @@ reconnectOrRemoveNextNodes(targetNode: IActionNode): void {
|
||||
return this.actionNodes.find(node => node.isRoot)
|
||||
}
|
||||
|
||||
createNewId():string{
|
||||
this.id=uuidv4();
|
||||
return this.id;
|
||||
}
|
||||
|
||||
static fromJSON(json: string): ActionFlow {
|
||||
const parsedObject = JSON.parse(json);
|
||||
|
||||
@@ -402,7 +414,5 @@ reconnectOrRemoveNextNodes(targetNode: IActionNode): void {
|
||||
actionFlow.id = parsedObject.id;
|
||||
return actionFlow;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
130
sample.json
130
sample.json
@@ -1,138 +1,20 @@
|
||||
{
|
||||
"id": "681ecde3-4439-4210-9fdf-424c6af98f09",
|
||||
"actionNodes": [
|
||||
{
|
||||
"id": "34dfd32e-ba1a-440f-bb46-a8a1999109cd",
|
||||
"name": "app.record.create.submit",
|
||||
"title": "レコード追加画面",
|
||||
"subTitle": "保存するとき",
|
||||
"inputPoint": "",
|
||||
"outputPoints": [],
|
||||
"isRoot": true,
|
||||
"actionProps": [],
|
||||
"ActionValue": {},
|
||||
"nextNodeIds": [
|
||||
[
|
||||
"",
|
||||
"ce07775d-9729-4516-a88c-78ee8f2f851e"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ce07775d-9729-4516-a88c-78ee8f2f851e",
|
||||
"name": "自動採番",
|
||||
"title": "文書番号を自動採番する",
|
||||
"inputPoint": "",
|
||||
"outputPoints": [],
|
||||
"actionProps": [
|
||||
{
|
||||
"component": "InputText",
|
||||
"props": {
|
||||
"name": "displayName",
|
||||
"displayName": "文書番号を自動採番する",
|
||||
"placeholder": "表示を入力してください",
|
||||
"modelValue": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "InputText",
|
||||
"props": {
|
||||
"displayName": "フォーマット",
|
||||
"modelValue": "",
|
||||
"name": "format",
|
||||
"placeholder": "フォーマットを入力してください"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "FieldInput",
|
||||
"props": {
|
||||
"displayName": "採番項目",
|
||||
"displayName": "フィールド",
|
||||
"modelValue": "",
|
||||
"name": "field",
|
||||
"placeholder": "採番項目を選択してください"
|
||||
"placeholder": "必須項目を選択してください"
|
||||
}
|
||||
}
|
||||
],
|
||||
"prevNodeId": "34dfd32e-ba1a-440f-bb46-a8a1999109cd",
|
||||
"nextNodeIds": [
|
||||
[
|
||||
"",
|
||||
"0d18c3c9-abee-44e5-83eb-82074316219b"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "0d18c3c9-abee-44e5-83eb-82074316219b",
|
||||
"name": "入力データ取得",
|
||||
"title": "電話番号を取得する",
|
||||
"inputPoint": "",
|
||||
"outputPoints": [],
|
||||
"actionProps": [
|
||||
{
|
||||
"component": "InputText",
|
||||
"props": {
|
||||
"name": "displayName",
|
||||
"displayName": "表示名",
|
||||
"placeholder": "表示を入力してください",
|
||||
"modelValue": ""
|
||||
"displayName": "エラーメッセージ",
|
||||
"modelValue": "",
|
||||
"name": "format",
|
||||
"placeholder": "エラーメッセージを入力してください"
|
||||
}
|
||||
}
|
||||
],
|
||||
"prevNodeId": "ce07775d-9729-4516-a88c-78ee8f2f851e",
|
||||
"nextNodeIds": [
|
||||
[
|
||||
"",
|
||||
"399d7c04-5345-4bf6-8da3-d745df554524"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "399d7c04-5345-4bf6-8da3-d745df554524",
|
||||
"name": "条件分岐",
|
||||
"title": "電話番号入力形式チャック",
|
||||
"inputPoint": "",
|
||||
"outputPoints": [
|
||||
"はい",
|
||||
"いいえ"
|
||||
],
|
||||
"actionProps": [
|
||||
{
|
||||
"component": "InputText",
|
||||
"props": {
|
||||
"name": "displayName",
|
||||
"displayName": "表示名",
|
||||
"placeholder": "表示を入力してください",
|
||||
"modelValue": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"prevNodeId": "0d18c3c9-abee-44e5-83eb-82074316219b",
|
||||
"nextNodeIds": [
|
||||
[
|
||||
"いいえ",
|
||||
"8173e6bc-3fa2-4403-b973-9368884e2dfa"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "8173e6bc-3fa2-4403-b973-9368884e2dfa",
|
||||
"name": "エラー表示",
|
||||
"title": "エラー表示して保存しない",
|
||||
"inputPoint": "いいえ",
|
||||
"outputPoints": [],
|
||||
"actionProps": [
|
||||
{
|
||||
"component": "InputText",
|
||||
"props": {
|
||||
"name": "displayName",
|
||||
"displayName": "表示名",
|
||||
"placeholder": "表示を入力してください",
|
||||
"modelValue": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"prevNodeId": "399d7c04-5345-4bf6-8da3-d745df554524",
|
||||
"nextNodeIds": []
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user