Compare commits

...

40 Commits

Author SHA1 Message Date
xiaozhe.ma
f70c27d814 confilct解決 2024-07-12 19:37:45 +09:00
xiaozhe.ma
432e52d322 Merge branch 'dev' of https://dev.azure.com/rj-se-service-design/App%20Builder%20for%20kintone/_git/App%20Builder%20for%20kintone into dev 2024-07-12 19:20:59 +09:00
xiaozhe.ma
f3893c2500 Conflict解決 2024-07-12 19:17:06 +09:00
xiaozhe.ma
e726843189 データ追加&更新処理アクション修正完了 2024-07-12 19:05:15 +09:00
tenraku ou
183abeba41 Merged PR 44: email-check-Fix Fixed505&507
email-check-Fix Fixed505&507
メールアドレスチェック厳格の修正

Related work items: #505, #507
2024-07-12 05:28:50 +00:00
Shohtetsu Ma
70d2513cd7 Merged PR 45: 値変更イベント非同期処理対応
原因:
ChangeイベントはPromiseの返し値を待たせないので、アクション処理途中event完了してしまうことがあります
対策:
値変更イベントは処理完了後、kintone.app.recordをリセットするように対応します

Related work items: #508
2024-07-12 05:28:28 +00:00
xiaozhe.ma
0fda3d143c 条件式の障害対応(511,512,513) 2024-07-12 09:50:28 +09:00
xiaozhe.ma
a85a3683f2 Merge branch 'feature/data-update' into dev 2024-07-11 23:22:50 +09:00
xiaozhe.ma
14287b6948 data-mappingはdata-updateへ変更 2024-07-11 23:20:33 +09:00
Mouriya
0443257f86 コードのコメントとその他のコンテンツの追加 2024-07-11 21:17:26 +09:00
Mouriya
18b97c249a bug修复 2024-07-11 20:34:32 +09:00
Mouriya
4ac4c9e9f4 「kintone lookup」と組み合わせるとロックされたフィールドを除外します 2024-07-11 20:23:48 +09:00
Mouriya
24a70aed2e 「DataMapping」コンポーネントとプラグイン 新機能「更新対象」 2024-07-11 18:57:30 +09:00
xiaozhe.ma
79e38ba6dd 値変更イベント非同期処理対応 2024-07-11 15:25:10 +09:00
wtl
303a3ffc23 email-check-Fix Fixed505&507 2024-07-11 14:10:16 +09:00
Mouriya
af86edd3e2 損傷した部品 2024-07-11 10:59:36 +09:00
Shohtetsu Ma
c87cff4181 Merged PR 43: データ集計計算アクション
以下の変更があります。
- データ集計アクション
- データ集計関連の共通UIの追加
- 条件式エディタの変更
2024-07-11 00:44:23 +00:00
xiaozhe.ma
05db5a0522 feat:データ集計処理実装完了 2024-07-10 17:26:47 +09:00
xiaozhe.ma
bac7020c15 feat:データ集計処理実装完了 2024-07-10 17:21:07 +09:00
Shohtetsu Ma
c1d33e3ff0 Merged PR 42: feat:lookup同期アクション
feat:lookup同期アクション
以下の変更があります。
1.ルックアップ同期アクション追加
2.BootStrapをPluginに導入
3.フローエディタの共通コンボの改修(Lookup対応)
4.Backendのjs/cssファイルデプロイの改修

Related work items: #241
2024-07-05 08:37:54 +00:00
832d46d360 feat:lookup同期アクション 2024-07-05 17:20:51 +09:00
Yu Wang
c8f9cbda9a Merged PR 41: feat:#262ログインユーザー取得コンポーネントの追加
feat:#262ログインユーザー取得コンポーネントの追加

Related work items: #262
2024-07-05 00:11:36 +00:00
王玉
c1c265c73e feat:#262ログインユーザー取得コンポーネントの追加 2024-07-04 19:48:37 +09:00
e4800d2937 bugfix:Jsファイルでデプロイ時の不具合修正 2024-06-28 02:42:30 +09:00
550e59b4db ZCC対応の改修 2024-06-28 01:09:24 +09:00
Kanaru Tsuda
26a685b872 Merged PR 39: feat 236(全角チェック),284(半角チェック)
コンポーネントの改修

Related work items: #236, #284
2024-06-13 06:32:02 +00:00
Shohtetsu Ma
8514adf15e Merged PR 40: 変数定義の型はstring->IVarNameへ変更
変数定義の型を変更しました。
今後変数はオブジェクト型を対応可能のため、インターフェースを変更しました
下記のアクションを対応しました。
・auto-numbering.ts
・datetime-getter.ts
・value-getter.ts
・condition-action.ts
2024-06-13 06:31:23 +00:00
kanarutsuda
5f2059fd6a feat 236,284 全半角の改修コミット 2024-06-13 15:20:04 +09:00
504a76b4ac feat:変数定義類型の変更対応 2024-06-13 15:16:44 +09:00
kanarutsuda
80694ee49c feat 236,284 全半角のチェック コミット 2024-06-13 15:12:30 +09:00
kanarutsuda
493b9ca0e9 Merge branch 'dev' into feature/validation-half-width 2024-06-13 15:04:20 +09:00
kanarutsuda
55bbf50656 feat 236,284
全半角の改修コミット
2024-06-13 14:51:28 +09:00
4b27504b99 bugfix:フィールド表示障害修正 2024-06-13 13:53:43 +09:00
kanarutsuda
1d248bde43 半角チェック文字コード修正変更 2024-06-12 17:34:13 +09:00
Kanaru Tsuda
5cad10575f Merged PR 38: 半角チェック、全角チェックファイル名変更
それぞれfull widthcheck,half widthcheckをfull-widthcheck,half-widthcheckに変更しました

Related work items: #380
2024-06-12 07:39:58 +00:00
kanarutsuda
3b56c78bf1 ファイル名変更(削除) 2024-06-12 16:37:14 +09:00
kanarutsuda
6ab668f86a ファイル名の変更 2024-06-12 16:13:32 +09:00
kanarutsuda
7b1daaab33 ファイル名の変更 2024-06-12 15:55:38 +09:00
kanarutsuda
ef47912c37 feat: #380 半角チェック
指定したフィールドが半角かどうか判定する(全角が1文字でも含まれていたらエラー表示)
2024-06-12 15:25:50 +09:00
Shohtetsu Ma
140c48bcb7 Merged PR 36: 属性UIの新機能追加
1.フィールド選択UIのフィールド種別指定追加
2.スペースにボタン配置可能にする
3.選択肢UIの複数選択可能にする
4.スペース表示するため、バックエンドの改修
5.ボタンクリックイベントと項目値変更イベントのノード削除機能追加

Related work items: #241, #316, #344
2024-06-11 10:32:54 +00:00
55 changed files with 3319 additions and 487 deletions

File diff suppressed because one or more lines are too long

View File

@@ -404,6 +404,12 @@ def updateappjscss(app,uploads,c:config.KINTONE_ENV):
r = httpx.put(url,headers=headers,data=json.dumps(data)) r = httpx.put(url,headers=headers,data=json.dumps(data))
return r.json() return r.json()
def getTempPath(filename):
scriptdir = Path(__file__).resolve().parent
rootdir = scriptdir.parent.parent.parent.parent
fpath = os.path.join(rootdir,"Temp",filename)
return fpath
def createappjs(domainid,app): def createappjs(domainid,app):
db = SessionLocal() db = SessionLocal()
flows = get_flows_by_app(db,domainid,app) flows = get_flows_by_app(db,domainid,app)
@@ -412,10 +418,10 @@ def createappjs(domainid,app):
for flow in flows: for flow in flows:
content[flow.eventid] = {'flowid':flow.flowid,'name':flow.name,'content':flow.content} content[flow.eventid] = {'flowid':flow.flowid,'name':flow.name,'content':flow.content}
js = 'const alcflow=' + json.dumps(content) js = 'const alcflow=' + json.dumps(content)
scriptdir = Path(__file__).resolve().parent # scriptdir = Path(__file__).resolve().parent
rootdir = scriptdir.parent.parent.parent.parent # rootdir = scriptdir.parent.parent.parent.parent
fpath = os.path.join(rootdir,"Temp",f"alc_setting_{app}.js") # fpath = os.path.join(rootdir,"Temp",f"alc_setting_{app}.js")
print(rootdir) fpath = getTempPath(f"alc_setting_{app}.js")
print(fpath) print(fpath)
with open(fpath,'w') as file: with open(fpath,'w') as file:
file.write(js) file.write(js)
@@ -503,7 +509,7 @@ async def app(request:Request,app:str,c:config.KINTONE_ENV=Depends(getkintoneenv
r = httpx.get(url,headers=headers,params=params) r = httpx.get(url,headers=headers,params=params)
return r.json() return r.json()
except Exception as e: except Exception as e:
raise APIException('kintone:app',request.url._url, f"Error occurred while get app({c.DOMAIN_NAM}->{app}):",e) raise APIException('kintone:app',request.url._url, f"Error occurred while get app({c.DOMAIN_NAME}->{app}):",e)
@r.get("/allapps") @r.get("/allapps")
async def allapps(request:Request,c:config.KINTONE_ENV=Depends(getkintoneenv)): async def allapps(request:Request,c:config.KINTONE_ENV=Depends(getkintoneenv)):
@@ -513,14 +519,14 @@ async def allapps(request:Request,c:config.KINTONE_ENV=Depends(getkintoneenv)):
r = httpx.get(url,headers=headers) r = httpx.get(url,headers=headers)
return r.json() return r.json()
except Exception as e: except Exception as e:
raise APIException('kintone:allapps',request.url._url, f"Error occurred while get allapps({c.DOMAIN_NAM}):",e) raise APIException('kintone:allapps',request.url._url, f"Error occurred while get allapps({c.DOMAIN_NAME}):",e)
@r.get("/appfields") @r.get("/appfields")
async def appfields(request:Request,app:str,env = Depends(getkintoneenv)): async def appfields(request:Request,app:str,env = Depends(getkintoneenv)):
try: try:
return getfieldsfromkintone(app,env) return getfieldsfromkintone(app,env)
except Exception as e: except Exception as e:
raise APIException('kintone:appfields',request.url._url, f"Error occurred while get app fileds({env.DOMAIN_NAM}->{app}):",e) raise APIException('kintone:appfields',request.url._url, f"Error occurred while get app fileds({env.DOMAIN_NAME}->{app}):",e)
@r.get("/allfields") @r.get("/allfields")
async def allfields(request:Request,app:str,env = Depends(getkintoneenv)): async def allfields(request:Request,app:str,env = Depends(getkintoneenv)):
@@ -529,14 +535,14 @@ async def allfields(request:Request,app:str,env = Depends(getkintoneenv)):
form_resp = getformfromkintone(app,env) form_resp = getformfromkintone(app,env)
return merge_kintone_fields(field_resp,form_resp) return merge_kintone_fields(field_resp,form_resp)
except Exception as e: except Exception as e:
raise APIException('kintone:allfields',request.url._url, f"Error occurred while get form fileds({env.DOMAIN_NAM}->{app}):",e) raise APIException('kintone:allfields',request.url._url, f"Error occurred while get form fileds({env.DOMAIN_NAME}->{app}):",e)
@r.get("/appprocess") @r.get("/appprocess")
async def appprocess(request:Request,app:str,env = Depends(getkintoneenv)): async def appprocess(request:Request,app:str,env = Depends(getkintoneenv)):
try: try:
return getprocessfromkintone(app,env) return getprocessfromkintone(app,env)
except Exception as e: except Exception as e:
raise APIException('kintone:appprocess',request.url._url, f"Error occurred while get app process({env.DOMAIN_NAM}->{app}):",e) raise APIException('kintone:appprocess',request.url._url, f"Error occurred while get app process({env.DOMAIN_NAME}->{app}):",e)
@r.get("/alljscss") @r.get("/alljscss")
async def alljscs(request:Request,app:str,c:config.KINTONE_ENV=Depends(getkintoneenv)): async def alljscs(request:Request,app:str,c:config.KINTONE_ENV=Depends(getkintoneenv)):
@@ -547,7 +553,7 @@ async def alljscs(request:Request,app:str,c:config.KINTONE_ENV=Depends(getkinton
r = httpx.get(url,headers=headers,params=params) r = httpx.get(url,headers=headers,params=params)
return r.json() return r.json()
except Exception as e: except Exception as e:
raise APIException('kintone:alljscss',request.url._url, f"Error occurred while get app js/css({c.DOMAIN_NAM}->{app}):",e) raise APIException('kintone:alljscss',request.url._url, f"Error occurred while get app js/css({c.DOMAIN_NAME}->{app}):",e)
@r.post("/createapp",) @r.post("/createapp",)
async def createapp(request:Request,name:str,c:config.KINTONE_ENV=Depends(getkintoneenv)): async def createapp(request:Request,name:str,c:config.KINTONE_ENV=Depends(getkintoneenv)):
@@ -563,7 +569,7 @@ async def createapp(request:Request,name:str,c:config.KINTONE_ENV=Depends(getkin
r = httpx.post(url,headers=headers,data=json.dumps(data)) r = httpx.post(url,headers=headers,data=json.dumps(data))
return r.json return r.json
except Exception as e: except Exception as e:
raise APIException('kintone:createapp',request.url._url, f"Error occurred while create app({c.DOMAIN_NAM}->{name}):",e) raise APIException('kintone:createapp',request.url._url, f"Error occurred while create app({c.DOMAIN_NAME}->{name}):",e)
@r.post("/createappfromexcel",) @r.post("/createappfromexcel",)
@@ -692,7 +698,7 @@ async def updateprocessfromexcel(request:Request,app:str,env = Depends(getkinton
if deploy: if deploy:
result = deoployappfromkintone(app,revision,env) result = deoployappfromkintone(app,revision,env)
except Exception as e: except Exception as e:
raise APIException('kintone:updateprocessfromexcel',request.url._url, f"Error occurred while update process ({env.DOMAIN_NAM}->{app}):",e) raise APIException('kintone:updateprocessfromexcel',request.url._url, f"Error occurred while update process ({env.DOMAIN_NAME}->{app}):",e)
return result return result
@@ -703,7 +709,8 @@ async def createjstokintone(request:Request,app:str,env:config.KINTONE_ENV = Dep
jscs=[] jscs=[]
files=[] files=[]
files.append(createappjs(env.DOMAIN_ID, app)) files.append(createappjs(env.DOMAIN_ID, app))
files.append('Temp\\alc_runtime.js') files.append(getTempPath('alc_runtime.js'))
files.append(getTempPath('alc_runtime.css'))
for file in files: for file in files:
upload = uploadkintonefiles(file,env) upload = uploadkintonefiles(file,env)
if upload.get('fileKey') != None: if upload.get('fileKey') != None:
@@ -713,4 +720,4 @@ async def createjstokintone(request:Request,app:str,env:config.KINTONE_ENV = Dep
deoployappfromkintone(app,appjscs["revision"],env) deoployappfromkintone(app,appjscs["revision"],env)
return appjscs return appjscs
except Exception as e: except Exception as e:
raise APIException('kintone:createjstokintone',request.url._url, f"Error occurred while create js ({env.DOMAIN_NAM}->{app}):",e) raise APIException('kintone:createjstokintone',request.url._url, f"Error occurred while create js ({env.DOMAIN_NAME}->{app}):",e)

View File

@@ -5,15 +5,14 @@ PROJECT_NAME = "KintoneAppBuilder"
#SQLALCHEMY_DATABASE_URI = "postgres://maxz64:m@xz1205@alicornkintone.postgres.database.azure.com/postgres" #SQLALCHEMY_DATABASE_URI = "postgres://maxz64:m@xz1205@alicornkintone.postgres.database.azure.com/postgres"
SQLALCHEMY_DATABASE_URI = "postgres://kabAdmin:P@ssw0rd!@kintonetooldb.postgres.database.azure.com/postgres" SQLALCHEMY_DATABASE_URI = "postgres://kabAdmin:P@ssw0rd!@kintonetooldb.postgres.database.azure.com/postgres"
#SQLALCHEMY_DATABASE_URI = "postgres://kabAdmin:P@ssw0rd!@kintonetooldb.postgres.database.azure.com/unittest"
API_V1_STR = "/k/v1" API_V1_STR = "/k/v1"
API_V1_AUTH_KEY = "X-Cybozu-Authorization" API_V1_AUTH_KEY = "X-Cybozu-Authorization"
DEPLOY_MODE = "DEV" #DEV,PROD DEPLOY_MODE = "PROD" #DEV,PROD
DEPLOY_JS_URL = "https://ka-addin.azurewebsites.net/alc_runtime.js" DEPLOY_JS_URL = "https://ka-addin.azurewebsites.net/alc_runtime.js"
#DEPLOY_JS_URL = "https://e84c-133-139-70-142.ngrok-free.app/alc_runtime.js"
KINTONE_FIELD_TYPE=["GROUP","GROUP_SELECT","CHECK_BOX","SUBTABLE","DROP_DOWN","USER_SELECT","RADIO_BUTTON","RICH_TEXT","LINK","REFERENCE_TABLE","CALC","TIME","NUMBER","ORGANIZATION_SELECT","FILE","DATETIME","DATE","MULTI_SELECT","SINGLE_LINE_TEXT","MULTI_LINE_TEXT"] KINTONE_FIELD_TYPE=["GROUP","GROUP_SELECT","CHECK_BOX","SUBTABLE","DROP_DOWN","USER_SELECT","RADIO_BUTTON","RICH_TEXT","LINK","REFERENCE_TABLE","CALC","TIME","NUMBER","ORGANIZATION_SELECT","FILE","DATETIME","DATE","MULTI_SELECT","SINGLE_LINE_TEXT","MULTI_LINE_TEXT"]

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +1,6 @@
#開発環境
KAB_BACKEND_URL="https://kab-backend.azurewebsites.net/" KAB_BACKEND_URL="https://kab-backend.azurewebsites.net/"
#単体テスト環境
#KAB_BACKEND_URL="https://kab-backend-unittest.azurewebsites.net/"
#ローカル開発環境
#KAB_BACKEND_URL="http://127.0.0.1:8000/" #KAB_BACKEND_URL="http://127.0.0.1:8000/"

View File

@@ -94,6 +94,7 @@ module.exports = configure(function (/* ctx */) {
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#devServer // Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#devServer
devServer: { devServer: {
// https: true // https: true
port:9001,
open: true, // opens browser window automatically open: true, // opens browser window automatically
env: { ...dotenv }, env: { ...dotenv },
}, },

View File

@@ -0,0 +1,131 @@
<template>
<div class="q-mx-md q-mb-lg">
<div class="q-mb-xs q-ml-md text-primary">アプリ選択</div>
<div class="q-pa-md row" style="border: 1px solid rgba(0, 0, 0, 0.12); border-radius: 4px;">
<div v-if="selField?.app && !showSelectApp">{{ selField?.app?.name }}</div>
<q-space />
<div>
<q-btn outline dense label="選 択" padding="none sm" color="primary" @click="() => {
showSelectApp = true;
}"></q-btn>
</div>
</div>
</div>
<div v-if="!showSelectApp && selField?.app?.name">
<div>
<div class="row q-mb-md">
<!-- <div class="col"> -->
<div class="q-mb-xs q-ml-md text-primary">フィールド選択</div>
<!-- </div> -->
<q-space />
<!-- <div class="col"> -->
<div class="q-mr-md">
<q-input dense debounce="300" v-model="fieldFilter" placeholder="フィールド検索" clearable>
<template v-slot:before>
<q-icon name="search" />
</template>
</q-input>
</div>
</div>
<div class="row">
<field-select ref="fieldDlg" name="フィールド" :type="selectType" :updateSelectFields="updateSelectFields"
:appId="selField?.app?.id" not_page :filter="fieldFilter"
:selectedFields="selField.fields" :fieldTypes="fieldTypes"></field-select>
</div>
</div>
</div>
<div style="min-width: 45vw;" v-else>
</div>
<show-dialog v-model:visible="showSelectApp" name="アプリ選択">
<template v-slot:toolbar>
<q-input dense debounce="300" v-model="filter" placeholder="検索" clearable>
<template v-slot:before>
<q-icon name="search" />
</template>
</q-input>
</template>
<AppSelectBox ref="appDlg" name="アプリ" type="single" :filter="filter"
:updateSelectApp="updateSelectApp"></AppSelectBox>
</show-dialog>
</template>
<script lang="ts">
import { defineComponent, ref, watchEffect, computed, reactive } from 'vue';
import ShowDialog from './ShowDialog.vue';
import FieldSelect from './FieldSelect.vue';
import AppSelectBox from './AppSelectBox.vue';
interface IApp {
id: string,
name: string
}
interface IField {
name: string,
code: string,
type: string
}
interface IAppFields {
app?: IApp,
fields: IField[]
}
export default defineComponent({
inheritAttrs: false,
name: 'AppFieldSelectBox',
components: {
ShowDialog,
FieldSelect,
AppSelectBox,
},
props: {
selectedField: {
type: Object,
required: true
},
selectType: {
type: String,
default: 'single'
},
fieldTypes:{
type:Array,
default:()=>[]
}
},
setup(props, { emit }) {
const showSelectApp = ref(false);
const selField = reactive(props.selectedField);
const isSelected = computed(() => {
return selField !== null && typeof selField === 'object' && ('app' in selField)
});
const updateSelectApp = (newAppinfo: IApp) => {
selField.app = newAppinfo
}
const updateSelectFields = (newFields: IField[]) => {
selField.fields = newFields
}
watchEffect(() => {
emit('update:modelValue', selField);
});
return {
showSelectApp,
isSelected,
updateSelectApp,
filter: ref(),
updateSelectFields,
fieldFilter: ref(),
selField
};
}
});
</script>

View File

@@ -21,12 +21,12 @@ import { ref, onMounted, reactive, watchEffect } from 'vue'
import { api } from 'boot/axios'; import { api } from 'boot/axios';
export default { export default {
name: 'AppSelect', name: 'AppSelectBox',
props: { props: {
name: String, name: String,
type: String, type: String,
filter: String, filter: String,
updateExternalSelectAppInfo: { updateSelectApp: {
type: Function type: Function
} }
}, },
@@ -42,8 +42,8 @@ export default {
const selected = ref([]) const selected = ref([])
watchEffect(()=>{ watchEffect(()=>{
if (selected.value && selected.value[0] && props.updateExternalSelectAppInfo) { if (selected.value && selected.value[0] && props.updateSelectApp) {
props.updateExternalSelectAppInfo(selected.value[0]) props.updateSelectApp(selected.value[0])
} }
}); });
onMounted(() => { onMounted(() => {

View File

@@ -1,96 +1,135 @@
<template> <template>
<q-field v-model="selectedObject" labelColor="primary" class="condition-object" <div class="q-pa-sm">
:clearable="isSelected" stack-label :dense="true" :outlined="true" > <q-field labelColor="primary" class="condition-object" dense outlined :label="label" :disable="disabled"
<template v-slot:control > :clearable="isSelected">
<q-chip color="primary" text-color="white" v-if="isSelected && selectedObject.objectType==='field'" :dense="true" class="selected-obj"> <template v-slot:control>
{{ selectedObject.name }} <q-chip color="primary" text-color="white" v-if="isSelected && selectedObject.objectType==='field'" :dense="true" class="selected-obj">
</q-chip> {{ selectedObject.name }}
<q-chip color="info" text-color="white" v-if="isSelected && selectedObject.objectType==='variable'" :dense="true" class="selected-obj"> </q-chip>
{{ selectedObject.name.name }} <q-chip color="info" text-color="white" v-if="isSelected && selectedObject.objectType==='variable'" :dense="true" class="selected-obj">
</q-chip> {{ selectedObject.name.name }}
</template> </q-chip>
<template v-slot:append> <div v-if="isSelected && selectedObject.objectType==='text'">{{ selectedObject?.sharedText }}</div>
<q-icon name="search" class="cursor-pointer" @click="showDg"/> </template>
</template> <template v-slot:append>
</q-field> <q-icon name="search" class="cursor-pointer" @click="showDg" />
<show-dialog v-model:visible="show" name="設定項目一覧" @close="closeDg" min-width="400px"> </template>
<template v-slot:toolbar> </q-field>
<q-input dense debounce="200" v-model="filter" placeholder="検索" clearable> <show-dialog v-model:visible="show" name="設定項目" @close="closeDg" min-width="400px">
<template v-slot:before> <!-- <template v-slot:toolbar>
<q-icon name="search" /> <q-input dense debounce="200" v-model="filter" placeholder="検索" clearable>
</template> <template v-slot:before>
</q-input> <q-icon name="search" />
</template> </template>
<condition-objects ref="appDg" name="フィールド" type="single" :filter="filter" :appId="store.appInfo?.appId" :vars="vars"></condition-objects> </q-input>
</template>
<condition-objects ref="appDg" name="フィールド" type="single" :filter="filter" :appId="store.appInfo?.appId" :vars="vars"></condition-objects>
-->
<DynamicItemInput v-model:selectedObject="selectedObject" :canInput="config.canInput"
:buttonsConfig="config.buttonsConfig" :appId="store.appInfo?.appId" />
</show-dialog> </show-dialog>
</template> </div>
</template>
<script lang="ts"> <script lang="ts">
import { defineComponent, reactive, ref ,watchEffect,computed} from 'vue'; import { defineComponent, reactive, ref, watchEffect, computed } from 'vue';
import ShowDialog from '../ShowDialog.vue'; import ShowDialog from '../ShowDialog.vue';
import ConditionObjects from '../ConditionObjects.vue'; // import ConditionObjects from '../ConditionObjects.vue';
import { useFlowEditorStore } from '../../stores/flowEditor'; import DynamicItemInput from '../DynamicItemInput/DynamicItemInput.vue';
import {IActionFlow,IActionNode,IActionVariable} from '../../types/ActionTypes'; import { useFlowEditorStore } from '../../stores/flowEditor';
export default defineComponent({ import { IActionFlow, IActionNode, IActionVariable } from '../../types/ActionTypes';
name: 'ConditionObject',
components: { export default defineComponent({
ShowDialog, name: 'ConditionObject',
ConditionObjects components: {
ShowDialog,
DynamicItemInput,
// ConditionObjects
},
props: {
disabled: {
type: Boolean,
default: false
}, },
props: { label: {
modelValue: { type: String,
type: Object, default: undefined
default: null
},
}, },
setup(props, { emit }) { config: {
const appDg = ref(); type: Object,
const show = ref(false); default: () => {
const selectedObject = ref(props.modelValue); return {
const store = useFlowEditorStore(); canInput: false,
const isSelected = computed(()=>{ buttonsConfig: [
return selectedObject.value!==null && typeof selectedObject.value === 'object' && ('name' in selectedObject.value) { label: 'フィールド', color: 'primary', type: 'FieldAdd' },
}); { label: '変数', color: 'green', type: 'VariableAdd' },
let vars:IActionVariable[] =[]; ]
if(store.currentFlow!==undefined && store.activeNode!==undefined ){ };
vars =store.currentFlow.getVarNames(store.activeNode);
} }
const filter=ref(''); },
const showDg = () => { modelValue: {
show.value = true; type: Object,
}; default: null
},
const closeDg = (val:string) => { },
if (val == 'OK') { setup(props, { emit }) {
selectedObject.value = appDg.value.selected[0]; // const appDg = ref();
} const show = ref(false);
}; const selectedObject = ref(props.modelValue);
const store = useFlowEditorStore();
watchEffect(() => { // const sharedText = ref(''); // 共享的文本状态
emit('update:modelValue', selectedObject.value); const isSelected = computed(() => {
}); return selectedObject.value?.sharedText !== '';
});
return { // const isSelected = computed(()=>{
store, // return selectedObject.value!==null && typeof selectedObject.value === 'object' && ('name' in selectedObject.value)
appDg, // });
show, let vars: IActionVariable[] = [];
showDg, if (store.currentFlow !== undefined && store.activeNode !== undefined) {
closeDg, vars = store.currentFlow.getVarNames(store.activeNode);
selectedObject,
vars:reactive(vars),
isSelected,
filter
};
} }
}); // const filter=ref('');
</script> const showDg = () => {
show.value = true;
};
const closeDg = (val: string) => {
if (val == 'OK') {
// selectedObject.value = appDg.value.selected[0];
}
};
watchEffect(() => {
emit('update:modelValue', selectedObject.value);
});
return {
store,
// appDg,
show,
showDg,
closeDg,
selectedObject,
vars: reactive(vars),
isSelected,
buttonsConfig: [
{ label: 'フィールド', color: 'primary', type: 'FieldAdd' },
{ label: '変数', color: 'green', type: 'VariableAdd' },
]
// filter
};
}
});
</script>
<style lang="scss"> <style lang="scss">
.condition-object{ .condition-object {
min-width: 200px; min-width: 200px;
max-height: 40px; max-height: 40px;
margin: 0 2px; margin: 0 2px;
} }
.selected-obj{
.selected-obj {
margin: 0 2px; margin: 0 2px;
} }
</style> </style>

View File

@@ -67,11 +67,13 @@
<!-- 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 q-my-xs">
<ConditionObject v-bind="prop.node" v-model="prop.node.object" class="col-4"></ConditionObject> <ConditionObject v-bind="prop.node" v-model="prop.node.object" :config="leftDynamicItemConfig" class="col-4"/>
<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)" <ConditionObject v-bind="prop.node" v-model="prop.node.value" :config="rightDynamicItemConfig" class="col-4"/>
<!-- <ConditionObject v-bind="prop.node" v-model="prop.node.object" class="col-4"/> -->
<!-- <q-input v-if="!prop.node.object || !('options' in prop.node.object)"
v-model="prop.node.value" v-model="prop.node.value"
class="condition-value" :outlined="true" :dense="true" ></q-input> class="condition-value" :outlined="true" :dense="true" ></q-input> -->
<q-select v-if="prop.node.object && ('options' in prop.node.object)" <q-select v-if="prop.node.object && ('options' in prop.node.object)"
v-model="prop.node.value" v-model="prop.node.value"
:options="objectValueOptions(prop.node.object.options)" :options="objectValueOptions(prop.node.object.options)"
@@ -113,7 +115,7 @@ import { finished } from 'stream';
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent,ref,reactive, computed } from 'vue'; import { defineComponent,ref,reactive, computed, inject } from 'vue';
import { INode,ConditionTree,GroupNode,ConditionNode, LogicalOperator,Operator,NodeType } from '../../types/Conditions'; import { INode,ConditionTree,GroupNode,ConditionNode, LogicalOperator,Operator,NodeType } from '../../types/Conditions';
import ConditionObject from './ConditionObject.vue'; import ConditionObject from './ConditionObject.vue';
export default defineComponent( { export default defineComponent( {
@@ -143,12 +145,9 @@ export default defineComponent( {
return opts; return opts;
}); });
const operator = inject('Operator')
const operators =computed(()=>{ const operators =computed(()=>{
const opts=[]; return operator ? operator : Object.values(Operator);
for(const op in Operator){
opts.push(Operator[op as keyof typeof Operator]);
}
return opts;
}); });
const tree = reactive(props.conditionTree); const tree = reactive(props.conditionTree);
@@ -228,6 +227,8 @@ export default defineComponent( {
// addCondition(tree.root); // addCondition(tree.root);
return { return {
leftDynamicItemConfig :inject('leftDynamicItemConfig'),
rightDynamicItemConfig:inject('rightDynamicItemConfig'),
showingCondition, showingCondition,
conditionString, conditionString,
tree, tree,
@@ -262,7 +263,8 @@ export default defineComponent( {
.operator{ .operator{
min-width: 150px; min-width: 150px;
max-height: 40px; max-height: 40px;
margin: 0 2px; margin-left: 12px;
text-align: center; text-align: center;
font-size: 12pt; font-size: 12pt;
} }

View File

@@ -0,0 +1,141 @@
<template>
<div class="q-mx-md" style="max-width: 600px;">
<!-- <q-card> -->
<div class="q-mb-md">
<q-input ref="inputRef" outlined dense debounce="200" @update:model-value="updateSharedText"
v-model="sharedText" :readonly="!canInput" autogrow>
<template v-slot:append>
<q-btn flat round padding="none" icon="cancel" @click="clearSharedText" color="grey-6" />
</template>
</q-input>
</div>
<div class="row q-gutter-sm">
<q-btn v-for="button in buttonsConfig" :key="button.type" :color="button.color" @mousedown.prevent
@click="openDialog(button)" size="sm">
{{ button.label }}
</q-btn>
</div>
<show-dialog v-model:visible="dialogVisible" :name="currentDialogName" @close="closeDialog" min-width="400px">
<template v-slot:toolbar>
<q-input dense debounce="200" v-model="filter" clearable>
<template v-slot:before>
<q-icon name="search" />
</template>
</q-input>
</template>
<!-- asdf -->
<component :is="currentComponent" @select="handleSelect" :filter="filter" :appId="appId" />
</show-dialog>
<!-- </q-card> -->
</div>
</template>
<script lang="ts">
import { ref, inject, watchEffect, defineComponent } from 'vue';
import FieldAdd from './FieldAdd.vue';
import VariableAdd from './VariableAdd.vue';
// import FunctionAdd from './FunctionAdd.vue';
import ShowDialog from '../ShowDialog.vue';
type ButtonConfig = {
label: string;
color: string;
type: string;
editable: boolean;
};
export default defineComponent({
name: 'DynamicItemInput',
components: {
FieldAdd,
VariableAdd,
// FunctionAdd,
ShowDialog
},
props: {
// canInput: {
// type: Boolean,
// default: false
// },
appId: {
type: String,
},
selectedObject: {
default: {}
},
buttonsConfig: {
type: Array as () => ButtonConfig[],
default: () => [
{ label: 'フィールド', color: 'primary', type: 'FieldAdd' }
]
}
},
setup(props, { emit }) {
const filter = ref('');
const dialogVisible = ref(false);
const currentDialogName = ref('');
const currentComponent = ref('FieldAdd');
const sharedText = ref(props.selectedObject?.sharedText ?? '');
const inputRef = ref();
const canInput = ref(true);
const editable = ref(false);
const openDialog = (button: ButtonConfig) => {
currentDialogName.value = button.label;
currentComponent.value = button.type;
dialogVisible.value = true;
editable.value = button.editable ?? true;
};
const closeDialog = () => {
dialogVisible.value = false;
};
const handleSelect = (value:any) => {
// 获取当前光标位置
// const cursorPosition = inputRef.value.getNativeElement().selectionStart;
// if (cursorPosition === undefined || cursorPosition === 0) {
sharedText.value = `${value._t}`;
// } else {
// const textBefore = sharedText.value.substring(0, cursorPosition);
// const textAfter = sharedText.value.substring(cursorPosition);
// sharedText.value = `${textBefore}${value._t}${textAfter}`;
// }
if (value && value._t && (value._t as string).length > 0) {
canInput.value = editable.value;
}
emit('update:selectedObject', { sharedText: sharedText.value, ...value });
dialogVisible.value = false;
};
const clearSharedText = () => {
sharedText.value = '';
canInput.value = true;
emit('update:selectedObject', {});
}
const updateSharedText = (value:string) => {
sharedText.value = value;
emit('update:selectedObject', { ...props.selectedObject, sharedText: value,objectType:'text' });
}
return {
filter,
dialogVisible,
currentDialogName,
currentComponent,
canInput,
openDialog,
closeDialog,
handleSelect,
clearSharedText,
updateSharedText,
sharedText,
inputRef
};
}
});
</script>

View File

@@ -0,0 +1,41 @@
<template>
<field-list v-model="selected" type="single" :filter="filter" :appId="sourceApp ? sourceApp : appId"
:fields="sourceFields" @update:modelValue="handleSelect" />
</template>
<script lang="ts">
import { computed, inject, ref } from 'vue';
import FieldList from '../FieldList.vue';
export default {
name: 'FieldAdd',
components: {
FieldList,
},
props: {
appId: Number,
filter: String
},
setup(props, { emit }) {
const sourceFields = inject<Array<unknown>>('sourceFields')
const sourceApp = inject<number>('sourceApp')
const appId = computed(() => {
if (sourceFields || sourceApp) {
return sourceApp.value
} else {
return props.appId
}
});
return {
sourceFields,
sourceApp,
selected: ref([]),
handleSelect: (newSelection: any[]) => {
if (newSelection.length > 0) {
const v = newSelection[0]
emit('select', { _t: `field(${appId.value},${v.name})`, ...v }); // 假设您只需要选择的第一个字段的名称
}
}
}
},
}
</script>

View File

@@ -0,0 +1,42 @@
<template>
<variable-list v-model="selected" type="single" :vars="vars" :filter="filter" @update:modelValue="handleSelect" />
</template>
<script lang="ts">
import { ref } from 'vue';
import VariableList from '../VariableList.vue';
import { useFlowEditorStore } from 'src/stores/flowEditor';
import { IActionVariable } from 'src/types/ActionTypes';
export default {
name: 'VariableAdd',
components: {
VariableList,
},
props: {
appId: Number,
filter: String
},
setup(props, { emit }) {
const store = useFlowEditorStore();
let vars: IActionVariable[] = [];
console.log(store.currentFlow !== undefined && store.activeNode !== undefined);
if (store.currentFlow !== undefined && store.activeNode !== undefined) {
vars = store.currentFlow.getVarNames(store.activeNode);
}
return {
vars,
selected: ref([]),
handleSelect: (newSelection: any[]) => {
if (newSelection.length > 0) {
const v = newSelection[0];
let name = v.name
if (typeof name === 'object') {
name = name.name
}
emit('select', { _t: `var(${name})`, ...v }); // 假设您只需要选择的第一个字段的名称
}
}
}
},
}
</script>

View File

@@ -30,9 +30,9 @@ export default {
{ 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 { state : rows, isReady: isLoaded, isLoading } = useAsyncState((args) => { const { state : rows, isReady: isLoaded, isLoading } = useAsyncState((args) => {
if (props.fields) { if (props.fields && Object.keys(props.fields).length > 0) {
return props.fields.map(f => ({ name: f.label, objectType: 'field', ...f })); return props.fields.map(f => ({ name: f.label, objectType: 'field', ...f }));
} else { } else {
return api.get('api/v1/appfields', { return api.get('api/v1/appfields', {

View File

@@ -34,6 +34,9 @@ export default {
default:()=>[] default:()=>[]
}, },
filter: String, filter: String,
updateSelectFields: {
type: Function
},
}, },
setup(props) { setup(props) {
const isLoaded = ref(false); const isLoaded = ref(false);
@@ -63,12 +66,21 @@ export default {
Object.keys(fields).forEach((key) => { Object.keys(fields).forEach((key) => {
const fld = fields[key]; const fld = fields[key];
if(props.fieldTypes.length===0 || props.fieldTypes.includes(fld.type)){ if(props.fieldTypes.length===0 || props.fieldTypes.includes(fld.type)){
rows.push({ name: fld.code, ...fld }); rows.push({ name: fld.label || fld.code, ...fld });
}else if(props.fieldTypes.includes("lookup") && ("lookup" in fld)){
rows.push({ name: fld.label || fld.code, ...fld });
} }
}); });
isLoaded.value = true; isLoaded.value = true;
}); });
watchEffect(()=>{
if (selected.value && selected.value[0] && props.updateSelectFields) {
props.updateSelectFields(selected)
}
});
return { return {
columns, columns,
rows, rows,

View File

@@ -1,20 +1,17 @@
<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 class="" style="min-width: 40vw; max-width: 80vw; max-height: 95vh;" :style="cardStyle">
<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>
<slot name="toolbar"></slot> <slot name="toolbar"></slot>
<q-btn flat round dense icon="close" @click="CloseDialogue('Cancel')" /> <q-btn flat round dense icon="close" @click="CloseDialogue('Cancel')" />
</q-toolbar> </q-toolbar>
<q-card-section> <q-card-section class="q-mt-md" :style="sectionStyle">
<!-- <div class="text-h6">{{ name }}</div> -->
</q-card-section>
<q-card-section class="q-pt-none" :style="sectionStyle">
<slot></slot> <slot></slot>
</q-card-section> </q-card-section>
<q-card-actions align="right" class="text-primary q-mt-lg"> <q-card-actions align="right" class="text-primary">
<q-btn flat label="確定" v-close-popup @click="CloseDialogue('OK')" /> <q-btn flat label="確定" v-close-popup @click="CloseDialogue('OK')" />
<q-btn flat label="キャンセル" v-close-popup @click="CloseDialogue('Cancel')" /> <q-btn flat label="キャンセル" v-close-popup @click="CloseDialogue('Cancel')" />
</q-card-actions> </q-card-actions>

View File

@@ -1,6 +1,6 @@
<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="id" :selection="type" :selected="modelValue" :filter="filter"
@update:selected="$emit('update:modelValue', $event)" :columns="columns" :rows="rows" /> @update:selected="$emit('update:modelValue', $event)" :columns="columns" :rows="rows" />
</div> </div>
</template> </template>
@@ -19,7 +19,8 @@ export default {
reqired: true, reqired: true,
default: () => [] default: () => []
}, },
modelValue: Array modelValue: Array,
filter: String
}, },
emits: [ emits: [
'update:modelValue' 'update:modelValue'

View File

@@ -30,7 +30,7 @@
</template> </template>
</q-input> </q-input>
</template> </template>
<AppSelect ref="appDg" name="アプリ" type="single" :filter="filter"></AppSelect> <AppSelectBox ref="appDg" name="アプリ" type="single" :filter="filter"></AppSelectBox>
</ShowDialog> </ShowDialog>
</template> </template>
@@ -38,7 +38,7 @@
import { defineComponent,ref } from 'vue'; import { defineComponent,ref } from 'vue';
import {AppInfo} from '../../types/ActionTypes' import {AppInfo} from '../../types/ActionTypes'
import ShowDialog from '../../components/ShowDialog.vue'; import ShowDialog from '../../components/ShowDialog.vue';
import AppSelect from '../../components/AppSelect.vue'; import AppSelectBox from '../../components/AppSelectBox.vue';
import { useFlowEditorStore } from 'stores/flowEditor'; import { useFlowEditorStore } from 'stores/flowEditor';
import { useAuthStore } from 'src/stores/useAuthStore'; import { useAuthStore } from 'src/stores/useAuthStore';
export default defineComponent({ export default defineComponent({
@@ -47,7 +47,7 @@ export default defineComponent({
"appSelected" "appSelected"
], ],
components:{ components:{
AppSelect, AppSelectBox,
ShowDialog ShowDialog
}, },
setup(props, context) { setup(props, context) {

View File

@@ -18,119 +18,69 @@
<q-separator /> <q-separator />
<q-card-section class="q-pa-none q-ma-none"> <q-card-section class="q-pa-none q-ma-none">
<div style=""> <div style="">
<div v-if="selectedField.fields && selectedField.fields.length > 0 "> <div v-if="selectedField.fields && selectedField.fields.length > 0">
<q-list bordered> <q-list bordered>
<q-virtual-scroll style="max-height: 160px;" :items="selectedField.fields" separator v-slot="{ item, index }"> <q-virtual-scroll style="max-height: 160px;" :items="selectedField.fields" separator
<q-item :key="index" dense clickable > v-slot="{ item, index }">
<q-item-section> <q-item :key="index" dense clickable>
<q-item-section>
<q-item-label> <q-item-label>
{{ item.label }} {{ item.label }}
</q-item-label> </q-item-label>
</q-item-section> </q-item-section>
<q-item-section side> <q-item-section side>
<q-btn round flat size="sm" icon="clear" @click="removeField(index)" /> <q-btn round flat size="sm" icon="clear" @click="removeField(index)" />
</q-item-section> </q-item-section>
</q-item> </q-item>
</q-virtual-scroll> </q-virtual-scroll>
</q-list> </q-list>
</div> </div>
<!-- <div v-else class="row q-mt-lg"> <!-- <div v-else class="row q-mt-lg">
</div> --> </div> -->
</div> </div>
<!-- <q-separator /> --> <!-- <q-separator /> -->
</q-card-section> </q-card-section>
<q-card-section class="q-px-none q-py-xs" v-if="selectedField.fields && selectedField.fields.length===0"> <q-card-section class="q-px-none q-py-xs" v-if="selectedField.fields && selectedField.fields.length === 0">
<div class="row"> <div class="row">
<div class="text-grey text-caption"> {{ $props.placeholder }}</div> <div class="text-grey text-caption"> {{ $props.placeholder }}</div>
<!-- <q-btn flat color="grey" label="clear" @click="clear" /> --> <!-- <q-btn flat color="grey" label="clear" @click="clear" /> -->
</div> </div>
</q-card-section> </q-card-section>
</q-card> </q-card>
</div> </div>
<show-dialog v-model:visible="show" name="フィールド一覧" @close="closeAFBox">
<show-dialog v-model:visible="show" name="フィールド一覧" @close="closeFieldDialog" ref="fieldDlg"> <AppFieldSelectBox v-model:selectedField="selectedField" :selectType="selectType" ref="afBox" :fieldTypes="fieldTypes"/>
<div class="q-mx-md q-mb-lg">
<div class="q-mb-xs q-ml-md text-primary">アプリ選択</div>
<div class="q-pa-md row" style="border: 1px solid rgba(0, 0, 0, 0.12); border-radius: 4px;">
<div v-if="!showSelectApp && selectedField.app">{{ selectedField.app?.name }}</div>
<q-space />
<div>
<q-btn outline dense label="選 択" padding="none sm" color="primary" @click="() => {
showSelectApp = true;
}"></q-btn>
</div>
</div>
</div>
<div v-if="!showSelectApp && selectedField.app?.name">
<div>
<div class="row q-mb-md">
<!-- <div class="col"> -->
<div class="q-mb-xs q-ml-md text-primary">フィールド選択</div>
<!-- </div> -->
<q-space />
<!-- <div class="col"> -->
<div class="q-mr-md">
<q-input dense debounce="300" v-model="fieldFilter" placeholder="フィールド検索" clearable>
<template v-slot:before>
<q-icon name="search" />
</template>
</q-input>
</div>
</div>
<div class="row">
<field-select ref="fieldDlg" name="フィールド" :type="selectType"
:appId="selectedField.app?.id" not_page :filter="fieldFilter" :selectedFields="selectedField.fields" :fieldTypes="fieldTypes"></field-select>
</div>
</div>
</div>
<div style="min-width: 45vw;" v-else>
</div>
</show-dialog>
<show-dialog v-model:visible="showSelectApp" name="アプリ選択" @close="closeAppDlg">
<template v-slot:toolbar>
<q-input dense debounce="300" v-model="filter" placeholder="検索" clearable>
<template v-slot:before>
<q-icon name="search" />
</template>
</q-input>
</template>
<AppSelect ref="appDlg" name="アプリ" type="single" :filter="filter" ></AppSelect>
</show-dialog> </show-dialog>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, ref, watchEffect, computed } from 'vue'; import { defineComponent, ref, watchEffect } from 'vue';
import AppFieldSelectBox from '../AppFieldSelectBox.vue';
import ShowDialog from '../ShowDialog.vue'; import ShowDialog from '../ShowDialog.vue';
import FieldSelect from '../FieldSelect.vue';
import { useFlowEditorStore } from 'stores/flowEditor'; import { useFlowEditorStore } from 'stores/flowEditor';
import AppSelect from '../AppSelect.vue';
interface IApp{ export interface IApp {
id:string, id: string,
name:string name: string
} }
interface IField { export interface IField {
name: string, name: string,
code: string, code: string,
type: string type: string,
label?:string
} }
interface IAppFields{ export interface IAppFields {
app?:IApp, app?: IApp,
fields:IField[] fields: IField[]
} }
export default defineComponent({ export default defineComponent({
inheritAttrs:false, inheritAttrs: false,
name: 'AppFieldSelect', name: 'AppFieldSelect',
components: { components: {
ShowDialog, ShowDialog,
FieldSelect, AppFieldSelectBox
AppSelect,
}, },
props: { props: {
displayName: { displayName: {
@@ -149,9 +99,9 @@ export default defineComponent({
type: Object, type: Object,
default: null default: null
}, },
selectType:{ selectType: {
type:String, type: String,
default:'single' default: 'single'
}, },
fieldTypes:{ fieldTypes:{
type:Array, type:Array,
@@ -159,69 +109,48 @@ export default defineComponent({
} }
}, },
setup(props, { emit }) { setup(props, { emit }) {
const appDlg = ref();
const fieldDlg = ref();
const show = ref(false); const show = ref(false);
const showSelectApp = ref(false); const afBox = ref();
const selectedField = ref<IAppFields>({ const selectedField = ref<IAppFields>({
app:undefined, app: undefined,
fields:[] fields: []
}); });
if(props.modelValue && "app" in props.modelValue && "fields" in props.modelValue){ if (props.modelValue && 'app' in props.modelValue && 'fields' in props.modelValue) {
selectedField.value=props.modelValue as IAppFields; selectedField.value = props.modelValue as IAppFields;
} }
const store = useFlowEditorStore(); const store = useFlowEditorStore();
const isSelected = computed(() => {
return selectedField.value !== null && typeof selectedField.value === 'object' && ('app' in selectedField.value)
});
const showDg = () => {
show.value = true;
};
const clear = () => { const clear = () => {
selectedField.value ={ selectedField.value = {
fields:[] fields: []
} ; };
} }
const closeAppDlg = (val: string) => { const removeField = (index: number) => {
selectedField.value.fields.splice(index, 1);
}
const closeAFBox = (val: string) => {
if (val == 'OK') { if (val == 'OK') {
selectedField.value.app = appDlg.value.selected[0]; console.log(afBox.value);
selectedField.value.fields=[];
showSelectApp.value=false; selectedField.value = afBox.value.selField;
} }
}; };
const closeFieldDialog=(val:string)=>{
if (val == 'OK') {
selectedField.value.fields = fieldDlg.value.selected;
}
};
const removeField=(index:number)=>{
selectedField.value.fields.splice(index,1);
}
watchEffect(() => { watchEffect(() => {
emit('update:modelValue', selectedField.value); emit('update:modelValue', selectedField.value);
}); });
return { return {
store, store,
appDlg, afBox,
fieldDlg,
show, show,
showDg, showDg: () => { show.value = true },
closeAppDlg,
closeFieldDialog,
selectedField, selectedField,
showSelectApp,
isSelected,
filter: ref(),
clear, clear,
fieldFilter: ref(), removeField,
removeField closeAFBox,
}; };
} }
}); });

View File

@@ -0,0 +1,93 @@
<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="selectedField.app.name">
{{ selectedField.app.name }}
</div>
<div v-else>{{ placeholder }}</div>
</q-card-section>
</q-card>
</template>
</q-field>
</div>
<ShowDialog v-model:visible="dgIsShow" name="アプリ選択" @close="closeDg" min-width="50vw" min-height="50vh">
<template v-slot:toolbar>
<q-input dense debounce="300" v-model="filter" placeholder="検索" clearable>
<template v-slot:before>
<q-icon name="search" />
</template>
</q-input>
</template>
<AppSelectBox ref="appDg" name="アプリ" type="single" :filter="filter"></AppSelectBox>
</ShowDialog>
</template>
<script lang="ts">
import { computed, defineComponent, reactive, ref, watchEffect } from 'vue';
import ShowDialog from '../ShowDialog.vue';
import AppSelectBox from '../AppSelectBox.vue';
export default defineComponent({
inheritAttrs: false,
name: 'AppSelect',
components: {
ShowDialog,
AppSelectBox
},
props: {
context: {
type: Array<Props>,
default: '',
},
displayName: {
type: String,
default: '',
},
name: {
type: String,
default: '',
},
placeholder: {
type: String,
default: '',
},
modelValue: {
type: Object,
default: null
}
},
setup(props, { emit }) {
const appDg = ref()
const dgIsShow = ref(false)
const selectedField = props.modelValue && props.modelValue.app ? props.modelValue : reactive({app:{}});
const closeDg = (state: string) => {
dgIsShow.value = false;
if (state == 'OK') {
selectedField.app = appDg.value.selected[0];
}
};
console.log(selectedField);
watchEffect(() => {
emit('update:modelValue', selectedField);
});
return {
filter: ref(''),
dgIsShow,
appDg,
closeDg,
selectedField
};
}
});
</script>

View File

@@ -4,7 +4,8 @@
<template v-slot:control> <template v-slot:control>
<q-card flat class="full-width"> <q-card flat class="full-width">
<q-card-actions vertical> <q-card-actions vertical>
<q-btn color="grey-3" text-color="black" @click="showDg()">クリックで設定{{ isSetted ? '設定済み' : '未設定' }}</q-btn> <q-btn color="grey-3" text-color="black" :disable="btnDisable" @click="showDg()">クリックで設定{{ isSetted ?
'設定済み' : '未設定' }}</q-btn>
</q-card-actions> </q-card-actions>
<q-card-section class="text-caption"> <q-card-section class="text-caption">
<div v-if="!isSetted">{{ placeholder }}</div> <div v-if="!isSetted">{{ placeholder }}</div>
@@ -20,7 +21,7 @@
<script lang="ts"> <script lang="ts">
import { ConditionNode, ConditionTree, Operator } from 'app/src/types/Conditions'; import { ConditionNode, ConditionTree, Operator, OperatorListItem } from 'app/src/types/Conditions';
import { computed, defineComponent, provide, reactive, ref, watchEffect } from 'vue'; import { computed, defineComponent, provide, reactive, ref, watchEffect } from 'vue';
import ConditionEditor from '../ConditionEditor/ConditionEditor.vue'; import ConditionEditor from '../ConditionEditor/ConditionEditor.vue';
@@ -28,6 +29,10 @@ type Props = {
props?: { props?: {
name: string; name: string;
modelValue?: { modelValue?: {
app: {
id: string;
name: string;
},
fields: { fields: {
type: string; type: string;
label: string; label: string;
@@ -37,6 +42,15 @@ type Props = {
} }
}; };
type InputConfg = {
canInput: boolean;
buttonsConfig: {
label: string;
color: string;
type: string;
}[]
};
export default defineComponent({ export default defineComponent({
name: 'FieldInput', name: 'FieldInput',
@@ -72,28 +86,71 @@ export default defineComponent({
sourceType: { sourceType: {
type: String, type: String,
default: 'field' default: 'field'
},
onlySourceSelect: {
type: Boolean,
default: false
},
operatorList: {
type: Array,
},
inputConfig: {
type: Object,
default: () => ({
left: {
canInput: false,
buttonsConfig: [
{ label: 'フィールド', color: 'primary', type: 'FieldAdd' },
{ label: '変数', color: 'green', type: 'VariableAdd' },
]
},
right: {
canInput: true,
buttonsConfig: [
{ label: '変数', color: 'green', type: 'VariableAdd' },
]
},
})
} }
}, },
setup(props, { emit }) { setup(props, { emit }) {
const source = props.context.find(element => element?.props?.name === 'sources') const source = props.context.find(element => element?.props?.name === 'sources')
if (source) { if (source) {
if(props.sourceType === 'field'){ if (props.sourceType === 'field') {
provide('sourceFields', computed( () => source.props?.modelValue?.fields ?? [])); provide('sourceFields', computed(() => source.props?.modelValue?.fields ?? []));
} else if(props.sourceType === 'app'){ } else if (props.sourceType === 'app') {
console.log('sourceApp', source.props?.modelValue); provide('sourceApp', computed(() => source.props?.modelValue?.app?.id));
provide('sourceApp', computed( () => source.props?.modelValue?.app?.id));
} }
} }
provide('leftDynamicItemConfig', props.inputConfig.left);
provide('rightDynamicItemConfig', props.inputConfig.right);
provide('Operator', props.operatorList);
const btnDisable = computed(() => {
const onlySourceSelect = props.onlySourceSelect;
if (!onlySourceSelect) {
return false;
}
if (props.sourceType === 'field') {
return source?.props?.modelValue?.fields?.length ?? 0 > 0;
} else if (props.sourceType === 'app') {
return source?.props?.modelValue?.app?.id ? false : true
}
return true;
})
const appDg = ref(); const appDg = ref();
const show = ref(false); const show = ref(false);
const tree = reactive(new ConditionTree()); const tree = reactive(new ConditionTree());
if (props.modelValue && props.modelValue !== '') { if (props.modelValue && props.modelValue !== '') {
tree.fromJson(props.modelValue); tree.fromJson(props.modelValue);
} else { } else {
const newNode = new ConditionNode({}, Operator.Equal, '', tree.root); const newNode = new ConditionNode({}, (props.operatorList && props.operatorList.length > 0) ? props.operatorList[0] as OperatorListItem : Operator.Equal, '', tree.root);
tree.addNode(tree.root, newNode); tree.addNode(tree.root, newNode);
} }
@@ -109,13 +166,15 @@ export default defineComponent({
const onClosed = (val: string) => { const onClosed = (val: string) => {
if (val == 'OK') { if (val == 'OK') {
const conditionJson = tree.toJson();
isSetted.value = true; isSetted.value = true;
tree.setQuery(tree.buildConditionQueryString(tree.root));
const conditionJson = tree.toJson();
emit('update:modelValue', conditionJson); emit('update:modelValue', conditionJson);
} }
}; };
watchEffect(() => { watchEffect(() => {
tree.setQuery(tree.buildConditionQueryString(tree.root));
const conditionJson = tree.toJson(); const conditionJson = tree.toJson();
emit('update:modelValue', conditionJson); emit('update:modelValue', conditionJson);
}); });
@@ -127,7 +186,8 @@ export default defineComponent({
showDg, showDg,
onClosed, onClosed,
tree, tree,
conditionString conditionString,
btnDisable
}; };
} }
}); });

View File

@@ -0,0 +1,284 @@
<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" :disable="btnDisable"
@click="() => { dgIsShow = true }">クリックで設定</q-btn>
</q-card-actions>
<q-card-section class="text-caption">
<div v-if="mappingObjectsInputDisplay && mappingObjectsInputDisplay.length > 0">
<div v-for="(item) in mappingObjectsInputDisplay" :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="55vw" min-height="60vh">
<div class="">
<div class="row q-col-gutter-x-xs flex-center">
<div class="col-5">
<div class="q-mx-xs">ソース</div>
</div>
<!-- <div class="col-1">
</div> -->
<div class="col-5">
<div class="row justify-between q-mr-md">
<div class="">{{ sourceApp?.name }}</div>
<q-btn outline color="primary" size="xs" label="最新のフィールドを取得する"
@click="() => updateFields(sourceAppId!)" />
</div>
</div>
<div class="col-1 q-pl-sm">
キー
</div>
</div>
<q-virtual-scroll style="max-height: 60vh;" :items="mappingProps" separator v-slot="{ item, index }">
<!-- <div class="q-my-sm" v-for="(item, index) in mappingProps" :key="item.id"> -->
<div class="row q-pa-sm q-col-gutter-x-md flex-center">
<div class="col-5">
<ConditionObject :config="config" v-model="item.from" :disabled="item.disabled"
:label="item.disabled ? '「Lookup」によってロックされる' : undefined" />
</div>
<!-- <div class="col-1">
</div> -->
<div class="col-5">
<q-field v-model="item.vName" type="text" outlined dense :disable="item.disabled" >
<!-- <template v-slot:append>
<q-icon name="search" class="cursor-pointer"
@click="() => { mappingProps[index].to.isDialogVisible = true }" />
</template> -->
<template v-slot:control>
<div class="self-center full-width no-outline" tabindex="0"
v-if="item.to.app?.name && item.to.fields?.length > 0 && item.to.fields[0].label">
{{ `${item.to.fields[0].label}` }}
<span class="text-red" v-if="item.to.fields[0].required">*</span>
<q-tooltip class="bg-yellow-2 text-black shadow-4" >
<div>アプリ : {{ item.to.app.name }}</div>
<div>フィールドのコード : {{ item.to.fields[0].code }}</div>
<div>フィールドのタイプ : {{ item.to.fields[0].type }}</div>
<div v-if="item.to.fields[0].required">必須項目</div>
<!-- <div>フィールド : {{ item.to.fields[0] }}</div>
<div>フィールド : {{ item.isKey }}</div> -->
</q-tooltip>
</div>
</template>
</q-field>
</div>
<div class="col-1">
<q-checkbox size="sm" v-model="item.isKey" :disable="item.disabled" />
<!-- <q-btn flat round dense icon="delete" size="sm" @click="() => deleteMappingObject(index)" /> -->
</div>
</div>
<show-dialog v-model:visible="mappingProps[index].to.isDialogVisible" name="フィールド一覧"
@close="closeToDg" ref="fieldDlg">
<FieldSelect v-if="onlySourceSelect" ref="fieldDlg" name="フィールド" :appId="sourceAppId" not_page
:selectedFields="mappingProps[index].to.fields"
:updateSelects="(fields) => { mappingProps[index].to.fields = fields; mappingProps[index].to.app = sourceApp }">
</FieldSelect>
<AppFieldSelectBox v-else v-model:selectedField="mappingProps[index].to" />
</show-dialog>
<!-- </div> -->
</q-virtual-scroll>
<div class="q-mt-lg q-ml-md row ">
<q-checkbox size="sm" v-model="createWithNull" label="キーが存在しない場合は新規に作成され、存在する場合はデータが更新されます。" />
</div>
</div>
</show-dialog>
</div>
</template>
<script lang="ts">
import { v4 as uuidv4 } from 'uuid';
import { computed, defineComponent, watch, isRef, reactive, ref, watchEffect } from 'vue';
import ConditionObject from '../ConditionEditor/ConditionObject.vue';
import ShowDialog from '../ShowDialog.vue';
import AppFieldSelectBox from '../AppFieldSelectBox.vue';
import FieldSelect from '../FieldSelect.vue';
import { IApp, IField } from './AppFieldSelect.vue';
import { api } from 'boot/axios';
type ContextProps = {
props?: {
name: string;
modelValue?: {
app: {
id: string;
name: string;
}
}
}
};
type CurrentModelValueType = {
data: MappingValueType[];
createWithNull: boolean;
}
type MappingValueType = {
id: string;
from: { sharedText?: string };
to: {
app?: IApp,
fields: IField[],
isDialogVisible: boolean;
};
isKey: boolean;
disabled: boolean;
}
const blackListLabelName = ['レコード番号', '作業者', '更新者', '更新日時', '作成日時', '作成者']
export default defineComponent({
name: 'DataMapping',
inheritAttrs: false,
components: {
ShowDialog,
ConditionObject,
AppFieldSelectBox,
FieldSelect
},
props: {
context: {
type: Array<ContextProps>,
default: '',
},
displayName: {
type: String,
default: '',
},
name: {
type: String,
default: '',
},
modelValue: {
type: Object as () => CurrentModelValueType,
},
placeholder: {
type: String,
default: '',
},
onlySourceSelect: {
type: Boolean,
default: false
},
fieldTypes:{
type:Array,
default:()=>[]
},
},
setup(props, { emit }) {
const source = props.context.find(element => element?.props?.name === 'sources')
const sourceApp = computed(() => source?.props?.modelValue?.app);
const sourceAppId = computed(() => sourceApp.value?.id);
const closeDg = () => {
emit('update:modelValue', { data: mappingProps.value, createWithNull: createWithNull.value });
}
const closeToDg = () => {
emit('update:modelValue', { data: mappingProps.value, createWithNull: createWithNull.value });
}
const mappingProps = ref(props.modelValue?.data ?? []);
const createWithNull = ref(props.modelValue?.createWithNull ?? false)
// 外部ソースコンポーネントの appid をリッスンし、変更されたときに現在のコンポーネントを更新します
watch(() => sourceAppId.value, async (newId,) => {
if (!newId) return;
updateFields(newId)
})
const updateFields = async (sourceAppId: string) => {
const ktAppFields = await api.get('api/v1/appfields', {
params: {
app: sourceAppId
}
}).then(res => {
return Object.values(res.data.properties)
// kintoneのデフォルトの非表示フィールドフィルタリング
.filter(f => !blackListLabelName.find(label => f.label === label))
.map(f => ({ name: f.label, objectType: 'field', ...f }))
.map(f => {
// 更新前の値を求める
const beforeData = mappingProps.value.find(m => m.to.fields[0].code === f.code)
return {
id: uuidv4(),
from: beforeData?.from ?? {}, // 以前のデータを入力します
to: {
app: sourceApp.value,
fields: [f],
isDialogVisible: false
},
isKey: beforeData?.isKey ?? false, // 以前のデータを入力します
disabled: false
}
})
})
// 「ルックアップ」によってロックされているフィールドを検索する
const lookupFixedField = ktAppFields
.filter(field => field.to.fields[0].lookup !== undefined)
.flatMap(field => field.to.fields[0].lookup.fieldMappings.map((m) => m.field))
// 「ルックアップ」でロックされたビューコンポーネントを非対話型に設定します
if (lookupFixedField.length > 0) {
ktAppFields.filter(f => lookupFixedField.includes(f.to.fields[0].code)).forEach(f => f.disabled = true)
}
mappingProps.value = ktAppFields
}
const mappingObjectsInputDisplay = computed(() =>
(mappingProps.value && Array.isArray(mappingProps.value)) ?
mappingProps.value
.filter(item => item.from?.sharedText && item.to.fields?.length > 0)
.map(item => {
return `field(${item.to.app?.id},${item.to.fields[0].label}) = ${item.from.sharedText} `;
})
: []
);
const btnDisable = computed(() => props.onlySourceSelect ? !(source?.props?.modelValue?.app?.id) : false);
watchEffect(() => {
emit('update:modelValue', { data: mappingProps.value, createWithNull: createWithNull.value });
});
return {
uuidv4,
dgIsShow: ref(false),
closeDg,
toDgIsShow: ref(false),
closeToDg,
mappingProps,
createWithNull,
updateFields,
// addMappingObject: () => mappingProps.push(defaultMappingProp()),
// deleteMappingObject,
mappingObjectsInputDisplay,
sourceApp,
sourceAppId,
btnDisable,
config: {
canInput: false,
buttonsConfig: [
{ label: 'フィールド', color: 'primary', type: 'FieldAdd' },
{ label: '変数', color: 'green', type: 'VariableAdd', editable: false },
]
}
};
},
});
</script>
<style lang="scss"></style>

View File

@@ -40,7 +40,7 @@
<div class="col-5"> <div class="col-5">
<ConditionObject v-model="item.field" /> <ConditionObject v-model="item.field" />
</div> </div>
<div class="col-2"> <div class="col-2 q-pa-sm">
<q-select v-model="item.logicalOperator" :options="logicalOperators" outlined dense></q-select> <q-select v-model="item.logicalOperator" :options="logicalOperators" outlined dense></q-select>
</div> </div>
<div class="col-4"> <div class="col-4">
@@ -78,14 +78,8 @@ type Props = {
type ProcessingObjectType = { type ProcessingObjectType = {
field?: { field?: {
name: string | { sharedText: string;
name: string; objectType: 'field';
};
objectType: string;
type: string;
code: string;
label: string;
noLabel: boolean;
}; };
logicalOperator?: string; logicalOperator?: string;
vName?: string; vName?: string;
@@ -139,44 +133,60 @@ export default defineComponent({
} }
return null; return null;
})); }));
provide('sourceApp', computed(() => source.props?.modelValue?.app?.id));
} }
const actionName = props.context.find(element => element?.props?.name === 'displayName') const actionName = props.context.find(element => element?.props?.name === 'displayName')
const processingProps: ValueType = props.modelValue && props.modelValue.vars const processingProps: ValueType = props.modelValue && props.modelValue.vars
? props.modelValue ? reactive(props.modelValue)
: reactive({ : reactive({
name: '', name: '',
actionName: actionName?.props?.modelValue as string, actionName: actionName?.props?.modelValue as string,
displayName: '結果(戻り値)', displayName: '結果(戻り値)',
vars: [{ id: uuidv4() }] vars: [
{
id: uuidv4(),
field:{
objectType:'field',
sharedText:''
}
}]
}); });
const closeDg = () => { const closeDg = () => {
emit('update:modelValue', processingProps emit('update:modelValue', processingProps);
);
} }
const processingObjects = processingProps.vars; const processingObjects = processingProps.vars;
const deleteProcessingObject = (index: number) => processingObjects.length === 1 const deleteProcessingObject = (index: number) => {
? processingObjects.splice(0, processingObjects.length, { id: uuidv4() }) if(processingObjects.length >0){
: processingObjects.splice(index, 1); processingObjects.splice(index, 1);
}
if(processingObjects.length===0){
addProcessingObject();
}
}
const processingObjectsInputDisplay = computed(() => const processingObjectsInputDisplay = computed(() =>
processingObjects ? processingObjects ?
processingObjects processingObjects
.filter(item => item.field && item.logicalOperator && item.vName) .filter(item => item.field && item.logicalOperator && item.vName)
.map(item => { .map(item => {
const name = typeof item.field?.name === 'string' return`var(${processingProps.name}.${item.vName}) = ${item.field?.sharedText}`
? 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 addProcessingObject=()=>{
processingObjects.push({
id: uuidv4(),
field:{
objectType:'field',
sharedText:''
}
});
}
//集計処理方法 //集計処理方法
const logicalOperators = ref([ const logicalOperators = ref([
{ {
@@ -218,7 +228,7 @@ export default defineComponent({
closeDg, closeDg,
processingObjects, processingObjects,
processingProps, processingProps,
addProcessingObject: () => processingObjects.push({ id: uuidv4() }), addProcessingObject,
deleteProcessingObject, deleteProcessingObject,
logicalOperators, logicalOperators,
processingObjectsInputDisplay, processingObjectsInputDisplay,

View File

@@ -22,6 +22,8 @@ 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 DataProcessing from './DataProcessing.vue';
import DataMapping from './DataMapping.vue';
import AppSelect from './AppSelect.vue';
import { IActionNode,IActionProperty,IProp } from 'src/types/ActionTypes'; import { IActionNode,IActionProperty,IProp } from 'src/types/ActionTypes';
export default defineComponent({ export default defineComponent({
@@ -37,7 +39,9 @@ export default defineComponent({
EventSetter, EventSetter,
ColorPicker, ColorPicker,
NumInput, NumInput,
DataProcessing DataProcessing,
DataMapping,
AppSelect
}, },
props: { props: {
nodeProps: { nodeProps: {

View File

@@ -24,7 +24,7 @@
<q-btn :label="model+'選択'" color="primary" @click="showDg()" /> <q-btn :label="model+'選択'" color="primary" @click="showDg()" />
<show-dialog v-model:visible="show" :name="model" @close="closeDg" width="400px"> <show-dialog v-model:visible="show" :name="model" @close="closeDg" width="400px">
<template v-if="model=='アプリ'"> <template v-if="model=='アプリ'">
<app-select ref="appDg" :name="model" type="single"></app-select> <app-select-box ref="appDg" :name="model" type="single"></app-select-box>
</template> </template>
<template v-if="model=='フィールド'"> <template v-if="model=='フィールド'">
<field-select ref="appDg" :name="model" type="multiple" :appId="1"></field-select> <field-select ref="appDg" :name="model" type="multiple" :appId="1"></field-select>
@@ -42,7 +42,7 @@
<script setup lang="ts"> <script setup lang="ts">
import ShowDialog from 'components/ShowDialog.vue'; import ShowDialog from 'components/ShowDialog.vue';
import AppSelect from 'components/AppSelect.vue'; import AppSelectBox from 'components/AppSelectBox.vue';
import FieldSelect from 'components/FieldSelect.vue'; import FieldSelect from 'components/FieldSelect.vue';
import ActionSelect from 'components/ActionSelect.vue'; import ActionSelect from 'components/ActionSelect.vue';
import { ref } from 'vue' import { ref } from 'vue'

View File

@@ -74,6 +74,11 @@ export class GroupNode implements INode {
} }
export type OperatorListItem = {
label: string;
value: string;
}
// 条件式ノード // 条件式ノード
export class ConditionNode implements INode { export class ConditionNode implements INode {
index: number; index: number;
@@ -83,13 +88,13 @@ export class ConditionNode implements INode {
return this.parent.logicalOperator; return this.parent.logicalOperator;
}; };
object: any; // 比較元 object: any; // 比較元
operator: Operator; // 比較子 operator: Operator | OperatorListItem; // 比較子
value: any; value: any;
get header():string{ get header():string{
return 'generic'; return 'generic';
} }
constructor(object: any, operator: Operator, value: any, parent: GroupNode) { constructor(object: any, operator: Operator | OperatorListItem, value: any, parent: GroupNode) {
this.index=0; this.index=0;
this.type = NodeType.Condition; this.type = NodeType.Condition;
this.object = object; this.object = object;
@@ -113,10 +118,12 @@ export class ConditionNode implements INode {
export class ConditionTree { export class ConditionTree {
root: GroupNode; root: GroupNode;
maxIndex:number; maxIndex:number;
queryString:string;
constructor() { constructor() {
this.maxIndex=0; this.maxIndex=0;
this.root = new GroupNode(LogicalOperator.AND, null); this.root = new GroupNode(LogicalOperator.AND, null);
this.queryString='';
} }
// ノード追加 // ノード追加
@@ -194,16 +201,53 @@ export class ConditionTree {
} else { } else {
const condNode=node as ConditionNode; const condNode=node as ConditionNode;
if (condNode.object && condNode.operator ) { if (condNode.object && condNode.operator ) {
let value=condNode.value; // let value=condNode.value;
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.sharedText} ${typeof condNode.operator === 'object' ? condNode.operator.label : condNode.operator} ${condNode.value.sharedText}`;
// return `${typeof condNode.object.name === 'object' ? condNode.object.name.name : condNode.object.name} ${typeof condNode.operator === 'object' ? condNode.operator.label : condNode.operator} '${value}'`;
} else { } else {
return ''; return '';
} }
} }
} }
buildConditionQueryString(node:INode){
if (node.type !== NodeType.Condition) {
let conditionString = '';
if(node.type !== NodeType.Root){
conditionString = '(';
}
const groupNode = node as GroupNode;
for (let i = 0; i < groupNode.children.length; i++) {
const childConditionString = this.buildConditionQueryString(groupNode.children[i]);
if (childConditionString !== '') {
conditionString += childConditionString;
if (i < groupNode.children.length - 1) {
conditionString += ` ${groupNode.logicalOperator.toLowerCase()} `;
}
}
}
if(node.type !== NodeType.Root){
conditionString += ')';
}
return conditionString;
} else {
const condNode=node as ConditionNode;
if (condNode.object && condNode.operator ) {
if (!condNode.object.code || !condNode.value.sharedText){
return '';
}
return `${condNode.object.code} ${typeof condNode.operator === 'object' ? condNode.operator.value : condNode.operator} "${condNode.value.sharedText}"`;
} else {
return '';
}
}
}
/** /**
* *
* @param node ノード移動 * @param node ノード移動
@@ -325,7 +369,7 @@ export class ConditionTree {
} }
toJson():string{ toJson():string{
return JSON.stringify(this.root, (key, value) => { return JSON.stringify({queryString :this.queryString, ...this.root}, (key, value) => {
if (key === 'parent') { if (key === 'parent') {
return value ? value.type : null; return value ? value.type : null;
} }
@@ -333,4 +377,7 @@ export class ConditionTree {
}); });
} }
setQuery(queryString:string){
this.queryString=queryString;
}
} }

11
node_modules/.yarn-integrity generated vendored
View File

@@ -1,8 +1,13 @@
{ {
"systemParams": "win32-x64-115", "systemParams": "win32-x64-108",
"modulesFolders": [], "modulesFolders": [
"node_modules"
],
"flags": [], "flags": [],
"linkedModules": [], "linkedModules": [
"@quasar\\quasar-ui-qactivity",
"docs"
],
"topLevelPatterns": [], "topLevelPatterns": [],
"lockfileEntries": {}, "lockfileEntries": {},
"files": [], "files": [],

View File

@@ -0,0 +1,2 @@
VITE_SOURCE_MAP = inline
VITE_PORT = 4173

View File

@@ -0,0 +1,2 @@
VITE_SOURCE_MAP = false
VITE_PORT = 4173

View File

@@ -4,25 +4,35 @@
"version": "0.0.0", "version": "0.0.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "tsc && set \"SOURCE_MAP=true\" && vite build && vite preview", "dev": "run-p watch server ngrok",
"build": "tsc && vite build && xcopy dist\\*.js ..\\..\\backend\\Temp\\ /E /I /Y", "watch": "vite build --watch --mode dev",
"build:linux": "tsc && vite build && cp -ur dist/*.js ../../backend/Temp", "server": "vite dev --mode dev",
"build:dev": "tsc && set \"SOURCE_MAP=true\" && vite build && xcopy dist\\*.js ..\\..\\backend\\Temp\\ /E /I /Y", "ngrok": "ngrok http 4173",
"preview": "vite preview", "build": "run-s b:production copyjs:windows copycss:windows",
"ngrok": "ngrok http http://localhost:4173/", "build:dev": "run-s b:dev copyjs:windows copycss:windows",
"vite": "vite dev" "build:linux": "run-s b:production copyjs:linux copycss:linux",
"build:linux-dev": "run-s b:dev copy:linux",
"b:production": "tsc & vite build --mode production",
"b:dev": "tsc & vite build --mode dev",
"copyjs:windows": "xcopy dist\\*.js ..\\..\\backend\\Temp\\ /E /I /Y",
"copyjs:linux": "cp -ur dist/*.js ../../backend/Temp",
"copycss:windows": "xcopy dist\\*.css ..\\..\\backend\\Temp\\ /E /I /Y",
"copycss:linux": "cp -ur dist/*.css ../../backend/Temp"
}, },
"devDependencies": { "devDependencies": {
"@types/jquery": "^3.5.24", "@types/jquery": "^3.5.24",
"@types/node": "^20.8.9", "@types/node": "^20.8.9",
"npm-run-all2": "^6.2.0",
"sass": "^1.69.5", "sass": "^1.69.5",
"typescript": "^5.0.2", "typescript": "^5.0.2",
"vite": "^4.4.5", "vite": "^4.4.5",
"vite-plugin-checker": "^0.6.4" "vite-plugin-checker": "^0.6.4"
}, },
"dependencies": { "dependencies": {
"jquery": "^3.7.1", "@kintone/rest-api-client": "^5.5.2",
"vite-plugin-css-injected-by-js": "^3.5.1", "@popperjs/core": "^2.11.8",
"yarn": "^1.22.22" "@types/bootstrap": "^5.2.10",
"bootstrap": "^5.3.3",
"jquery": "^3.7.1"
} }
} }

View File

@@ -0,0 +1 @@
@import 'bootstrap/scss/bootstrap';

View File

@@ -0,0 +1,272 @@
import {
IAction,
IActionResult,
IActionNode,
IActionProperty,
IContext,
IField,
} from "../types/ActionTypes";
import { actionAddins } from ".";
import type { Record} from "@kintone/rest-api-client/lib/src/client/types";
import { KintoneRestAPIClient} from "@kintone/rest-api-client";
import "./auto-lookup.scss";
import "bootstrap/js/dist/modal";
// import "bootstrap/js/dist/spinner";
import {Modal} from "bootstrap"
import $ from "jquery";
interface Props {
displayName: string;
lookupField: LookupField;
condition: Condition;
}
interface Condition {
queryString: string;
index: number;
type: string;
children: Child[];
parent: null;
logicalOperator: string;
}
interface Child {
index: number;
type: string;
parent: string;
object: any;
operator: string;
value: string;
}
interface LookupField {
app: App;
fields: Field[];
}
interface Field {
name: string;
type: string;
code: string;
label: string;
noLabel: boolean;
required: boolean;
lookup: Lookup;
}
interface Lookup {
relatedApp: RelatedApp;
relatedKeyField: string;
fieldMappings: FieldMapping[];
lookupPickerFields: any[];
filterCond: string;
sort: string;
}
interface FieldMapping {
field: string;
relatedField: string;
}
interface RelatedApp {
app: string;
code: string;
}
interface App {
id: string;
name: string;
description: string;
createdate: string;
}
export class AutoLookUpAction implements IAction {
name: string;
actionProps: IActionProperty[];
props: Props;
constructor() {
this.name = "ルックアップ更新";
this.actionProps = [];
this.props = {} as Props;
this.register();
}
/***
* アクセスのメインの処理関数
*/
async process(
prop: IActionNode,
event: any,
context: IContext
): Promise<IActionResult> {
this.actionProps = prop.actionProps;
this.props = {
...prop.ActionValue,
condition: JSON.parse((prop.ActionValue as any).condition),
} as Props;
// console.log(context);
let result = {
canNext: true,
result: "",
} as IActionResult;
try {
const lookUpFields = this.props.lookupField.fields.filter(
(f) => f.lookup && f.lookup.relatedApp.app === String(kintone.app.getId())
);
if (!lookUpFields || lookUpFields.length===0) {
throw new Error(
`ルックアップの設定は不正です。${this.props.lookupField.fields[0].label} `
);
}
const lookUpField = this.props.lookupField.fields[0];
const key = event.record[lookUpField.lookup.relatedKeyField].value;
const targetRecords = await this.getUpdateRecords(lookUpField, key);
//更新対象がない時にスキップ
if(targetRecords.length===0){
return result;
}
const updateRecords = this.convertForLookup(targetRecords,lookUpField,key);
console.log("updateRecords", updateRecords);
this.showSpinnerModel(this.props.lookupField.app);
await this.updateLookupTarget(updateRecords);
this.showResult(this.props.lookupField.app,updateRecords.length);
} catch (error) {
console.error("ルックアップ更新中例外が発生しました。", error);
if(error instanceof Error){
event.error = error.message;
}else{
event.error = "ルックアップ更新中例外が発生しました。";
}
result.canNext = false;
}
console.log("autoLookupProps", this.props);
return result;
}
/**
* REST API用クエリ作成
* TODO:共通関数として作成
* @param lookUpField
* @param key
* @returns
*/
makeQuery=(lookUpField:Field,key:any)=>{
if(typeof key==='number'){
return `${lookUpField.code} = ${key}`
}
if(typeof key==='string'){
return `${lookUpField.code} = "${key}"`
}
}
/**
* 更新対象のレコードを取得する
*/
getUpdateRecords = async (lookUpField:Field,key:any):Promise< Record[]>=>{
const client=new KintoneRestAPIClient();
const resp = await client.record.getAllRecords({
app:this.props.lookupField.app.id,
fields:["$id"],
condition:this.makeQuery(lookUpField,key)
});
return resp;
}
/**
* ルックアップ更新用レコードに変換する
* @param targetRecords 更新対象レコード
* @param lookUpField ルックアップフィールド
* @param key ルックアップフィールドの値
* @returns
*/
convertForLookup = (targetRecords:Record[],lookUpField:Field,key:any):Array<any>=>{
return targetRecords.map((r) => ({
id: Number(r["$id"].value),
record: { [lookUpField.code]: { value: key } },
}));
}
/**
* ルックアップ先を更新する
* @param updateRecords
*/
updateLookupTarget = async (updateRecords:Array<any>)=>{
if (updateRecords && updateRecords.length > 0) {
const client=new KintoneRestAPIClient();
client.record.updateAllRecords({
app:this.props.lookupField.app.id,
records:updateRecords
});
// await kintone.api(kintone.api.url("/k/v1/records.json", true), "PUT", {
// app: this.props.lookupField.app.id,
// records: updateRecords
// });
}
}
/**
* 更新中のダイアログ表示
* @param app
*/
showSpinnerModel = (app:App) => {
let dialog = $("#alcLookupModal");
if(dialog.length===0){
const modalHTML = `
<div class="modal" id="alcLookupModal" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog-centered">
<div class="modal-dialog modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="alcLookupModalLabel">ルックアップ同期処理</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="row" id="app${app.id}">
<div class="spinner-border text-secondary col-1 " role="alert"></div>
<div class="col">${app.name}</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">OK</button>
</div>
</div>
</div>
</div>`;
dialog = $(modalHTML).appendTo("body");
dialog.get()[0].addEventListener('hidden.bs.modal',(ev)=>{
Modal.getOrCreateInstance(dialog.get()[0]).dispose();
$("#alcLookupModal").remove();
});
}else{
const dialogBody=$("#alcLookupModal .modal-body");
const htmlrow=`
<div class="row" id="app${app.id}">
<div class="spinner-border text-secondary col-1 " role="alert">
</div>
<div class="col">${app.name}</div>
<div>`;
dialogBody.append(htmlrow);
}
Modal.getOrCreateInstance(dialog.get()[0]).show();
}
/**
* 更新結果を表示する
* @param app  更新先アプリ情報
* @param count 更新件数
*/
showResult=(app:App,count:number)=>{
const dialogBody=$(`#alcLookupModal .modal-body #app${app.id}`);
const html=` <div class="col-1 text-success">✔</div>
<div class="col">${app.name}</div>
<div class="col">更新件数:${count}件</div>`;
dialogBody.html(html);
}
register(): void {
actionAddins[this.name] = this;
}
}
new AutoLookUpAction();

View File

@@ -1,6 +1,6 @@
import { actionAddins } from "."; import { actionAddins } from ".";
import { IField, IAction,IActionResult, IActionNode, IActionProperty, IContext } from "../types/ActionTypes"; import { IField, IAction,IActionResult, IActionNode, IActionProperty, IContext, IVarName } from "../types/ActionTypes";
import { Formatter } from "../util/format"; import { Formatter } from "../util/format";
declare global { declare global {
@@ -13,7 +13,7 @@ interface IAutoNumberingProps{
format:string; format:string;
prefix:string; prefix:string;
suffix:string; suffix:string;
verName:string; verName:IVarName;
} }
export class AutoNumbering implements IAction{ export class AutoNumbering implements IAction{
@@ -29,7 +29,7 @@ export class AutoNumbering implements IAction{
format:'', format:'',
prefix:'', prefix:'',
suffix:'', suffix:'',
verName:'' verName:{name:''}
} }
globalThis.window.$format=this.format; globalThis.window.$format=this.format;
this.register(); this.register();
@@ -56,8 +56,8 @@ export class AutoNumbering implements IAction{
const docNum = await this.createNumber(this.props); const docNum = await this.createNumber(this.props);
record[this.props.field.code].value=docNum; record[this.props.field.code].value=docNum;
//変数設定 //変数設定
if(this.props.verName){ if(this.props.verName && this.props.verName.name!==''){
context.variables[this.props.verName]=docNum; context.variables[this.props.verName.name]=docNum;
} }
result= { result= {
canNext:true, canNext:true,

View File

@@ -1,13 +1,13 @@
import { actionAddins } from "."; import { actionAddins } from ".";
import { IAction,IActionResult, IActionNode, IActionProperty, IContext } from "../types/ActionTypes"; import { IAction,IActionResult, IActionNode, IActionProperty, IContext, IVarName } from "../types/ActionTypes";
import { ConditionTree } from '../types/Conditions'; import { ConditionTree } from '../types/Conditions';
/** /**
* アクションの属性定義 * アクションの属性定義
*/ */
interface ICondition{ interface ICondition{
condition:string; condition:string;
verName:string; verName:IVarName;
} }
/** /**
* 条件分岐アクション * 条件分岐アクション
@@ -21,7 +21,7 @@ export class ConditionAction implements IAction{
this.actionProps=[]; this.actionProps=[];
this.props={ this.props={
condition:'', condition:'',
verName:'' verName:{name:''}
} }
//アクションを登録する //アクションを登録する
this.register(); this.register();
@@ -58,8 +58,8 @@ export class ConditionAction implements IAction{
result:'いいえ' result:'いいえ'
} }
} }
if(this.props.verName){ if(this.props.verName && this.props.verName.name!==''){
context.variables[this.props.verName]=result.result; context.variables[this.props.verName.name]=result.result;
} }
return result; return result;
}catch(error){ }catch(error){

View File

@@ -0,0 +1,74 @@
import {
IAction,
IActionResult,
IActionNode,
IActionProperty,
IContext,
} from "../types/ActionTypes";
import { actionAddins } from ".";
interface Props {
displayName: string;
field: Field;
verName: VerName;
}
interface VerName {
name: string;
}
interface Field {
name: string;
type: string;
code: string;
label: string;
noLabel: boolean;
required: boolean;
minLength: string;
maxLength: string;
expression: string;
hideExpression: boolean;
unique: boolean;
defaultValue: string;
}
export class CurrentFieldGetAction implements IAction {
name: string;
actionProps: IActionProperty[];
currentFieldGetProps: Props;
constructor() {
this.name = "フィールドの値を取得する";
this.actionProps = [];
this.currentFieldGetProps = {} as Props;
this.register();
}
async process(
prop: IActionNode,
event: any,
context: IContext
): Promise<IActionResult> {
this.currentFieldGetProps = prop.ActionValue as Props;
this.actionProps = prop.actionProps;
let result = {
canNext: true,
result: "",
} as IActionResult;
try {
context.variables[this.currentFieldGetProps.verName.name] = context.record[this.currentFieldGetProps.field.code].value;
} catch (error) {
console.error("CurrentFieldGetAction error", error);
result.canNext = false;
}
return result;
}
register(): void {
actionAddins[this.name] = this;
}
}
new CurrentFieldGetAction();

View File

@@ -0,0 +1,185 @@
import {
IAction,
IActionResult,
IActionNode,
IActionProperty,
IContext,
} from "../types/ActionTypes";
import { actionAddins } from ".";
import {KintoneRestAPIClient} from '@kintone/rest-api-client';
import { Aggregator,Operator} from '../util/aggregates';
import { FieldForm } from "../types/FieldLayout";
interface IDataProcessingProps {
displayName: string;
sources: Sources;
condition: string;
verName?: VerName;
}
interface Condition {
queryString: string;
}
interface VerName {
name: string;
actionName: string;
displayName: string;
vars: Var[];
}
interface Var {
id: string;
field: FieldForm;
logicalOperator: CalcOperator;
vName: string;
}
interface CalcOperator {
operator: Operator;
label: string;
}
interface Sources {
app: App;
fields: FieldForm[];
}
interface App {
id: string;
name?: string;
}
type Result = {
[key: string]: {
type: string;
value: any[];
};
};
type AnyObject = {
[key: string]: any;
};
export class DataProcessingAction implements IAction {
name: string;
actionProps: IActionProperty[];
props: IDataProcessingProps ;
constructor() {
this.name = "データ処理";
this.actionProps = [];
this.props = {
displayName:'',
condition:'',
sources:{
app:{
id:""
},
fields:[]
},
};
this.register();
}
async process(
nodes: IActionNode,
event: any,
context: IContext
): Promise<IActionResult> {
this.actionProps = nodes.actionProps;
this.props = nodes.ActionValue as IDataProcessingProps;
const condition = JSON.parse(this.props.condition) as Condition;
let result = {
canNext: true,
result: "",
} as IActionResult;
try {
if (!this.props) {
return result;
}
const query = this.getQuery(condition.queryString,context.variables);
const data = await this.selectData(query);
console.log("data ", data);
if(this.props.verName){
const varValues= this.props.verName.vars.reduce((acc, f) => {
const datas=data[f.field.code].value;
const agg = new Aggregator(datas,f.field);
const result = agg.calculate(f.logicalOperator.operator)
acc[f.vName]=result;
return acc;
}, {} as AnyObject);
context.variables[this.props.verName.name]=varValues;
console.log("context ", context);
}
return result;
} catch (error) {
console.error("データ集計中例外が発生しました。", error);
if(error instanceof Error){
event.error = `データ集計中例外が発生しました。 ${error.message}`;
}else{
event.error = "データ集計中例外が発生しました。";
}
result.canNext = false;
return result;
}
}
/**
*
* @param str
* @param vars
* @returns
*/
getQuery = (str: string, vars: any) => {
console.log(str);
const regex = /var\((.*?)\)/g;
let match;
while ((match = regex.exec(str)) !== null) {
const varName = match[1];
if (varName in vars) {
str = str.replace(match[0], vars[varName]);
} else {
throw new Error(`変数${varName}が見つかりません`);
}
}
console.log(str);
return str;
};
/**
* データを取得する
* @param query
* @returns
*/
selectData = async ( query?: string) => {
const api = new KintoneRestAPIClient();
const fields = this.props.sources.fields.map((field)=>field.code);
const resp = await api.record.getAllRecords({
app: this.props.sources.app.id,
fields:fields,
condition:query
});
const result: Result = {};
resp.forEach((element) => {
for (const [key, value] of Object.entries(element)) {
if (!result[key]) {
result[key] = { type: value.type, value: [] };
}
result[key].value.push(value.value);
}
});
return result;
};
register(): void {
actionAddins[this.name] = this;
}
}
new DataProcessingAction();

View File

@@ -0,0 +1,334 @@
import {
IAction,
IActionResult,
IActionNode,
IActionProperty,
IContext,
} from "../types/ActionTypes";
import { actionAddins } from ".";
import { KintoneRestAPIClient } from "@kintone/rest-api-client";
import { Lookup } from "@kintone/rest-api-client/lib/src/KintoneFields/types/property";
import { FieldForm, FieldType } from "../types/FieldLayout";
interface Props {
displayName: string;
sources: Sources;
dataMapping: DataMapping;
}
interface DataMapping {
data: Mapping[];
createWithNull: boolean;
}
interface Mapping {
id: string;
from: From;
to: To;
isKey: boolean;
}
interface To {
app: App;
fields:FieldForm[];
isDialogVisible: boolean;
}
interface From {
sharedText: string;
id: string;
objectType: 'variable'|'field'|'text';
}
interface IVar extends From{
name:{
name:string;
}
}
interface IFromField extends From,FieldForm{
}
interface Sources {
app: App;
}
interface App {
id: string;
name: string;
description: string;
createdate: string;
}
export class DataUpdateAction implements IAction {
name: string;
actionProps: IActionProperty[];
dataMappingProps: Props;
constructor() {
this.name = "データ更新";
this.actionProps = [];
this.dataMappingProps = {} as Props;
this.register();
}
async process(
prop: IActionNode,
event: any,
context: IContext
): Promise<IActionResult> {
this.actionProps = prop.actionProps;
this.dataMappingProps = prop.ActionValue as Props;
console.log(context);
let result = {
canNext: true,
result: "",
} as IActionResult;
try {
const lookupFixedFieldCodes = await getLookupFixedFieldCodes(
this.dataMappingProps.sources.app.id
);
// createWithNull が有効な場合は、4 番目のパラメーターを true にして doUpdate 関数ブランチを実行します。
if (this.dataMappingProps.dataMapping.createWithNull) {
await doUpdate(
this.dataMappingProps.dataMapping.data,
this.dataMappingProps.sources.app.id,
context,
true, // キーがない場合、またはキーでターゲットが見つからない場合に、マッピング条件によって新しいレコードを作成するかどうかを決定するために使用されます。
lookupFixedFieldCodes
);
} else if (
// キーがないと更新対象を取得できないため、この時点でのみ更新が行われます。 doUpdate 関数の 4 番目のパラメーターは false です。
this.dataMappingProps.dataMapping.data
.map((m) => m.isKey)
.find((isKey) => isKey === true)
) {
await doUpdate(
this.dataMappingProps.dataMapping.data,
this.dataMappingProps.sources.app.id,
context,
false,
lookupFixedFieldCodes
);
} else {
await doCreate(
this.dataMappingProps.dataMapping.data,
this.dataMappingProps.sources.app.id,
context,
lookupFixedFieldCodes
);
}
} catch (error) {
console.error("DataMappingAction error", error);
result.canNext = false;
}
console.log("dataMappingProps", this.dataMappingProps);
return result;
}
register(): void {
actionAddins[this.name] = this;
}
}
new DataUpdateAction();
const getContextVarByPath = (obj: any, path: string) => {
return path.split(".").reduce((o, k) => (o || {})[k], obj);
};
interface UpdateRecord {
id: string;
record: {
[key: string]: {
value: any;
};
};
}
const client = new KintoneRestAPIClient();
const getFromValue=(item:Mapping,context:IContext)=>{
if (item.from.objectType === "variable") {
const rfrom =item.from as IVar;
return getContextVarByPath(context.variables,rfrom.name.name);
}else if(item.from.objectType === "field"){
const field = item.from as IFromField;
return context.record[field.code].value;
}
else {
return item.from.sharedText;
}
}
const doUpdate = async (
mappingData: Mapping[],
appId: string,
context: IContext,
needCreate: boolean,
lookupFixedFieldCodes: string[]
) => {
const targetField = await findUpdateField(mappingData, appId, context);
console.log(targetField);
if (targetField.records.length === 0 && needCreate) {
await doCreate(mappingData, appId, context, lookupFixedFieldCodes);
} else {
// マッピングデータを単純なオブジェクトに処理し、ソース値が変数の場合は変数を置き換えます。
const mappingRules = mappingData
.filter(
(m) =>
Object.keys(m.from).length > 0 &&
!lookupFixedFieldCodes.includes(m.to.fields[0].code)
)
.map((m) => {
if (m.from.objectType === "variable") {
const rfrom =m.from as IVar;
return {
value: getContextVarByPath(context.variables,rfrom.name.name),
code: m.to.fields[0].code,
};
}else if(m.from.objectType === "field"){
const field = m.from as IFromField;
return {
value: context.record[field.code].value,
code: m.to.fields[0].code,
}
}
else {
return {
value: m.from.sharedText,
code: m.to.fields[0].code,
};
}
});
const updateRecords: UpdateRecord[] = targetField.records.map(
(targetRecord) => {
const updateRecord: UpdateRecord["record"] = {};
// マッピング内のルールにヒットしたフィールドのみが更新されます。
for (const mapping of mappingRules) {
if (targetRecord[mapping.code]) {
updateRecord[mapping.code] = {
value: mapping.value,
};
}
}
return {
id: targetRecord.$id.value as string,
record: updateRecord,
};
}
);
console.log(updateRecords);
await client.record.updateRecords({
app: appId,
records: updateRecords,
});
}
};
const makeQuery=(field:FieldForm,key:any)=>{
if(field.type===FieldType.NUMBER || field.type===FieldType.RECORD_NUMBER){
return `${field.code} = ${Number(key)}`
}
if(typeof key==='string'){
return `${field.code} = "${key}"`
}
}
const findUpdateField = async (
mappingData: Mapping[],
appId: string,
context: IContext
) => {
const queryStr = mappingData
.filter((m) => m.to.app && m.to.fields && m.to.fields.length > 0 && m.isKey)
.map((m) => {
if (m.from.objectType === "variable") {
const vfrom = m.from as IVar;
return makeQuery(m.to.fields[0],getContextVarByPath(context.variables , vfrom.name.name));
}
else if(m.from.objectType === "field"){
const field = m.from as IFromField;
return makeQuery(m.to.fields[0],context.record[field.code].value);
}
else{
return makeQuery(m.to.fields[0],m.from.sharedText);
}
})
.join("&");
// 検索条件が空の場合は全レコードを返すため、検索対象が見つからない場合は検索は行われません。
if (queryStr.length === 0) {
return {
records: [],
};
} else {
return await client.record.getRecords({
app: appId,
// query: undefined
query: queryStr,
});
}
};
const doCreate = async (
mappingData: Mapping[],
appId: string,
context: IContext,
lookupFixedFieldCodes: string[]
) => {
const filterHandler = (item:Mapping)=>{
if(!item.to.fields || item.to.fields.length===0){
return false;
}
if(item.from.objectType === "variable" && (item.from as IVar).name.name ){
return true;
}
if(item.from.objectType === "field" && (item.from as IFromField).code){
return true;
}
if(item.from.objectType === "text" && item.from.sharedText!==null){
return true;
}
return false;
}
const record = mappingData
.filter(filterHandler)
.filter((item) => !lookupFixedFieldCodes.includes(item.to.fields[0].code))
.reduce((accumulator, item) => {
return {
...accumulator,
[item.to.fields[0].code]: {
value: getFromValue(item,context),
},
};
}, {});
if (record && Object.keys(record).length > 0) {
console.log(record);
await client.record.addRecord({
app:appId,
record:record
});
// await kintone.api(kintone.api.url("/k/v1/record.json", true), "POST", {
// app: appId,
// record: record,
// });
}
};
const getLookupFixedFieldCodes = async (appId: string) => {
return await client.app
.getFormFields({ app: appId })
.then((resp) =>
Object.values(resp.properties)
.filter((f) => (f as Lookup).lookup !== undefined)
.flatMap((f) => (f as Lookup).lookup.fieldMappings.map((m) => m.field))
);
};

View File

@@ -1,11 +1,11 @@
import { actionAddins } from "."; import { actionAddins } from ".";
import { IAction, IActionResult, IActionNode, IActionProperty, IField ,IContext} from "../types/ActionTypes"; import { IAction, IActionResult, IActionNode, IActionProperty, IField ,IContext, IVarName} from "../types/ActionTypes";
/** /**
* アクションの属性定義 * アクションの属性定義
*/ */
interface IDatetimeGetterProps { interface IDatetimeGetterProps {
/**変数の名前 */ /**変数の名前 */
verName:string; verName:IVarName;
} }
/** /**
* 現在日時を取得するアクション * 現在日時を取得するアクション
@@ -18,7 +18,7 @@ export class DatetimeGetterAction implements IAction {
this.name = "現在日時"; this.name = "現在日時";
this.actionProps = []; this.actionProps = [];
this.props = { this.props = {
verName:'' verName:{name:''}
} }
this.register(); this.register();
} }
@@ -45,8 +45,8 @@ export class DatetimeGetterAction implements IAction {
let today = new Date(); let today = new Date();
if(this.props.verName){ if(this.props.verName && this.props.verName.name!==''){
context.variables[this.props.verName]=today.toISOString(); context.variables[this.props.verName.name]=today.toISOString();
} }
return result; return result;

View File

@@ -0,0 +1,76 @@
import { actionAddins } from ".";
import { IField,IAction,IActionResult, IActionNode, IActionProperty,IContext,IVarName} from "../types/ActionTypes";
//右UI画面propertyのname:型:
interface ILoginUserGetterProps{
//変数名にセット:値がオブジェクトの形式
verName:IVarName;
}
//IActionインタフェースを実装する新しいクラスActionを作成
export class LoginUserGetterAction implements IAction{
name: string;
//importから導入顕示定義
actionProps: IActionProperty[];
//上方のinterface Propsから、props受ける属性を定義
props:ILoginUserGetterProps;
//関数定義に必要な類名を構築:
constructor(){
//pgAdminDBに登録したアクション名(name/subtitle)一致する必要がある:
this.name="ログインユーザー取得";
this.actionProps=[];
this.register();
//プロパティ属性初期化:
this.props={
verName:{name:''}
}
//リセット上記登録表:
this.register();
}
/**
* アクションの処理を実装する
* @param actionNode アクションノード
* @param event Kintoneのイベント
* @param context コンテキスト(レコード、変数情報を持っている)
* @returns
*/
  //非同期処理ある関数下のある属性:
async process(actionNode:IActionNode,event:any,context:IContext):Promise<IActionResult> {
let result={
canNext:true,
result:false
};
try{
//属性設定を取得する:
this.actionProps=actionNode.actionProps;
//プロパティ設定のデータ型は必要な情報含めますか全部不存在時return:
if (!('verName' in actionNode.ActionValue)) {
return result
}
//既定のプロパティのインタフェースへ変換:
this.props = actionNode.ActionValue as ILoginUserGetterProps;
//////////////////////////////////////////////////////////////////////////////////////
if(this.props.verName&&this.props.verName.name!==''){
context.variables[this.props.verName.name]=kintone.getLoginUser();
// window.alert("変数名"+this.props.verName.name+"の値は"+context.variables[this.props.verName.name]+"です");
// event.record["変数運用先のユーザ選択フィールド"].value= [{code:context.variables[this.props.verName.name].code}];
}
//////////////////////////////////////////////////////////////////////////////////////
result= {
canNext:true,
result:true
}
return result;
//////////////////////////////////////////////////////////////////////////////////////
}catch(error:any){;
event.error=error.message;
return {
canNext:false,
result:false
}
}
}
//////////////////////////////////////////////////////////////////////////////////////
register(): void {
actionAddins[this.name]=this;
}
}
new LoginUserGetterAction();

View File

@@ -51,13 +51,19 @@ export class MailCheckAction implements IAction {
const value = record[this.props.field.code].value; const value = record[this.props.field.code].value;
if (this.props.emailCheck === '厳格') { if (this.props.emailCheck === '厳格') {
if (!/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(value)) { if (!/^[a-zA-Z0-9_-¥.]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(value)) {
record[this.props.field.code].error = this.props.message; record[this.props.field.code].error = this.props.message;
} }
else {
record[this.props.field.code].error = null;
}
} else if (this.props.emailCheck === 'ゆるめ') { } else if (this.props.emailCheck === 'ゆるめ') {
if (!/^[^@]+@[^@]+$/.test(value)) { if (!/^[^@]+@[^@]+$/.test(value)) {
record[this.props.field.code].error = this.props.message; record[this.props.field.code].error = this.props.message;
} }
else {
record[this.props.field.code].error = null;
}
} else { } else {
result = { result = {
canNext: true, canNext: true,

View File

@@ -44,7 +44,7 @@ export class StringJoinAction implements IAction{
* @param context コンテキスト(レコード、変数情報を持っている) * @param context コンテキスト(レコード、変数情報を持っている)
* @returns * @returns
*/ */
  //非同期処理ある関数下のある属性: //非同期処理ある関数下のある属性:
async process(actionNode:IActionNode,event:any):Promise<IActionResult> { async process(actionNode:IActionNode,event:any):Promise<IActionResult> {
let result={ let result={
//後継処理不可: //後継処理不可:
@@ -107,7 +107,7 @@ export class StringJoinAction implements IAction{
for(let i=0;i<mototext.length;i++){ for(let i=0;i<mototext.length;i++){
arr.push(mototext[i].name); arr.push(mototext[i].name);
} }
   //配列要素を,で連結して文字列を作成: //配列要素を,で連結して文字列を作成:
value=arr.join(); value=arr.join();
} }
//カテゴリー、チェックボックス、複数選択: //カテゴリー、チェックボックス、複数選択:
@@ -120,7 +120,7 @@ export class StringJoinAction implements IAction{
for(let i=0;i<mototext.length;i++){ for(let i=0;i<mototext.length;i++){
arr.push(mototext[i]); arr.push(mototext[i]);
} }
   //配列要素を,で連結して文字列を作成: //配列要素を,で連結して文字列を作成:
value=arr.join(); value=arr.join();
} }
//詳細画面プロセス実行後のステータス: //詳細画面プロセス実行後のステータス:

View File

@@ -66,6 +66,7 @@ export class FullWidthAction implements IAction{
result:true result:true
} }
return result; return result;
//例外処理 //例外処理
}catch(error){ }catch(error){
event.error=error; event.error=error;
@@ -74,26 +75,19 @@ export class FullWidthAction implements IAction{
return result; return result;
} }
} }
//全て全角の文字列の場合はtrue、そうでない場合はfalse // 全て全角の文字列の場合はtrue、そうでない場合はfalse
containsFullWidthChars(text: string): boolean { containsFullWidthChars(text: string): boolean {
//半角英数字カナを除外
// 半角英数字カナ記号を除外
const checkRegex="^[^\x01-\x7E\uFF61-\uFF9F]+$"; const checkRegex="^[^\x01-\x7E\uFF61-\uFF9F]+$";
//正規表現オブジェクト生成 //正規表現オブジェクト生成
const fullWidthRegex = new RegExp(checkRegex); const fullWidthRegex = new RegExp(checkRegex);
//正規表現チェック //正規表現チェック
return fullWidthRegex.test(text); return fullWidthRegex.test(text);
//全角を表すUnicodeの全角正規表現(参照先URL)
// \u3000-\u303F句読点・記号
// \u3040-\u309Fすべてのひらがな
// \u30A0-\u30FF:すべてのカタカナ
// \u4E00-\u9FAF:すべての漢字
// \uFF00-\uFFEF:全角英数字と半角カタカナ
// \u3400-\u4DBF:CJK統合漢字拡張
//const fullWidthRegex = /[/^[\u3000-\u303F\u3040-\u309F\u30A0-\u30FF\uFF00-\uFFEF\u4E00-\u9FAF\u3400-\u4DBF]+$/g;
} }
//戻り値を持たないためvoid型 //戻り値を持たないためvoid型
register(): void { register(): void {
actionAddins[this.name]=this; actionAddins[this.name]=this;

View File

@@ -0,0 +1,90 @@
import { actionAddins } from ".";
import { IAction,IActionResult, IActionNode, IActionProperty, IField, IContext } from "../types/ActionTypes";
/**
* アクションの属性定義
*/
interface HalfWidthProps{
field:IField
}
/**
* 半角チェックアクション
*/
export class HalfWidthAction implements IAction{
name: string;
actionProps: IActionProperty[];
props:HalfWidthProps;
constructor(){
this.name="半角チェック"; /* pgadminのnameと同様 */
this.actionProps=[];
this.props={
field:{code:''}
}
//アクションを登録する
this.register();
}
/**
* アクションの実行を呼び出す
* @param actionNode
* @param event
* @returns
*/
async process(actionNode:IActionNode,event:any,context:IContext):Promise<IActionResult> {
let result={
canNext:true,
result:false
};
try{
//属性設定を取得する
this.actionProps=actionNode.actionProps;
if (!('field' in actionNode.ActionValue) ) {
return result
}
this.props = actionNode.ActionValue as HalfWidthProps;
//条件式の計算結果を取得
const record = event.record;
const value = record[this.props.field.code]?.value;
//条件分岐
//未入力時は何も処理をせず終了
if(value===undefined || value===''){
return result;
}
//全角が含まれていた場合保存処理中止(エラー処理)
if(!this.containsHalfWidthChars(value)){
//エラー時に出力される文字設定
record[this.props.field.code].error="全角が含まれています";
//次の処理を中止する値設定
result.canNext=false;
return result;
}
//半角の場合問題なく実行
//resultプロパティ指定
result= {
canNext:true,
result:true
}
return result;
//例外処理
}catch(error){
event.error=error;
console.error(error);
result.canNext=false;
return result;
}
}
// 全て全角の文字列の場合はtrue、そうでない場合はfalse
containsHalfWidthChars(text: string): boolean {
const checkRegex = "^[\x01-\x7E\uFF61-\uFF9F]+$";
//正規表現オブジェクト生成
const halfWidthRegex = new RegExp(checkRegex);
//正規表現チェック
return halfWidthRegex.test(text);
}
//戻り値を持たないためvoid型
register(): void {
actionAddins[this.name]=this;
}
}
new HalfWidthAction();

View File

@@ -1,11 +1,11 @@
import { actionAddins } from "."; import { actionAddins } from ".";
import { IAction,IActionResult, IActionNode, IActionProperty, IField, IContext} from "../types/ActionTypes"; import { IAction,IActionResult, IActionNode, IActionProperty, IField, IContext, IVarName} from "../types/ActionTypes";
/** /**
* アクションの属性定義 * アクションの属性定義
*/ */
interface IGetValueProps{ interface IGetValueProps{
field:IField;//チェックするフィールドの対象 field:IField;//チェックするフィールドの対象
verName:string; verName:IVarName;
} }
/** /**
* 正規表現チェックアクション * 正規表現チェックアクション
@@ -19,7 +19,7 @@ export class GetValueAciton implements IAction{
this.actionProps=[]; this.actionProps=[];
this.props={ this.props={
field:{code:''}, field:{code:''},
verName:'' verName:{name:''}
} }
//アクションを登録する //アクションを登録する
this.register(); this.register();
@@ -46,7 +46,9 @@ export class GetValueAciton implements IAction{
//条件式の計算結果を取得 //条件式の計算結果を取得
const record = event.record; const record = event.record;
const value = record[this.props.field.code].value; const value = record[this.props.field.code].value;
context.variables[this.props.verName] = value; if(this.props.verName && this.props.verName.name!==''){
context.variables[this.props.verName.name] = value;
}
result = { result = {
canNext:true, canNext:true,
result:true result:true

View File

@@ -42,7 +42,12 @@ $(function (){
const flow=ActionFlow.fromJSON(flowinfo.content); const flow=ActionFlow.fromJSON(flowinfo.content);
if(flow!==undefined){ if(flow!==undefined){
const process = new ActionProcess(event.type,flow,event); const process = new ActionProcess(event.type,flow,event);
process.exec(); process.exec().then((res)=>{
const record = event.record;
kintone.app.record.set({record});
}).catch((err)=>{
console.error(err);
});
} }
return event; return event;
}); });
@@ -58,7 +63,7 @@ $(function (){
await process.exec(); await process.exec();
} }
const record = event.record; const record = event.record;
kintone.app.record.set({record}) kintone.app.record.set({record});
}); });
}); });
} }

View File

@@ -92,6 +92,11 @@ export interface IField{
required?:boolean; required?:boolean;
options?:string; options?:string;
} }
//変数のインターフェース
export interface IVarName{
name:string;
fields?:IVarName[];
}
/** /**
* アクションのプロパティ定義に基づいたクラス * アクションのプロパティ定義に基づいたクラス

View File

@@ -347,6 +347,9 @@ export class ConditionTree {
if(!object || typeof object!=="object"){ if(!object || typeof object!=="object"){
return object; return object;
} }
if("sharedText" in object){
return object.sharedText;
}
if("label" in object){ if("label" in object){
return object.label; return object.label;
} }

View File

@@ -0,0 +1,240 @@
// src/types/field.d.ts
export enum FieldType {
CALC = "CALC",
CATEGORY = "CATEGORY",
CHECK_BOX = "CHECK_BOX",
CREATED_TIME = "CREATED_TIME",
CREATOR = "CREATOR",
DATE = "DATE",
DATETIME = "DATETIME",
DROP_DOWN = "DROP_DOWN",
FILE = "FILE",
GROUP = "GROUP",
GROUP_SELECT = "GROUP_SELECT",
LINK = "LINK",
MODIFIER = "MODIFIER",
MULTI_LINE_TEXT = "MULTI_LINE_TEXT",
MULTI_SELECT = "MULTI_SELECT",
NUMBER = "NUMBER",
ORGANIZATION_SELECT = "ORGANIZATION_SELECT",
RADIO_BUTTON = "RADIO_BUTTON",
RECORD_NUMBER = "RECORD_NUMBER",
REFERENCE_TABLE = "REFERENCE_TABLE",
RICH_TEXT = "RICH_TEXT",
SINGLE_LINE_TEXT = "SINGLE_LINE_TEXT",
STATUS = "STATUS",
STATUS_ASSIGNEE = "STATUS_ASSIGNEE",
SUBTABLE = "SUBTABLE",
TIME = "TIME",
UPDATED_TIME = "UPDATED_TIME",
USER_SELECT = "USER_SELECT"
}
export enum CalcFormat{
NUMBER = "NUMBER",
NUMBER_DIGIT = "NUMBER_DIGIT",
DATETIME = "DATETIME",
DATE = "DATE",
TIME = "TIME",
HOUR_MINUTE= "HOUR_MINUTE",
DAY_HOUR_MINUTE= "DAY_HOUR_MINUTE"
}
export interface FieldForm {
code: string;
type: FieldType;
required?: boolean;
noLabel?: boolean;
}
export interface OptionForm{
index: string;
label: string;
}
export interface EntityForm {
code: string;
type: 'USER' | 'ORGANIZATION' | 'GROUP' | 'FUNCTION';
}
export interface CalcFieldForm extends FieldForm {
unit?: string;
expression?: string;
format?:CalcFormat;
unitPosition?: 'BEFORE' | 'AFTER';
displayScale?: string;
hideExpression?: boolean;
}
export interface CategoryFieldForm extends FieldForm {
enabled?: boolean;
}
export interface DateFieldForm extends FieldForm {
defaultValue?: string;
unique?: boolean;
defaultNowValue?: boolean;
}
export interface DatetimeFieldForm extends FieldForm {
defaultValue?: string;
unique?: boolean;
defaultNowValue?: boolean;
}
export interface DecimalFieldForm extends FieldForm {
maxValue?: string;
defaultValue?: string;
unitPosition?: 'BEFORE' | 'AFTER';
minValue?: string;
unit?: string;
unique?: boolean;
displayScale?: string;
digit?: boolean;
}
export interface EditorFieldForm extends FieldForm {
defaultValue?: string;
}
export interface EntityForm {
code: string;
type: 'USER' | 'ORGANIZATION' | 'GROUP' | 'FUNCTION';
}
export interface FieldMappingForm {
relatedField: string;
field: string;
}
export interface FileFieldForm extends FieldForm {
thumbnailSize?: string;
}
export interface GroupFieldForm extends FieldForm {
openGroup?: boolean;
}
export interface GroupSelectFieldForm extends FieldForm {
entities: EntityForm[];
defaultValue?: EntityForm[];
}
export interface LinkFieldForm extends FieldForm {
protocol?: 'WEB' | 'CALL' | 'MAIL';
defaultValue?: string;
minLength?: string;
unique?: boolean;
maxLength?: string;
}
export interface LookupFieldForm extends FieldForm {
lookup: {
lookupPickerFields: string[];
relatedKeyField: string;
relatedApp: {
app: string;
code: string;
};
fieldMappings: FieldMappingForm[];
sort?: string;
filterCond?: string;
};
}
export interface ModifiedAtFieldForm extends FieldForm {}
export interface ModifierFieldForm extends FieldForm {}
export interface MultipleCheckFieldForm extends FieldForm {
defaultValue?: string[];
options: {
[key: string]: OptionForm;
};
align?: 'HORIZONTAL' | 'VERTICAL';
}
export interface MultipleLineTextFieldForm extends FieldForm {
defaultValue?: string;
}
export interface MultipleSelectFieldForm extends FieldForm {
defaultValue?: string[];
options: {
[key: string]: OptionForm;
};
}
export interface OrganizationSelectFieldForm extends FieldForm {
entities: EntityForm[];
defaultValue?: EntityForm[];
}
export interface RecordIdFieldForm extends FieldForm {}
export interface ReferenceTableFieldForm extends FieldForm {
referenceTable: {
condition: {
relatedField: string;
field: string;
};
size?: string;
relatedApp: {
app: string;
code: string;
};
sort?: string;
filterCond?: string;
displayFields: string[];
};
}
export interface SingleCheckFieldForm extends FieldForm {
defaultValue?: string;
options: {
[key: string]: OptionForm;
};
align?: 'HORIZONTAL' | 'VERTICAL';
}
export interface SingleLineTextFieldForm extends FieldForm {
expression?: string;
defaultValue?: string;
minLength?: string;
unique?: boolean;
maxLength?: string;
hideExpression?: boolean;
}
export interface SingleSelectFieldForm extends FieldForm {
defaultValue?: string;
options: {
[key: string]: OptionForm;
};
}
export interface StatusAssigneeFieldForm extends FieldForm {
enabled?: boolean;
}
export interface StatusFieldForm extends FieldForm {
enabled?: boolean;
}
export interface TableForm extends FieldForm {
fields: {
[key: string]: CalcFieldForm | CategoryFieldForm | DateFieldForm | DatetimeFieldForm | DecimalFieldForm | EditorFieldForm | FileFieldForm | GroupFieldForm | GroupSelectFieldForm | LinkFieldForm | LookupFieldForm | ModifiedAtFieldForm | ModifierFieldForm | MultipleCheckFieldForm | MultipleLineTextFieldForm | MultipleSelectFieldForm | OrganizationSelectFieldForm | RecordIdFieldForm | ReferenceTableFieldForm | SingleCheckFieldForm | SingleLineTextFieldForm | SingleSelectFieldForm | StatusAssigneeFieldForm | StatusFieldForm | TableForm | TimeFieldForm | UserSelectFieldForm;
};
}
export interface TimeFieldForm extends FieldForm {
defaultValue?: string;
defaultNowValue?: boolean;
}
export interface UserSelectFieldForm extends FieldForm {
entities: EntityForm[];
defaultValue?: EntityForm[];
}

View File

@@ -6,6 +6,9 @@ import '../actions/field-shown';
import '../actions/error-show'; import '../actions/error-show';
import '../actions/button-add'; import '../actions/button-add';
import '../actions/condition-action'; import '../actions/condition-action';
import '../actions/data-processing';
import '../actions/data-update';
import '../actions/current-field-get';
import '../actions/regular-check'; import '../actions/regular-check';
import '../actions/mail-check'; import '../actions/mail-check';
import '../actions/counter-check'; import '../actions/counter-check';
@@ -13,7 +16,11 @@ import '../actions/datetime-getter';
import '../actions/insert-value'; import '../actions/insert-value';
import '../actions/value-getter'; import '../actions/value-getter';
import '../actions/string-join'; import '../actions/string-join';
import '../actions/validation fullwidth'; import '../actions/validation-fullwidth';
import '../actions/validation-halfwidth';
import '../actions/login-user-getter';
import '../actions/auto-lookup';
import { ActionFlow,IActionFlow, IActionResult,IContext } from "./ActionTypes"; import { ActionFlow,IActionFlow, IActionResult,IContext } from "./ActionTypes";
export class ActionProcess{ export class ActionProcess{
@@ -47,7 +54,7 @@ export class ActionProcess{
result = await action.process(nextAction,this.event,this.context); result = await action.process(nextAction,this.event,this.context);
} }
let nextInput = ''; let nextInput = '';
//outputPoints一以上㝮場坈〝次㝮InputPoint戻り値を設定 //outputPoints一以上の場合、次のInputPoint戻り値を設定
if(nextAction.outputPoints && nextAction.outputPoints.length>1){ if(nextAction.outputPoints && nextAction.outputPoints.length>1){
nextInput = result.result||''; nextInput = result.result||'';
} }

View File

@@ -0,0 +1,121 @@
import { FieldForm,CalcFieldForm,FieldType, CalcFormat} from "../types/FieldLayout";
/**
* 集計操作子
*/
export enum Operator {
SUM = "SUM",
AVG = "AVG",
MAX = "MAX",
MIN = "MIN",
COUNT = "COUNT",
FIRST = "FIRST",
LAST = "LAST"
}
/**
* 集計関数
*/
export class Aggregator {
private data: string[];
private field: FieldForm;
constructor(data: string[], field: FieldForm) {
this.data = data;
this.field = field;
}
private toNumberArray(): number[] {
const numberArray = this.data.map(item => {
const num = Number(item);
if (isNaN(num)) {
throw new Error(`フィールド「${this.field.code} 」は数値に変換できないため、計算を実行できません。`);
}
return num;
});
return numberArray;
}
private sum(): number | null {
if (this.data.length === 0) return null;
const numberArray = this.toNumberArray();
return numberArray.reduce((acc, val) => acc + val, 0);
}
private avg(): number | null {
if (this.data.length === 0) return null;
const numberArray = this.toNumberArray();
const total = numberArray.reduce((acc, val) => acc + val, 0);
return total / numberArray.length;
}
private max(): number | string | null {
if (this.data.length === 0) return null;
if (this.field.type === FieldType.NUMBER ) {
const numberArray = this.toNumberArray();
return Math.max(...numberArray);
}
if(this.field.type===FieldType.CALC){
const calcField = this.field as CalcFieldForm;
if(calcField.format===CalcFormat.NUMBER || calcField.format===CalcFormat.NUMBER_DIGIT){
const numberArray = this.toNumberArray();
return Math.max(...numberArray);
}
}
return this.data.reduce((max, item) => (item > max ? item : max), this.data[0]);
}
private min(): number | string | null {
if (this.data.length === 0) return null;
if (this.field.type === FieldType.NUMBER ) {
const numberArray = this.toNumberArray();
return Math.min(...numberArray);
}
if(this.field.type===FieldType.CALC){
const calcField = this.field as CalcFieldForm;
if(calcField.format===CalcFormat.NUMBER || calcField.format===CalcFormat.NUMBER_DIGIT){
const numberArray = this.toNumberArray();
return Math.min(...numberArray);
}
}
if(this.data===null || this.data.length===0){
return null;
}
return this.data.reduce((min, item) => (item < min ? item : min), this.data[0]);
}
private count(): number {
return this.data.length;
}
private first(): string | null {
return this.data.length ? this.data[0] : null;
}
private last(): string | null {
return this.data.length ? this.data[this.data.length - 1] : null;
}
public calculate(operator: Operator): number | string | null {
switch (operator) {
case Operator.SUM:
return this.sum();
case Operator.AVG:
return this.avg();
case Operator.MAX:
return this.max();
case Operator.MIN:
return this.min();
case Operator.COUNT:
return this.count();
case Operator.FIRST:
return this.first();
case Operator.LAST:
return this.last();
default:
return null;
}
}
}

View File

@@ -1,26 +1,33 @@
// vite.config.js // vite.config.js
import { defineConfig } from "vite"; import { defineConfig, loadEnv } from "vite";
import cssInjectedByJsPlugin from "vite-plugin-css-injected-by-js";
import checker from "vite-plugin-checker"; import checker from "vite-plugin-checker";
// import { libInjectCss } from 'vite-plugin-lib-inject-css';
const sourcemap = process.env.SOURCE_MAP === "true"; export default ({ mode }) => {
process.env = { ...process.env, ...loadEnv(mode, process.cwd()) };
export default defineConfig({ const sourcemap = process.env.VITE_SOURCE_MAP=== 'false'?false:process.env.VITE_SOURCE_MAP;
plugins: [ // console.log(process.env);
checker({ return defineConfig({
typescript: true, plugins: [
}), checker({
cssInjectedByJsPlugin(), typescript: true,
], }),
build: { // libInjectCss(),
cssCodeSplit: false, ],
rollupOptions: { build: {
input: "src/index.ts", // entry file cssCodeSplit: false,
output: { rollupOptions: {
entryFileNames: "alc_runtime.js", input: "src/index.ts", // entry file
// assetFileNames:'alc_kintone_style.css' output: {
entryFileNames: "alc_runtime.js",
assetFileNames:'alc_runtime.css'
},
}, },
sourcemap: sourcemap,
}, },
sourcemap: sourcemap, server: {
}, port: process.env.VITE_PORT,
}); // open: "/dist/alc_runtime.js",
},
});
};

View File

@@ -135,6 +135,18 @@
resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz" resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz"
integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==
"@kintone/rest-api-client@^5.5.2":
version "5.5.2"
resolved "https://registry.yarnpkg.com/@kintone/rest-api-client/-/rest-api-client-5.5.2.tgz#501cd72dcfe51cd84c1a65fb1e2fdd4a92933e5b"
integrity sha512-1nKynN5Lp1PdfGOr73tlEyGjT0gqr+fW5eV7BfkI5jEqbtNIqHfKNZi93zzPGIxz6cFr+PNGlfKO0+tZsO9DYw==
dependencies:
axios "^1.7.2"
core-js "^3.37.1"
form-data "^4.0.0"
js-base64 "^3.7.7"
mime "^3.0.0"
qs "^6.12.1"
"@nodelib/fs.scandir@2.1.5": "@nodelib/fs.scandir@2.1.5":
version "2.1.5" version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
@@ -156,6 +168,18 @@
"@nodelib/fs.scandir" "2.1.5" "@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0" fastq "^1.6.0"
"@popperjs/core@^2.11.8", "@popperjs/core@^2.9.2":
version "2.11.8"
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f"
integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
"@types/bootstrap@^5.2.10":
version "5.2.10"
resolved "https://registry.yarnpkg.com/@types/bootstrap/-/bootstrap-5.2.10.tgz#58506463bccc6602bc051487ad8d3a6458f94c6c"
integrity sha512-F2X+cd6551tep0MvVZ6nM8v7XgGN/twpdNDjqS1TUM7YFNEtQYWk+dKAnH+T1gr6QgCoGMPl487xw/9hXooa2g==
dependencies:
"@popperjs/core" "^2.9.2"
"@types/jquery@^3.5.24": "@types/jquery@^3.5.24":
version "3.5.24" version "3.5.24"
resolved "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.24.tgz" resolved "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.24.tgz"
@@ -201,6 +225,11 @@ ansi-styles@^4.1.0:
dependencies: dependencies:
color-convert "^2.0.1" color-convert "^2.0.1"
ansi-styles@^6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5"
integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==
anymatch@~3.1.2: anymatch@~3.1.2:
version "3.1.3" version "3.1.3"
resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz"
@@ -209,6 +238,20 @@ anymatch@~3.1.2:
normalize-path "^3.0.0" normalize-path "^3.0.0"
picomatch "^2.0.4" picomatch "^2.0.4"
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
axios@^1.7.2:
version "1.7.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.2.tgz#b625db8a7051fbea61c35a3cbb3a1daa7b9c7621"
integrity sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==
dependencies:
follow-redirects "^1.15.6"
form-data "^4.0.0"
proxy-from-env "^1.1.0"
balanced-match@^1.0.0: balanced-match@^1.0.0:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
@@ -219,6 +262,11 @@ binary-extensions@^2.0.0:
resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz"
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
bootstrap@^5.3.3:
version "5.3.3"
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.3.3.tgz#de35e1a765c897ac940021900fcbb831602bac38"
integrity sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==
brace-expansion@^1.1.7: brace-expansion@^1.1.7:
version "1.1.11" version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -227,6 +275,13 @@ brace-expansion@^1.1.7:
balanced-match "^1.0.0" balanced-match "^1.0.0"
concat-map "0.0.1" concat-map "0.0.1"
brace-expansion@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
dependencies:
balanced-match "^1.0.0"
braces@^3.0.3: braces@^3.0.3:
version "3.0.3" version "3.0.3"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
@@ -241,6 +296,17 @@ braces@~3.0.2:
dependencies: dependencies:
fill-range "^7.0.1" fill-range "^7.0.1"
call-bind@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
dependencies:
es-define-property "^1.0.0"
es-errors "^1.3.0"
function-bind "^1.1.2"
get-intrinsic "^1.2.4"
set-function-length "^1.2.1"
chalk@^2.4.2: chalk@^2.4.2:
version "2.4.2" version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
@@ -312,6 +378,13 @@ color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
combined-stream@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
dependencies:
delayed-stream "~1.0.0"
commander@^8.0.0: commander@^8.0.0:
version "8.3.0" version "8.3.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
@@ -322,6 +395,46 @@ concat-map@0.0.1:
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
core-js@^3.37.1:
version "3.37.1"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.37.1.tgz#d21751ddb756518ac5a00e4d66499df981a62db9"
integrity sha512-Xn6qmxrQZyB0FFY8E3bgRXei3lWDJHhvI+u0q9TKIYM49G8pAr0FgnnrFRAmsbptZL1yxRADVXn+x5AGsbBfyw==
cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
dependencies:
path-key "^3.1.0"
shebang-command "^2.0.0"
which "^2.0.1"
define-data-property@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
dependencies:
es-define-property "^1.0.0"
es-errors "^1.3.0"
gopd "^1.0.1"
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
es-define-property@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845"
integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==
dependencies:
get-intrinsic "^1.2.4"
es-errors@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
esbuild@^0.18.10: esbuild@^0.18.10:
version "0.18.20" version "0.18.20"
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz" resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz"
@@ -387,6 +500,20 @@ fill-range@^7.1.1:
dependencies: dependencies:
to-regex-range "^5.0.1" to-regex-range "^5.0.1"
follow-redirects@^1.15.6:
version "1.15.6"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==
form-data@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
mime-types "^2.1.12"
fs-extra@^11.1.0: fs-extra@^11.1.0:
version "11.2.0" version "11.2.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b"
@@ -401,6 +528,22 @@ fsevents@~2.3.2:
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
function-bind@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
get-intrinsic@^1.1.3, get-intrinsic@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
dependencies:
es-errors "^1.3.0"
function-bind "^1.1.2"
has-proto "^1.0.1"
has-symbols "^1.0.3"
hasown "^2.0.0"
glob-parent@^5.1.2, glob-parent@~5.1.2: glob-parent@^5.1.2, glob-parent@~5.1.2:
version "5.1.2" version "5.1.2"
resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz"
@@ -408,6 +551,13 @@ glob-parent@^5.1.2, glob-parent@~5.1.2:
dependencies: dependencies:
is-glob "^4.0.1" is-glob "^4.0.1"
gopd@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
dependencies:
get-intrinsic "^1.1.3"
graceful-fs@^4.1.6, graceful-fs@^4.2.0: graceful-fs@^4.1.6, graceful-fs@^4.2.0:
version "4.2.11" version "4.2.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
@@ -423,6 +573,30 @@ has-flag@^4.0.0:
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
has-property-descriptors@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
dependencies:
es-define-property "^1.0.0"
has-proto@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd"
integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==
has-symbols@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
hasown@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
dependencies:
function-bind "^1.1.2"
immutable@^4.0.0: immutable@^4.0.0:
version "4.3.4" version "4.3.4"
resolved "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz" resolved "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz"
@@ -452,16 +626,31 @@ is-number@^7.0.0:
resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
jquery@^3.7.1: jquery@^3.7.1:
version "3.7.1" version "3.7.1"
resolved "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz" resolved "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz"
integrity sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg== integrity sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==
js-base64@^3.7.7:
version "3.7.7"
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.7.tgz#e51b84bf78fbf5702b9541e2cb7bfcb893b43e79"
integrity sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==
js-tokens@^4.0.0: js-tokens@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
json-parse-even-better-errors@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz#b43d35e89c0f3be6b5fbbe9dc6c82467b30c28da"
integrity sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==
jsonfile@^6.0.1: jsonfile@^6.0.1:
version "6.1.0" version "6.1.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
@@ -471,6 +660,11 @@ jsonfile@^6.0.1:
optionalDependencies: optionalDependencies:
graceful-fs "^4.1.6" graceful-fs "^4.1.6"
memorystream@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2"
integrity sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==
merge2@^1.3.0: merge2@^1.3.0:
version "1.4.1" version "1.4.1"
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
@@ -484,6 +678,23 @@ micromatch@^4.0.4:
braces "^3.0.3" braces "^3.0.3"
picomatch "^2.3.1" picomatch "^2.3.1"
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
mime-types@^2.1.12:
version "2.1.35"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
dependencies:
mime-db "1.52.0"
mime@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7"
integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==
minimatch@^3.0.4: minimatch@^3.0.4:
version "3.1.2" version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
@@ -491,6 +702,13 @@ minimatch@^3.0.4:
dependencies: dependencies:
brace-expansion "^1.1.7" brace-expansion "^1.1.7"
minimatch@^9.0.0:
version "9.0.5"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5"
integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==
dependencies:
brace-expansion "^2.0.1"
nanoid@^3.3.6: nanoid@^3.3.6:
version "3.3.6" version "3.3.6"
resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz" resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz"
@@ -501,6 +719,24 @@ normalize-path@^3.0.0, normalize-path@~3.0.0:
resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
npm-normalize-package-bin@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz#25447e32a9a7de1f51362c61a559233b89947832"
integrity sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==
npm-run-all2@^6.2.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/npm-run-all2/-/npm-run-all2-6.2.0.tgz#ac0a893a593e1ab3ef85c5ac3526321d2e3137bd"
integrity sha512-wA7yVIkthe6qJBfiJ2g6aweaaRlw72itsFGF6HuwCHKwtwAx/4BY1vVpk6bw6lS8RLMsexoasOkd0aYOmsFG7Q==
dependencies:
ansi-styles "^6.2.1"
cross-spawn "^7.0.3"
memorystream "^0.3.1"
minimatch "^9.0.0"
pidtree "^0.6.0"
read-package-json-fast "^3.0.2"
shell-quote "^1.7.3"
npm-run-path@^4.0.1: npm-run-path@^4.0.1:
version "4.0.1" version "4.0.1"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
@@ -508,7 +744,12 @@ npm-run-path@^4.0.1:
dependencies: dependencies:
path-key "^3.0.0" path-key "^3.0.0"
path-key@^3.0.0: object-inspect@^1.13.1:
version "1.13.2"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff"
integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==
path-key@^3.0.0, path-key@^3.1.0:
version "3.1.1" version "3.1.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
@@ -523,6 +764,11 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
pidtree@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c"
integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==
postcss@^8.4.27: postcss@^8.4.27:
version "8.4.31" version "8.4.31"
resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz" resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz"
@@ -532,11 +778,31 @@ postcss@^8.4.27:
picocolors "^1.0.0" picocolors "^1.0.0"
source-map-js "^1.0.2" source-map-js "^1.0.2"
proxy-from-env@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
qs@^6.12.1:
version "6.12.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.12.2.tgz#5443b587f3bf73ac68968de491e5b25bafe04478"
integrity sha512-x+NLUpx9SYrcwXtX7ob1gnkSems4i/mGZX5SlYxwIau6RrUSODO89TR/XDGGpn5RPWSYIB+aSfuSlV5+CmbTBg==
dependencies:
side-channel "^1.0.6"
queue-microtask@^1.2.2: queue-microtask@^1.2.2:
version "1.2.3" version "1.2.3"
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
read-package-json-fast@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz#394908a9725dc7a5f14e70c8e7556dff1d2b1049"
integrity sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==
dependencies:
json-parse-even-better-errors "^3.0.0"
npm-normalize-package-bin "^3.0.0"
readdirp@~3.6.0: readdirp@~3.6.0:
version "3.6.0" version "3.6.0"
resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz"
@@ -577,6 +843,45 @@ semver@^7.3.4, semver@^7.5.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13"
integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==
set-function-length@^1.2.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
dependencies:
define-data-property "^1.1.4"
es-errors "^1.3.0"
function-bind "^1.1.2"
get-intrinsic "^1.2.4"
gopd "^1.0.1"
has-property-descriptors "^1.0.2"
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
dependencies:
shebang-regex "^3.0.0"
shebang-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
shell-quote@^1.7.3:
version "1.8.1"
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680"
integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==
side-channel@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2"
integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==
dependencies:
call-bind "^1.0.7"
es-errors "^1.3.0"
get-intrinsic "^1.2.4"
object-inspect "^1.13.1"
"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2: "source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz" resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz"
@@ -656,11 +961,6 @@ vite-plugin-checker@^0.6.4:
vscode-languageserver-textdocument "^1.0.1" vscode-languageserver-textdocument "^1.0.1"
vscode-uri "^3.0.2" vscode-uri "^3.0.2"
vite-plugin-css-injected-by-js@^3.5.1:
version "3.5.1"
resolved "https://registry.yarnpkg.com/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.5.1.tgz#b9c568c21b131d08e31aa6d368ee39c9d6c1b6c1"
integrity sha512-9ioqwDuEBxW55gNoWFEDhfLTrVKXEEZgl5adhWmmqa88EQGKfTmexy4v1Rh0pAS6RhKQs2bUYQArprB32JpUZQ==
vite@^4.4.5: vite@^4.4.5:
version "4.5.0" version "4.5.0"
resolved "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz" resolved "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz"
@@ -716,7 +1016,9 @@ vscode-uri@^3.0.2:
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.8.tgz#1770938d3e72588659a172d0fd4642780083ff9f" resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.8.tgz#1770938d3e72588659a172d0fd4642780083ff9f"
integrity sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw== integrity sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==
yarn@^1.22.22: which@^2.0.1:
version "1.22.22" version "2.0.2"
resolved "https://registry.npmjs.org/yarn/-/yarn-1.22.22.tgz" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
integrity sha512-prL3kGtyG7o9Z9Sv8IPfBNrWTDmXB4Qbes8A9rEzt6wkJV8mUvoirjU0Mp3GGAU06Y0XQyA3/2/RQFVuK7MTfg== integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
dependencies:
isexe "^2.0.0"

View File

@@ -2,7 +2,7 @@
"id": "", "id": "",
"actionNodes": [ "actionNodes": [
{ {
"id": "c5cd772a-04be-418e-a811-3787f98a2285", "id": "822b5b2c-cfb7-447a-ae77-01bf3a530fae",
"name": "app.record.create.show", "name": "app.record.create.show",
"title": "レコード追加画面", "title": "レコード追加画面",
"subTitle": "レコード追加画面を表示した後", "subTitle": "レコード追加画面を表示した後",
@@ -12,12 +12,12 @@
"actionProps": [], "actionProps": [],
"ActionValue": {}, "ActionValue": {},
"nextNodeIds": { "nextNodeIds": {
"": "1eb097b1-9d08-462e-97b0-6e3e1232edef" "": "3a762b11-8e15-4353-8148-306bfed6cd5e"
} }
}, },
{ {
"id": "1eb097b1-9d08-462e-97b0-6e3e1232edef", "id": "3a762b11-8e15-4353-8148-306bfed6cd5e",
"name": "属性UIテスト用", "name": "ルックアップ更新",
"inputPoint": "", "inputPoint": "",
"outputPoints": [], "outputPoints": [],
"actionProps": [ "actionProps": [
@@ -28,85 +28,73 @@
"displayName": "表示名", "displayName": "表示名",
"placeholder": "表示を入力してください", "placeholder": "表示を入力してください",
"hint": "", "hint": "",
"modelValue": "属性UIテスト用" "modelValue": "元データ更新時にルックアップ先が同期する"
} }
}, },
{ {
"component": "AppFieldSelect", "component": "AppFieldSelect",
"props": { "props": {
"displayName": "フィールド選択(複数)", "displayName": "更新先選択",
"modelValue": { "modelValue": {
"app": { "app": {
"id": "64", "id": "247",
"name": "日報テスト", "name": "商品購買記録",
"description": "日々の業務内容、報告事項、所感などを記載していくアプリです。\n記録を行うだけでなく、あとからの振り返りやメンバー間のコミュニケーションにも活用できます。",
"createdate": "2023/07/15 10:15:03"
},
"fields": [
{
"name": "ステータス",
"type": "STATUS",
"code": "ステータス",
"label": "ステータス",
"enabled": false
}
]
},
"name": "selectFields",
"placeholder": "アプリ選択後、フィールドを選んでください",
"selectType": "multiple"
}
},
{
"component": "AppFieldSelect",
"props": {
"displayName": "フィールド選択(単一)",
"modelValue": {
"app": {
"id": "58",
"name": "日報",
"description": "", "description": "",
"createdate": "2023/07/13 19:05:26" "createdate": "2024/06/24 02:49:12"
}, },
"fields": [ "fields": [
{ {
"name": "所感、学び", "name": "商品ID",
"type": "MULTI_LINE_TEXT", "type": "SINGLE_LINE_TEXT",
"code": "文字列__複数行__0", "code": "商品ID",
"label": "所感、学び", "label": "商品ID",
"noLabel": false, "noLabel": false,
"required": false, "required": true,
"defaultValue": "" "lookup": {
"relatedApp": {
"app": "246",
"code": ""
},
"relatedKeyField": "商品ID",
"fieldMappings": [
{
"field": "商品名",
"relatedField": "商品名"
},
{
"field": "単価",
"relatedField": "価格"
}
],
"lookupPickerFields": [
"商品名",
"価格"
],
"filterCond": "",
"sort": "レコード番号 desc"
}
} }
] ]
}, },
"name": "selectField", "name": "lookupField",
"placeholder": "アプリ選択後、フィールドを選んでください", "placeholder": "",
"selectType": "single" "fieldTypes": [
"lookup"
],
"hint": "更新先のルックアップフィールドを選択する"
} }
}, },
{ {
"component": "ColorPicker", "component": "ConditionInput",
"props": { "props": {
"displayName": "色選択", "displayName": "更新条件",
"modelValue": "#f50000", "modelValue": "{\"index\":0,\"type\":\"root\",\"children\":[{\"index\":1,\"type\":\"condition\",\"parent\":\"root\",\"object\":{},\"operator\":\"=\",\"value\":\"\"}],\"parent\":null,\"logicalOperator\":\"AND\"}",
"name": "color", "name": "condition",
"placeholder": "カラーを選択してください" "placeholder": "条件式を設定してください"
}
},
{
"component": "NumInput",
"props": {
"displayName": "数値入力フィールド",
"modelValue": 100,
"name": "num",
"max": 100,
"min": 0,
"placeholder": "数値を入力してください"
} }
} }
], ],
"prevNodeId": "c5cd772a-04be-418e-a811-3787f98a2285", "prevNodeId": "822b5b2c-cfb7-447a-ae77-01bf3a530fae",
"nextNodeIds": {} "nextNodeIds": {}
} }
] ]

View File

@@ -1,22 +1,24 @@
[ [
{ {
"component": "FieldInput", "component": "AppFieldSelect",
"props": { "props": {
"displayName": "フィールド", "displayName": "更新先選択",
"modelValue": {}, "modelValue": {},
"name": "field", "name": "lookupField",
"placeholder": "対象項目を選択してください" "placeholder": "",
"fieldTypes": [
"lookup"
],
"hint": "更新先のルックアップフィールドを選択する"
} }
}, },
{ {
"component": "SelectBox", "component": "ConditionInput",
"props": { "props": {
"displayName": "チェックする全角文字", "displayName": "更新条件",
"modelValue": null, "modelValue": "",
"name": "options", "name": "condition",
"placeholder": "チェックしたい全角文字を選択する", "placeholder": "条件式を設定してください"
"selectType":"multiple",
"options":["全角記号および句読点","ひらがな","カタカナ","全角英数字","常用漢字","拡張漢字"]
} }
} }
] ]