Compare commits

..

1 Commits

Author SHA1 Message Date
Mouriya
700fa24868 保存ボタンクリック時にイベントを一括削除 2024-05-13 00:53:24 +09:00
24 changed files with 728 additions and 812 deletions

View File

@@ -2,6 +2,7 @@
<html lang="ja-jp"> <html lang="ja-jp">
<head> <head>
<title><%= productName %></title> <title><%= productName %></title>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="description" content="<%= productDescription %>"> <meta name="description" content="<%= productDescription %>">
<meta name="format-detection" content="telephone=no"> <meta name="format-detection" content="telephone=no">

View File

@@ -17,9 +17,8 @@
}, },
"dependencies": { "dependencies": {
"@quasar/extras": "^1.16.4", "@quasar/extras": "^1.16.4",
"@vueuse/core": "^10.9.0",
"axios": "^1.4.0", "axios": "^1.4.0",
"pinia": "^2.1.7", "pinia": "^2.1.6",
"quasar": "^2.6.0", "quasar": "^2.6.0",
"uuid": "^9.0.0", "uuid": "^9.0.0",
"vue": "^3.0.0", "vue": "^3.0.0",

View File

@@ -4,7 +4,6 @@ import { Router } from 'vue-router';
import { App } from 'vue'; import { App } from 'vue';
export default boot(({ app, router }: { app: App<Element>; router: Router }) => { export default boot(({ app, router }: { app: App<Element>; router: Router }) => {
document.documentElement.lang="ja-JP";
app.config.errorHandler = (err: any, instance: any, info: string) => { app.config.errorHandler = (err: any, instance: any, info: string) => {
if (err.response && err.response.status === 401) { if (err.response && err.response.status === 401) {
// 認証エラーの場合再ログインする // 認証エラーの場合再ログインする

View File

@@ -1,5 +1,5 @@
<template> <template>
<show-dialog v-model:visible="showflg" name="条件エディタ" @close="closeDg" min-width="50vw" min-height="60vh"> <show-dialog v-model:visible="showflg" name="条件エディタ" @close="closeDg" min-width="60vw" min-height="60vh">
<template v-slot:toolbar> <template v-slot:toolbar>
<q-btn flat round dense icon="more_vert" > <q-btn flat round dense icon="more_vert" >
<q-menu auto-close anchor="bottom start"> <q-menu auto-close anchor="bottom start">

View File

@@ -6,14 +6,14 @@
{{ selectedObject.name }} {{ selectedObject.name }}
</q-chip> </q-chip>
<q-chip color="info" text-color="white" v-if="isSelected && selectedObject.objectType==='variable'" :dense="true" class="selected-obj"> <q-chip color="info" text-color="white" v-if="isSelected && selectedObject.objectType==='variable'" :dense="true" class="selected-obj">
{{ selectedObject.name.name }} {{ selectedObject.name }}
</q-chip> </q-chip>
</template> </template>
<template v-slot:append> <template v-slot:append>
<q-icon name="search" class="cursor-pointer" @click="showDg"/> <q-icon name="search" class="cursor-pointer" @click="showDg"/>
</template> </template>
</q-field> </q-field>
<show-dialog v-model:visible="show" name="設定項目一覧" @close="closeDg" min-width="400px"> <show-dialog v-model:visible="show" name="条件設定項目一覧" @close="closeDg" width="600px">
<template v-slot:toolbar> <template v-slot:toolbar>
<q-input dense debounce="200" v-model="filter" placeholder="検索" clearable> <q-input dense debounce="200" v-model="filter" placeholder="検索" clearable>
<template v-slot:before> <template v-slot:before>
@@ -88,9 +88,9 @@
.condition-object{ .condition-object{
min-width: 200px; min-width: 200px;
max-height: 40px; max-height: 40px;
margin: 0 2px; padding: 2px;
} }
.selected-obj{ .selected-obj{
margin: 0 2px; margin: 0px;
} }
</style> </style>

View File

@@ -66,7 +66,7 @@
</div> </div>
<!-- condition --> <!-- condition -->
<div @click.stop @keypress.stop v-else > <div @click.stop @keypress.stop v-else >
<div class="row no-wrap items-center q-my-xs"> <div class="row no-wrap items-center">
<ConditionObject v-bind="prop.node" v-model="prop.node.object" class="col-4"></ConditionObject> <ConditionObject v-bind="prop.node" v-model="prop.node.object" class="col-4"></ConditionObject>
<q-select v-model="prop.node.operator" :options="operators" class="operator" :outlined="true" :dense="true"></q-select> <q-select v-model="prop.node.operator" :options="operators" class="operator" :outlined="true" :dense="true"></q-select>
<q-input v-if="!prop.node.object || !('options' in prop.node.object)" <q-input v-if="!prop.node.object || !('options' in prop.node.object)"
@@ -257,12 +257,12 @@ export default defineComponent( {
.condition-value{ .condition-value{
min-width: 200px; min-width: 200px;
max-height: 40px; max-height: 40px;
margin: 0 2px; padding: 2px;
} }
.operator{ .operator{
min-width: 150px; min-width: 150px;
max-height: 40px; max-height: 40px;
margin: 0 2px; padding: 2px;
text-align: center; text-align: center;
font-size: 12pt; font-size: 12pt;
} }

View File

@@ -19,7 +19,7 @@
<q-tab-panels v-model="tab" animated> <q-tab-panels v-model="tab" animated>
<q-tab-panel name="fields"> <q-tab-panel name="fields">
<field-list v-model="selected" type="single" :filter="filter" :appId="sourceApp ? sourceApp :appId " :fields="sourceFields"></field-list> <field-list v-model="selected" type="single" :filter="filter" :appId="appId"></field-list>
</q-tab-panel> </q-tab-panel>
<q-tab-panel name="vars" > <q-tab-panel name="vars" >
@@ -30,7 +30,7 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { ref, onMounted, reactive, inject } from 'vue' import { ref, onMounted, reactive } from 'vue'
import FieldList from './FieldList.vue'; import FieldList from './FieldList.vue';
import VariableList from './VariableList.vue'; import VariableList from './VariableList.vue';
@@ -48,14 +48,10 @@ export default {
filter:String filter:String
}, },
setup(props) { setup(props) {
const selected = ref([]);
console.log(selected);
return { return {
sourceFields : inject('sourceFields'),
sourceApp : inject('sourceApp'),
tab: ref('fields'), tab: ref('fields'),
selected selected: ref([])
} }
}, },

View File

@@ -1,18 +1,19 @@
<template> <template>
<div class="q-pa-md"> <div class="q-pa-md">
<q-table flat bordered :loading="!isLoaded" row-key="name" :selection="type" :selected="modelValue" <q-table flat bordered :loading="!isLoaded" row-key="name" :selection="type"
@update:selected="$emit('update:modelValue', $event)" :filter="filter" :columns="columns" :rows="rows" /> :selected="modelValue"
@update:selected="$emit('update:modelValue', $event)"
:filter="filter"
:columns="columns" :rows="rows" />
</div> </div>
</template> </template>
<script lang="ts"> <script>
import { useAsyncState } from '@vueuse/core'; import { ref, onMounted, reactive } from 'vue'
import { api } from 'boot/axios'; import { api } from 'boot/axios';
import { computed } from 'vue';
export default { export default {
name: 'FieldList', name: 'FieldList',
props: { props: {
fields: Array,
name: String, name: String,
type: String, type: String,
appId: Number, appId: Number,
@@ -23,28 +24,27 @@ export default {
'update:modelValue' 'update:modelValue'
], ],
setup(props) { setup(props) {
// const rows = ref([]); const isLoaded = ref(false);
// const isLoaded = ref(false);
const columns = [ const columns = [
{ name: 'name', required: true, label: 'フィールド名', align: 'left', field: 'name', sortable: true }, { name: 'name', required: true, label: 'フィールド名', align: 'left', field: row => row.name, sortable: true },
{ name: 'code', label: 'フィールドコード', align: 'left', field: 'code', sortable: true }, { name: 'code', label: 'フィールドコード', align: 'left', field: 'code', sortable: true },
{ name: 'type', label: 'フィールドタイプ', align: 'left', field: 'type', sortable: true } { name: 'type', label: 'フィールドタイプ', align: 'left', field: 'type', sortable: true }
] ]
const rows = reactive([]);
const { state : rows, isReady: isLoaded, isLoading } = useAsyncState((args) => { onMounted(async () => {
if (props.fields) { const res = await api.get('api/v1/appfields', {
return props.fields.map(f => ({ name: f.label, objectType: 'field', ...f }));
} else {
return api.get('api/v1/appfields', {
params: { params: {
app: props.appId app: props.appId
} }
}).then(res => {
console.log(res);
return Object.values(res.data.properties).map(f => ({ name: f.label, objectType: 'field', ...f }));
}); });
} let fields = res.data.properties;
}, [{ name: '', objectType: '', type: '', code: '', label: '' }]) console.log(fields);
Object.keys(fields).forEach((key) => {
const fld = fields[key];
rows.push({ name: fld.label, objectType: 'field', ...fld });
});
isLoaded.value = true;
});
return { return {
columns, columns,

View File

@@ -1,7 +1,7 @@
<template> <template>
<!-- <div class="q-pa-md q-gutter-sm" > --> <!-- <div class="q-pa-md q-gutter-sm" > -->
<q-dialog :model-value="visible" persistent bordered > <q-dialog :model-value="visible" persistent bordered >
<q-card style="min-width: 40vw; max-width: 80vw; max-height: 95vh;" :style="cardStyle"> <q-card :style="cardStyle" style=" min-width: 40vw; max-width: 80vw; max-height: 95vh;">
<q-toolbar class="bg-grey-4"> <q-toolbar class="bg-grey-4">
<q-toolbar-title>{{ name }}</q-toolbar-title> <q-toolbar-title>{{ name }}</q-toolbar-title>
<q-space></q-space> <q-space></q-space>

View File

@@ -1,13 +1,14 @@
<template> <template>
<div class="q-pa-md"> <div class="q-pa-md">
<q-table flat bordered row-key="id" :selection="type" :selected="modelValue" <q-table flat bordered row-key="name" :selection="type"
@update:selected="$emit('update:modelValue', $event)" :columns="columns" :rows="rows" /> :selected="modelValue"
@update:selected="$emit('update:modelValue', $event)"
:columns="columns" :rows="rows" />
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { PropType, reactive } from 'vue'; import { ref, reactive, PropType, compile } from 'vue';
import { IActionVariable } from '../types/ActionTypes'; import {IActionNode,IActionVariable} from '../types/ActionTypes';
import { v4 as uuidv4 } from 'uuid';
export default { export default {
name: 'VariableList', name: 'VariableList',
@@ -25,30 +26,13 @@ export default {
'update:modelValue' 'update:modelValue'
], ],
setup(props) { setup(props) {
const variableName = (field) => {
const name = field.name;
return name.name;
}
const columns= [ const columns= [
{ name: 'actionName', label: 'アクション名',align: 'left',field: 'actionName',sortable: true}, { name: 'actionName', label: 'アクション名',align: 'left',field: 'actionName',sortable: true},
{ name: 'displayName', label: '変数表示名', align: 'left',field: 'displayName', sortable: true }, { name: 'displayName', label: '変数表示名', align: 'left',field: 'displayName', sortable: true },
{ name: 'name', label: '変数名', align: 'left', field: variableName, required: true, sortable: true } { name: 'name', label: '変数名', align: 'left',field: 'name',required: true, sortable: true }
]; ];
const rows= props.vars.map((v)=>{
const rows = props.vars.flatMap((v) => { return {objectType:'variable',...v};
if (v.name.vars && v.name.vars.length > 0) {
return v.name.vars
.filter(o => o.vName && o.logicalOperator && o.field)
.map(o => ({
id: uuidv4(),
objectType: 'variable',
name: { name: `${v.name.name}.${o.vName}` },
actionName: v.name.actionName,
displayName: v.name.displayName
}));
} else {
return [{ objectType: 'variable', ...v }];
}
}); });
return { return {

View File

@@ -1,48 +1,55 @@
<template> <template>
<!-- <div class="q-pa-md q-gutter-sm"> --> <!-- <div class="q-pa-md q-gutter-sm"> -->
<q-tree <q-tree :nodes="store.eventTree.screens" node-key="eventId" children-key="events" no-connectors
:nodes="store.eventTree.screens" v-model:expanded="store.expandedScreen" :dense="true" :ref="tree">
node-key="eventId"
children-key="events"
no-connectors
v-model:expanded="store.expandedScreen"
:dense="true"
:ref="tree"
>
<template v-slot:header-EVENT="prop"> <template v-slot:header-EVENT="prop">
<div class="row col items-start no-wrap event-node" @click="onSelected(prop.node)"> <div :ref="prop.node.eventId" class="row col items-center no-wrap event-node">
<q-icon v-if="prop.node.eventId" <q-icon v-if="prop.node.eventId" name="play_circle" :color="prop.node.hasFlow ? 'green' : 'grey'" size="16px"
name="play_circle" class="q-mr-sm">
:color="prop.node.hasFlow?'green':'grey'"
size="16px" class="q-mr-sm">
</q-icon> </q-icon>
<div class="no-wrap" :class="selectedEvent && prop.node.eventId===selectedEvent.eventId?'selected-node':''">{{ prop.node.label }}</div> <div class="no-wrap" @click="onSelected(prop.node)"
:class="selectedEvent && prop.node.eventId === selectedEvent.eventId ? 'selected-node' : ''">{{
prop.node.label }}</div>
<q-space></q-space> <q-space></q-space>
<!-- <q-icon v-if="prop.node.hasFlow" name="delete" color="negative" size="16px" class="q-mr-sm"></q-icon> --> <!-- <q-icon v-if="prop.node.hasFlow" name="delete" color="negative" size="16px" class="q-mr-sm"></q-icon> -->
</div> </div>
</template> </template>
<template v-slot:header-CHANGE="prop"> <template v-slot:header-CHANGE="prop">
<div class="row col items-start no-wrap event-node" > <div class="row col items-center no-wrap event-node">
<div class="no-wrap">{{ prop.node.label }}</div> <div class="no-wrap">{{ prop.node.label }}</div>
<q-space></q-space> <q-space></q-space>
<q-icon name="add_circle" color="primary" size="16px" class="q-mr-sm" @click="addChangeEvent(prop.node)"></q-icon> <q-icon name="add_circle" color="primary" size="16px" class="q-mr-sm"
@click="addChangeEvent(prop.node)"></q-icon>
</div>
</template>
<template v-slot:header-DELETABLE="prop">
<div class="row col items-center event-node">
<div class="row col items-center" @click="onSelected(prop.node)">
<q-icon v-if="prop.node.eventId" name="play_circle" :color="prop.node.hasFlow ? 'green' : 'grey'" size="16px"
class="q-mr-sm">
</q-icon>
<div>{{ prop.node.label }}</div>
</div>
<div>
<q-btn class="q-mr-sm delete-btn" flat fab-mini icon="delete_forever" padding="none" color="negative"
@click="deleteEvent(prop.node)"></q-btn>
</div>
</div> </div>
</template> </template>
</q-tree> </q-tree>
<show-dialog v-model:visible="showDialog" name="フィールド選択" @close="closeDg" widht="400px"> <show-dialog v-model:visible="showDialog" name="フィールド選択" @close="closeDg">
<field-select ref="appDg" name="フィールド" type="single" :appId="store.appInfo?.appId"></field-select> <field-select ref="appDg" name="フィールド" type="single" :appId="store.appInfo?.appId"></field-select>
</show-dialog> </show-dialog>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, computed, ref } from 'vue';
import { IKintoneEvent ,IKintoneEventGroup, IKintoneEventNode, kintoneEvent} from '../../types/KintoneEvents';
import { storeToRefs } from 'pinia';
import { useFlowEditorStore } from 'stores/flowEditor';
import { ActionFlow, ActionNode, RootAction } from 'src/types/ActionTypes';
import ShowDialog from '../ShowDialog.vue';
import FieldSelect from '../FieldSelect.vue';
import { QTree } from 'quasar'; import { QTree } from 'quasar';
import { ActionFlow, RootAction } from 'src/types/ActionTypes';
import { useFlowEditorStore } from 'stores/flowEditor';
import { defineComponent, ref } from 'vue';
import { IKintoneEvent, IKintoneEventGroup, IKintoneEventNode } from '../../types/KintoneEvents';
import FieldSelect from '../FieldSelect.vue';
import ShowDialog from '../ShowDialog.vue';
export default defineComponent({ export default defineComponent({
name: 'EventTree', name: 'EventTree',
components: { components: {
@@ -72,12 +79,12 @@ export default defineComponent({
if (store.eventTree.findEventById(eventid)) { if (store.eventTree.findEventById(eventid)) {
return; return;
} }
selectedChangeEvent.value?.events.push( selectedChangeEvent.value?.events.push({
new kintoneEvent( eventId: eventid,
field.label, label: field.name,
eventid, parentId: selectedChangeEvent.value.eventId,
selectedChangeEvent.value.eventId) header: 'DELETABLE'
); });
tree.value?.expanded?.push(selectedChangeEvent.value.eventId); tree.value?.expanded?.push(selectedChangeEvent.value.eventId);
tree.value?.expandAll(); tree.value?.expandAll();
} }
@@ -89,6 +96,17 @@ export default defineComponent({
selectedChangeEvent.value = node; selectedChangeEvent.value = node;
showDialog.value = true; showDialog.value = true;
} }
const deleteEvent = (node: IKintoneEvent) => {
if (!node.eventId) {
return;
}
store.deleteStoreEventAndFlow(node);
store.selectFlow(undefined)
console.log(store.selectedFlow);
}
const onSelected = (node: IKintoneEvent) => { const onSelected = (node: IKintoneEvent) => {
if (!node.eventId) { if (!node.eventId) {
return; return;
@@ -98,6 +116,7 @@ export default defineComponent({
return; return;
} }
const screen = store.eventTree.findEventById(node.parentId); const screen = store.eventTree.findEventById(node.parentId);
let flow = store.findFlowByEventId(node.eventId); let flow = store.findFlowByEventId(node.eventId);
let screenName = screen !== null ? screen.label : ""; let screenName = screen !== null ? screen.label : "";
let nodeLabel = node.label; let nodeLabel = node.label;
@@ -105,6 +124,7 @@ export default defineComponent({
// screenName=nodeLabel; // screenName=nodeLabel;
// nodeLabel=`${node.label}の値を変更したとき`; // nodeLabel=`${node.label}の値を変更したとき`;
// } // }
if (flow !== undefined && flow !== null) { if (flow !== undefined && flow !== null) {
store.selectFlow(flow); store.selectFlow(flow);
} else { } else {
@@ -125,6 +145,7 @@ export default defineComponent({
onSelected, onSelected,
selectedEvent, selectedEvent,
addChangeEvent, addChangeEvent,
deleteEvent,
closeDg, closeDg,
store store
} }
@@ -136,16 +157,21 @@ export default defineComponent({
flex-wrap: nowarp; flex-wrap: nowarp;
text-wrap: nowarp; text-wrap: nowarp;
} }
.event-node { .event-node {
cursor: pointer; cursor: pointer;
} }
.selected-node { .selected-node {
color: $primary; color: $primary;
font-weight: bolder; font-weight: bolder;
} }
.event-node:hover { .event-node:hover {
background-color: $light-blue-1; background-color: $light-blue-1;
} }
.delete-btn {
margin-right: 5px;
}
</style> </style>

View File

@@ -205,7 +205,7 @@ export default defineComponent({
*/ */
const varName =(node:IActionNode)=>{ const varName =(node:IActionNode)=>{
const prop = node.actionProps.find((prop) => prop.props.name === "verName"); const prop = node.actionProps.find((prop) => prop.props.name === "verName");
return prop?.props.modelValue.name; return prop?.props.modelValue;
}; };
const copyFlow=()=>{ const copyFlow=()=>{
context.emit('copyFlow', props.actionNode); context.emit('copyFlow', props.actionNode);

View File

@@ -128,7 +128,7 @@ interface IAppFields{
export default defineComponent({ export default defineComponent({
inheritAttrs:false, inheritAttrs:false,
name: 'AppFieldSelect', name: 'FieldInput',
components: { components: {
ShowDialog, ShowDialog,
FieldSelect, FieldSelect,

View File

@@ -17,27 +17,10 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { ConditionNode, ConditionTree, Operator } from 'app/src/types/Conditions'; import { defineComponent, ref ,watchEffect,computed,reactive} from 'vue';
import { computed, defineComponent, provide, reactive, ref, watchEffect } from 'vue'; import { ConditionTree,GroupNode,ConditionNode,LogicalOperator,Operator } from 'app/src/types/Conditions';
import ConditionEditor from '../ConditionEditor/ConditionEditor.vue'; import ConditionEditor from '../ConditionEditor/ConditionEditor.vue'
type Props = {
props?: {
name: string;
modelValue?: {
fields: {
type: string;
label: string;
code: string;
}[]
}
}
};
export default defineComponent({ export default defineComponent({
name: 'FieldInput', name: 'FieldInput',
inheritAttrs:false, inheritAttrs:false,
@@ -45,10 +28,6 @@ export default defineComponent({
ConditionEditor ConditionEditor
}, },
props: { props: {
context: {
type: Array<Props>,
default: '',
},
displayName:{ displayName:{
type: String, type: String,
default: '', default: '',
@@ -69,24 +48,9 @@ export default defineComponent({
type: String, type: String,
default: null default: null
}, },
sourceType: {
type: String,
default: 'field'
}
}, },
setup(props, { emit }) { setup(props, { emit }) {
const source = props.context.find(element => element?.props?.name === 'sources')
if (source) {
if(props.sourceType === 'field'){
provide('sourceFields', computed( () => source.props?.modelValue?.fields ?? []));
} else if(props.sourceType === 'app'){
console.log('sourceApp', source.props?.modelValue);
provide('sourceApp', computed( () => source.props?.modelValue?.app?.id));
}
}
const appDg = ref(); const appDg = ref();
const show = ref(false); const show = ref(false);
const tree = reactive(new ConditionTree()); const tree = reactive(new ConditionTree());

View File

@@ -1,229 +0,0 @@
<template>
<div>
<q-field :label="displayName" labelColor="primary" stack-label>
<template v-slot:control>
<q-card flat class="full-width">
<q-card-actions vertical>
<q-btn color="grey-3" text-color="black" @click="() => { dgIsShow = true }">クリックで設定</q-btn>
</q-card-actions>
<q-card-section class="text-caption">
<div v-if="processingObjectsInputDisplay && processingObjectsInputDisplay.length>0">
<div v-for="(item) in processingObjectsInputDisplay" :key="item">{{ item }}</div>
</div>
<div v-else>{{ placeholder }}</div>
</q-card-section>
</q-card>
</template>
</q-field>
<show-dialog v-model:visible="dgIsShow" name="集計処理" @close="closeDg" min-width="50vw" min-height="60vh">
<div class="q-mx-md q-mb-md">
<q-input v-model="processingProps.name" type="text" label-color="primary" label="集計結果の変数名"
placeholder="集計結果を格納する変数名を入力してください" stack-label />
</div>
<div class="q-mx-md">
<div class="row q-col-gutter-x-xs flex-center">
<div class="col-5">
<div class="q-mx-xs">データソース</div>
</div>
<div class="col-2">
<div class="q-mx-xs">集計計算</div>
</div>
<div class="col-4">
<div class="q-mx-xs">集計結果変数名</div>
</div>
<div class="col-1"><q-btn flat round dense icon="add" size="sm" @click="addProcessingObject" />
</div>
</div>
<div class="q-my-sm" v-for="(item, index) in processingObjects" :key="item.id">
<div class="row q-col-gutter-x-xs flex-center">
<div class="col-5">
<ConditionObject v-model="item.field" />
</div>
<div class="col-2">
<q-select v-model="item.logicalOperator" :options="logicalOperators" outlined dense></q-select>
</div>
<div class="col-4">
<q-input v-model="item.vName" type="text" outlined dense />
</div>
<div class="col-1">
<q-btn flat round dense icon="delete" size="sm" @click="() => deleteProcessingObject(index)" />
</div>
</div>
</div>
</div>
</show-dialog>
</div>
</template>
<script lang="ts">
import { v4 as uuidv4 } from 'uuid';
import { computed, defineComponent, provide, reactive, ref, watchEffect } from 'vue';
import ConditionObject from '../ConditionEditor/ConditionObject.vue';
import ShowDialog from '../ShowDialog.vue';
type Props = {
props?: {
name: string;
modelValue?: {
fields: {
type: string;
label: string;
code: string;
}[]
} | string
}
};
type ProcessingObjectType = {
field?: {
name: string | {
name: string;
};
objectType: string;
type: string;
code: string;
label: string;
noLabel: boolean;
};
logicalOperator?: string;
vName?: string;
id: string;
}
type ValueType = {
name: string;
actionName: string,
displayName: string,
vars: ProcessingObjectType[];
}
export default defineComponent({
name: 'DataProcessing',
inheritAttrs: false,
components: {
ShowDialog,
ConditionObject,
},
props: {
context: {
type: Array<Props>,
default: '',
},
displayName: {
type: String,
default: '',
},
name: {
type: String,
default: '',
},
modelValue: {
type: Object as () => ValueType,
},
placeholder: {
type: String,
default: '',
},
},
setup(props, { emit }) {
const source = props.context.find(element => element?.props?.name === 'sources')
if (source) {
provide('sourceFields', computed(() => {
const modelValue = source.props?.modelValue;
if (modelValue && typeof modelValue !== 'string') {
return modelValue.fields;
}
return null;
}));
}
const actionName = props.context.find(element => element?.props?.name === 'displayName')
const processingProps: ValueType = props.modelValue && props.modelValue.vars
? props.modelValue
: reactive({
name: '',
actionName: actionName?.props?.modelValue as string,
displayName: '結果(戻り値)',
vars: [{ id: uuidv4() }]
});
const closeDg = () => {
emit('update:modelValue', processingProps
);
}
const processingObjects = processingProps.vars;
const deleteProcessingObject = (index: number) => processingObjects.length === 1
? processingObjects.splice(0, processingObjects.length, { id: uuidv4() })
: processingObjects.splice(index, 1);
const processingObjectsInputDisplay = computed(() =>
processingObjects ?
processingObjects
.filter(item => item.field && item.logicalOperator && item.vName)
.map(item => {
const name = typeof item.field?.name === 'string'
? item.field.name
: item.field?.name.name;
return item.logicalOperator.operator!==''?
`${processingProps.name}.${item.vName} = ${item.logicalOperator.operator}(${name})`
:`${processingProps.name}.${item.vName} = ${name}`
})
: []
);
//集計処理方法
const logicalOperators = ref([
{
"operator": "",
"label": "なし"
},
{
"operator": "SUM",
"label": "合計"
},
{
"operator": "AVG",
"label": "平均"
},
{
"operator": "MAX",
"label": "最大値"
},
{
"operator": "MIN",
"label": "最小値"
},
{
"operator": "COUNT",
"label": "カウント"
},
{
"operator": "FIRST",
"label": "最初の値"
}
]);
watchEffect(() => {
emit('update:modelValue', processingProps);
});
return {
uuidv4,
dgIsShow: ref(false),
closeDg,
processingObjects,
processingProps,
addProcessingObject: () => processingObjects.push({ id: uuidv4() }),
deleteProcessingObject,
logicalOperators,
processingObjectsInputDisplay,
};
},
});
</script>
<style lang="scss"></style>

View File

@@ -1,7 +1,10 @@
<template> <template>
<div v-bind="$attrs"> <div v-bind="$attrs">
<q-input :label="displayName" v-model="inputValue" label-color="primary" :placeholder="placeholder" stack-label <q-input :label="displayName" v-model="inputValue" label-color="primary"
:rules="rulesExp" :maxlength="maxLength"> :placeholder="placeholder" stack-label
:rules="rulesExp"
:maxlength="maxLength"
>
<template v-slot:append v-if="hint !== ''"> <template v-slot:append v-if="hint !== ''">
<q-icon name="help" size="22px" color="blue-8"> <q-icon name="help" size="22px" color="blue-8">
<q-tooltip class="bg-yellow-2 text-black shadow-4" anchor="bottom right"> <q-tooltip class="bg-yellow-2 text-black shadow-4" anchor="bottom right">
@@ -15,7 +18,7 @@
<script lang="ts"> <script lang="ts">
import { kMaxLength } from 'buffer'; import { kMaxLength } from 'buffer';
import { defineComponent, ref, watchEffect, computed } from 'vue'; import { defineComponent, ref, watchEffect } from 'vue';
export default defineComponent({ export default defineComponent({
name: 'InputText', name: 'InputText',
@@ -47,40 +50,17 @@ export default defineComponent({
default:undefined default:undefined
}, },
modelValue: { modelValue: {
// type: Any, type: String,
default: '', default: '',
}, },
}, },
setup(props, { emit }) { setup(props, { emit }) {
const inputValue = computed({ const inputValue = ref(props.modelValue);
get: () => {
if (props.modelValue !== null && typeof props.modelValue === 'object' && 'name' in props.modelValue) {
return props.modelValue.name;
} else {
return props.modelValue;
}
},
set: (val) => {
if (props.name === 'verName') {
// return props.modelValue.name;
emit('update:modelValue', { name: val });
} else {
emit('update:modelValue', val);
}
},
});
// const inputValue = ref(props.modelValue);
const rulesExp = props.rules===undefined?null : eval(props.rules); const rulesExp = props.rules===undefined?null : eval(props.rules);
watchEffect(() => {
// const finalValue = computed(() => { emit('update:modelValue', inputValue.value);
// return props.name !== 'verName' ? inputValue.value : { });
// name: inputValue.value,
// };
// });
// watchEffect(() => {
// emit('update:modelValue', finalValue);
// });
return { return {
inputValue, inputValue,

View File

@@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<div v-for="(item, index) in properties" :key="index" > <div v-for="(item, index) in properties" :key="index" >
<component :is="item.component" v-bind="item.props" :context="properties" :connectProps="connectProps(item.props)" v-model="item.props.modelValue"></component> <component :is="item.component" v-bind="item.props" :connectProps="connectProps(item.props)" v-model="item.props.modelValue"></component>
</div> </div>
</div> </div>
</template> </template>
@@ -21,7 +21,6 @@ import ConditionInput from '../right/ConditionInput.vue';
import EventSetter from '../right/EventSetter.vue'; import EventSetter from '../right/EventSetter.vue';
import ColorPicker from './ColorPicker.vue'; import ColorPicker from './ColorPicker.vue';
import NumInput from './NumInput.vue'; import NumInput from './NumInput.vue';
import DataProcessing from './DataProcessing.vue';
import { IActionNode,IActionProperty,IProp } from 'src/types/ActionTypes'; import { IActionNode,IActionProperty,IProp } from 'src/types/ActionTypes';
export default defineComponent({ export default defineComponent({
@@ -36,8 +35,7 @@ export default defineComponent({
ConditionInput, ConditionInput,
EventSetter, EventSetter,
ColorPicker, ColorPicker,
NumInput, NumInput
DataProcessing
}, },
props: { props: {
nodeProps: { nodeProps: {
@@ -52,7 +50,7 @@ export default defineComponent({
setup(props, context) { setup(props, context) {
const properties=ref(props.nodeProps); const properties=ref(props.nodeProps);
const connectProps=(props:IProp)=>{ const connectProps=(props:IProp)=>{
const connProps:any={context:properties}; const connProps:any={};
if(props && "connectProps" in props && props.connectProps!=undefined){ if(props && "connectProps" in props && props.connectProps!=undefined){
for(let connProp of props.connectProps){ for(let connProp of props.connectProps){
let targetProp = properties.value.find((prop)=>prop.props.name===connProp.propName); let targetProp = properties.value.find((prop)=>prop.props.name===connProp.propName);

View File

@@ -1,12 +1,11 @@
<template> <template>
<div v-bind="$attrs"> <div v-bind="$attrs">
<q-select v-model="selectedValue" :use-chips="multiple" :label="displayName" label-color="primary" :options="options" stack-label <q-select v-model="selectedValue" :label="displayName" :options="options"/>
:multiple="multiple"/>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent,ref,watchEffect,computed } from 'vue'; import { defineComponent,ref,watchEffect } from 'vue';
export default defineComponent({ export default defineComponent({
name: 'SelectBox', name: 'SelectBox',
@@ -24,27 +23,20 @@ export default defineComponent({
type: Array, type: Array,
required: true, required: true,
}, },
selectType:{ modelValue: {
type: String, type: String,
default: '', default: '',
}, },
modelValue: {
type: Object,
default: null,
},
}, },
setup(props, { emit }) { setup(props, { emit }) {
const selectedValue = ref(props.modelValue); const selectedValue = ref(props.modelValue);
const multiple = computed(()=>{
return props.selectType==='multiple'
});
watchEffect(() => { watchEffect(() => {
emit('update:modelValue', selectedValue.value); emit('update:modelValue', selectedValue.value);
}); });
return { return {
selectedValue, selectedValue
multiple
}; };
}, },
}); });

View File

@@ -1,11 +1,8 @@
import { api } from 'boot/axios'; import { api } from 'boot/axios';
import { ActionFlow } from 'src/types/ActionTypes'; import { ActionFlow } from 'src/types/ActionTypes';
export class FlowCtrl export class FlowCtrl {
{ async getFlows(appId: string): Promise<ActionFlow[]> {
async getFlows(appId:string):Promise<ActionFlow[]>
{
const flows: ActionFlow[] = []; const flows: ActionFlow[] = [];
try { try {
const result = await api.get(`api/flows/${appId}`); const result = await api.get(`api/flows/${appId}`);
@@ -24,10 +21,9 @@ export class FlowCtrl
} }
} }
async SaveFlow(jsonData:any):Promise<boolean> async SaveFlow(jsonData: any): Promise<boolean> {
{
const result = await api.post('api/flow', jsonData); const result = await api.post('api/flow', jsonData);
console.info(result.data) console.info(result.data);
return true; return true;
} }
/** /**
@@ -35,10 +31,19 @@ export class FlowCtrl
* @param jsonData * @param jsonData
* @returns * @returns
*/ */
async UpdateFlow(jsonData:any):Promise<boolean> async UpdateFlow(jsonData: any): Promise<boolean> {
{
const result = await api.put('api/flow/' + jsonData.flowid, jsonData); const result = await api.put('api/flow/' + jsonData.flowid, jsonData);
console.info(result.data) console.info(result.data);
return true;
}
/**
* フローを消去する
* @param flowId
* @returns
*/
async DeleteFlow(flowId: string): Promise<boolean> {
const result = await api.delete('api/flow/' + flowId);
console.info(result.data);
return true; return true;
} }
/** /**
@@ -46,12 +51,9 @@ export class FlowCtrl
* @param appid * @param appid
* @returns * @returns
*/ */
async depoly(appid:string):Promise<boolean> async depoly(appid: string): Promise<boolean> {
{
const result = await api.post(`api/v1/createjstokintone?app=${appid}`); const result = await api.post(`api/v1/createjstokintone?app=${appid}`);
console.info(result.data); console.info(result.data);
return true; return true;
} }
} }

View File

@@ -20,10 +20,9 @@
</div> </div>
</q-drawer> </q-drawer>
</div> </div>
<q-btn flat dense round <q-btn flat dense round :icon="drawerLeft ? 'keyboard_double_arrow_left' : 'keyboard_double_arrow_right'"
:icon="drawerLeft?'keyboard_double_arrow_left':'keyboard_double_arrow_right'" :style="[drawerLeft ? { 'left': '300px' } : { 'left': '0px' }]" @click="drawerLeft = !drawerLeft"
:style="[drawerLeft?{'left':'300px'}:{'left':'0px'}]" class="expand" />
@click="drawerLeft=!drawerLeft" class="expand" />
<div class="q-pa-md q-gutter-sm" :style="{ minWidth: minPanelWidth }"> <div class="q-pa-md q-gutter-sm" :style="{ minWidth: minPanelWidth }">
<div class="flowchart" v-if="store.currentFlow" :style="[drawerLeft ? { paddingLeft: '300px' } : {}]"> <div class="flowchart" v-if="store.currentFlow" :style="[drawerLeft ? { paddingLeft: '300px' } : {}]">
<node-item v-if="rootNode !== undefined" :key="rootNode.id" :isSelected="rootNode === store.activeNode" <node-item v-if="rootNode !== undefined" :key="rootNode.id" :isSelected="rootNode === store.activeNode"
@@ -195,7 +194,22 @@ const onDeploy = async () => {
const onSaveFlow = async () => { const onSaveFlow = async () => {
const targetFlow = store.selectedFlow; const targetFlow = store.selectedFlow;
const deleteFlows = () => {
$q.notify({
type: 'positive',
caption: "通知",
message: `削除 ${store.deleteFlowIds.length} イベント`
});
store.deletebackendFlow();
}
if (targetFlow === undefined) { if (targetFlow === undefined) {
if (store.deleteFlowIds.length > 0) {
deleteFlows();
return;
}
$q.notify({ $q.notify({
type: 'negative', type: 'negative',
caption: "エラー", caption: "エラー",
@@ -204,6 +218,9 @@ const onSaveFlow = async () => {
return; return;
} }
try { try {
if (store.deleteFlowIds.length > 0) {
deleteFlows();
}
saveLoading.value = true; saveLoading.value = true;
await store.saveFlow(targetFlow); await store.saveFlow(targetFlow);
saveLoading.value = false; saveLoading.value = false;
@@ -265,6 +282,7 @@ onMounted(() => {
top: 50px; top: 50px;
z-index: 999; z-index: 999;
} }
.expand { .expand {
position: fixed; position: fixed;
left: 0px; left: 0px;

View File

@@ -12,10 +12,11 @@ export interface FlowEditorState{
eventTree: KintoneEventManager; eventTree: KintoneEventManager;
selectedEvent: IKintoneEvent | undefined; selectedEvent: IKintoneEvent | undefined;
expandedScreen: any[]; expandedScreen: any[];
deleteFlowIds: string[];
} }
const flowCtrl = new FlowCtrl(); const flowCtrl = new FlowCtrl();
const eventTree = new KintoneEventManager(); const eventTree = new KintoneEventManager();
export const useFlowEditorStore = defineStore("flowEditor",{ export const useFlowEditorStore = defineStore('flowEditor', {
state: (): FlowEditorState => ({ state: (): FlowEditorState => ({
flowNames1: '', flowNames1: '',
appInfo: undefined, appInfo: undefined,
@@ -24,7 +25,8 @@ export const useFlowEditorStore = defineStore("flowEditor",{
activeNode: undefined, activeNode: undefined,
eventTree: eventTree, eventTree: eventTree,
selectedEvent: undefined, selectedEvent: undefined,
expandedScreen:[] expandedScreen: [],
deleteFlowIds: [],
}), }),
getters: { getters: {
/** /**
@@ -43,17 +45,29 @@ export const useFlowEditorStore = defineStore("flowEditor",{
return (eventId: string) => { return (eventId: string) => {
return state.flows?.find((flow) => { return state.flows?.find((flow) => {
const root = flow.getRoot(); const root = flow.getRoot();
return root?.name===eventId return root?.name === eventId;
}); });
} };
} },
findEventById(state) {
return (eventId: string) => {
return state.eventTree.findEventById(eventId);
};
},
findEventFrist(state) {
return () => {
return state.eventTree.findEventFrist();
};
},
}, },
actions: { actions: {
setFlows(flows: IActionFlow[]) { setFlows(flows: IActionFlow[]) {
this.flows = flows; this.flows = flows;
}, },
selectFlow(flow:IActionFlow){ selectFlow(flow: IActionFlow | undefined) {
this.selectedFlow = flow; this.selectedFlow = flow;
}, },
setActiveNode(node: IActionNode) { setActiveNode(node: IActionNode) {
@@ -62,6 +76,12 @@ export const useFlowEditorStore = defineStore("flowEditor",{
setApp(app: AppInfo) { setApp(app: AppInfo) {
this.appInfo = app; this.appInfo = app;
}, },
addDeleteFlowId(flowId: string) {
this.deleteFlowIds.push(flowId);
},
clearDeleteFlowIds() {
this.deleteFlowIds = [];
},
/** /**
* DBからフルーを保存する * DBからフルーを保存する
* @returns * @returns
@@ -80,7 +100,7 @@ export const useFlowEditorStore = defineStore("flowEditor",{
if (actionFlows && actionFlows.length > 0) { if (actionFlows && actionFlows.length > 0) {
this.selectFlow(actionFlows[0]); this.selectFlow(actionFlows[0]);
} }
const expandNames = actionFlows.map(flow=>flow.getRoot()?.title); const expandNames = actionFlows.map((flow) => flow.getRoot()?.title);
// const expandName =actionFlows[0].getRoot()?.title; // const expandName =actionFlows[0].getRoot()?.title;
this.expandedScreen = expandNames; this.expandedScreen = expandNames;
}, },
@@ -95,8 +115,8 @@ export const useFlowEditorStore = defineStore("flowEditor",{
appid: this.appInfo?.appId, appid: this.appInfo?.appId,
eventid: root?.name, eventid: root?.name,
name: root?.subTitle, name: root?.subTitle,
content: JSON.stringify(flow) content: JSON.stringify(flow),
} };
if (isNew) { if (isNew) {
return await flowCtrl.SaveFlow(jsonData); return await flowCtrl.SaveFlow(jsonData);
@@ -104,6 +124,33 @@ export const useFlowEditorStore = defineStore("flowEditor",{
return await flowCtrl.UpdateFlow(jsonData); return await flowCtrl.UpdateFlow(jsonData);
} }
}, },
async deletebackendFlow() {
const deletePromises = Object.values(this.deleteFlowIds).map((flowId) =>
flowCtrl.DeleteFlow(flowId)
);
await Promise.all(deletePromises);
this.clearDeleteFlowIds();
},
deleteStoreEventAndFlow(event: IKintoneEvent) {
const store = useFlowEditorStore();
if (event.flowData) {
const flow = event.flowData;
if (flow.id === '') {
return;
}
console.log('delete flow', flow);
this.addDeleteFlowId(flow.id);
eventTree.deleteEvent(event, store);
if(this.flows){
this.flows = this.flows.filter((f) => f.id !== flow.id);
}
} else {
eventTree.deleteEvent(event, store);
}
},
/** /**
* デプロイする * デプロイする
*/ */
@@ -112,7 +159,6 @@ export const useFlowEditorStore = defineStore("flowEditor",{
return false; return false;
} }
return await flowCtrl.depoly(this.appInfo?.appId); return await flowCtrl.depoly(this.appInfo?.appId);
} },
},
}
}); });

View File

@@ -45,16 +45,7 @@ export interface IActionProperty {
export interface IActionVariable{ export interface IActionVariable{
actionName:string; actionName:string;
displayName:string; displayName:string;
name: {
name:string; name:string;
actionName:string;
displayName:string;
vars : {
vName:string;
logicalOperator:string;
field: object;
}[]
};
} }
/** /**
* アクションタイプ定義 * アクションタイプ定義
@@ -457,12 +448,6 @@ export class ActionFlow implements IActionFlow {
getPrevVarNames(prevNode:IActionNode):IActionVariable[]{ getPrevVarNames(prevNode:IActionNode):IActionVariable[]{
let varNames:IActionVariable[]=[]; let varNames:IActionVariable[]=[];
if(prevNode.varName!==undefined && prevNode.varName.modelValue){ if(prevNode.varName!==undefined && prevNode.varName.modelValue){
if(prevNode.varName.modelValue ==='object'){
console.log(prevNode);
}
varNames.unshift({ varNames.unshift({
actionName:prevNode.name, actionName:prevNode.name,
displayName:prevNode.varName.displayName, displayName:prevNode.varName.displayName,

View File

@@ -198,7 +198,7 @@ export class ConditionTree {
if(value && typeof value ==='object' && ('label' in value)){ if(value && typeof value ==='object' && ('label' in value)){
value =condNode.value.label; value =condNode.value.label;
} }
return `${typeof condNode.object.name === 'object' ? condNode.object.name.name : condNode.object.name} ${condNode.operator} '${value}'`; return `${condNode.object.name} ${condNode.operator} '${value}'`;
} else { } else {
return ''; return '';
} }

View File

@@ -1,3 +1,4 @@
import { useFlowEditorStore } from 'src/stores/flowEditor';
import { IActionFlow } from './ActionTypes'; import { IActionFlow } from './ActionTypes';
export interface IKintoneEventNode { export interface IKintoneEventNode {
label: string; label: string;
@@ -15,18 +16,15 @@ export interface IKintoneEventGroup extends IKintoneEventNode {
events: IKintoneEventNode[]; events: IKintoneEventNode[];
} }
export class kintoneEvent implements IKintoneEvent { export class kintoneEvent implements IKintoneEvent {
eventId: string; eventId: string;
parentId: string; parentId: string;
get hasFlow(): boolean { get hasFlow(): boolean {
return this.flowData!==undefined && this.flowData.actionNodes.length>1 return this.flowData !== undefined && this.flowData.actionNodes.length > 1;
}; }
flowData?: IActionFlow | undefined; flowData?: IActionFlow | undefined;
label: string; label: string;
get header():string{ header = 'EVENT';
return "EVENT";
}
constructor(label: string, eventId: string, parentId: string) { constructor(label: string, eventId: string, parentId: string) {
this.eventId = eventId; this.eventId = eventId;
this.label = label; this.label = label;
@@ -40,9 +38,14 @@ export class kintoneEventGroup implements IKintoneEventGroup{
label: string; label: string;
events: IKintoneEventNode[]; events: IKintoneEventNode[];
get header(): string { get header(): string {
return "EVENTGROUP"; return 'EVENTGROUP';
} }
constructor(eventId:string,label:string,events:IKintoneEventNode[],parentId:string){ constructor(
eventId: string,
label: string,
events: IKintoneEventNode[],
parentId: string
) {
this.eventId = eventId; this.eventId = eventId;
this.label = label; this.label = label;
this.events = events; this.events = events;
@@ -50,16 +53,20 @@ export class kintoneEventGroup implements IKintoneEventGroup{
} }
} }
export class kintoneEventForChange implements IKintoneEventGroup { export class kintoneEventForChange implements IKintoneEventGroup {
eventId: string; eventId: string;
parentId: string; parentId: string;
label: string; label: string;
events: IKintoneEventNode[]; events: IKintoneEventNode[];
get header(): string { get header(): string {
return "CHANGE"; return 'CHANGE';
} }
constructor(eventId:string,label:string,events:IKintoneEventNode[],parentId:string){ constructor(
eventId: string,
label: string,
events: IKintoneEventNode[],
parentId: string
) {
this.eventId = eventId; this.eventId = eventId;
this.label = label; this.label = label;
this.events = events; this.events = events;
@@ -67,8 +74,6 @@ export class kintoneEventForChange implements IKintoneEventGroup{
} }
} }
export class KintoneEventManager { export class KintoneEventManager {
public screens: IKintoneEventGroup[]; public screens: IKintoneEventGroup[];
@@ -80,24 +85,38 @@ export class KintoneEventManager {
this.screens = this.getKintoneEvents(); this.screens = this.getKintoneEvents();
for (const flow of flows) { for (const flow of flows) {
const eventId = flow.getRoot()?.name; const eventId = flow.getRoot()?.name;
console.log('eventId:', eventId);
if (eventId !== undefined) { if (eventId !== undefined) {
const eventNode = this.findEventById(eventId); const eventNode = this.findEventById(eventId);
if(eventNode!==null && eventNode.header==="EVENT"){ if (eventNode !== null && eventNode.header === 'EVENT') {
const event = eventNode as kintoneEvent; const event = eventNode as kintoneEvent;
event.flowData = flow; event.flowData = flow;
} else { } else {
//EventGroupのIDを取得 //EventGroupのIDを取得
const lastIndex = eventId.lastIndexOf("."); const lastIndex = eventId.lastIndexOf('.');
const groupId = eventId.substring(0, lastIndex); const groupId = eventId.substring(0, lastIndex);
const eventNode = this.findEventById(groupId); const eventNode = this.findEventById(groupId);
if(eventNode && (eventNode.header==="EVENTGROUP" || eventNode.header==="CHANGE")){ if (
eventNode &&
(eventNode.header === 'EVENTGROUP' || eventNode.header === 'CHANGE')
) {
const groupEvent = eventNode as kintoneEventGroup; const groupEvent = eventNode as kintoneEventGroup;
const newEvent =new kintoneEvent( console.log('label:', flow.getRoot()?.subTitle);
flow.getRoot()?.subTitle || "",
eventId, const newEvent = {
groupEvent.parentId label: flow.getRoot()?.subTitle || '',
); eventId: eventId,
newEvent.flowData=flow; parentId: groupId,
header: 'DELETABLE',
hasFlow: true,
flowData: flow,
};
// new kintoneEvent(
// flow.getRoot()?.subTitle || '',
// eventId,
// groupEvent.parentId
// );
groupEvent.events.push(newEvent); groupEvent.events.push(newEvent);
} }
} }
@@ -105,19 +124,25 @@ export class KintoneEventManager {
} }
} }
public findEventFrist() {
return this.findEventById('app.record.create.show') as IKintoneEvent;
}
public findEventById(eventId: string): IKintoneEventNode | null { public findEventById(eventId: string): IKintoneEventNode | null {
const screen = this.findScreen(eventId); const screen = this.findScreen(eventId);
if(screen) {return screen;} if (screen) {
return screen;
}
for (const screen of this.screens) { for (const screen of this.screens) {
for (const event of screen.events) { for (const event of screen.events) {
if (event.eventId === eventId) { if (event.eventId === eventId) {
return event; return event;
} }
if(event.header==="EVENTGROUP"||event.header==="CHANGE"){ if (event.header === 'EVENTGROUP' || event.header === 'CHANGE') {
const eventGroup = event as IKintoneEventGroup; const eventGroup = event as IKintoneEventGroup;
const targetEvent = eventGroup.events.find((ev) => { const targetEvent = eventGroup.events.find((ev) => {
return ev.eventId === eventId; return ev.eventId === eventId;
}) });
if (targetEvent) { if (targetEvent) {
return targetEvent; return targetEvent;
} }
@@ -128,39 +153,169 @@ export class KintoneEventManager {
} }
public findScreen(eventId: string): IKintoneEventGroup | undefined { public findScreen(eventId: string): IKintoneEventGroup | undefined {
return this.screens.find(screen=>screen.eventId==eventId); return this.screens.find((screen) => screen.eventId == eventId);
}
public deleteEvent(
event: kintoneEvent,
store: ReturnType<typeof useFlowEditorStore>
) {
if (event.header !== 'DELETABLE') {
return;
}
const parent = store.findEventById(event.parentId);
if (parent?.header !== 'CHANGE' && parent?.header !== 'EVENTGROUP') {
return;
}
const realParent = parent as kintoneEventForChange;
const index = realParent.events.findIndex(
(e) => e.eventId === event.eventId
);
if (index !== -1) {
realParent.events.splice(index, 1);
}
} }
public getKintoneEvents(): IKintoneEventGroup[] { public getKintoneEvents(): IKintoneEventGroup[] {
return [ return [
new kintoneEventGroup("app.record.create","レコード追加画面",[ new kintoneEventGroup(
new kintoneEvent('レコード追加画面を表示した後','app.record.create.show',"app.record.create"), 'app.record.create',
new kintoneEvent('保存をクリックしたとき','app.record.create.submit',"app.record.create"), 'レコード追加画面',
new kintoneEvent('保存が成功したとき','app.record.create.submit.success',"app.record.create"), [
new kintoneEventForChange('app.record.create.change','フィールドの値を変更したとき',[],"app.record.create"), new kintoneEvent(
new kintoneEventGroup('app.record.create.show.customButtonClick','ボタンをクリックした',[],"app.record.create") 'レコード追加画面を表示した',
],""), 'app.record.create.show',
new kintoneEventGroup("app.record.detail","レコード詳細画面",[ 'app.record.create'
new kintoneEvent('レコード詳細画面を表示した後','app.record.detail.show',"app.record.detail"), ),
new kintoneEvent('レコードを削除するとき','app.record.detail.delete.submit',"app.record.detail"), new kintoneEvent(
new kintoneEvent('プロセス管理のアクションを実行したとき','app.record.detail.process.proceed',"app.record.detail"), '保存をクリックしたとき',
new kintoneEventGroup('app.record.detail.show.customButtonClick','ボタンをクリックした時',[],"app.record.detail"), 'app.record.create.submit',
],""), 'app.record.create'
new kintoneEventGroup("app.record.edit","レコード編集画面",[ ),
new kintoneEvent('レコード編集画面を表示した後','app.record.edit.show',"app.record.edit"), new kintoneEvent(
new kintoneEvent('保存をクリックしたとき','app.record.edit.submit',"app.record.edit"), '保存が成功したとき',
new kintoneEvent('保存が成功したとき','app.record.edit.submit.success',"app.record.edit"), 'app.record.create.submit.success',
new kintoneEventForChange('app.record.edit.change','フィールドの値を変更したとき',[],"app.record.edit"), 'app.record.create'
new kintoneEventGroup('app.record.edit.show.customButtonClick','ボタンをクリックした時',[],"app.record.edit"), ),
],""), new kintoneEventForChange(
new kintoneEventGroup("app.record.index","レコード一覧画面",[ 'app.record.create.change',
new kintoneEvent('一覧画面を表示した後', 'app.record.index.show',"app.record.index"), 'フィールドの値を変更したとき',
new kintoneEvent('インライン編集を開始したとき','app.record.index.edit.show',"app.record.index"), [],
new kintoneEvent('インライン編集の【保存】をクリックしたとき','app.record.index.edit.submit',"app.record.index"), 'app.record.create'
new kintoneEvent('インライン編集の保存が成功したとき', 'app.record.index.edit.submit.success',"app.record.index"), ),
new kintoneEventForChange('app.record.index.edit.change','インライン編集のフィールド値を変更したとき' ,[],"app.record.index"), new kintoneEventGroup(
new kintoneEventGroup('app.record.detail.show.customButtonClick','ボタンをクリックした時',[],"app.record.index"), 'app.record.create.show.customButtonClick',
],"") 'ボタンをクリックした時',
[],
'app.record.create'
),
],
''
),
new kintoneEventGroup(
'app.record.detail',
'レコード詳細画面',
[
new kintoneEvent(
'レコード詳細画面を表示した後',
'app.record.detail.show',
'app.record.detail'
),
new kintoneEvent(
'レコードを削除するとき',
'app.record.detail.delete.submit',
'app.record.detail'
),
new kintoneEvent(
'プロセス管理のアクションを実行したとき',
'app.record.detail.process.proceed',
'app.record.detail'
),
new kintoneEventGroup(
'app.record.detail.show.customButtonClick',
'ボタンをクリックした時',
[],
'app.record.detail'
),
],
''
),
new kintoneEventGroup(
'app.record.edit',
'レコード編集画面',
[
new kintoneEvent(
'レコード編集画面を表示した後',
'app.record.edit.show',
'app.record.edit'
),
new kintoneEvent(
'保存をクリックしたとき',
'app.record.edit.submit',
'app.record.edit'
),
new kintoneEvent(
'保存が成功したとき',
'app.record.edit.submit.success',
'app.record.edit'
),
new kintoneEventForChange(
'app.record.edit.change',
'フィールドの値を変更したとき',
[],
'app.record.edit'
),
new kintoneEventGroup(
'app.record.edit.show.customButtonClick',
'ボタンをクリックした時',
[],
'app.record.edit'
),
],
''
),
new kintoneEventGroup(
'app.record.index',
'レコード一覧画面',
[
new kintoneEvent(
'一覧画面を表示した後',
'app.record.index.show',
'app.record.index'
),
new kintoneEvent(
'インライン編集を開始したとき',
'app.record.index.edit.show',
'app.record.index'
),
new kintoneEvent(
'インライン編集の【保存】をクリックしたとき',
'app.record.index.edit.submit',
'app.record.index'
),
new kintoneEvent(
'インライン編集の保存が成功したとき',
'app.record.index.edit.submit.success',
'app.record.index'
),
new kintoneEventForChange(
'app.record.index.edit.change',
'インライン編集のフィールド値を変更したとき',
[],
'app.record.index'
),
new kintoneEventGroup(
'app.record.detail.show.customButtonClick',
'ボタンをクリックした時',
[],
'app.record.index'
),
],
''
),
]; ];
} }
} }