Compare commits
205 Commits
maxz-real-
...
fix/condit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6fff3ec006 | ||
|
|
64e72a66d5 | ||
|
|
af5f27c8c5 | ||
|
|
5823c989c2 | ||
|
|
ee362a6a93 | ||
|
|
6ba1e0d958 | ||
|
|
fde66aa480 | ||
|
|
79a8598468 | ||
|
|
f70c27d814 | ||
|
|
432e52d322 | ||
|
|
f3893c2500 | ||
|
|
e726843189 | ||
|
|
183abeba41 | ||
|
|
70d2513cd7 | ||
|
|
0fda3d143c | ||
|
|
a85a3683f2 | ||
|
|
14287b6948 | ||
|
|
0443257f86 | ||
|
|
18b97c249a | ||
|
|
4ac4c9e9f4 | ||
|
|
24a70aed2e | ||
|
|
79e38ba6dd | ||
|
|
303a3ffc23 | ||
|
|
af86edd3e2 | ||
|
|
c87cff4181 | ||
|
|
05db5a0522 | ||
|
|
bac7020c15 | ||
|
|
c1d33e3ff0 | ||
| 832d46d360 | |||
|
|
c8f9cbda9a | ||
|
|
c1c265c73e | ||
| e4800d2937 | |||
| 550e59b4db | |||
|
|
26a685b872 | ||
|
|
8514adf15e | ||
|
|
5f2059fd6a | ||
| 504a76b4ac | |||
|
|
80694ee49c | ||
|
|
493b9ca0e9 | ||
|
|
55bbf50656 | ||
| 4b27504b99 | |||
|
|
1d248bde43 | ||
|
|
5cad10575f | ||
|
|
3b56c78bf1 | ||
|
|
6ab668f86a | ||
|
|
7b1daaab33 | ||
|
|
ef47912c37 | ||
|
|
140c48bcb7 | ||
| ba0b96146e | |||
| 53aa5dff88 | |||
| e52b02ec7f | |||
| 47dbaaf87d | |||
| 478c751ea7 | |||
| 4ee72a8a75 | |||
|
|
e2db112080 | ||
|
|
3c0d572a0e | ||
|
|
c225ddd39d | ||
| 0e9b0ea693 | |||
| 36f225a5b6 | |||
| 9496128e02 | |||
| 612962cc83 | |||
| 52514b7197 | |||
|
|
234e55bc01 | ||
|
|
f4a1bc3e58 | ||
|
|
192174b2ca | ||
|
|
544370688e | ||
|
|
6a6e772e32 | ||
|
|
f4500a09bc | ||
|
|
e7c3d3c8ad | ||
|
|
91bd72f7e0 | ||
|
|
2e69dc4dcf | ||
|
|
535049a188 | ||
|
|
5bde55e5fc | ||
|
|
c1cad3d7a9 | ||
|
|
c378bfe20c | ||
|
|
0e0d028c24 | ||
|
|
3b6eed32ec | ||
|
|
f62a7c3389 | ||
|
|
a161d8e2c8 | ||
|
|
b97888fca9 | ||
|
|
371ec3a133 | ||
|
|
711b9afaea | ||
|
|
00227ca713 | ||
|
|
842edd6f1f | ||
|
|
cd0c3197fa | ||
|
|
7f35a91765 | ||
| c44b42f498 | |||
| cff6ee5478 | |||
|
|
40b21604f9 | ||
|
|
98fcd2eb47 | ||
|
|
c3b560dbc9 | ||
| 53aadfcaaa | |||
|
|
dda9b7adad | ||
|
|
7fb3d08ccb | ||
|
|
cf4209333d | ||
|
|
61ac281134 | ||
|
|
22e9094d4c | ||
|
|
a13721f63e | ||
|
|
05b9a0ce1b | ||
|
|
b25c17ab53 | ||
|
|
64d2cadd82 | ||
|
|
371e2ee073 | ||
|
|
a7078b54c5 | ||
|
|
5663c313ea | ||
|
|
7da9b81319 | ||
| c426bbf793 | |||
| 329debaab8 | |||
|
|
994a0174f5 | ||
| 2846297112 | |||
| 5cf60ddfdc | |||
| 0de33f04bc | |||
| 472353632c | |||
|
|
1a48fb5b20 | ||
| 99d3a01991 | |||
|
|
da24972482 | ||
| ecb90e7120 | |||
|
|
784cb7a473 | ||
| 5349c46225 | |||
| 3be4402239 | |||
| 4c482ea289 | |||
| 44a73478a7 | |||
| bceac2f172 | |||
| 98842db343 | |||
| 03904a4e35 | |||
| 09b3c8df47 | |||
| 26761f6d39 | |||
| 72608a8ffd | |||
| d1ec123c8b | |||
| 4102ff5522 | |||
| 08e857884b | |||
| c0db2d230b | |||
| 2b9b772b39 | |||
| c46e8a7047 | |||
| 6e6350d6ce | |||
| 1e7d553bd6 | |||
| 35ae2539cb | |||
|
|
a614d754f4 | ||
| 46a6ba534e | |||
| 8fecde4c42 | |||
|
|
3e73799532 | ||
| 3159366560 | |||
| 5176cff2bd | |||
| 978aa723ae | |||
| 926c338f73 | |||
| 6de60c82ba | |||
| 6ed17a50e5 | |||
| 5cd6d02f6e | |||
| 276e5e9122 | |||
| 6e75a2a524 | |||
| ea6e603036 | |||
| edad30e264 | |||
| 58616100f4 | |||
| 359558bad3 | |||
| 6a6554ed1f | |||
| e20625abdb | |||
| f83dd693d5 | |||
| a464297511 | |||
| 991c8e8083 | |||
| 9ea183ff2d | |||
| 34d368b730 | |||
| 17760a6926 | |||
| 8b9cfa34c7 | |||
| 5fb8fe53bb | |||
| 5cb9375db3 | |||
| 55181f2c57 | |||
| 4577df371a | |||
| 0f154832a5 | |||
| 5951fcc108 | |||
| 7966217ac2 | |||
| 64851bd51d | |||
| 10e584d2ac | |||
| b97a728624 | |||
| 5a875e6853 | |||
| 57a4823f61 | |||
| 761eb4c13e | |||
| 354fc6868d | |||
| 2538e4526f | |||
| 26890f5b35 | |||
| 086b5e2621 | |||
| 617b060869 | |||
| a782e92bd6 | |||
| f60f97380f | |||
| cfc416fd14 | |||
| df593d2ffe | |||
| 9cd4c8a5ab | |||
|
|
ead6658455 | ||
| f6d677b51f | |||
| 25f05ab018 | |||
| 178cf33949 | |||
| b54c0f8022 | |||
| c5cc3c1a24 | |||
| 0b414fbfbe | |||
| 981d7a5062 | |||
| 33fc0b74ef | |||
| 286acc4584 | |||
| cdfb1d4310 | |||
| 6844652b5d | |||
| 76457b6667 | |||
| e1f2afa942 | |||
| 8d5dff60f1 | |||
| 6aa057e590 | |||
| 2721cd60d1 | |||
| 1f8d079d4d | |||
| 3ae685a0e2 | |||
| c1e50736e8 |
4
backend/.gitignore
vendored
4
backend/.gitignore
vendored
@@ -56,6 +56,7 @@ coverage.xml
|
|||||||
|
|
||||||
# Django stuff:
|
# Django stuff:
|
||||||
*.log
|
*.log
|
||||||
|
*.log.*
|
||||||
local_settings.py
|
local_settings.py
|
||||||
db.sqlite3
|
db.sqlite3
|
||||||
db.sqlite3-journal
|
db.sqlite3-journal
|
||||||
@@ -125,4 +126,5 @@ cython_debug/
|
|||||||
# VS Code settings
|
# VS Code settings
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
*.lock
|
*.lock
|
||||||
|
Temp/
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
FROM python:3.8
|
FROM python:3.11.4
|
||||||
|
|
||||||
RUN mkdir /app
|
RUN mkdir /app
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|||||||
100
backend/Temp/alc_runtime.js
Normal file
100
backend/Temp/alc_runtime.js
Normal file
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -29,18 +29,19 @@ async def login(
|
|||||||
else:
|
else:
|
||||||
permissions = "user"
|
permissions = "user"
|
||||||
access_token = security.create_access_token(
|
access_token = security.create_access_token(
|
||||||
data={"sub": user.email, "permissions": permissions},
|
data={"sub": user.id, "permissions": permissions},
|
||||||
expires_delta=access_token_expires,
|
expires_delta=access_token_expires,
|
||||||
)
|
)
|
||||||
|
|
||||||
return {"access_token": access_token, "token_type": "bearer"}
|
return {"access_token": access_token, "token_type": "bearer","user_name":user.first_name + " " + user.last_name}
|
||||||
|
|
||||||
|
|
||||||
@r.post("/signup")
|
@r.post("/signup")
|
||||||
async def signup(
|
async def signup(
|
||||||
|
firstname:str, lastname:str,
|
||||||
db=Depends(get_db), form_data: OAuth2PasswordRequestForm = Depends()
|
db=Depends(get_db), form_data: OAuth2PasswordRequestForm = Depends()
|
||||||
):
|
):
|
||||||
user = sign_up_new_user(db, form_data.username, form_data.password)
|
user = sign_up_new_user(db, form_data.username, form_data.password,firstname,lastname)
|
||||||
if not user:
|
if not user:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_409_CONFLICT,
|
status_code=status.HTTP_409_CONFLICT,
|
||||||
@@ -56,8 +57,8 @@ async def signup(
|
|||||||
else:
|
else:
|
||||||
permissions = "user"
|
permissions = "user"
|
||||||
access_token = security.create_access_token(
|
access_token = security.create_access_token(
|
||||||
data={"sub": user.email, "permissions": permissions},
|
data={"sub": user.id, "permissions": permissions},
|
||||||
expires_delta=access_token_expires,
|
expires_delta=access_token_expires,
|
||||||
)
|
)
|
||||||
|
|
||||||
return {"access_token": access_token, "token_type": "bearer"}
|
return {"access_token": access_token, "token_type": "bearer","user_name":user.first_name + " " + user.last_name}
|
||||||
|
|||||||
@@ -5,33 +5,150 @@ import pandas as pd
|
|||||||
import json
|
import json
|
||||||
import httpx
|
import httpx
|
||||||
import deepdiff
|
import deepdiff
|
||||||
import app.core.config as c
|
import app.core.config as config
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
from app.db.session import SessionLocal
|
||||||
|
from app.db.crud import get_flows_by_app,get_activedomain,get_kintoneformat
|
||||||
|
from app.core.auth import get_current_active_user,get_current_user
|
||||||
|
from app.core.apiexception import APIException
|
||||||
|
|
||||||
kinton_router = r = APIRouter()
|
kinton_router = r = APIRouter()
|
||||||
|
|
||||||
def getfieldsfromexcel(df):
|
def getkintoneenv(user = Depends(get_current_user)):
|
||||||
|
db = SessionLocal()
|
||||||
|
domain = get_activedomain(db, user.id)
|
||||||
|
db.close()
|
||||||
|
kintoneevn = config.KINTONE_ENV(domain)
|
||||||
|
return kintoneevn
|
||||||
|
|
||||||
|
|
||||||
|
def getkintoneformat():
|
||||||
|
db = SessionLocal()
|
||||||
|
formats = get_kintoneformat(db)
|
||||||
|
db.close()
|
||||||
|
return formats
|
||||||
|
|
||||||
|
|
||||||
|
def createkintonefields(property,value,trueformat):
|
||||||
|
p = []
|
||||||
|
if(property=="options"):
|
||||||
|
o=[]
|
||||||
|
for v in value.split(','):
|
||||||
|
o.append(f"\"{v.split('|')[0]}\":{{\"label\":\"{v.split('|')[0]}\",\"index\":\"{v.split('|')[1]}\"}}")
|
||||||
|
p.append(f"\"options\":{{{','.join(o)}}}")
|
||||||
|
elif(property =="expression"):
|
||||||
|
p.append(f"\"hideExpression\":true")
|
||||||
|
p.append(f"\"expression\":\"{value.split(':')[1]}\"")
|
||||||
|
elif(property =="required" or property =="unique" or property =="defaultNowValue" or property =="hideExpression" or property =="digit"):
|
||||||
|
if str(value) == trueformat:
|
||||||
|
p.append(f"\"{property}\":true")
|
||||||
|
else:
|
||||||
|
p.append(f"\"{property}\":false")
|
||||||
|
elif(property =="protocol"):
|
||||||
|
if(value == "メールアドレス"):
|
||||||
|
p.append("\"protocol\":\"MAIL\"")
|
||||||
|
elif(value == "Webサイト"):
|
||||||
|
p.append("\"protocol\":\"WEB\"")
|
||||||
|
elif(value == "電話番号"):
|
||||||
|
p.append("\"protocol\":\"CALL\"")
|
||||||
|
else:
|
||||||
|
p.append(f"\"{property}\":\"{value}\"")
|
||||||
|
return p
|
||||||
|
|
||||||
|
def getfieldsfromexcel(df,mapping):
|
||||||
|
startrow = mapping.startrow
|
||||||
|
startcolumn = mapping.startcolumn
|
||||||
|
typecolumn = mapping.typecolumn
|
||||||
|
codecolumn = mapping.codecolumn
|
||||||
|
property = mapping.field.split(",")
|
||||||
|
trueformat = mapping.trueformat
|
||||||
appname = df.iloc[0,2]
|
appname = df.iloc[0,2]
|
||||||
col=[]
|
col=[]
|
||||||
for row in range(5,len(df)):
|
for row in range(startrow,len(df)):
|
||||||
if pd.isna(df.iloc[row,1]):
|
if pd.isna(df.iloc[row,startcolumn]):
|
||||||
break
|
break
|
||||||
if not df.iloc[row,3] in c.KINTONE_FIELD_TYPE:
|
if not df.iloc[row,typecolumn] in config.KINTONE_FIELD_TYPE:
|
||||||
continue
|
continue
|
||||||
p=[]
|
p=[]
|
||||||
for column in range(1,7):
|
for column in range(startcolumn,startcolumn + len(property)):
|
||||||
if(not pd.isna(df.iloc[row,column])):
|
if(not pd.isna(df.iloc[row,column])):
|
||||||
if(property[column-1]=="options"):
|
propertyname =property[column-1]
|
||||||
o=[]
|
if(propertyname.find("[") == 0):
|
||||||
for v in df.iloc[row,column].split(','):
|
continue
|
||||||
o.append(f"\"{v.split('|')[0]}\":{{\"label\":\"{v.split('|')[0]}\",\"index\":\"{v.split('|')[1]}\"}}")
|
elif (propertyname =="remark"):
|
||||||
p.append(f"\"{property[column-1]}\":{{{','.join(o)}}}")
|
if (df.iloc[row,column].find("|") !=-1):
|
||||||
elif(property[column-1]=="required"):
|
propertyname = "options"
|
||||||
p.append(f"\"{property[column-1]}\":{df.iloc[row,column]}")
|
p = p + createkintonefields(propertyname, df.iloc[row,column],trueformat)
|
||||||
|
if (df.iloc[row,column] == "メールアドレス" or df.iloc[row,column] == "Webサイト" or df.iloc[row,column] == "電話番号"):
|
||||||
|
propertyname = "protocol"
|
||||||
|
p = p + createkintonefields(propertyname, df.iloc[row,column],trueformat)
|
||||||
|
if (df.iloc[row,column].find("桁区切り") !=-1):
|
||||||
|
propertyname = "digit"
|
||||||
|
p = p + createkintonefields(propertyname, df.iloc[row,column],trueformat)
|
||||||
|
if (df.iloc[row,column].find("前単位") !=-1):
|
||||||
|
propertyname = "unitPosition"
|
||||||
|
p = p + createkintonefields(propertyname, "BEFORE",trueformat)
|
||||||
|
if (df.iloc[row,column].find("後単位") !=-1):
|
||||||
|
propertyname = "unitPosition"
|
||||||
|
p = p + createkintonefields(propertyname, "AFTER",trueformat)
|
||||||
|
if (df.iloc[row,column].find("単位「") !=-1):
|
||||||
|
propertyname = "unit"
|
||||||
|
ids = df.iloc[row,column].index("単位「")
|
||||||
|
ide = df.iloc[row,column].index("」")
|
||||||
|
unit = df.iloc[row,column][ids+3:ide]
|
||||||
|
p = p + createkintonefields(propertyname, unit,trueformat)
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
elif(propertyname =="mixValue"):
|
||||||
|
if(df.iloc[row,column].find("レコード登録時の日") != -1):
|
||||||
|
propertyname = "defaultNowValue"
|
||||||
|
df.iloc[row,column] = trueformat
|
||||||
|
p = p + createkintonefields(propertyname, df.iloc[row,column],trueformat)
|
||||||
|
elif(df.iloc[row,column].find("計:") != -1):
|
||||||
|
propertyname = "expression"
|
||||||
|
p = p + createkintonefields(propertyname, df.iloc[row,column],trueformat)
|
||||||
|
elif(df.iloc[row,column] !=""):
|
||||||
|
propertyname = "defaultValue"
|
||||||
|
p = p + createkintonefields(propertyname, df.iloc[row,column],trueformat)
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
elif(propertyname=="max" or propertyname == "min"):
|
||||||
|
if(df.iloc[row,typecolumn] == "NUMBER"):
|
||||||
|
propertyname = property[column-1] + "Value"
|
||||||
|
p = p + createkintonefields(propertyname, df.iloc[row,column],trueformat)
|
||||||
|
else:
|
||||||
|
propertyname = property[column-1] + "Length"
|
||||||
|
p = p + createkintonefields(propertyname, df.iloc[row,column],trueformat)
|
||||||
else:
|
else:
|
||||||
p.append(f"\"{property[column-1]}\":\"{df.iloc[row,column]}\"")
|
p = p + createkintonefields(propertyname, df.iloc[row,column],trueformat)
|
||||||
col.append(f"\"{df.iloc[row,2]}\":{{{','.join(p)}}}")
|
|
||||||
fields = ",".join(col).replace("False","false").replace("True","true")
|
# if(propertyname=="options"):
|
||||||
|
# o=[]
|
||||||
|
# for v in df.iloc[row,column].split(','):
|
||||||
|
# o.append(f"\"{v.split('|')[0]}\":{{\"label\":\"{v.split('|')[0]}\",\"index\":\"{v.split('|')[1]}\"}}")
|
||||||
|
# p.append(f"\"options\":{{{','.join(o)}}}")
|
||||||
|
# elif(propertyname=="expression"):
|
||||||
|
# p.append(f"\"hideExpression\":true")
|
||||||
|
# p.append(f"\"expression\":{df.iloc[row,column].split(':')[1]}")
|
||||||
|
# elif(propertyname=="required" or propertyname =="unique" or propertyname=="defaultNowValue" or propertyname=="hideExpression" or propertyname=="digit"):
|
||||||
|
# if (df.iloc[row,column] == trueformat):
|
||||||
|
# p.append(f"\"{propertyname}\":true")
|
||||||
|
# else:
|
||||||
|
# p.append(f"\"{propertyname}\":false")
|
||||||
|
# elif(propertyname =="protocol"):
|
||||||
|
# if(df.iloc[row,column] == "メールアドレス"):
|
||||||
|
# p.append("\"protocol\":\"MAIL\"")
|
||||||
|
# elif(df.iloc[row,column] == "Webサイト"):
|
||||||
|
# p.append("\"protocol\":\"WEB\"")
|
||||||
|
# elif(df.iloc[row,column] == "電話番号"):
|
||||||
|
# p.append("\"protocol\":\"CALL\"")
|
||||||
|
# else:
|
||||||
|
# p.append(f"\"{propertyname}\":\"{df.iloc[row,column]}\"")
|
||||||
|
|
||||||
|
|
||||||
|
col.append(f"\"{df.iloc[row,codecolumn]}\":{{{','.join(p)}}}")
|
||||||
|
fields = ",".join(col).replace("\\", "\\\\")
|
||||||
return json.loads(f"{{{fields}}}")
|
return json.loads(f"{{{fields}}}")
|
||||||
|
|
||||||
def getsettingfromexcel(df):
|
def getsettingfromexcel(df):
|
||||||
@@ -39,10 +156,10 @@ def getsettingfromexcel(df):
|
|||||||
des = df.iloc[2,2]
|
des = df.iloc[2,2]
|
||||||
return {"name":appname,"description":des}
|
return {"name":appname,"description":des}
|
||||||
|
|
||||||
def getsettingfromkintone(app:str):
|
def getsettingfromkintone(app:str,c:config.KINTONE_ENV):
|
||||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||||
params = {"app":app}
|
params = {"app":app}
|
||||||
url = f"{c.BASE_URL}{c.API_V1_STR}/app/settings.json"
|
url = f"{c.BASE_URL}{config.API_V1_STR}/app/settings.json"
|
||||||
r = httpx.get(url,headers=headers,params=params)
|
r = httpx.get(url,headers=headers,params=params)
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
@@ -54,24 +171,24 @@ def analysesettings(excel,kintone):
|
|||||||
updatesettings[key] = excel[key]
|
updatesettings[key] = excel[key]
|
||||||
return updatesettings
|
return updatesettings
|
||||||
|
|
||||||
def createkintoneapp(name:str):
|
def createkintoneapp(name:str,c:config.KINTONE_ENV):
|
||||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
||||||
data = {"name":name}
|
data = {"name":name}
|
||||||
url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app.json"
|
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app.json"
|
||||||
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()
|
||||||
|
|
||||||
def updateappsettingstokintone(app:str,updates:dict):
|
def updateappsettingstokintone(app:str,updates:dict,c:config.KINTONE_ENV):
|
||||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
||||||
url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/settings.json"
|
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app/settings.json"
|
||||||
data = {"app":app}
|
data = {"app":app}
|
||||||
data.update(updates)
|
data.update(updates)
|
||||||
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 addfieldstokintone(app:str,fields:dict,revision:str = None):
|
def addfieldstokintone(app:str,fields:dict,c:config.KINTONE_ENV,revision:str = None):
|
||||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
||||||
url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/form/fields.json"
|
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app/form/fields.json"
|
||||||
if revision != None:
|
if revision != None:
|
||||||
data = {"app":app,"revision":revision,"properties":fields}
|
data = {"app":app,"revision":revision,"properties":fields}
|
||||||
else:
|
else:
|
||||||
@@ -79,35 +196,75 @@ def addfieldstokintone(app:str,fields:dict,revision:str = None):
|
|||||||
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()
|
||||||
|
|
||||||
def updatefieldstokintone(app:str,revision:str,fields:dict):
|
def updatefieldstokintone(app:str,revision:str,fields:dict,c:config.KINTONE_ENV):
|
||||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
||||||
url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/form/fields.json"
|
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app/form/fields.json"
|
||||||
data = {"app":app,"properties":fields}
|
data = {"app":app,"properties":fields}
|
||||||
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 deletefieldsfromkintone(app:str,revision:str,fields:dict):
|
def deletefieldsfromkintone(app:str,revision:str,fields:dict,c:config.KINTONE_ENV):
|
||||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
||||||
url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/form/fields.json"
|
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app/form/fields.json"
|
||||||
params = {"app":app,"revision":revision,"fields":fields}
|
params = {"app":app,"revision":revision,"fields":fields}
|
||||||
#r = httpx.delete(url,headers=headers,content=json.dumps(params))
|
#r = httpx.delete(url,headers=headers,content=json.dumps(params))
|
||||||
r = httpx.request(method="DELETE",url=url,headers=headers,content=json.dumps(params))
|
r = httpx.request(method="DELETE",url=url,headers=headers,content=json.dumps(params))
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
def deoployappfromkintone(app:str,revision:str):
|
def deoployappfromkintone(app:str,revision:str,c:config.KINTONE_ENV):
|
||||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
||||||
url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/deploy.json"
|
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app/deploy.json"
|
||||||
data = {"apps":[{"app":app,"revision":revision}],"revert": False}
|
data = {"apps":[{"app":app,"revision":revision}],"revert": False}
|
||||||
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
|
||||||
|
|
||||||
def getfieldsfromkintone(app):
|
# 既定項目に含めるアプリのフィールドのみ取得する
|
||||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
# スペース、枠線、ラベルを含まない
|
||||||
|
def getfieldsfromkintone(app:str,c:config.KINTONE_ENV):
|
||||||
|
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||||
params = {"app":app}
|
params = {"app":app}
|
||||||
url = f"{c.BASE_URL}{c.API_V1_STR}/app/form/fields.json"
|
url = f"{c.BASE_URL}{config.API_V1_STR}/app/form/fields.json"
|
||||||
r = httpx.get(url,headers=headers,params=params)
|
r = httpx.get(url,headers=headers,params=params)
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
|
# フォームに配置するフィールドのみ取得する
|
||||||
|
# スペース、枠線、ラベルも含める
|
||||||
|
def getformfromkintone(app:str,c:config.KINTONE_ENV):
|
||||||
|
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||||
|
params = {"app":app}
|
||||||
|
url = f"{c.BASE_URL}{config.API_V1_STR}/form.json"
|
||||||
|
r = httpx.get(url,headers=headers,params=params)
|
||||||
|
return r.json()
|
||||||
|
|
||||||
|
|
||||||
|
def merge_kintone_fields(fields_response: dict, form_response: dict) -> dict:
|
||||||
|
fields_properties = fields_response.get('properties', {})
|
||||||
|
form_properties = form_response.get('properties', [])
|
||||||
|
|
||||||
|
merged_properties = {k: v for k, v in fields_properties.items()}
|
||||||
|
|
||||||
|
for index, form_field in enumerate(form_properties):
|
||||||
|
code = form_field.get('code')
|
||||||
|
if code:
|
||||||
|
if code and code not in merged_properties:
|
||||||
|
merged_properties[code] = form_field
|
||||||
|
else:
|
||||||
|
element_id = form_field.get('elementId')
|
||||||
|
if element_id:
|
||||||
|
key = element_id
|
||||||
|
form_field['code']=element_id
|
||||||
|
form_field['label']=form_field.get('type')
|
||||||
|
# else:
|
||||||
|
# key = f"{form_field.get('type')}_{index}"
|
||||||
|
merged_properties[key] = form_field
|
||||||
|
|
||||||
|
merged_response = {
|
||||||
|
'revision': fields_response.get('revision', ''),
|
||||||
|
'properties': merged_properties
|
||||||
|
}
|
||||||
|
|
||||||
|
return merged_response
|
||||||
|
|
||||||
def analysefields(excel,kintone):
|
def analysefields(excel,kintone):
|
||||||
updatefields={}
|
updatefields={}
|
||||||
addfields={}
|
addfields={}
|
||||||
@@ -116,22 +273,22 @@ def analysefields(excel,kintone):
|
|||||||
adds = excel.keys() - kintone.keys()
|
adds = excel.keys() - kintone.keys()
|
||||||
dels = kintone.keys() - excel.keys()
|
dels = kintone.keys() - excel.keys()
|
||||||
for key in updates:
|
for key in updates:
|
||||||
for p in property:
|
for p in config.KINTONE_FIELD_PROPERTY:
|
||||||
if excel[key].get(p) != None and kintone[key][p] != excel[key][p]:
|
if excel[key].get(p) != None and kintone[key].get(p) != None and kintone[key][p] != excel[key][p]:
|
||||||
updatefields[key] = excel[key]
|
updatefields[key] = excel[key]
|
||||||
break
|
break
|
||||||
for key in adds:
|
for key in adds:
|
||||||
addfields[key] = excel[key]
|
addfields[key] = excel[key]
|
||||||
for key in dels:
|
for key in dels:
|
||||||
if kintone[key]["type"] in c.KINTONE_FIELD_TYPE:
|
if kintone[key]["type"] in config.KINTONE_FIELD_TYPE:
|
||||||
delfields.append(key)
|
delfields.append(key)
|
||||||
|
|
||||||
return {"update":updatefields,"add":addfields,"del":delfields}
|
return {"update":updatefields,"add":addfields,"del":delfields}
|
||||||
|
|
||||||
def getprocessfromkintone(app:str):
|
def getprocessfromkintone(app:str,c:config.KINTONE_ENV):
|
||||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||||
params = {"app":app}
|
params = {"app":app}
|
||||||
url = f"{c.BASE_URL}{c.API_V1_STR}/app/status.json"
|
url = f"{c.BASE_URL}{config.API_V1_STR}/app/status.json"
|
||||||
r = httpx.get(url,headers=headers,params=params)
|
r = httpx.get(url,headers=headers,params=params)
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
@@ -195,27 +352,81 @@ def analysprocess(excel,kintone):
|
|||||||
# return True
|
# return True
|
||||||
return diff
|
return diff
|
||||||
|
|
||||||
def updateprocesstokintone(app:str,process:dict):
|
def updateprocesstokintone(app:str,process:dict,c:config.KINTONE_ENV):
|
||||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
||||||
url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/status.json"
|
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app/status.json"
|
||||||
data = {"app":app,"enable":True}
|
data = {"app":app,"enable":True}
|
||||||
data.update(process)
|
data.update(process)
|
||||||
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 getkintoneusers():
|
def getkintoneusers(c:config.KINTONE_ENV):
|
||||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||||
url = f"{c.BASE_URL}/v1/users.json"
|
url = f"{c.BASE_URL}/v1/users.json"
|
||||||
r = httpx.get(url,headers=headers)
|
r = httpx.get(url,headers=headers)
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
def getkintoneorgs():
|
def getkintoneorgs(c:config.KINTONE_ENV):
|
||||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||||
params = {"code":c.KINTONE_USER}
|
params = {"code":c.KINTONE_USER}
|
||||||
url = f"{c.BASE_URL}/v1/user/organizations.json"
|
url = f"{c.BASE_URL}/v1/user/organizations.json"
|
||||||
r = httpx.get(url,headers=headers,params=params)
|
r = httpx.get(url,headers=headers,params=params)
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
|
def uploadkintonefiles(file,c:config.KINTONE_ENV):
|
||||||
|
if (file.endswith('alc_runtime.js') and config.DEPLOY_MODE == "DEV"):
|
||||||
|
return {'fileKey':file}
|
||||||
|
upload_files = {'file': open(file,'rb')}
|
||||||
|
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||||
|
data ={'name':'file','filename':os.path.basename(file)}
|
||||||
|
url = f"{c.BASE_URL}/k/v1/file.json"
|
||||||
|
r = httpx.post(url,headers=headers,data=data,files=upload_files)
|
||||||
|
return r.json()
|
||||||
|
|
||||||
|
def updateappjscss(app,uploads,c:config.KINTONE_ENV):
|
||||||
|
dsjs = []
|
||||||
|
dscss = []
|
||||||
|
for upload in uploads:
|
||||||
|
for key in upload:
|
||||||
|
if key.endswith('.js'):
|
||||||
|
if (key.endswith('alc_runtime.js') and config.DEPLOY_MODE == "DEV"):
|
||||||
|
dsjs.append({'type':'URL','url':config.DEPLOY_JS_URL})
|
||||||
|
else:
|
||||||
|
dsjs.append({'type':'FILE','file':{'fileKey':upload[key]}})
|
||||||
|
elif key.endswith('.css'):
|
||||||
|
dscss.append({'type':'FILE','file':{'fileKey':upload[key]}})
|
||||||
|
ds ={'js':dsjs,'css':dscss}
|
||||||
|
mb ={'js':[],'css':[]}
|
||||||
|
data = {'app':app,'scope':'ALL','desktop':ds,'mobile':mb}
|
||||||
|
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
||||||
|
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app/customize.json"
|
||||||
|
print(data)
|
||||||
|
r = httpx.put(url,headers=headers,data=json.dumps(data))
|
||||||
|
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):
|
||||||
|
db = SessionLocal()
|
||||||
|
flows = get_flows_by_app(db,domainid,app)
|
||||||
|
db.close()
|
||||||
|
content={}
|
||||||
|
for flow in flows:
|
||||||
|
content[flow.eventid] = {'flowid':flow.flowid,'name':flow.name,'content':flow.content}
|
||||||
|
js = 'const alcflow=' + json.dumps(content)
|
||||||
|
# scriptdir = Path(__file__).resolve().parent
|
||||||
|
# rootdir = scriptdir.parent.parent.parent.parent
|
||||||
|
# fpath = os.path.join(rootdir,"Temp",f"alc_setting_{app}.js")
|
||||||
|
fpath = getTempPath(f"alc_setting_{app}.js")
|
||||||
|
print(fpath)
|
||||||
|
with open(fpath,'w') as file:
|
||||||
|
file.write(js)
|
||||||
|
return fpath
|
||||||
|
|
||||||
@r.post("/test",)
|
@r.post("/test",)
|
||||||
async def test(file:UploadFile= File(...),app:str=None):
|
async def test(file:UploadFile= File(...),app:str=None):
|
||||||
if file.filename.endswith('.xlsx'):
|
if file.filename.endswith('.xlsx'):
|
||||||
@@ -233,15 +444,26 @@ async def test(file:UploadFile= File(...),app:str=None):
|
|||||||
# kintone = getfieldsfromkintone(app)
|
# kintone = getfieldsfromkintone(app)
|
||||||
# fields = analysefields(excel,kintone["properties"])
|
# fields = analysefields(excel,kintone["properties"])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=400, detail=f"Error occurred while parsing file {file.filename}: {str(e)}")
|
raise HTTPException(status_code=400, detail=f"Error occurred while parsing file {file.filename}")
|
||||||
else:
|
else:
|
||||||
raise HTTPException(status_code=400, detail=f"File {file.filename} is not an Excel file")
|
raise HTTPException(status_code=400, detail=f"File {file.filename} is not an Excel file")
|
||||||
|
|
||||||
return test
|
return test
|
||||||
|
|
||||||
|
|
||||||
@r.post("/upload",)
|
@r.post("/download",)
|
||||||
async def upload(files:t.List[UploadFile] = File(...)):
|
async def download(request:Request,key,c:config.KINTONE_ENV=Depends(getkintoneenv)):
|
||||||
|
try:
|
||||||
|
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||||
|
params = {"fileKey":key}
|
||||||
|
url = f"{c.BASE_URL}/k/v1/file.json"
|
||||||
|
r = httpx.get(url,headers=headers,params=params)
|
||||||
|
return r.json()
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('kintone:upload',request.url._url,f"Error occurred while download file.json:",e)
|
||||||
|
|
||||||
|
@r.post("/upload")
|
||||||
|
async def upload(request:Request,files:t.List[UploadFile] = File(...)):
|
||||||
dataframes = []
|
dataframes = []
|
||||||
for file in files:
|
for file in files:
|
||||||
if file.filename.endswith('.xlsx'):
|
if file.filename.endswith('.xlsx'):
|
||||||
@@ -251,64 +473,112 @@ async def upload(files:t.List[UploadFile] = File(...)):
|
|||||||
print(df)
|
print(df)
|
||||||
dataframes.append(df)
|
dataframes.append(df)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=400, detail=f"Error occurred while parsing file {file.filename}: {str(e)}")
|
raise APIException('kintone:upload',request.url._url,f"Error occurred while uploading file {file.filename}:",e)
|
||||||
else:
|
else:
|
||||||
raise HTTPException(status_code=400, detail=f"File {file.filename} is not an Excel file")
|
raise APIException('kintone:upload',request.url._url, f"File {file.filename} is not an Excel file",e)
|
||||||
|
|
||||||
return {"files": [file.filename for file in files]}
|
return {"files": [file.filename for file in files]}
|
||||||
|
|
||||||
@r.get("/allapps",)
|
@r.post("/updatejscss")
|
||||||
async def allapps():
|
async def jscss(request:Request,app:str,files:t.List[UploadFile] = File(...),env = Depends(getkintoneenv)):
|
||||||
try:
|
try:
|
||||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
jscs=[]
|
||||||
url = f"{c.BASE_URL}{c.API_V1_STR}/apps.json"
|
for file in files:
|
||||||
r = httpx.get(url,headers=headers,timeout=httpx.Timeout(10))
|
fbytes = file.file.read()
|
||||||
|
fname = file.filename
|
||||||
|
fpath = '{}\\{}'.format('Temp',fname)
|
||||||
|
fout = open(fpath,'wb')
|
||||||
|
fout.write(fbytes)
|
||||||
|
fout.close()
|
||||||
|
upload = uploadkintonefiles(fpath,env)
|
||||||
|
if upload.get('fileKey') != None:
|
||||||
|
jscs.append({ file.filename:upload['fileKey']})
|
||||||
|
appjscs = updateappjscss(app,jscs,env)
|
||||||
|
if appjscs.get("revision") != None:
|
||||||
|
deoployappfromkintone(app,appjscs["revision"],env)
|
||||||
|
return appjscs
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('kintone:updatejscss',request.url._url, f"Error occurred while update js/css {file.filename} is not an Excel file",e)
|
||||||
|
|
||||||
|
@r.get("/app")
|
||||||
|
async def app(request:Request,app:str,c:config.KINTONE_ENV=Depends(getkintoneenv)):
|
||||||
|
try:
|
||||||
|
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||||
|
url = f"{c.BASE_URL}{config.API_V1_STR}/app.json"
|
||||||
|
params ={"id":app}
|
||||||
|
r = httpx.get(url,headers=headers,params=params)
|
||||||
return r.json()
|
return r.json()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"異常発生しました。{type(e).__name__},{e}")
|
raise APIException('kintone:app',request.url._url, f"Error occurred while get app({c.DOMAIN_NAME}->{app}):",e)
|
||||||
|
|
||||||
@r.get("/app")
|
|
||||||
async def app(app:str):
|
|
||||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
|
||||||
url = f"{c.BASE_URL}{c.API_V1_STR}/app.json"
|
|
||||||
params ={"id":app}
|
|
||||||
r = httpx.get(url,headers=headers,params=params)
|
|
||||||
return r.json()
|
|
||||||
|
|
||||||
|
@r.get("/allapps")
|
||||||
|
async def allapps(request:Request,c:config.KINTONE_ENV=Depends(getkintoneenv)):
|
||||||
|
try:
|
||||||
|
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||||
|
url = f"{c.BASE_URL}{config.API_V1_STR}/apps.json"
|
||||||
|
r = httpx.get(url,headers=headers)
|
||||||
|
return r.json()
|
||||||
|
except Exception as 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(app:str):
|
async def appfields(request:Request,app:str,env = Depends(getkintoneenv)):
|
||||||
return getfieldsfromkintone(app)
|
try:
|
||||||
|
return getfieldsfromkintone(app,env)
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('kintone:appfields',request.url._url, f"Error occurred while get app fileds({env.DOMAIN_NAME}->{app}):",e)
|
||||||
|
|
||||||
|
@r.get("/allfields")
|
||||||
|
async def allfields(request:Request,app:str,env = Depends(getkintoneenv)):
|
||||||
|
try:
|
||||||
|
field_resp = getfieldsfromkintone(app,env)
|
||||||
|
form_resp = getformfromkintone(app,env)
|
||||||
|
return merge_kintone_fields(field_resp,form_resp)
|
||||||
|
except Exception as 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(app:str):
|
async def appprocess(request:Request,app:str,env = Depends(getkintoneenv)):
|
||||||
return getprocessfromkintone(app)
|
try:
|
||||||
|
return getprocessfromkintone(app,env)
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('kintone:appprocess',request.url._url, f"Error occurred while get app process({env.DOMAIN_NAME}->{app}):",e)
|
||||||
|
|
||||||
@r.get("/alljscs")
|
@r.get("/alljscss")
|
||||||
async def alljscs(app:str):
|
async def alljscs(request:Request,app:str,c:config.KINTONE_ENV=Depends(getkintoneenv)):
|
||||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
try:
|
||||||
url = f"{c.BASE_URL}{c.API_V1_STR}/app/customize.json"
|
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||||
params = {"app":app}
|
url = f"{c.BASE_URL}{config.API_V1_STR}/app/customize.json"
|
||||||
r = httpx.get(url,headers=headers,params=params)
|
params = {"app":app}
|
||||||
return r.json()
|
r = httpx.get(url,headers=headers,params=params)
|
||||||
|
return r.json()
|
||||||
|
except Exception as 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(name:str):
|
async def createapp(request:Request,name:str,c:config.KINTONE_ENV=Depends(getkintoneenv)):
|
||||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
try:
|
||||||
data = {"name":name}
|
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
||||||
url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app.json"
|
data = {"name":name}
|
||||||
r = httpx.post(url,headers=headers,data=json.dumps(data))
|
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app.json"
|
||||||
result = r.json()
|
|
||||||
if result.get("app") != None:
|
|
||||||
url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/deploy.json"
|
|
||||||
data = {"apps":[result],"revert": False}
|
|
||||||
r = httpx.post(url,headers=headers,data=json.dumps(data))
|
r = httpx.post(url,headers=headers,data=json.dumps(data))
|
||||||
return r.json
|
result = r.json()
|
||||||
|
if result.get("app") != None:
|
||||||
|
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app/deploy.json"
|
||||||
|
data = {"apps":[result],"revert": False}
|
||||||
|
r = httpx.post(url,headers=headers,data=json.dumps(data))
|
||||||
|
return r.json
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('kintone:createapp',request.url._url, f"Error occurred while create app({c.DOMAIN_NAME}->{name}):",e)
|
||||||
|
|
||||||
property=["label","code","type","required","defaultValue","options"]
|
|
||||||
|
|
||||||
@r.post("/createappfromexcel",)
|
@r.post("/createappfromexcel",)
|
||||||
async def createappfromexcel(files:t.List[UploadFile] = File(...)):
|
async def createappfromexcel(request:Request,files:t.List[UploadFile] = File(...),format:int = 0,env = Depends(getkintoneenv)):
|
||||||
|
try:
|
||||||
|
mapping = getkintoneformat()[format]
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('kintone:createappfromexcel',request.url._url, f"Error occurred while get kintone format:",e)
|
||||||
|
|
||||||
for file in files:
|
for file in files:
|
||||||
if file.filename.endswith('.xlsx'):
|
if file.filename.endswith('.xlsx'):
|
||||||
try:
|
try:
|
||||||
@@ -318,87 +588,90 @@ async def createappfromexcel(files:t.List[UploadFile] = File(...)):
|
|||||||
appname = df.iloc[0,2]
|
appname = df.iloc[0,2]
|
||||||
desc = df.iloc[2,2]
|
desc = df.iloc[2,2]
|
||||||
result = {"app":0,"revision":0,"msg":""}
|
result = {"app":0,"revision":0,"msg":""}
|
||||||
fields = getfieldsfromexcel(df)
|
fields = getfieldsfromexcel(df,mapping)
|
||||||
users = getkintoneusers()
|
users = getkintoneusers(env)
|
||||||
orgs = getkintoneorgs()
|
orgs = getkintoneorgs(env)
|
||||||
processes = getprocessfromexcel(df,users["users"], orgs["organizationTitles"])
|
processes = getprocessfromexcel(df,users["users"], orgs["organizationTitles"])
|
||||||
app = createkintoneapp(appname)
|
app = createkintoneapp(appname,env)
|
||||||
if app.get("app") != None:
|
if app.get("app") != None:
|
||||||
result["app"] = app["app"]
|
result["app"] = app["app"]
|
||||||
app = updateappsettingstokintone(result["app"],{"description":desc})
|
app = updateappsettingstokintone(result["app"],{"description":desc},env)
|
||||||
if app.get("revision") != None:
|
if app.get("revision") != None:
|
||||||
result["revision"] = app["revision"]
|
result["revision"] = app["revision"]
|
||||||
app = addfieldstokintone(result["app"],fields)
|
app = addfieldstokintone(result["app"],fields,env)
|
||||||
if len(processes)> 0:
|
if len(processes)> 0:
|
||||||
app = updateprocesstokintone(result["app"],processes)
|
app = updateprocesstokintone(result["app"],processes,env)
|
||||||
if app.get("revision") != None:
|
if app.get("revision") != None:
|
||||||
result["revision"] = app["revision"]
|
result["revision"] = app["revision"]
|
||||||
deoployappfromkintone(result["app"],result["revision"])
|
deoployappfromkintone(result["app"],result["revision"],env)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=400, detail=f"Error occurred while parsing file {file.filename}: {str(e)}")
|
raise APIException('kintone:createappfromexcel',request.url._url, f"Error occurred while parsing file ({env.DOMAIN_NAME}->{file.filename}):",e)
|
||||||
else:
|
else:
|
||||||
raise HTTPException(status_code=400, detail=f"File {file.filename} is not an Excel file")
|
raise APIException('kintone:createappfromexcel',request.url._url, f"File {file.filename} is not an Excel file",e)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@r.post("/updateappfromexcel",)
|
@r.post("/updateappfromexcel")
|
||||||
async def updateappfromexcel(app:str,files:t.List[UploadFile] = File(...)):
|
async def updateappfromexcel(request:Request,app:str,files:t.List[UploadFile] = File(...),format:int = 0,env = Depends(getkintoneenv)):
|
||||||
|
try:
|
||||||
|
mapping = getkintoneformat()[format]
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('kintone:updateappfromexcel',request.url._url, f"Error occurred while get kintone format:",e)
|
||||||
|
|
||||||
for file in files:
|
for file in files:
|
||||||
if file.filename.endswith('.xlsx'):
|
if file.filename.endswith('.xlsx'):
|
||||||
try:
|
try:
|
||||||
content = await file.read()
|
content = await file.read()
|
||||||
df = pd.read_excel(BytesIO(content))
|
df = pd.read_excel(BytesIO(content))
|
||||||
excel = getsettingfromexcel(df)
|
excel = getsettingfromexcel(df)
|
||||||
kintone= getsettingfromkintone(app)
|
kintone= getsettingfromkintone(app,env)
|
||||||
settings = analysesettings(excel,kintone)
|
settings = analysesettings(excel,kintone)
|
||||||
excel = getfieldsfromexcel(df)
|
excel = getfieldsfromexcel(df,mapping)
|
||||||
kintone = getfieldsfromkintone(app)
|
kintone = getfieldsfromkintone(app,env)
|
||||||
users = getkintoneusers()
|
users = getkintoneusers(env)
|
||||||
orgs = getkintoneorgs()
|
orgs = getkintoneorgs(env)
|
||||||
exp = getprocessfromexcel(df,users["users"], orgs["organizationTitles"])
|
exp = getprocessfromexcel(df,users["users"], orgs["organizationTitles"])
|
||||||
#exp = getprocessfromexcel(df)
|
#exp = getprocessfromexcel(df)
|
||||||
kinp = getprocessfromkintone(app)
|
kinp = getprocessfromkintone(app,env)
|
||||||
process = analysprocess(exp,kinp)
|
process = analysprocess(exp,kinp)
|
||||||
revision = kintone["revision"]
|
revision = kintone["revision"]
|
||||||
fields = analysefields(excel,kintone["properties"])
|
fields = analysefields(excel,kintone["properties"])
|
||||||
result = {"app":app,"revision":revision,"msg":"No Update"}
|
result = {"app":app,"revision":revision,"msg":"No Update"}
|
||||||
deploy = False
|
deploy = False
|
||||||
if len(fields["update"]) > 0:
|
if len(fields["update"]) > 0:
|
||||||
result = updatefieldstokintone(app,revision,fields["update"])
|
result = updatefieldstokintone(app,revision,fields["update"],env)
|
||||||
revision = result["revision"]
|
revision = result["revision"]
|
||||||
deploy = True
|
deploy = True
|
||||||
if len(fields["add"]) > 0:
|
if len(fields["add"]) > 0:
|
||||||
result = addfieldstokintone(app,fields["add"],revision)
|
result = addfieldstokintone(app,fields["add"],env,revision)
|
||||||
revision = result["revision"]
|
revision = result["revision"]
|
||||||
deploy = True
|
deploy = True
|
||||||
if len(fields["del"]) > 0:
|
if len(fields["del"]) > 0:
|
||||||
result = deletefieldsfromkintone(app,revision,fields["del"])
|
result = deletefieldsfromkintone(app,revision,fields["del"],env)
|
||||||
revision = result["revision"]
|
revision = result["revision"]
|
||||||
deploy = True
|
deploy = True
|
||||||
if len(settings) > 0:
|
if len(settings) > 0:
|
||||||
result = updateappsettingstokintone(app,settings)
|
result = updateappsettingstokintone(app,settings,env)
|
||||||
revision = result["revision"]
|
revision = result["revision"]
|
||||||
deploy = True
|
deploy = True
|
||||||
if len(process)>0:
|
if len(process)>0:
|
||||||
result = updateprocesstokintone(app,exp)
|
result = updateprocesstokintone(app,exp,env)
|
||||||
revision = result["revision"]
|
revision = result["revision"]
|
||||||
deploy = True
|
deploy = True
|
||||||
if deploy:
|
if deploy:
|
||||||
result = deoployappfromkintone(app,revision)
|
result = deoployappfromkintone(app,revision,env)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=400, detail=f"Error occurred while parsing file {file.filename}: {str(e)}")
|
raise APIException('kintone:updateappfromexcel',request.url._url, f"Error occurred while parsing file ({env.DOMAIN_NAME}->{file.filename}):",e)
|
||||||
else:
|
else:
|
||||||
raise HTTPException(status_code=400, detail=f"File {file.filename} is not an Excel file")
|
raise APIException('kintone:updateappfromexcel',request.url._url, f"File {file.filename} is not an Excel file",e)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@r.post("/updateprocessfromexcel",)
|
@r.post("/updateprocessfromexcel",)
|
||||||
async def updateprocessfromexcel(app:str):
|
async def updateprocessfromexcel(request:Request,app:str,env = Depends(getkintoneenv)):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
excel = getprocessfromexcel()
|
excel = getprocessfromexcel()
|
||||||
kintone = getprocessfromkintone(app)
|
kintone = getprocessfromkintone(app,env)
|
||||||
revision = kintone["revision"]
|
revision = kintone["revision"]
|
||||||
#fields = analysefields(excel,kintone["properties"])
|
#fields = analysefields(excel,kintone["properties"])
|
||||||
result = {"app":app,"revision":revision,"msg":"No Update"}
|
result = {"app":app,"revision":revision,"msg":"No Update"}
|
||||||
@@ -419,14 +692,32 @@ async def updateprocessfromexcel(app:str):
|
|||||||
# result = updateappsettingstokintone(app,settings)
|
# result = updateappsettingstokintone(app,settings)
|
||||||
# revision = result["revision"]
|
# revision = result["revision"]
|
||||||
# deploy = True
|
# deploy = True
|
||||||
result = updateprocesstokintone(app,excel)
|
result = updateprocesstokintone(app,excel,env)
|
||||||
revision = result["revision"]
|
revision = result["revision"]
|
||||||
deploy = True
|
deploy = True
|
||||||
if deploy:
|
if deploy:
|
||||||
result = deoployappfromkintone(app,revision)
|
result = deoployappfromkintone(app,revision,env)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=400, detail=f"Error occurred : {str(e)}")
|
raise APIException('kintone:updateprocessfromexcel',request.url._url, f"Error occurred while update process ({env.DOMAIN_NAME}->{app}):",e)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@r.post("/createjstokintone",)
|
||||||
|
async def createjstokintone(request:Request,app:str,env:config.KINTONE_ENV = Depends(getkintoneenv)):
|
||||||
|
try:
|
||||||
|
jscs=[]
|
||||||
|
files=[]
|
||||||
|
files.append(createappjs(env.DOMAIN_ID, app))
|
||||||
|
files.append(getTempPath('alc_runtime.js'))
|
||||||
|
files.append(getTempPath('alc_runtime.css'))
|
||||||
|
for file in files:
|
||||||
|
upload = uploadkintonefiles(file,env)
|
||||||
|
if upload.get('fileKey') != None:
|
||||||
|
jscs.append({ file :upload['fileKey']})
|
||||||
|
appjscs = updateappjscss(app,jscs,env)
|
||||||
|
if appjscs.get("revision") != None:
|
||||||
|
deoployappfromkintone(app,appjscs["revision"],env)
|
||||||
|
return appjscs
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('kintone:createjstokintone',request.url._url, f"Error occurred while create js ({env.DOMAIN_NAME}->{app}):",e)
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ from app.db.session import get_db
|
|||||||
from app.db.crud import *
|
from app.db.crud import *
|
||||||
from app.db.schemas import *
|
from app.db.schemas import *
|
||||||
from typing import List
|
from typing import List
|
||||||
|
from app.core.auth import get_current_active_user,get_current_user
|
||||||
|
from app.core.apiexception import APIException
|
||||||
|
|
||||||
platform_router = r = APIRouter()
|
platform_router = r = APIRouter()
|
||||||
|
|
||||||
@@ -17,9 +19,11 @@ async def appsetting_details(
|
|||||||
id: int,
|
id: int,
|
||||||
db=Depends(get_db),
|
db=Depends(get_db),
|
||||||
):
|
):
|
||||||
app = get_appsetting(db, id)
|
try:
|
||||||
return app
|
app = get_appsetting(db, id)
|
||||||
|
return app
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:appsettings',request.url._url,f"Error occurred while get app setting:",e)
|
||||||
|
|
||||||
@r.post("/appsettings", response_model=App, response_model_exclude_none=True)
|
@r.post("/appsettings", response_model=App, response_model_exclude_none=True)
|
||||||
async def appsetting_create(
|
async def appsetting_create(
|
||||||
@@ -27,7 +31,10 @@ async def appsetting_create(
|
|||||||
app: AppBase,
|
app: AppBase,
|
||||||
db=Depends(get_db),
|
db=Depends(get_db),
|
||||||
):
|
):
|
||||||
return create_appsetting(db, app)
|
try:
|
||||||
|
return create_appsetting(db, app)
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:appsettings',request.url._url,f"Error occurred while get create app setting:",e)
|
||||||
|
|
||||||
|
|
||||||
@r.put(
|
@r.put(
|
||||||
@@ -39,7 +46,10 @@ async def appsetting_edit(
|
|||||||
app: AppEdit,
|
app: AppEdit,
|
||||||
db=Depends(get_db),
|
db=Depends(get_db),
|
||||||
):
|
):
|
||||||
return edit_appsetting(db, id, app)
|
try:
|
||||||
|
return edit_appsetting(db, id, app)
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:appsettings',request.url._url,f"Error occurred while edit app setting:",e)
|
||||||
|
|
||||||
|
|
||||||
@r.delete(
|
@r.delete(
|
||||||
@@ -50,8 +60,10 @@ async def appsettings_delete(
|
|||||||
id: int,
|
id: int,
|
||||||
db=Depends(get_db),
|
db=Depends(get_db),
|
||||||
):
|
):
|
||||||
|
try:
|
||||||
return delete_appsetting(db, id)
|
return delete_appsetting(db, id)
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:appsettings',request.url._url,f"Error occurred while delete app setting:",e)
|
||||||
|
|
||||||
|
|
||||||
@r.get(
|
@r.get(
|
||||||
@@ -64,8 +76,11 @@ async def kintone_data(
|
|||||||
type: int,
|
type: int,
|
||||||
db=Depends(get_db),
|
db=Depends(get_db),
|
||||||
):
|
):
|
||||||
kintone = get_kintones(db, type)
|
try:
|
||||||
return kintone
|
kintone = get_kintones(db, type)
|
||||||
|
return kintone
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:kintone',request.url._url,f"Error occurred while get kintone env:",e)
|
||||||
|
|
||||||
@r.get(
|
@r.get(
|
||||||
"/actions",
|
"/actions",
|
||||||
@@ -77,8 +92,11 @@ async def action_data(
|
|||||||
request: Request,
|
request: Request,
|
||||||
db=Depends(get_db),
|
db=Depends(get_db),
|
||||||
):
|
):
|
||||||
actions = get_actions(db)
|
try:
|
||||||
return actions
|
actions = get_actions(db)
|
||||||
|
return actions
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:actions',request.url._url,f"Error occurred while get actions:",e)
|
||||||
|
|
||||||
@r.get(
|
@r.get(
|
||||||
"/flow/{flowid}",
|
"/flow/{flowid}",
|
||||||
@@ -90,8 +108,11 @@ async def flow_details(
|
|||||||
flowid: str,
|
flowid: str,
|
||||||
db=Depends(get_db),
|
db=Depends(get_db),
|
||||||
):
|
):
|
||||||
app = get_flow(db, flowid)
|
try:
|
||||||
return app
|
app = get_flow(db, flowid)
|
||||||
|
return app
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:flow',request.url._url,f"Error occurred while get flow by flowid:",e)
|
||||||
|
|
||||||
|
|
||||||
@r.get(
|
@r.get(
|
||||||
@@ -102,19 +123,30 @@ async def flow_details(
|
|||||||
async def flow_list(
|
async def flow_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
appid: str,
|
appid: str,
|
||||||
|
user=Depends(get_current_user),
|
||||||
db=Depends(get_db),
|
db=Depends(get_db),
|
||||||
):
|
):
|
||||||
flows = get_flows_by_app(db, appid)
|
try:
|
||||||
return flows
|
domain = get_activedomain(db, user.id)
|
||||||
|
print("domain=>",domain)
|
||||||
|
flows = get_flows_by_app(db, domain.id, appid)
|
||||||
|
return flows
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:flow',request.url._url,f"Error occurred while get flow by appid:",e)
|
||||||
|
|
||||||
|
|
||||||
@r.post("/flow", response_model=Flow, response_model_exclude_none=True)
|
@r.post("/flow", response_model=Flow, response_model_exclude_none=True)
|
||||||
async def flow_create(
|
async def flow_create(
|
||||||
request: Request,
|
request: Request,
|
||||||
flow: FlowBase,
|
flow: FlowBase,
|
||||||
|
user=Depends(get_current_user),
|
||||||
db=Depends(get_db),
|
db=Depends(get_db),
|
||||||
):
|
):
|
||||||
return create_flow(db, flow)
|
try:
|
||||||
|
domain = get_activedomain(db, user.id)
|
||||||
|
return create_flow(db, domain.id, flow)
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:flow',request.url._url,f"Error occurred while create flow:",e)
|
||||||
|
|
||||||
|
|
||||||
@r.put(
|
@r.put(
|
||||||
@@ -125,7 +157,10 @@ async def flow_edit(
|
|||||||
flow: FlowBase,
|
flow: FlowBase,
|
||||||
db=Depends(get_db),
|
db=Depends(get_db),
|
||||||
):
|
):
|
||||||
return edit_flow(db, flow)
|
try:
|
||||||
|
return edit_flow(db, flow)
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:flow',request.url._url,f"Error occurred while edit flow:",e)
|
||||||
|
|
||||||
|
|
||||||
@r.delete(
|
@r.delete(
|
||||||
@@ -136,5 +171,175 @@ async def flow_delete(
|
|||||||
flowid: str,
|
flowid: str,
|
||||||
db=Depends(get_db),
|
db=Depends(get_db),
|
||||||
):
|
):
|
||||||
|
try:
|
||||||
|
return delete_flow(db, flowid)
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:flow',request.url._url,f"Error occurred while delete flow:",e)
|
||||||
|
|
||||||
return delete_flow(db, flowid)
|
@r.get(
|
||||||
|
"/domains/{tenantid}",
|
||||||
|
response_model=List[Domain],
|
||||||
|
response_model_exclude_none=True,
|
||||||
|
)
|
||||||
|
async def domain_details(
|
||||||
|
request: Request,
|
||||||
|
tenantid:str,
|
||||||
|
db=Depends(get_db),
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
domains = get_domains(db,tenantid)
|
||||||
|
return domains
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:domains',request.url._url,f"Error occurred while get domains:",e)
|
||||||
|
|
||||||
|
@r.post("/domain", response_model=Domain, response_model_exclude_none=True)
|
||||||
|
async def domain_create(
|
||||||
|
request: Request,
|
||||||
|
domain: DomainBase,
|
||||||
|
db=Depends(get_db),
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
return create_domain(db, domain)
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:domain',request.url._url,f"Error occurred while create domain:",e)
|
||||||
|
|
||||||
|
|
||||||
|
@r.put(
|
||||||
|
"/domain", response_model=Domain, response_model_exclude_none=True
|
||||||
|
)
|
||||||
|
async def domain_edit(
|
||||||
|
request: Request,
|
||||||
|
domain: DomainBase,
|
||||||
|
db=Depends(get_db),
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
return edit_domain(db, domain)
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:domain',request.url._url,f"Error occurred while edit domain:",e)
|
||||||
|
|
||||||
|
|
||||||
|
@r.delete(
|
||||||
|
"/domain/{id}", response_model=Domain, response_model_exclude_none=True
|
||||||
|
)
|
||||||
|
async def domain_delete(
|
||||||
|
request: Request,
|
||||||
|
id: int,
|
||||||
|
db=Depends(get_db),
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
return delete_domain(db,id)
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:domain',request.url._url,f"Error occurred while delete domain:",e)
|
||||||
|
|
||||||
|
@r.get(
|
||||||
|
"/domain",
|
||||||
|
response_model=List[Domain],
|
||||||
|
response_model_exclude_none=True,
|
||||||
|
)
|
||||||
|
async def userdomain_details(
|
||||||
|
request: Request,
|
||||||
|
user=Depends(get_current_user),
|
||||||
|
db=Depends(get_db),
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
domains = get_domain(db, user.id)
|
||||||
|
return domains
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:domain',request.url._url,f"Error occurred while get user({user.id}) domain:",e)
|
||||||
|
|
||||||
|
@r.post(
|
||||||
|
"/domain/{userid}",
|
||||||
|
response_model_exclude_none=True,
|
||||||
|
)
|
||||||
|
async def create_userdomain(
|
||||||
|
request: Request,
|
||||||
|
userid: int,
|
||||||
|
domainids:list,
|
||||||
|
db=Depends(get_db),
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
domain = add_userdomain(db, userid,domainids)
|
||||||
|
return domain
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:domain',request.url._url,f"Error occurred while add user({userid}) domain:",e)
|
||||||
|
|
||||||
|
@r.delete(
|
||||||
|
"/domain/{domainid}/{userid}", response_model_exclude_none=True
|
||||||
|
)
|
||||||
|
async def userdomain_delete(
|
||||||
|
request: Request,
|
||||||
|
domainid:int,
|
||||||
|
userid: int,
|
||||||
|
db=Depends(get_db),
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
return delete_userdomain(db, userid,domainid)
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:delete',request.url._url,f"Error occurred while delete user({userid}) domain:",e)
|
||||||
|
|
||||||
|
|
||||||
|
@r.get(
|
||||||
|
"/activedomain",
|
||||||
|
response_model=Domain,
|
||||||
|
response_model_exclude_none=True,
|
||||||
|
)
|
||||||
|
async def get_useractivedomain(
|
||||||
|
request: Request,
|
||||||
|
user=Depends(get_current_user),
|
||||||
|
db=Depends(get_db),
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
domain = get_activedomain(db, user.id)
|
||||||
|
return domain
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:activedomain',request.url._url,f"Error occurred while get user({user.id}) activedomain:",e)
|
||||||
|
|
||||||
|
@r.put(
|
||||||
|
"/activedomain/{domainid}",
|
||||||
|
response_model_exclude_none=True,
|
||||||
|
)
|
||||||
|
async def update_activeuserdomain(
|
||||||
|
request: Request,
|
||||||
|
domainid:int,
|
||||||
|
user=Depends(get_current_user),
|
||||||
|
db=Depends(get_db),
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
domain = active_userdomain(db, user.id,domainid)
|
||||||
|
return domain
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:activedomain',request.url._url,f"Error occurred while update user({user.id}) activedomain:",e)
|
||||||
|
|
||||||
|
@r.get(
|
||||||
|
"/events",
|
||||||
|
response_model=t.List[Event],
|
||||||
|
response_model_exclude={"id"},
|
||||||
|
response_model_exclude_none=True,
|
||||||
|
)
|
||||||
|
async def event_data(
|
||||||
|
request: Request,
|
||||||
|
db=Depends(get_db),
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
events = get_events(db)
|
||||||
|
return events
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:events',request.url._url,f"Error occurred while get events:",e)
|
||||||
|
|
||||||
|
|
||||||
|
@r.get(
|
||||||
|
"/eventactions/{eventid}",
|
||||||
|
response_model=t.List[Action],
|
||||||
|
response_model_exclude={"id"},
|
||||||
|
response_model_exclude_none=True,
|
||||||
|
)
|
||||||
|
async def eventactions_data(
|
||||||
|
request: Request,
|
||||||
|
eventid: str,
|
||||||
|
db=Depends(get_db),
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
actions = get_eventactions(db,eventid)
|
||||||
|
return actions
|
||||||
|
except Exception as e:
|
||||||
|
raise APIException('platform:eventactions',request.url._url,f"Error occurred while get eventactions:",e)
|
||||||
26
backend/app/core/apiexception.py
Normal file
26
backend/app/core/apiexception.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
from fastapi import HTTPException, status
|
||||||
|
from app.db.schemas import ErrorCreate
|
||||||
|
from app.db.session import SessionLocal
|
||||||
|
from app.db.crud import create_log
|
||||||
|
|
||||||
|
class APIException(Exception):
|
||||||
|
|
||||||
|
def __init__(self,location:str,title:str,content:str,e:Exception):
|
||||||
|
if(str(e) == ''):
|
||||||
|
content += e.detail
|
||||||
|
self.detail = e.detail
|
||||||
|
self.status_code = e.status_code
|
||||||
|
else:
|
||||||
|
self.detail = str(e)
|
||||||
|
content += str(e)
|
||||||
|
self.status_code = 500
|
||||||
|
if(len(content) > 5000):
|
||||||
|
content =content[0:5000]
|
||||||
|
self.error = ErrorCreate(location=location,title=title,content=content)
|
||||||
|
|
||||||
|
def writedblog(exc: APIException):
|
||||||
|
db = SessionLocal()
|
||||||
|
try:
|
||||||
|
create_log(db,exc.error)
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
@@ -3,7 +3,7 @@ from fastapi import Depends, HTTPException, status
|
|||||||
from jwt import PyJWTError
|
from jwt import PyJWTError
|
||||||
|
|
||||||
from app.db import models, schemas, session
|
from app.db import models, schemas, session
|
||||||
from app.db.crud import get_user_by_email, create_user
|
from app.db.crud import get_user_by_email, create_user,get_user
|
||||||
from app.core import security
|
from app.core import security
|
||||||
|
|
||||||
|
|
||||||
@@ -19,14 +19,14 @@ async def get_current_user(
|
|||||||
payload = jwt.decode(
|
payload = jwt.decode(
|
||||||
token, security.SECRET_KEY, algorithms=[security.ALGORITHM]
|
token, security.SECRET_KEY, algorithms=[security.ALGORITHM]
|
||||||
)
|
)
|
||||||
email: str = payload.get("sub")
|
id: int = payload.get("sub")
|
||||||
if email is None:
|
if id is None:
|
||||||
raise credentials_exception
|
raise credentials_exception
|
||||||
permissions: str = payload.get("permissions")
|
permissions: str = payload.get("permissions")
|
||||||
token_data = schemas.TokenData(email=email, permissions=permissions)
|
token_data = schemas.TokenData(id = id, permissions=permissions)
|
||||||
except PyJWTError:
|
except PyJWTError:
|
||||||
raise credentials_exception
|
raise credentials_exception
|
||||||
user = get_user_by_email(db, token_data.email)
|
user = get_user(db, token_data.id)
|
||||||
if user is None:
|
if user is None:
|
||||||
raise credentials_exception
|
raise credentials_exception
|
||||||
return user
|
return user
|
||||||
@@ -58,7 +58,7 @@ def authenticate_user(db, email: str, password: str):
|
|||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
def sign_up_new_user(db, email: str, password: str):
|
def sign_up_new_user(db, email: str, password: str, firstname: str,lastname: str):
|
||||||
user = get_user_by_email(db, email)
|
user = get_user_by_email(db, email)
|
||||||
if user:
|
if user:
|
||||||
return False # User already exists
|
return False # User already exists
|
||||||
@@ -67,6 +67,8 @@ def sign_up_new_user(db, email: str, password: str):
|
|||||||
schemas.UserCreate(
|
schemas.UserCreate(
|
||||||
email=email,
|
email=email,
|
||||||
password=password,
|
password=password,
|
||||||
|
first_name = firstname,
|
||||||
|
last_name = lastname,
|
||||||
is_active=True,
|
is_active=True,
|
||||||
is_superuser=False,
|
is_superuser=False,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,18 +1,38 @@
|
|||||||
import os
|
import os
|
||||||
|
import base64
|
||||||
|
|
||||||
PROJECT_NAME = "KintoneAppBuilder"
|
PROJECT_NAME = "KintoneAppBuilder"
|
||||||
|
|
||||||
SQLALCHEMY_DATABASE_URI = "mssql+pymssql://maxz64@maxzdb:m@xz1205@maxzdb.database.windows.net/alloc"
|
#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"
|
||||||
BASE_URL = "https://mfu07rkgnb7c.cybozu.com"
|
#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"
|
||||||
|
|
||||||
API_V1_AUTH_VALUE = "TVhaOm1heHoxMjA1"
|
DEPLOY_MODE = "PROD" #DEV,PROD
|
||||||
|
|
||||||
KINTONE_USER = "MXZ"
|
DEPLOY_JS_URL = "https://ka-addin.azurewebsites.net/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"]
|
||||||
|
|
||||||
|
KINTONE_FIELD_PROPERTY=['label','code','type','required','unique','maxValue','minValue','maxLength','minLength','defaultValue','defaultNowValue','options','expression','hideExpression','digit','protocol','displayScale','unit','unitPosition']
|
||||||
|
|
||||||
|
class KINTONE_ENV:
|
||||||
|
|
||||||
|
BASE_URL = ""
|
||||||
|
|
||||||
|
API_V1_AUTH_VALUE = ""
|
||||||
|
|
||||||
|
KINTONE_USER = ""
|
||||||
|
|
||||||
|
DOMAIN_ID = ""
|
||||||
|
|
||||||
|
DOMAIN_NAME =""
|
||||||
|
|
||||||
|
def __init__(self,domain) -> None:
|
||||||
|
self.DOMAIN_NAME=domain.name
|
||||||
|
self.DOMAIN_ID=domain.id
|
||||||
|
self.BASE_URL = domain.url
|
||||||
|
self.KINTONE_USER = domain.kintoneuser
|
||||||
|
self.API_V1_AUTH_VALUE = base64.b64encode(bytes(f"{domain.kintoneuser}:{domain.kintonepwd}","utf-8"))
|
||||||
@@ -9,7 +9,7 @@ pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
|||||||
|
|
||||||
SECRET_KEY = "alicorns"
|
SECRET_KEY = "alicorns"
|
||||||
ALGORITHM = "HS256"
|
ALGORITHM = "HS256"
|
||||||
ACCESS_TOKEN_EXPIRE_MINUTES = 30
|
ACCESS_TOKEN_EXPIRE_MINUTES = 2880
|
||||||
|
|
||||||
|
|
||||||
def get_password_hash(password: str) -> str:
|
def get_password_hash(password: str) -> str:
|
||||||
@@ -25,7 +25,7 @@ def create_access_token(*, data: dict, expires_delta: timedelta = None):
|
|||||||
if expires_delta:
|
if expires_delta:
|
||||||
expire = datetime.utcnow() + expires_delta
|
expire = datetime.utcnow() + expires_delta
|
||||||
else:
|
else:
|
||||||
expire = datetime.utcnow() + timedelta(minutes=15)
|
expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||||
to_encode.update({"exp": expire})
|
to_encode.update({"exp": expire})
|
||||||
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
|
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
|
||||||
return encoded_jwt
|
return encoded_jwt
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from fastapi import HTTPException, status
|
from fastapi import HTTPException, status
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
from sqlalchemy import and_
|
||||||
import typing as t
|
import typing as t
|
||||||
|
|
||||||
from . import models, schemas
|
from . import models, schemas
|
||||||
@@ -124,11 +125,12 @@ def get_actions(db: Session):
|
|||||||
return actions
|
return actions
|
||||||
|
|
||||||
|
|
||||||
def create_flow(db: Session, flow: schemas.FlowBase):
|
def create_flow(db: Session, domainid: int, flow: schemas.FlowBase):
|
||||||
db_flow = models.Flow(
|
db_flow = models.Flow(
|
||||||
flowid=flow.flowid,
|
flowid=flow.flowid,
|
||||||
appid=flow.appid,
|
appid=flow.appid,
|
||||||
eventid=flow.eventid,
|
eventid=flow.eventid,
|
||||||
|
domainid=domainid,
|
||||||
name=flow.name,
|
name=flow.name,
|
||||||
content=flow.content
|
content=flow.content
|
||||||
)
|
)
|
||||||
@@ -175,8 +177,122 @@ def get_flow(db: Session, flowid: str):
|
|||||||
raise HTTPException(status_code=404, detail="Data not found")
|
raise HTTPException(status_code=404, detail="Data not found")
|
||||||
return flow
|
return flow
|
||||||
|
|
||||||
def get_flows_by_app(db: Session, appid: str):
|
def get_flows_by_app(db: Session, domainid: int, appid: str):
|
||||||
flows = db.query(models.Flow).filter(models.Flow.appid == appid).all()
|
flows = db.query(models.Flow).filter(and_(models.Flow.domainid == domainid,models.Flow.appid == appid)).all()
|
||||||
if not flows:
|
if not flows:
|
||||||
|
raise Exception("Data not found")
|
||||||
|
return flows
|
||||||
|
|
||||||
|
def create_domain(db: Session, domain: schemas.DomainBase):
|
||||||
|
db_domain = models.Domain(
|
||||||
|
tenantid = domain.tenantid,
|
||||||
|
name=domain.name,
|
||||||
|
url=domain.url,
|
||||||
|
kintoneuser=domain.kintoneuser,
|
||||||
|
kintonepwd=domain.kintonepwd
|
||||||
|
)
|
||||||
|
db.add(db_domain)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(db_domain)
|
||||||
|
return db_domain
|
||||||
|
|
||||||
|
def delete_domain(db: Session,id: int):
|
||||||
|
db_domain = db.query(models.Domain).get(id)
|
||||||
|
if not db_domain:
|
||||||
|
raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Domain not found")
|
||||||
|
db.delete(db_domain)
|
||||||
|
db.commit()
|
||||||
|
return db_domain
|
||||||
|
|
||||||
|
|
||||||
|
def edit_domain(
|
||||||
|
db: Session, domain: schemas.DomainBase
|
||||||
|
) -> schemas.Domain:
|
||||||
|
db_domain = db.query(models.Domain).get(domain.id)
|
||||||
|
if not db_domain:
|
||||||
|
raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Domain not found")
|
||||||
|
update_data = domain.dict(exclude_unset=True)
|
||||||
|
|
||||||
|
for key, value in update_data.items():
|
||||||
|
if(key != "id"):
|
||||||
|
setattr(db_domain, key, value)
|
||||||
|
|
||||||
|
db.add(db_domain)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(db_domain)
|
||||||
|
return db_domain
|
||||||
|
|
||||||
|
def add_userdomain(db: Session, userid:int,domainids:list):
|
||||||
|
for domainid in domainids:
|
||||||
|
db_domain = models.UserDomain(
|
||||||
|
userid = userid,
|
||||||
|
domainid = domainid
|
||||||
|
)
|
||||||
|
db.add(db_domain)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(db_domain)
|
||||||
|
return db_domain
|
||||||
|
|
||||||
|
def delete_userdomain(db: Session, userid: int,domainid: int):
|
||||||
|
db_domain = db.query(models.UserDomain).filter(and_(models.UserDomain.userid == userid,models.UserDomain.domainid == domainid)).first()
|
||||||
|
if not db_domain:
|
||||||
|
raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Domain not found")
|
||||||
|
db.delete(db_domain)
|
||||||
|
db.commit()
|
||||||
|
return db_domain
|
||||||
|
|
||||||
|
def active_userdomain(db: Session, userid: int,domainid: int):
|
||||||
|
db_userdomains = db.query(models.UserDomain).filter(models.UserDomain.userid == userid).all()
|
||||||
|
if not db_userdomains:
|
||||||
|
raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Domain not found")
|
||||||
|
for domain in db_userdomains:
|
||||||
|
if domain.domainid == domainid:
|
||||||
|
domain.active = True
|
||||||
|
else:
|
||||||
|
domain.active = False
|
||||||
|
db.add(domain)
|
||||||
|
db.commit()
|
||||||
|
return db_userdomains
|
||||||
|
|
||||||
|
def get_activedomain(db: Session, userid: int):
|
||||||
|
db_domain = db.query(models.Domain).join(models.UserDomain,models.UserDomain.domainid == models.Domain.id ).filter(and_(models.UserDomain.userid == userid,models.UserDomain.active == True)).first()
|
||||||
|
if not db_domain:
|
||||||
|
raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Domain not found")
|
||||||
|
return db_domain
|
||||||
|
|
||||||
|
def get_domain(db: Session, userid: str):
|
||||||
|
domains = db.query(models.Domain).join(models.UserDomain,models.UserDomain.domainid == models.Domain.id ).filter(models.UserDomain.userid == userid).all()
|
||||||
|
if not domains:
|
||||||
raise HTTPException(status_code=404, detail="Data not found")
|
raise HTTPException(status_code=404, detail="Data not found")
|
||||||
return flows
|
return domains
|
||||||
|
|
||||||
|
def get_domains(db: Session,tenantid:str):
|
||||||
|
domains = db.query(models.Domain).filter(models.Domain.tenantid == tenantid ).all()
|
||||||
|
if not domains:
|
||||||
|
raise HTTPException(status_code=404, detail="Data not found")
|
||||||
|
return domains
|
||||||
|
|
||||||
|
def get_events(db: Session):
|
||||||
|
events = db.query(models.Event).all()
|
||||||
|
if not events:
|
||||||
|
raise HTTPException(status_code=404, detail="Data not found")
|
||||||
|
return events
|
||||||
|
|
||||||
|
def get_eventactions(db: Session,eventid: str):
|
||||||
|
#eveactions = db.query(models.Action).join(models.EventAction,models.EventAction.actionid == models.Action.id ).join(models.Event,models.Event.id == models.EventAction.eventid).filter(models.Event.eventid == eventid).all()
|
||||||
|
eveactions = db.query(models.Action).join(models.EventAction,models.EventAction.actionid != models.Action.id and models.EventAction.eventid == eventid ).join(models.Event,models.Event.id == models.EventAction.eventid).filter(models.Event.eventid == eventid).all()
|
||||||
|
if not eveactions:
|
||||||
|
raise HTTPException(status_code=404, detail="Data not found")
|
||||||
|
return eveactions
|
||||||
|
|
||||||
|
|
||||||
|
def create_log(db: Session, error:schemas.ErrorCreate):
|
||||||
|
db_log = models.ErrorLog(title=error.title,location=error.location,content=error.content)
|
||||||
|
db.add(db_log)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(db_log)
|
||||||
|
return db_log
|
||||||
|
|
||||||
|
def get_kintoneformat(db: Session):
|
||||||
|
formats = db.query(models.KintoneFormat).order_by(models.KintoneFormat.id).all()
|
||||||
|
return formats
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
from sqlalchemy import Boolean, Column, Integer, String, DateTime
|
from sqlalchemy import Boolean, Column, Integer, String, DateTime,ForeignKey
|
||||||
from sqlalchemy.ext.declarative import as_declarative
|
from sqlalchemy.ext.declarative import as_declarative
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
@@ -47,5 +47,67 @@ class Flow(Base):
|
|||||||
flowid = Column(String(100), index=True, nullable=False)
|
flowid = Column(String(100), index=True, nullable=False)
|
||||||
appid = Column(String(100), index=True, nullable=False)
|
appid = Column(String(100), index=True, nullable=False)
|
||||||
eventid = Column(String(100), index=True, nullable=False)
|
eventid = Column(String(100), index=True, nullable=False)
|
||||||
|
domainid = Column(Integer,ForeignKey("domain.id"))
|
||||||
name = Column(String(200))
|
name = Column(String(200))
|
||||||
content = Column(String)
|
content = Column(String)
|
||||||
|
|
||||||
|
class Tenant(Base):
|
||||||
|
__tablename__ = "tenant"
|
||||||
|
|
||||||
|
tenantid = Column(String(100), index=True, nullable=False)
|
||||||
|
name = Column(String(200))
|
||||||
|
licence = Column(String(200))
|
||||||
|
startdate = Column(DateTime)
|
||||||
|
enddate = Column(DateTime)
|
||||||
|
|
||||||
|
class Domain(Base):
|
||||||
|
__tablename__ = "domain"
|
||||||
|
|
||||||
|
tenantid = Column(String(100), index=True, nullable=False)
|
||||||
|
name = Column(String(100), nullable=False)
|
||||||
|
url = Column(String(200), nullable=False)
|
||||||
|
kintoneuser = Column(String(100), nullable=False)
|
||||||
|
kintonepwd = Column(String(100), nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
class UserDomain(Base):
|
||||||
|
__tablename__ = "userdomain"
|
||||||
|
|
||||||
|
userid = Column(Integer,ForeignKey("user.id"))
|
||||||
|
domainid = Column(Integer,ForeignKey("domain.id"))
|
||||||
|
active = Column(Boolean, default=False)
|
||||||
|
|
||||||
|
class Event(Base):
|
||||||
|
__tablename__ = "event"
|
||||||
|
|
||||||
|
category = Column(String(100), nullable=False)
|
||||||
|
type = Column(String(100), nullable=False)
|
||||||
|
eventid= Column(String(100), nullable=False)
|
||||||
|
function = Column(String(500), nullable=False)
|
||||||
|
mobile = Column(Boolean, default=False)
|
||||||
|
eventgroup = Column(Boolean, default=False)
|
||||||
|
|
||||||
|
class EventAction(Base):
|
||||||
|
__tablename__ = "eventaction"
|
||||||
|
|
||||||
|
eventid = Column(Integer,ForeignKey("event.id"))
|
||||||
|
actionid = Column(Integer,ForeignKey("action.id"))
|
||||||
|
|
||||||
|
|
||||||
|
class ErrorLog(Base):
|
||||||
|
__tablename__ = "errorlog"
|
||||||
|
|
||||||
|
title = Column(String(50))
|
||||||
|
location = Column(String(500))
|
||||||
|
content = Column(String(5000))
|
||||||
|
|
||||||
|
class KintoneFormat(Base):
|
||||||
|
__tablename__ = "kintoneformat"
|
||||||
|
|
||||||
|
name = Column(String(50))
|
||||||
|
startrow =Column(Integer)
|
||||||
|
startcolumn =Column(Integer)
|
||||||
|
typecolumn =Column(Integer)
|
||||||
|
codecolumn =Column(Integer)
|
||||||
|
field = Column(String(5000))
|
||||||
|
trueformat = Column(String(10))
|
||||||
@@ -20,7 +20,12 @@ class UserOut(UserBase):
|
|||||||
|
|
||||||
|
|
||||||
class UserCreate(UserBase):
|
class UserCreate(UserBase):
|
||||||
|
email:str
|
||||||
password: str
|
password: str
|
||||||
|
first_name: str
|
||||||
|
last_name: str
|
||||||
|
is_active:bool
|
||||||
|
is_superuser:bool
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
orm_mode = True
|
orm_mode = True
|
||||||
@@ -46,6 +51,7 @@ class Token(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class TokenData(BaseModel):
|
class TokenData(BaseModel):
|
||||||
|
id:int = 0
|
||||||
email: str = None
|
email: str = None
|
||||||
permissions: str = "user"
|
permissions: str = "user"
|
||||||
|
|
||||||
@@ -98,8 +104,45 @@ class Flow(Base):
|
|||||||
flowid: str
|
flowid: str
|
||||||
appid: str
|
appid: str
|
||||||
eventid: str
|
eventid: str
|
||||||
|
domainid: int
|
||||||
name: str = None
|
name: str = None
|
||||||
content: str = None
|
content: str = None
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
orm_mode = True
|
orm_mode = True
|
||||||
|
|
||||||
|
class DomainBase(BaseModel):
|
||||||
|
id: int
|
||||||
|
tenantid: str
|
||||||
|
name: str
|
||||||
|
url: str
|
||||||
|
kintoneuser: str
|
||||||
|
kintonepwd: str
|
||||||
|
|
||||||
|
class Domain(Base):
|
||||||
|
id: int
|
||||||
|
tenantid: str
|
||||||
|
name: str
|
||||||
|
url: str
|
||||||
|
kintoneuser: str
|
||||||
|
kintonepwd: str
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
orm_mode = True
|
||||||
|
|
||||||
|
class Event(Base):
|
||||||
|
id: int
|
||||||
|
category: str
|
||||||
|
type: str
|
||||||
|
eventid: str
|
||||||
|
function: str
|
||||||
|
mobile: bool
|
||||||
|
eventgroup: bool
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
orm_mode = True
|
||||||
|
|
||||||
|
class ErrorCreate(BaseModel):
|
||||||
|
title:str
|
||||||
|
location:str
|
||||||
|
content:str
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import os
|
||||||
from fastapi import FastAPI, Depends
|
from fastapi import FastAPI, Depends
|
||||||
from starlette.requests import Request
|
from starlette.requests import Request
|
||||||
import uvicorn
|
import uvicorn
|
||||||
@@ -11,6 +12,11 @@ from app.core.auth import get_current_active_user
|
|||||||
from app.core.celery_app import celery_app
|
from app.core.celery_app import celery_app
|
||||||
from app import tasks
|
from app import tasks
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
import logging
|
||||||
|
from app.core.apiexception import APIException, writedblog
|
||||||
|
from app.db.crud import create_log
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
import asyncio
|
||||||
|
|
||||||
Base.metadata.create_all(bind=engine)
|
Base.metadata.create_all(bind=engine)
|
||||||
|
|
||||||
@@ -19,9 +25,7 @@ app = FastAPI(
|
|||||||
)
|
)
|
||||||
|
|
||||||
origins = [
|
origins = [
|
||||||
"http://localhost:9000",
|
"*"
|
||||||
"http://localhost",
|
|
||||||
"http://localhost:8080",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
@@ -39,6 +43,25 @@ app.add_middleware(
|
|||||||
# request.state.db.close()
|
# request.state.db.close()
|
||||||
# return response
|
# return response
|
||||||
|
|
||||||
|
@app.on_event("startup")
|
||||||
|
async def startup_event():
|
||||||
|
log_dir="log"
|
||||||
|
if not os.path.exists(log_dir):
|
||||||
|
os.makedirs(log_dir)
|
||||||
|
|
||||||
|
logger = logging.getLogger("uvicorn.access")
|
||||||
|
handler = logging.handlers.RotatingFileHandler(f"{log_dir}/api.log",mode="a",maxBytes = 100*1024, backupCount = 3)
|
||||||
|
handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
|
||||||
|
logger.addHandler(handler)
|
||||||
|
|
||||||
|
@app.exception_handler(APIException)
|
||||||
|
async def api_exception_handler(request: Request, exc: APIException):
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
loop.run_in_executor(None,writedblog,exc)
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=exc.status_code,
|
||||||
|
content={"detail": f"{exc.detail}"},
|
||||||
|
)
|
||||||
|
|
||||||
@app.get("/api/v1")
|
@app.get("/api/v1")
|
||||||
async def root():
|
async def root():
|
||||||
|
|||||||
@@ -24,4 +24,8 @@ python -m venv env
|
|||||||
```bash
|
```bash
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
|
||||||
```
|
```
|
||||||
|
4. backend 起動
|
||||||
|
```bash
|
||||||
|
uvicorn app.main:app --reload
|
||||||
|
```
|
||||||
|
|||||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
document/Kintone自動作成ツールのプラグインについて.xlsx
Normal file
BIN
document/Kintone自動作成ツールのプラグインについて.xlsx
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
document/action-property.png
Normal file
BIN
document/action-property.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 56 KiB |
147
document/サイトマップ.drawio
Normal file
147
document/サイトマップ.drawio
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
<mxfile host="app.diagrams.net" modified="2024-02-21T05:42:02.026Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36" etag="T2S5cjvthSOlO5DmGw-C" version="23.1.5" type="device">
|
||||||
|
<diagram id="Z6uZM46JtkVaKDzPjE9h" name="サイトマップ">
|
||||||
|
<mxGraphModel dx="1434" dy="820" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||||
|
<root>
|
||||||
|
<mxCell id="0" />
|
||||||
|
<mxCell id="1" parent="0" />
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-14" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="Gi77RX5G2m4J9-6cMje4-1" target="Gi77RX5G2m4J9-6cMje4-13" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-1" value="テナント登録" style="html=1;whiteSpace=wrap;strokeColor=none;fillColor=#0079D6;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;fontColor=#FFFFFF;sketch=0;shape=mxgraph.sitemap.login;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="60" y="50" width="120" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-2" value="Admin Login" style="html=1;whiteSpace=wrap;strokeColor=#2D7600;fillColor=#60a917;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;fontColor=#ffffff;sketch=0;shape=mxgraph.sitemap.login;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="60" y="270" width="120" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-8" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="Gi77RX5G2m4J9-6cMje4-5" target="Gi77RX5G2m4J9-6cMje4-7" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-9" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="Gi77RX5G2m4J9-6cMje4-5" target="Gi77RX5G2m4J9-6cMje4-7" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-12" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="Gi77RX5G2m4J9-6cMje4-5" target="Gi77RX5G2m4J9-6cMje4-11" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-5" value="Home" style="html=1;whiteSpace=wrap;strokeColor=#2D7600;fillColor=#60a917;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;fontColor=#ffffff;sketch=0;shape=mxgraph.sitemap.home;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="240" y="270" width="120" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="Gi77RX5G2m4J9-6cMje4-2" target="Gi77RX5G2m4J9-6cMje4-5" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-42" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="Gi77RX5G2m4J9-6cMje4-7" target="Gi77RX5G2m4J9-6cMje4-41" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-7" value="ユーザー登録" style="html=1;whiteSpace=wrap;strokeColor=none;fillColor=#0079D6;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;fontColor=#FFFFFF;sketch=0;shape=mxgraph.sitemap.home;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="440" y="220" width="120" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-11" value="ドメイン登録" style="html=1;whiteSpace=wrap;strokeColor=none;fillColor=#0079D6;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;fontColor=#FFFFFF;sketch=0;shape=mxgraph.sitemap.home;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="440" y="340" width="120" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-13" value="テナント管理者作成" style="html=1;whiteSpace=wrap;strokeColor=none;fillColor=#0079D6;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;fontColor=#FFFFFF;sketch=0;shape=mxgraph.sitemap.login;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="240" y="50" width="120" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-15" value="ライセンス情報" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="480" y="10" width="90" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-16" value="Adminユーザー" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="480" y="90" width="90" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-17" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="Gi77RX5G2m4J9-6cMje4-13" target="Gi77RX5G2m4J9-6cMje4-15" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-18" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="Gi77RX5G2m4J9-6cMje4-13" target="Gi77RX5G2m4J9-6cMje4-16" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-19" value="テナントDB<br>作成" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="550" y="50" width="90" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-22" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="Gi77RX5G2m4J9-6cMje4-20" target="Gi77RX5G2m4J9-6cMje4-21" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-20" value="Login" style="html=1;whiteSpace=wrap;strokeColor=#005700;fillColor=#008a00;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;sketch=0;shape=mxgraph.sitemap.login;fontColor=#ffffff;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="50" y="610" width="120" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-24" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="Gi77RX5G2m4J9-6cMje4-21" target="Gi77RX5G2m4J9-6cMje4-25" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="430" y="645" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-21" value="Home" style="html=1;whiteSpace=wrap;strokeColor=#005700;fillColor=#008a00;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;fontColor=#ffffff;sketch=0;shape=mxgraph.sitemap.home;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="230" y="610" width="120" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-27" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="Gi77RX5G2m4J9-6cMje4-25" target="Gi77RX5G2m4J9-6cMje4-26" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-25" value="アプリ一覧" style="html=1;whiteSpace=wrap;strokeColor=none;fillColor=#0079D6;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;fontColor=#FFFFFF;sketch=0;shape=mxgraph.sitemap.news;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="440" y="610" width="120" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-29" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="Gi77RX5G2m4J9-6cMje4-26" target="Gi77RX5G2m4J9-6cMje4-28" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-26" value="フロー一覧" style="html=1;whiteSpace=wrap;strokeColor=none;fillColor=#0079D6;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;fontColor=#FFFFFF;sketch=0;shape=mxgraph.sitemap.news;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="620" y="610" width="120" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-40" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="Gi77RX5G2m4J9-6cMje4-28" target="Gi77RX5G2m4J9-6cMje4-39" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-28" value="フローエディタ" style="html=1;whiteSpace=wrap;strokeColor=#005700;fillColor=#008a00;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;fontColor=#ffffff;sketch=0;shape=mxgraph.sitemap.news;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="800" y="610" width="120" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-33" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="Gi77RX5G2m4J9-6cMje4-30" target="Gi77RX5G2m4J9-6cMje4-32" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-30" value="設計書取込" style="html=1;whiteSpace=wrap;strokeColor=#005700;fillColor=#008a00;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;fontColor=#ffffff;sketch=0;shape=mxgraph.sitemap.news;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="440" y="715" width="120" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-31" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="Gi77RX5G2m4J9-6cMje4-21" target="Gi77RX5G2m4J9-6cMje4-30" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-32" value="取込結果表示" style="html=1;whiteSpace=wrap;strokeColor=#005700;fillColor=#008a00;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;fontColor=#ffffff;sketch=0;shape=mxgraph.sitemap.news;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="620" y="715" width="120" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-37" value="設計書ダウロード" style="html=1;whiteSpace=wrap;strokeColor=none;fillColor=#0079D6;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;fontColor=#FFFFFF;sketch=0;shape=mxgraph.sitemap.news;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="440" y="825" width="120" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-38" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="Gi77RX5G2m4J9-6cMje4-21" target="Gi77RX5G2m4J9-6cMje4-37" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-39" value="フロー履歴管理" style="html=1;whiteSpace=wrap;strokeColor=none;fillColor=#0079D6;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;fontColor=#FFFFFF;sketch=0;shape=mxgraph.sitemap.news;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="980" y="610" width="120" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-41" value="ALC設定" style="html=1;whiteSpace=wrap;strokeColor=none;fillColor=#0079D6;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;fontColor=#FFFFFF;sketch=0;shape=mxgraph.sitemap.home;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="620" y="220" width="120" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-43" value="管理ドメイン設定" style="html=1;whiteSpace=wrap;strokeColor=none;fillColor=#0079D6;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;fontColor=#FFFFFF;sketch=0;shape=mxgraph.sitemap.home;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="800" y="220" width="120" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-44" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="Gi77RX5G2m4J9-6cMje4-41" target="Gi77RX5G2m4J9-6cMje4-43" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-45" value="プロファイル" style="html=1;whiteSpace=wrap;strokeColor=none;fillColor=#0079D6;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;fontColor=#FFFFFF;sketch=0;shape=mxgraph.sitemap.home;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="440" y="935" width="120" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-46" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="Gi77RX5G2m4J9-6cMje4-21" target="Gi77RX5G2m4J9-6cMje4-45" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-50" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="Gi77RX5G2m4J9-6cMje4-47" target="Gi77RX5G2m4J9-6cMje4-49" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-47" value="プロファイル" style="html=1;whiteSpace=wrap;strokeColor=none;fillColor=#0079D6;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;fontColor=#FFFFFF;sketch=0;shape=mxgraph.sitemap.home;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="440" y="450" width="120" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-48" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="Gi77RX5G2m4J9-6cMje4-5" target="Gi77RX5G2m4J9-6cMje4-47" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-49" value="ライセンス情報" style="html=1;whiteSpace=wrap;strokeColor=none;fillColor=#0079D6;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;fontColor=#FFFFFF;sketch=0;shape=mxgraph.sitemap.home;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="620" y="450" width="120" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-51" value="ライセンス情報" style="html=1;whiteSpace=wrap;strokeColor=none;fillColor=#0079D6;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;fontColor=#FFFFFF;sketch=0;shape=mxgraph.sitemap.home;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="620" y="935" width="120" height="70" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="Gi77RX5G2m4J9-6cMje4-52" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="Gi77RX5G2m4J9-6cMje4-45" target="Gi77RX5G2m4J9-6cMje4-51" edge="1">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</root>
|
||||||
|
</mxGraphModel>
|
||||||
|
</diagram>
|
||||||
|
</mxfile>
|
||||||
194
document/ルックアップ同期仕様.drawio
Normal file
194
document/ルックアップ同期仕様.drawio
Normal file
File diff suppressed because one or more lines are too long
BIN
document/収支明細管理設計書.xlsx
Normal file
BIN
document/収支明細管理設計書.xlsx
Normal file
Binary file not shown.
BIN
document/日報設計書new.xlsx
Normal file
BIN
document/日報設計書new.xlsx
Normal file
Binary file not shown.
@@ -1,2 +1,6 @@
|
|||||||
KAB_BACKEND_URL="http://127.0.0.1:8000/api/v1/"
|
#開発環境
|
||||||
|
#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/"
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
VUE_BACKEND_URL="http://localhost:8000/api/"
|
#KAB_BACKEND_URL="https://kab-backend.azurewebsites.net/"
|
||||||
|
KAB_BACKEND_URL="http://127.0.0.1:8000/"
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
<html lang="ja-jp">
|
<html lang="ja-jp">
|
||||||
<head>
|
<head>
|
||||||
<title><%= productName %></title>
|
<title><%= productName %></title>
|
||||||
|
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="description" content="<%= productDescription %>">
|
<meta name="description" content="<%= productDescription %>">
|
||||||
<meta name="format-detection" content="telephone=no">
|
<meta name="format-detection" content="telephone=no">
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "kintone-app-builder",
|
"name": "kintone-automate",
|
||||||
"version": "0.0.1",
|
"version": "0.2.0",
|
||||||
"description": "Kintoneアプリの自動生成とデプロイを支援ツールです",
|
"description": "Kintoneアプリの自動生成とデプロイを支援ツールです",
|
||||||
"productName": "Kintone App Builder",
|
"productName": "kintone Automate",
|
||||||
"author": "maxiaozhe@alicorns.co.jp <maxiaozhe@alicorns.co.jp>",
|
"author": "maxiaozhe@alicorns.co.jp <maxiaozhe@alicorns.co.jp>",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -10,12 +10,16 @@
|
|||||||
"format": "prettier --write \"**/*.{js,ts,vue,scss,html,md,json}\" --ignore-path .gitignore",
|
"format": "prettier --write \"**/*.{js,ts,vue,scss,html,md,json}\" --ignore-path .gitignore",
|
||||||
"test": "echo \"No test specified\" && exit 0",
|
"test": "echo \"No test specified\" && exit 0",
|
||||||
"dev": "quasar dev",
|
"dev": "quasar dev",
|
||||||
"build": "quasar build"
|
"dev:local": "set \"LOCAL=true\" && quasar dev",
|
||||||
|
"build": "set \"SOURCE_MAP=false\" && quasar build",
|
||||||
|
"build:dev":"set \"SOURCE_MAP=true\" && quasar build"
|
||||||
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@quasar/extras": "^1.16.4",
|
"@quasar/extras": "^1.16.4",
|
||||||
|
"@vueuse/core": "^10.9.0",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"pinia": "^2.1.6",
|
"pinia": "^2.1.7",
|
||||||
"quasar": "^2.6.0",
|
"quasar": "^2.6.0",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"vue": "^3.0.0",
|
"vue": "^3.0.0",
|
||||||
|
|||||||
8
frontend/public/web.config
Normal file
8
frontend/public/web.config
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<configuration>
|
||||||
|
<system.webServer>
|
||||||
|
<staticContent>
|
||||||
|
<mimeMap fileExtension=".woff" mimeType="application/font-woff" />
|
||||||
|
<mimeMap fileExtension=".woff2" mimeType="application/font-woff2" />
|
||||||
|
</staticContent>
|
||||||
|
</system.webServer>
|
||||||
|
</configuration>
|
||||||
@@ -10,10 +10,14 @@
|
|||||||
|
|
||||||
|
|
||||||
const { configure } = require('quasar/wrappers');
|
const { configure } = require('quasar/wrappers');
|
||||||
const dotenv = require('dotenv').config().parsed;
|
const envPath = process.env.LOCAL==='true'?'.env.development':'.env';
|
||||||
const package = require('./package.json');
|
const dotenv = require('dotenv').config({path:envPath}).parsed;
|
||||||
|
console.log('dotenv=>',dotenv);
|
||||||
|
// const package = require('./package.json');
|
||||||
const { Notify } = require('quasar');
|
const { Notify } = require('quasar');
|
||||||
const version = package.version;
|
const version = process.env.npm_package_version;
|
||||||
|
const productName=process.env.npm_package_productName;
|
||||||
|
// console.log(process.env);
|
||||||
module.exports = configure(function (/* ctx */) {
|
module.exports = configure(function (/* ctx */) {
|
||||||
return {
|
return {
|
||||||
eslint: {
|
eslint: {
|
||||||
@@ -32,7 +36,8 @@ module.exports = configure(function (/* ctx */) {
|
|||||||
// --> boot files are part of "main.js"
|
// --> boot files are part of "main.js"
|
||||||
// https://v2.quasar.dev/quasar-cli-vite/boot-files
|
// https://v2.quasar.dev/quasar-cli-vite/boot-files
|
||||||
boot: [
|
boot: [
|
||||||
'axios'
|
'axios',
|
||||||
|
'error-handler'
|
||||||
],
|
],
|
||||||
|
|
||||||
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css
|
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css
|
||||||
@@ -49,7 +54,6 @@ module.exports = configure(function (/* ctx */) {
|
|||||||
// 'themify',
|
// 'themify',
|
||||||
// 'line-awesome',
|
// 'line-awesome',
|
||||||
// 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
|
// 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
|
||||||
|
|
||||||
'roboto-font', // optional, you are not bound to it
|
'roboto-font', // optional, you are not bound to it
|
||||||
'material-icons', // optional, you are not bound to it
|
'material-icons', // optional, you are not bound to it
|
||||||
],
|
],
|
||||||
@@ -60,6 +64,7 @@ module.exports = configure(function (/* ctx */) {
|
|||||||
browser: ['es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1'],
|
browser: ['es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1'],
|
||||||
node: 'node16'
|
node: 'node16'
|
||||||
},
|
},
|
||||||
|
sourcemap:process.env.SOURCE_MAP === 'true',
|
||||||
|
|
||||||
vueRouterMode: 'hash', // available values: 'hash', 'history'
|
vueRouterMode: 'hash', // available values: 'hash', 'history'
|
||||||
// vueRouterBase,
|
// vueRouterBase,
|
||||||
@@ -70,7 +75,7 @@ module.exports = configure(function (/* ctx */) {
|
|||||||
|
|
||||||
// publicPath: '/',
|
// publicPath: '/',
|
||||||
// analyze: true,
|
// analyze: true,
|
||||||
env: { ...dotenv, version },
|
env: { ...dotenv, version ,productName},
|
||||||
// rawDefine: {}
|
// rawDefine: {}
|
||||||
// ignorePublicFolder: true,
|
// ignorePublicFolder: true,
|
||||||
// minify: false,
|
// minify: false,
|
||||||
@@ -89,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 },
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { boot } from 'quasar/wrappers';
|
import { boot } from 'quasar/wrappers';
|
||||||
import axios, { AxiosInstance } from 'axios';
|
import axios, { AxiosInstance } from 'axios';
|
||||||
|
import {router} from 'src/router';
|
||||||
|
|
||||||
declare module '@vue/runtime-core' {
|
declare module '@vue/runtime-core' {
|
||||||
interface ComponentCustomProperties {
|
interface ComponentCustomProperties {
|
||||||
@@ -15,7 +16,26 @@ declare module '@vue/runtime-core' {
|
|||||||
// "export default () => {}" function below (which runs individually
|
// "export default () => {}" function below (which runs individually
|
||||||
// for each client)
|
// for each client)
|
||||||
const api:AxiosInstance = axios.create({ baseURL: process.env.KAB_BACKEND_URL });
|
const api:AxiosInstance = axios.create({ baseURL: process.env.KAB_BACKEND_URL });
|
||||||
|
const token=localStorage.getItem('token')||'';
|
||||||
|
if(token!==''){
|
||||||
|
api.defaults.headers["Authorization"]='Bearer ' + token;
|
||||||
|
}
|
||||||
|
//axios例外キャプチャー
|
||||||
|
api.interceptors.response.use(
|
||||||
|
(response)=>response,
|
||||||
|
(error)=>{
|
||||||
|
if (error.response && error.response.status === 401) {
|
||||||
|
// 認証エラーの場合再ログインする
|
||||||
|
console.error('(; ゚Д゚)/認証エラー(401):', error);
|
||||||
|
localStorage.removeItem('token');
|
||||||
|
router.replace({
|
||||||
|
path:"/login",
|
||||||
|
query:{redirect:router.currentRoute.value.fullPath}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
)
|
||||||
export default boot(({ app }) => {
|
export default boot(({ app }) => {
|
||||||
// for use inside Vue files (Options API) through this.$axios and this.$api
|
// for use inside Vue files (Options API) through this.$axios and this.$api
|
||||||
|
|
||||||
|
|||||||
21
frontend/src/boot/error-handler.ts
Normal file
21
frontend/src/boot/error-handler.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
// src/boot/error-handler.ts
|
||||||
|
import { boot } from 'quasar/wrappers';
|
||||||
|
import { Router } from 'vue-router';
|
||||||
|
import { App } from 'vue';
|
||||||
|
|
||||||
|
export default boot(({ app, router }: { app: App<Element>; router: Router }) => {
|
||||||
|
document.documentElement.lang="ja-JP";
|
||||||
|
app.config.errorHandler = (err: any, instance: any, info: string) => {
|
||||||
|
if (err.response && err.response.status === 401) {
|
||||||
|
// 認証エラーの場合再ログインする
|
||||||
|
console.error('(; ゚Д゚)/認証エラー(401):', err, info);
|
||||||
|
localStorage.removeItem('token');
|
||||||
|
router.replace({
|
||||||
|
path:"/login",
|
||||||
|
query:{redirect:router.currentRoute.value.fullPath}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error('(; ゚Д゚)例外:', err, info);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -1,12 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="q-pa-md">
|
<div class="q-pa-md">
|
||||||
<q-table row-key="name" :selection="type" v-model:selected="selected" :columns="columns" :rows="rows"
|
<div v-if="!isLoaded" class="spinner flex flex-center">
|
||||||
|
<q-spinner color="primary" size="3em" />
|
||||||
|
</div>
|
||||||
|
<q-table v-else row-key="index" :selection="type" v-model:selected="selected" :columns="columns" :rows="rows"
|
||||||
class="action-table"
|
class="action-table"
|
||||||
flat bordered
|
flat bordered
|
||||||
virtual-scroll
|
virtual-scroll
|
||||||
:pagination="pagination"
|
:pagination="pagination"
|
||||||
:rows-per-page-options="[0]"
|
:rows-per-page-options="[0]"
|
||||||
/>
|
:filter="filter"
|
||||||
|
>
|
||||||
|
</q-table>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
@@ -17,23 +22,24 @@ export default {
|
|||||||
name: 'actionSelect',
|
name: 'actionSelect',
|
||||||
props: {
|
props: {
|
||||||
name: String,
|
name: String,
|
||||||
type: String
|
type: String,
|
||||||
|
filter:String
|
||||||
},
|
},
|
||||||
setup() {
|
setup(props) {
|
||||||
const columns = [
|
const isLoaded=ref(false);
|
||||||
{ name: 'name', required: true,label: 'アクション名',align: 'left',field: 'name',sortable: true},
|
const columns = [
|
||||||
{ name: 'desc', align: 'left', label: '説明', field: 'desc', sortable: true },
|
{ name: 'name', required: true,label: 'アクション名',align: 'left',field: 'name',sortable: true},
|
||||||
// { name: 'content', label: '内容', field: 'content', sortable: true }
|
{ name: 'desc', align: 'left', label: '説明', field: 'desc', sortable: true },
|
||||||
]
|
// { name: 'content', label: '内容', field: 'content', sortable: true }
|
||||||
const rows = reactive([])
|
];
|
||||||
|
const rows = reactive([])
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await api.get('http://127.0.0.1:8000/api/kintone/1').then(res =>{
|
const res =await api.get('api/actions');
|
||||||
res.data.forEach((item) =>
|
res.data.forEach((item,index) =>
|
||||||
{
|
{
|
||||||
rows.push({name:item.name,desc:item.desc,content:item.content});
|
rows.push({index,name:item.name,desc:item.title,outputPoints:item.outputpoints,property:item.property});
|
||||||
}
|
});
|
||||||
)
|
isLoaded.value=true;
|
||||||
});
|
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
columns,
|
columns,
|
||||||
@@ -41,7 +47,8 @@ export default {
|
|||||||
selected: ref([]),
|
selected: ref([]),
|
||||||
pagination:ref({
|
pagination:ref({
|
||||||
rowsPerPage:0
|
rowsPerPage:0
|
||||||
})
|
}),
|
||||||
|
isLoaded,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -49,6 +56,7 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.action-table{
|
.action-table{
|
||||||
height: 100%;
|
min-height: 10vh;
|
||||||
|
max-height: 68vh;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
131
frontend/src/components/AppFieldSelectBox.vue
Normal file
131
frontend/src/components/AppFieldSelectBox.vue
Normal 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>
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
import { AppInfo, AppSeed } from './models';
|
import { AppInfo, AppSeed } from './models';
|
||||||
import { ref, defineComponent, watch, onMounted , toRefs } from 'vue';
|
import { ref, defineComponent, watch, onMounted , toRefs } from 'vue';
|
||||||
import { api } from 'boot/axios';
|
import { api } from 'boot/axios';
|
||||||
import { promises } from 'dns';
|
import { useAuthStore } from 'src/stores/useAuthStore';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@@ -44,12 +44,13 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const { app } = toRefs(props);
|
const { app } = toRefs(props);
|
||||||
|
const authStore = useAuthStore();
|
||||||
const appinfo = ref<AppInfo>({
|
const appinfo = ref<AppInfo>({
|
||||||
appId: "",
|
appId: "",
|
||||||
name: "",
|
name: "",
|
||||||
description: ""
|
description: ""
|
||||||
});
|
});
|
||||||
const link= ref('https://mfu07rkgnb7c.cybozu.com/k/' + app.value);
|
const link= ref(`${authStore.currentDomain.kintoneUrl}/k/${app.value}`);
|
||||||
const getAppInfo = async (appId:string|undefined) => {
|
const getAppInfo = async (appId:string|undefined) => {
|
||||||
if(!appId){
|
if(!appId){
|
||||||
return;
|
return;
|
||||||
@@ -59,7 +60,7 @@ export default defineComponent({
|
|||||||
let retry =0;
|
let retry =0;
|
||||||
while(retry<=3 && result && result.appId!==appId){
|
while(retry<=3 && result && result.appId!==appId){
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
const response = await api.get('app', {
|
const response = await api.get('api/v1/app', {
|
||||||
params:{
|
params:{
|
||||||
app: appId
|
app: appId
|
||||||
}
|
}
|
||||||
@@ -73,7 +74,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
watch(app, async (newApp) => {
|
watch(app, async (newApp) => {
|
||||||
appinfo.value = await getAppInfo(newApp);
|
appinfo.value = await getAppInfo(newApp);
|
||||||
link.value = 'https://mfu07rkgnb7c.cybozu.com/k/' + newApp;
|
link.value = `${authStore.currentDomain.kintoneUrl}/k/${newApp}`;
|
||||||
}, { immediate: true });
|
}, { immediate: true });
|
||||||
|
|
||||||
const linkClick=(ev : MouseEvent)=>{
|
const linkClick=(ev : MouseEvent)=>{
|
||||||
@@ -82,7 +83,7 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
onMounted(async ()=>{
|
onMounted(async ()=>{
|
||||||
appinfo.value = await getAppInfo(app.value);
|
appinfo.value = await getAppInfo(app.value);
|
||||||
link.value = 'https://mfu07rkgnb7c.cybozu.com/k/' + app.value;
|
link.value = `${authStore.currentDomain.kintoneUrl}/k/${app.value}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
100
frontend/src/components/AppSelectBox.vue
Normal file
100
frontend/src/components/AppSelectBox.vue
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
<template>
|
||||||
|
<div class="q-px-xs">
|
||||||
|
<div v-if="!isLoaded" class="spinner flex flex-center">
|
||||||
|
<q-spinner color="primary" size="3em" />
|
||||||
|
</div>
|
||||||
|
<q-table v-else class="app-table" :selection="type" row-key="id" v-model:selected="selected" flat bordered
|
||||||
|
virtual-scroll :columns="columns" :rows="rows" :pagination="pagination" :rows-per-page-options="[0]"
|
||||||
|
:filter="filter" style="max-height: 65vh;">
|
||||||
|
<template v-slot:body-cell-description="props">
|
||||||
|
<q-td :props="props">
|
||||||
|
<q-scroll-area class="description-cell">
|
||||||
|
<div v-html="props.row.description"></div>
|
||||||
|
</q-scroll-area>
|
||||||
|
</q-td>
|
||||||
|
</template>
|
||||||
|
</q-table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { ref, onMounted, reactive, watchEffect } from 'vue'
|
||||||
|
import { api } from 'boot/axios';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'AppSelectBox',
|
||||||
|
props: {
|
||||||
|
name: String,
|
||||||
|
type: String,
|
||||||
|
filter: String,
|
||||||
|
updateSelectApp: {
|
||||||
|
type: Function
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const columns = [
|
||||||
|
{ name: 'id', required: true, label: 'ID', align: 'left', field: 'id', sortable: true },
|
||||||
|
{ name: 'name', label: 'アプリ名', field: 'name', sortable: true, align: 'left' },
|
||||||
|
{ name: 'description', label: '概要', field: 'description', align: 'left', sortable: false },
|
||||||
|
{ name: 'createdate', label: '作成日時', field: 'createdate', align: 'left' }
|
||||||
|
]
|
||||||
|
const isLoaded = ref(false);
|
||||||
|
const rows: any[] = reactive([]);
|
||||||
|
const selected = ref([])
|
||||||
|
|
||||||
|
watchEffect(()=>{
|
||||||
|
if (selected.value && selected.value[0] && props.updateSelectApp) {
|
||||||
|
props.updateSelectApp(selected.value[0])
|
||||||
|
}
|
||||||
|
});
|
||||||
|
onMounted(() => {
|
||||||
|
api.get('api/v1/allapps').then(res => {
|
||||||
|
res.data.apps.forEach((item: any) => {
|
||||||
|
rows.push({
|
||||||
|
id: item.appId,
|
||||||
|
name: item.name,
|
||||||
|
description: item.description,
|
||||||
|
createdate: dateFormat(item.createdAt)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
isLoaded.value = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const dateFormat = (dateStr: string) => {
|
||||||
|
const date = new Date(dateStr);
|
||||||
|
const pad = (num: number) => num.toString().padStart(2, '0');
|
||||||
|
const year = date.getFullYear();
|
||||||
|
const month = pad(date.getMonth() + 1);
|
||||||
|
const day = pad(date.getDate());
|
||||||
|
const hours = pad(date.getHours());
|
||||||
|
const minutes = pad(date.getMinutes());
|
||||||
|
const seconds = pad(date.getSeconds());
|
||||||
|
return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
columns,
|
||||||
|
rows,
|
||||||
|
selected,
|
||||||
|
isLoaded,
|
||||||
|
pagination: ref({
|
||||||
|
rowsPerPage: 10
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.description-cell {
|
||||||
|
height: 60px;
|
||||||
|
width: 300px;
|
||||||
|
max-height: 60px;
|
||||||
|
max-width: 300px;
|
||||||
|
white-space: break-spaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner {
|
||||||
|
min-height: 300px;
|
||||||
|
min-width: 400px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
107
frontend/src/components/ConditionEditor/ConditionEditor.vue
Normal file
107
frontend/src/components/ConditionEditor/ConditionEditor.vue
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
<template>
|
||||||
|
<show-dialog v-model:visible="showflg" name="条件エディタ" @close="closeDg" min-width="50vw" min-height="60vh">
|
||||||
|
<template v-slot:toolbar>
|
||||||
|
<q-btn flat round dense icon="more_vert" >
|
||||||
|
<q-menu auto-close anchor="bottom start">
|
||||||
|
<q-list>
|
||||||
|
<q-item clickable @click="copyCondition()">
|
||||||
|
<q-item-section avatar><q-icon name="content_copy" ></q-icon></q-item-section>
|
||||||
|
<q-item-section >コピー</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-item clickable @click="pasteCondition()">
|
||||||
|
<q-item-section avatar><q-icon name="content_paste" ></q-icon></q-item-section>
|
||||||
|
<q-item-section >貼り付け</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-menu>
|
||||||
|
</q-btn>
|
||||||
|
</template>
|
||||||
|
<NodeCondition v-model:conditionTree="tree"></NodeCondition>
|
||||||
|
</show-dialog>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, ref ,watchEffect} from 'vue';
|
||||||
|
import ShowDialog from '../../components/ShowDialog.vue';
|
||||||
|
import NodeCondition from './NodeCondition.vue';
|
||||||
|
import { ConditionTree } from '../../types/Conditions';
|
||||||
|
import { useQuasar } from 'quasar';
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'ConditionObject',
|
||||||
|
components: {
|
||||||
|
ShowDialog,
|
||||||
|
NodeCondition,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
conditionTree: {
|
||||||
|
type: ConditionTree,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
show:{
|
||||||
|
type:Boolean,
|
||||||
|
default:false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits:[
|
||||||
|
"closed",
|
||||||
|
"update:conditionTree",
|
||||||
|
"update:show"
|
||||||
|
],
|
||||||
|
setup(props,context) {
|
||||||
|
const appDg = ref();
|
||||||
|
const $q=useQuasar();
|
||||||
|
const tree = ref(props.conditionTree);
|
||||||
|
const closeDg = (val:string) => {
|
||||||
|
if (val == 'OK') {
|
||||||
|
if(tree.value.root.children.length===0){
|
||||||
|
$q.notify({
|
||||||
|
type: 'negative',
|
||||||
|
message: `条件式を設定してください。`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
context.emit("update:conditionTree",tree.value);
|
||||||
|
}
|
||||||
|
showflg.value=false;
|
||||||
|
context.emit("update:show",false);
|
||||||
|
context.emit("closed",val);
|
||||||
|
};
|
||||||
|
const showflg =ref(props.show);
|
||||||
|
//条件式をコピーする
|
||||||
|
const copyCondition=()=>{
|
||||||
|
if (navigator.clipboard) {
|
||||||
|
const jsonData=tree.value.toJson();
|
||||||
|
navigator.clipboard.writeText(jsonData).then(() => {
|
||||||
|
console.log('Text successfully copied to clipboard');
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
console.error('Error in copying text: ', err);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log('Clipboard API not available');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//条件式を貼り付ける
|
||||||
|
const pasteCondition=async ()=>{
|
||||||
|
try {
|
||||||
|
const text = await navigator.clipboard.readText();
|
||||||
|
console.log('Text from clipboard:', text);
|
||||||
|
tree.value.fromJson(text);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to read text from clipboard: ', err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
watchEffect(() => {
|
||||||
|
showflg.value=props.show;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
tree,
|
||||||
|
appDg,
|
||||||
|
closeDg,
|
||||||
|
showflg,
|
||||||
|
copyCondition,
|
||||||
|
pasteCondition
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
144
frontend/src/components/ConditionEditor/ConditionObject.vue
Normal file
144
frontend/src/components/ConditionEditor/ConditionObject.vue
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
<template>
|
||||||
|
<q-field labelColor="primary" class="condition-object" dense outlined :label="label" :disable="disabled"
|
||||||
|
:clearable="isSelected">
|
||||||
|
<template v-slot:control>
|
||||||
|
<q-chip color="primary" text-color="white" v-if="isSelected && selectedObject.objectType==='field'" :dense="true" class="selected-obj">
|
||||||
|
{{ selectedObject.name }}
|
||||||
|
</q-chip>
|
||||||
|
<q-chip color="info" text-color="white" v-if="isSelected && selectedObject.objectType==='variable'" :dense="true" class="selected-obj">
|
||||||
|
{{ selectedObject.name.name }}
|
||||||
|
</q-chip>
|
||||||
|
<div v-if="isSelected && selectedObject.objectType==='text'">{{ selectedObject?.sharedText }}</div>
|
||||||
|
</template>
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-icon name="search" class="cursor-pointer" @click="showDg" />
|
||||||
|
</template>
|
||||||
|
</q-field>
|
||||||
|
<show-dialog v-model:visible="show" name="設定項目" @close="closeDg" min-width="400px">
|
||||||
|
<!-- <template v-slot:toolbar>
|
||||||
|
<q-input dense debounce="200" v-model="filter" placeholder="検索" clearable>
|
||||||
|
<template v-slot:before>
|
||||||
|
<q-icon name="search" />
|
||||||
|
</template>
|
||||||
|
</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" :options="options" ref="inputRef" />
|
||||||
|
|
||||||
|
</show-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, reactive, ref, watchEffect, computed ,PropType} from 'vue';
|
||||||
|
import ShowDialog from '../ShowDialog.vue';
|
||||||
|
// import ConditionObjects from '../ConditionObjects.vue';
|
||||||
|
import DynamicItemInput from '../DynamicItemInput/DynamicItemInput.vue';
|
||||||
|
import { useFlowEditorStore } from '../../stores/flowEditor';
|
||||||
|
import { IActionFlow, IActionNode, IActionVariable } from '../../types/ActionTypes';
|
||||||
|
import { IDynamicInputConfig } from 'src/types/ComponentTypes';
|
||||||
|
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'ConditionObject',
|
||||||
|
components: {
|
||||||
|
ShowDialog,
|
||||||
|
DynamicItemInput,
|
||||||
|
// ConditionObjects
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
type: Object as PropType<IDynamicInputConfig>,
|
||||||
|
default: () => {
|
||||||
|
return {
|
||||||
|
canInput: false,
|
||||||
|
buttonsConfig: [
|
||||||
|
{ label: 'フィールド', color: 'primary', type: 'FieldAdd' },
|
||||||
|
{ label: '変数', color: 'green', type: 'VariableAdd' },
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
options:
|
||||||
|
{
|
||||||
|
type:Array as PropType< string[]>,
|
||||||
|
default:()=>[]
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props, { emit }) {
|
||||||
|
// const appDg = ref();
|
||||||
|
const inputRef=ref();
|
||||||
|
const show = ref(false);
|
||||||
|
const selectedObject = ref(props.modelValue);
|
||||||
|
const store = useFlowEditorStore();
|
||||||
|
// const sharedText = ref(''); // 共享的文本状态
|
||||||
|
const isSelected = computed(() => {
|
||||||
|
return selectedObject.value?.sharedText !== '';
|
||||||
|
});
|
||||||
|
// const isSelected = computed(()=>{
|
||||||
|
// return selectedObject.value!==null && typeof selectedObject.value === 'object' && ('name' in selectedObject.value)
|
||||||
|
// });
|
||||||
|
let vars: IActionVariable[] = [];
|
||||||
|
if (store.currentFlow !== undefined && store.activeNode !== undefined) {
|
||||||
|
vars = store.currentFlow.getVarNames(store.activeNode);
|
||||||
|
}
|
||||||
|
// const filter=ref('');
|
||||||
|
const showDg = () => {
|
||||||
|
show.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeDg = (val: string) => {
|
||||||
|
if (val == 'OK') {
|
||||||
|
// selectedObject.value = appDg.value.selected[0];
|
||||||
|
selectedObject.value = inputRef.value.selectedObjectRef
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
emit('update:modelValue', selectedObject.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
inputRef,
|
||||||
|
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">
|
||||||
|
.condition-object {
|
||||||
|
min-width: 200px;
|
||||||
|
max-height: 40px;
|
||||||
|
margin: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-obj {
|
||||||
|
margin: 0 2px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
277
frontend/src/components/ConditionEditor/NodeCondition.vue
Normal file
277
frontend/src/components/ConditionEditor/NodeCondition.vue
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
<template>
|
||||||
|
<!-- <q-toolbar class="bg-grey-3" flat dense round icon="menu" aria-label="Menu" @click.stop>
|
||||||
|
<q-toolbar-title>条件エディタ</q-toolbar-title>
|
||||||
|
<q-space></q-space>
|
||||||
|
<q-btn flat round dense icon="info" color="blue" @click="showingCondition=!showingCondition"></q-btn>
|
||||||
|
</q-toolbar> -->
|
||||||
|
<div class="q-pa-md">
|
||||||
|
<q-tree :nodes="[tree.root]" node-key="index" children-key="children"
|
||||||
|
tick-strategy="strict" v-model:ticked="ticked" :expanded="expanded" default-expand-all dense color="primary" >
|
||||||
|
<template v-slot:header-root="prop">
|
||||||
|
<!-- root -->
|
||||||
|
<div class="row items-center" @click.stop>
|
||||||
|
<q-select v-model="prop.node.logicalOperator" :options="logicalOperators" filled outlined dense></q-select>
|
||||||
|
<q-btn flat round dense icon="more_horiz" size="sm" >
|
||||||
|
<q-menu auto-close anchor="top right">
|
||||||
|
<q-list>
|
||||||
|
<q-item clickable @click="addGroup(prop.node, LogicalOperator.AND)">
|
||||||
|
<q-item-section avatar><q-icon name="playlist_add" ></q-icon></q-item-section>
|
||||||
|
<q-item-section>グループの追加</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-item clickable @click="addCondition(prop.node)">
|
||||||
|
<q-item-section avatar><q-icon name="add_circle_outline" ></q-icon></q-item-section>
|
||||||
|
<q-item-section >条件式の追加</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-menu>
|
||||||
|
</q-btn>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-slot:header-generic="prop">
|
||||||
|
<!-- logic group -->
|
||||||
|
<div v-if="prop.node.type !== NodeType.Condition" class="row items-center" @click.stop>
|
||||||
|
<q-select v-model="prop.node.logicalOperator" :options="logicalOperators" :outlined="true" :filled="true" :dense="true"></q-select>
|
||||||
|
<q-btn flat round dense icon="more_horiz" size="sm" >
|
||||||
|
<q-menu auto-close anchor="top right">
|
||||||
|
<q-list>
|
||||||
|
<q-item clickable @click="moveUp(prop.node)">
|
||||||
|
<q-item-section avatar><q-icon name="arrow_upward" ></q-icon></q-item-section>
|
||||||
|
<q-item-section >一つ上に移動</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-item clickable @click="moveDown(prop.node)">
|
||||||
|
<q-item-section avatar><q-icon name="arrow_downward" ></q-icon></q-item-section>
|
||||||
|
<q-item-section >一つ下に移動</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-separator inset/>
|
||||||
|
<q-item clickable @click="addGroup(prop.node, LogicalOperator.AND)">
|
||||||
|
<q-item-section avatar><q-icon name="playlist_add" ></q-icon></q-item-section>
|
||||||
|
<q-item-section >グループ追加</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-item clickable @click="addCondition(prop.node)">
|
||||||
|
<q-item-section avatar><q-icon name="add_circle_outline" ></q-icon></q-item-section>
|
||||||
|
<q-item-section >条件式追加</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-separator inset/>
|
||||||
|
<q-item clickable @click="splitGroup(prop.node)">
|
||||||
|
<q-item-section avatar><q-icon name="playlist_remove" color="negative"></q-icon></q-item-section>
|
||||||
|
<q-item-section >グループ化解除</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-item clickable @click="removeNode(prop.node)">
|
||||||
|
<q-item-section avatar><q-icon name="delete" color="negative"></q-icon></q-item-section>
|
||||||
|
<q-item-section >削除</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-menu>
|
||||||
|
</q-btn>
|
||||||
|
</div>
|
||||||
|
<!-- condition -->
|
||||||
|
<div @click.stop @keypress.stop v-else >
|
||||||
|
<div class="row no-wrap items-center q-my-xs">
|
||||||
|
<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>
|
||||||
|
<ConditionObject v-bind="prop.node" v-model="prop.node.value" :config="rightDynamicItemConfig" class="col-4"
|
||||||
|
:options="objectValueOptions(prop.node?.object?.options)"
|
||||||
|
/>
|
||||||
|
<!-- <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"
|
||||||
|
class="condition-value" :outlined="true" :dense="true" ></q-input> -->
|
||||||
|
<!-- <q-select v-if="prop.node.object && ('options' in prop.node.object)"
|
||||||
|
v-model="prop.node.value"
|
||||||
|
:options="objectValueOptions(prop.node.object.options)"
|
||||||
|
clearable
|
||||||
|
value-key="index"
|
||||||
|
class="condition-value" :outlined="true" :dense="true" ></q-select> -->
|
||||||
|
<q-btn flat round dense icon="more_horiz" size="sm" >
|
||||||
|
<q-menu auto-close anchor="top right">
|
||||||
|
<q-list>
|
||||||
|
<q-item clickable @click="moveUp(prop.node)">
|
||||||
|
<q-item-section avatar><q-icon name="arrow_upward" ></q-icon></q-item-section>
|
||||||
|
<q-item-section >一つ上に移動</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-item clickable @click="moveDown(prop.node)">
|
||||||
|
<q-item-section avatar><q-icon name="arrow_downward" ></q-icon></q-item-section>
|
||||||
|
<q-item-section >一つ下に移動</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-separator inset/>
|
||||||
|
<q-item clickable @click="groupMerge(prop.node)" v-if="canMerge(prop.node)">
|
||||||
|
<q-item-section avatar><q-icon name="playlist_add"></q-icon></q-item-section>
|
||||||
|
<q-item-section >グループ化</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-separator inset/>
|
||||||
|
<q-item clickable @click="removeNode(prop.node)">
|
||||||
|
<q-item-section avatar><q-icon name="delete" color="negative"></q-icon></q-item-section>
|
||||||
|
<q-item-section>削除</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-menu>
|
||||||
|
</q-btn>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</q-tree>
|
||||||
|
<q-tooltip anchor="center middle" v-model="showingCondition" no-parent-event>
|
||||||
|
import { finished } from 'stream';
|
||||||
|
{{ conditionString }}
|
||||||
|
</q-tooltip>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent,ref,reactive, computed, inject } from 'vue';
|
||||||
|
import { INode,ConditionTree,GroupNode,ConditionNode, LogicalOperator,Operator,NodeType } from '../../types/Conditions';
|
||||||
|
import ConditionObject from './ConditionObject.vue';
|
||||||
|
import { IDynamicInputConfig } from 'src/types/ComponentTypes';
|
||||||
|
export default defineComponent( {
|
||||||
|
name: 'NodeCondition',
|
||||||
|
components: {
|
||||||
|
ConditionObject
|
||||||
|
},
|
||||||
|
props:{
|
||||||
|
conditionTree: {
|
||||||
|
type: ConditionTree,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
show:{
|
||||||
|
type:Boolean,
|
||||||
|
default:false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const ticked= ref([]);
|
||||||
|
const showingCondition=ref(false);
|
||||||
|
|
||||||
|
const logicalOperators = computed(()=>{
|
||||||
|
const opts=[];
|
||||||
|
for(const op in LogicalOperator){
|
||||||
|
opts.push(LogicalOperator[op as keyof typeof LogicalOperator]);
|
||||||
|
}
|
||||||
|
return opts;
|
||||||
|
});
|
||||||
|
|
||||||
|
const operatorSet = inject<Array<any>>('Operator')
|
||||||
|
const operators = ref(operatorSet ? operatorSet : Object.values(Operator));
|
||||||
|
const tree = reactive(props.conditionTree);
|
||||||
|
|
||||||
|
const conditionString = computed(()=>{
|
||||||
|
return tree.buildConditionString(tree.root);
|
||||||
|
});
|
||||||
|
|
||||||
|
const objectValueOptions=(options:any):any[]|null=>{
|
||||||
|
if(!options){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const opts:any[] =[];
|
||||||
|
Object.keys(options).forEach((key) =>
|
||||||
|
{
|
||||||
|
const opt=options[key];
|
||||||
|
opts.push(opt);
|
||||||
|
});
|
||||||
|
return opts;
|
||||||
|
};
|
||||||
|
|
||||||
|
const addGroup = (parent:GroupNode, logicOp:LogicalOperator) => {
|
||||||
|
if(!parent){
|
||||||
|
parent=tree.root;
|
||||||
|
}
|
||||||
|
tree.addNode(parent,new GroupNode(logicOp,parent));
|
||||||
|
};
|
||||||
|
|
||||||
|
const addCondition = (parent:GroupNode) => {
|
||||||
|
const newNode = new ConditionNode({},Operator.Equal,'',parent);
|
||||||
|
tree.addNode(parent,newNode);
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeNode = (node:INode) => {
|
||||||
|
tree.removeNode(node);
|
||||||
|
};
|
||||||
|
|
||||||
|
const moveUp =(node:INode)=>{
|
||||||
|
tree.moveNode(node,'up');
|
||||||
|
}
|
||||||
|
|
||||||
|
const moveDown =(node:INode)=>{
|
||||||
|
tree.moveNode(node,'down');
|
||||||
|
}
|
||||||
|
|
||||||
|
const getConditionJson=()=>{
|
||||||
|
return tree.toJson();
|
||||||
|
}
|
||||||
|
//JsonからConditionTreeのインスタンスを作成
|
||||||
|
const LoadCondition=()=>{
|
||||||
|
tree.fromJson(conditionString.value);
|
||||||
|
}
|
||||||
|
//グループ化
|
||||||
|
const groupMerge=(node:INode)=>{
|
||||||
|
const checkedNodes:INode[]=[];
|
||||||
|
const checkedIndexs:number[] = ticked.value;
|
||||||
|
checkedIndexs.forEach(index => {
|
||||||
|
const node = tree.findByIndex(index);
|
||||||
|
if(node){
|
||||||
|
checkedNodes.push(node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tree.createGroupNode(node,checkedNodes,LogicalOperator.AND);
|
||||||
|
ticked.value=[];
|
||||||
|
}
|
||||||
|
//グループ化可能かをチェックする
|
||||||
|
const canMerge =(node:INode)=>{
|
||||||
|
const checkedIndexs:number[] = ticked.value;
|
||||||
|
const findNode = checkedIndexs.find(index=>node.index===index);
|
||||||
|
console.log("findNode=>",findNode!==undefined,findNode);
|
||||||
|
return findNode!==undefined;
|
||||||
|
}
|
||||||
|
//グループ化解散
|
||||||
|
const splitGroup=(node:INode)=>{
|
||||||
|
tree.dissolveGroupNode(node as GroupNode);
|
||||||
|
ticked.value=[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const expanded=computed(()=>tree.getGroups(tree.root));
|
||||||
|
// addCondition(tree.root);
|
||||||
|
const leftDynamicItemConfig = inject<IDynamicInputConfig>('leftDynamicItemConfig');
|
||||||
|
const rightDynamicItemConfig = inject<IDynamicInputConfig>('rightDynamicItemConfig');
|
||||||
|
|
||||||
|
return {
|
||||||
|
leftDynamicItemConfig,
|
||||||
|
rightDynamicItemConfig,
|
||||||
|
showingCondition,
|
||||||
|
conditionString,
|
||||||
|
tree,
|
||||||
|
ticked,
|
||||||
|
logicalOperators,
|
||||||
|
operators,
|
||||||
|
addGroup,
|
||||||
|
addCondition,
|
||||||
|
removeNode,
|
||||||
|
moveUp,
|
||||||
|
moveDown,
|
||||||
|
LogicalOperator,
|
||||||
|
Operator,
|
||||||
|
NodeType,
|
||||||
|
getConditionJson,
|
||||||
|
LoadCondition,
|
||||||
|
objectValueOptions,
|
||||||
|
expanded,
|
||||||
|
canMerge,
|
||||||
|
groupMerge,
|
||||||
|
splitGroup
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.condition-value{
|
||||||
|
min-width: 200px;
|
||||||
|
max-height: 40px;
|
||||||
|
margin: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operator{
|
||||||
|
min-width: 150px;
|
||||||
|
max-height: 40px;
|
||||||
|
margin: 0 2px;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
font-size: 12pt;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
63
frontend/src/components/ConditionObjects.vue
Normal file
63
frontend/src/components/ConditionObjects.vue
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<template>
|
||||||
|
<div class="q-gutter-y-md" style="max-width: 600px;">
|
||||||
|
<q-card >
|
||||||
|
<q-tabs
|
||||||
|
v-model="tab"
|
||||||
|
dense
|
||||||
|
class="text-grey"
|
||||||
|
active-color="white"
|
||||||
|
active-bg-color="primary"
|
||||||
|
indicator-color="primary"
|
||||||
|
align="justify"
|
||||||
|
narrow-indicator
|
||||||
|
>
|
||||||
|
<q-tab name="fields" label="フィールド"></q-tab>
|
||||||
|
<q-tab name="vars" label="変数"></q-tab>
|
||||||
|
</q-tabs>
|
||||||
|
|
||||||
|
<q-separator></q-separator>
|
||||||
|
|
||||||
|
<q-tab-panels v-model="tab" animated>
|
||||||
|
<q-tab-panel name="fields">
|
||||||
|
<field-list v-model="selected" type="single" :filter="filter" :appId="sourceApp ? sourceApp :appId " :fields="sourceFields"></field-list>
|
||||||
|
</q-tab-panel>
|
||||||
|
|
||||||
|
<q-tab-panel name="vars" >
|
||||||
|
<variable-list v-model="selected" type="single" :vars="vars"></variable-list>
|
||||||
|
</q-tab-panel>
|
||||||
|
</q-tab-panels>
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { ref, onMounted, reactive, inject } from 'vue'
|
||||||
|
import FieldList from './FieldList.vue';
|
||||||
|
import VariableList from './VariableList.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ConditionObjects',
|
||||||
|
components:{
|
||||||
|
FieldList,
|
||||||
|
VariableList
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
name: String,
|
||||||
|
type: String,
|
||||||
|
appId: Number,
|
||||||
|
vars: Array,
|
||||||
|
filter:String
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const selected = ref([]);
|
||||||
|
console.log(selected);
|
||||||
|
|
||||||
|
return {
|
||||||
|
sourceFields : inject('sourceFields'),
|
||||||
|
sourceApp : inject('sourceApp'),
|
||||||
|
tab: ref('fields'),
|
||||||
|
selected
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
style="max-width: 400px"
|
style="max-width: 400px"
|
||||||
:url="uploadUrl"
|
:url="uploadUrl"
|
||||||
:label="title"
|
:label="title"
|
||||||
|
:headers="headers"
|
||||||
accept=".csv,.xlsx"
|
accept=".csv,.xlsx"
|
||||||
v-on:rejected="onRejected"
|
v-on:rejected="onRejected"
|
||||||
v-on:uploaded="onUploadFinished"
|
v-on:uploaded="onUploadFinished"
|
||||||
@@ -15,7 +16,10 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { createUploaderComponent, useQuasar } from 'quasar';
|
import { createUploaderComponent, useQuasar } from 'quasar';
|
||||||
|
import { useAuthStore } from 'src/stores/useAuthStore';
|
||||||
|
import { ref } from 'vue';
|
||||||
const $q=useQuasar();
|
const $q=useQuasar();
|
||||||
|
const authStore = useAuthStore();
|
||||||
const emit =defineEmits(['uploaded']);
|
const emit =defineEmits(['uploaded']);
|
||||||
/**
|
/**
|
||||||
* ファイルアップロードを拒否する時の処理
|
* ファイルアップロードを拒否する時の処理
|
||||||
@@ -67,9 +71,12 @@
|
|||||||
title: string;
|
title: string;
|
||||||
uploadUrl:string;
|
uploadUrl:string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const headers = ref([{name:"Authorization",value:'Bearer ' + authStore.token}]);
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
title:"設計書から導入する(csv or excel)",
|
title:"設計書から導入する(csv or excel)",
|
||||||
uploadUrl: `${process.env.KAB_BACKEND_URL}createappfromexcel`
|
uploadUrl: `${process.env.KAB_BACKEND_URL}api/v1/createappfromexcel?format=1`
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|||||||
@@ -8,24 +8,25 @@ import { ref,onMounted,reactive } from 'vue'
|
|||||||
import { api } from 'boot/axios';
|
import { api } from 'boot/axios';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AppSelect',
|
name: 'DomainSelect',
|
||||||
props: {
|
props: {
|
||||||
name: String,
|
name: String,
|
||||||
type: String
|
type: String
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const columns = [
|
const columns = [
|
||||||
{ name: 'id', required: true,label: 'アプリID',align: 'left',field: 'id',sortable: true},
|
{ name: 'id'},
|
||||||
{ name: 'name', align: 'center', label: 'アプリ名', field: 'name', sortable: true },
|
{ name: 'tenantid', required: true,label: 'テナント',align: 'left',field: 'tenantid',sortable: true},
|
||||||
{ name: 'creator', label: '作成者', field: 'creator', sortable: true },
|
{ name: 'name', align: 'center', label: 'ドメイン', field: 'name', sortable: true },
|
||||||
{ name: 'createdate', label: '作成日時', field: 'createdate' }
|
{ name: 'url', label: 'URL', field: 'url', sortable: true },
|
||||||
|
{ name: 'kintoneuser', label: 'アカウント', field: 'kintoneuser' }
|
||||||
]
|
]
|
||||||
const rows = reactive([])
|
const rows = reactive([])
|
||||||
onMounted( () => {
|
onMounted( () => {
|
||||||
api.get('allapps').then(res =>{
|
api.get(`api/domains/1`).then(res =>{
|
||||||
res.data.apps.forEach((item) =>
|
res.data.forEach((item) =>
|
||||||
{
|
{
|
||||||
rows.push({id:item.appId,name:item.name,creator:item.creator.name,createdate:item.createdAt});
|
rows.push({id:item.id,tenantid:item.tenantid,name:item.name,url:item.url,kintoneuser:item.kintoneuser});
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
43
frontend/src/components/DomainSelector.vue
Normal file
43
frontend/src/components/DomainSelector.vue
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<template>
|
||||||
|
<q-btn-dropdown
|
||||||
|
color="primay"
|
||||||
|
push
|
||||||
|
flat
|
||||||
|
no-caps
|
||||||
|
icon="share"
|
||||||
|
size="md"
|
||||||
|
:label="userStore.currentDomain.domainName"
|
||||||
|
>
|
||||||
|
<q-list>
|
||||||
|
<q-item v-for="domain in domains" :key="domain.domainName"
|
||||||
|
clickable v-close-popup @click="onItemClick(domain)">
|
||||||
|
<q-item-section side>
|
||||||
|
<q-icon name="share" size="sm" color="orange" text-color="white"></q-icon>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>{{domain.domainName}}</q-item-label>
|
||||||
|
<q-item-label caption>{{domain.kintoneUrl}}</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-btn-dropdown>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts" >
|
||||||
|
import { IDomainInfo } from 'src/types/ActionTypes';
|
||||||
|
import { useAuthStore,IUserState } from 'stores/useAuthStore';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
const userStore = useAuthStore();
|
||||||
|
const domains = ref<IDomainInfo[]>([]);
|
||||||
|
(async ()=>{
|
||||||
|
domains.value = await userStore.getUserDomains();
|
||||||
|
})();
|
||||||
|
|
||||||
|
const onItemClick=(domain:IDomainInfo)=>{
|
||||||
|
console.log(domain);
|
||||||
|
userStore.setCurrentDomain(domain);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
|
||||||
|
</style>
|
||||||
161
frontend/src/components/DynamicItemInput/DynamicItemInput.vue
Normal file
161
frontend/src/components/DynamicItemInput/DynamicItemInput.vue
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
<template>
|
||||||
|
<div class="q-mx-md" style="max-width: 600px;">
|
||||||
|
<!-- <q-card> -->
|
||||||
|
<div class="q-mb-md">
|
||||||
|
<q-input ref="inputRef" v-if="!optionsRef|| optionsRef.length===0"
|
||||||
|
outlined dense debounce="200" @update:model-value="updateSharedText"
|
||||||
|
v-model="sharedText" :readonly="!canInputFlag" autogrow>
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-btn flat round padding="none" icon="cancel" @click="clearSharedText" color="grey-6" />
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
<q-select v-if="optionsRef && optionsRef.length>0"
|
||||||
|
:model-value="sharedText"
|
||||||
|
:options="optionsRef"
|
||||||
|
clearable
|
||||||
|
value-key="index"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
use-input
|
||||||
|
hide-selected
|
||||||
|
input-debounce="10"
|
||||||
|
fill-input
|
||||||
|
@input-value="setValue"
|
||||||
|
@clear="sharedText=null"
|
||||||
|
hide-dropdown-icon
|
||||||
|
:readonly="!canInputFlag"
|
||||||
|
>
|
||||||
|
</q-select>
|
||||||
|
</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,PropType } from 'vue';
|
||||||
|
import FieldAdd from './FieldAdd.vue';
|
||||||
|
import VariableAdd from './VariableAdd.vue';
|
||||||
|
// import FunctionAdd from './FunctionAdd.vue';
|
||||||
|
import ShowDialog from '../ShowDialog.vue';
|
||||||
|
import { IButtonConfig } from 'src/types/ComponentTypes';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'DynamicItemInput',
|
||||||
|
components: {
|
||||||
|
FieldAdd,
|
||||||
|
VariableAdd,
|
||||||
|
// FunctionAdd,
|
||||||
|
ShowDialog
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
canInput: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
appId: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
selectedObject: {
|
||||||
|
default: {}
|
||||||
|
},
|
||||||
|
options:{
|
||||||
|
type:Array as PropType< string[]>
|
||||||
|
},
|
||||||
|
buttonsConfig: {
|
||||||
|
type: Array as PropType<IButtonConfig[]>,
|
||||||
|
default: () => [
|
||||||
|
{ label: 'フィールド', color: 'primary', type: 'FieldAdd' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const filter = ref('');
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
const currentDialogName = ref('');
|
||||||
|
const selectedObjectRef = ref(props.selectedObject);
|
||||||
|
const currentComponent = ref('FieldAdd');
|
||||||
|
const sharedText = ref(props.selectedObject?.sharedText ?? '');
|
||||||
|
const inputRef = ref();
|
||||||
|
const canInputFlag = ref(props.canInput);
|
||||||
|
const editable = ref(false);
|
||||||
|
|
||||||
|
const openDialog = (button: IButtonConfig) => {
|
||||||
|
currentDialogName.value = button.label;
|
||||||
|
currentComponent.value = button.type;
|
||||||
|
dialogVisible.value = true;
|
||||||
|
editable.value = canInputFlag.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeDialog = () => {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelect = (value:any) => {
|
||||||
|
|
||||||
|
if (value && value._t && (value._t as string).length > 0) {
|
||||||
|
canInputFlag.value = editable.value;
|
||||||
|
}
|
||||||
|
selectedObjectRef.value={ sharedText: value._t, ...value };
|
||||||
|
sharedText.value = `${value._t}`;
|
||||||
|
// emit('update:selectedObject', { sharedText: sharedText.value, ...value });
|
||||||
|
dialogVisible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearSharedText = () => {
|
||||||
|
sharedText.value = '';
|
||||||
|
selectedObjectRef.value={};
|
||||||
|
canInputFlag.value = true;
|
||||||
|
// emit('update:selectedObject', {});
|
||||||
|
}
|
||||||
|
const updateSharedText = (value:string) => {
|
||||||
|
sharedText.value = value;
|
||||||
|
selectedObjectRef.value= { sharedText: value,objectType:'text' }
|
||||||
|
// emit('update:selectedObject', { ...props.selectedObject, sharedText: value,objectType:'text' });
|
||||||
|
}
|
||||||
|
const setValue=(value:string)=>{
|
||||||
|
sharedText.value = value;
|
||||||
|
if(selectedObjectRef.value.sharedText!==value){
|
||||||
|
selectedObjectRef.value= { sharedText: value,objectType:'text' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const optionsRef=ref(props.options);
|
||||||
|
|
||||||
|
return {
|
||||||
|
filter,
|
||||||
|
dialogVisible,
|
||||||
|
currentDialogName,
|
||||||
|
currentComponent,
|
||||||
|
canInputFlag,
|
||||||
|
openDialog,
|
||||||
|
closeDialog,
|
||||||
|
handleSelect,
|
||||||
|
clearSharedText,
|
||||||
|
updateSharedText,
|
||||||
|
setValue,
|
||||||
|
sharedText,
|
||||||
|
inputRef,
|
||||||
|
optionsRef,
|
||||||
|
selectedObjectRef
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
41
frontend/src/components/DynamicItemInput/FieldAdd.vue
Normal file
41
frontend/src/components/DynamicItemInput/FieldAdd.vue
Normal 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>
|
||||||
42
frontend/src/components/DynamicItemInput/VariableAdd.vue
Normal file
42
frontend/src/components/DynamicItemInput/VariableAdd.vue
Normal 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>
|
||||||
58
frontend/src/components/FieldList.vue
Normal file
58
frontend/src/components/FieldList.vue
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<template>
|
||||||
|
<div class="q-pa-md">
|
||||||
|
<q-table flat bordered :loading="!isLoaded" row-key="name" :selection="type" :selected="modelValue"
|
||||||
|
@update:selected="$emit('update:modelValue', $event)" :filter="filter" :columns="columns" :rows="rows" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { useAsyncState } from '@vueuse/core';
|
||||||
|
import { api } from 'boot/axios';
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'FieldList',
|
||||||
|
props: {
|
||||||
|
fields: Array,
|
||||||
|
name: String,
|
||||||
|
type: String,
|
||||||
|
appId: Number,
|
||||||
|
modelValue: Array,
|
||||||
|
filter: String
|
||||||
|
},
|
||||||
|
emits: [
|
||||||
|
'update:modelValue'
|
||||||
|
],
|
||||||
|
setup(props) {
|
||||||
|
// const rows = ref([]);
|
||||||
|
// const isLoaded = ref(false);
|
||||||
|
const columns = [
|
||||||
|
{ name: 'name', required: true, label: 'フィールド名', align: 'left', field: 'name', sortable: true },
|
||||||
|
{ name: 'code', label: 'フィールドコード', align: 'left', field: 'code', sortable: true },
|
||||||
|
{ name: 'type', label: 'フィールドタイプ', align: 'left', field: 'type', sortable: true }
|
||||||
|
]
|
||||||
|
|
||||||
|
const { state : rows, isReady: isLoaded, isLoading } = useAsyncState((args) => {
|
||||||
|
if (props.fields && Object.keys(props.fields).length > 0) {
|
||||||
|
return props.fields.map(f => ({ name: f.label, objectType: 'field', ...f }));
|
||||||
|
} else {
|
||||||
|
return api.get('api/v1/appfields', {
|
||||||
|
params: {
|
||||||
|
app: props.appId
|
||||||
|
}
|
||||||
|
}).then(res => {
|
||||||
|
console.log(res);
|
||||||
|
return Object.values(res.data.properties).map(f => ({ name: f.label, objectType: 'field', ...f }));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [{ name: '', objectType: '', type: '', code: '', label: '' }])
|
||||||
|
|
||||||
|
return {
|
||||||
|
columns,
|
||||||
|
rows,
|
||||||
|
// selected: ref([]),
|
||||||
|
isLoaded
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -1,45 +1,92 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="q-pa-md">
|
<div class="q-px-md" style=" min-width: 50vw; max-width: 85vw;">
|
||||||
<q-table :title="name+'一覧'" row-key="name" :selection="type" v-model:selected="selected" :columns="columns" :rows="rows" />
|
<div v-if="!isLoaded" class="spinner flex flex-center">
|
||||||
|
<q-spinner color="primary" size="3em" />
|
||||||
|
</div>
|
||||||
|
<q-table flat bordered v-else row-key="name" :selection="type" v-model:selected="selected" :columns="columns"
|
||||||
|
:rows="rows" :pagination="pageSetting" :filter="filter" style="max-height: 55vh;"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { ref,onMounted,reactive } from 'vue'
|
import { ref, onMounted, reactive, watchEffect } from 'vue'
|
||||||
import { api } from 'boot/axios';
|
import { api } from 'boot/axios';
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'fieldSelect',
|
name: 'fieldSelect',
|
||||||
props: {
|
props: {
|
||||||
name: String,
|
name: String,
|
||||||
type: String,
|
type: {
|
||||||
appId:Number
|
type: String,
|
||||||
|
default: 'single'
|
||||||
|
},
|
||||||
|
appId: Number,
|
||||||
|
not_page: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
selectedFields:{
|
||||||
|
type:Array,
|
||||||
|
default:()=>[]
|
||||||
|
},
|
||||||
|
fieldTypes:{
|
||||||
|
type:Array,
|
||||||
|
default:()=>[]
|
||||||
|
},
|
||||||
|
filter: String,
|
||||||
|
updateSelectFields: {
|
||||||
|
type: Function
|
||||||
|
},
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const columns = [
|
const isLoaded = ref(false);
|
||||||
{ name: 'name', required: true,label: 'フィールド名',align: 'left',field: row=>row.name,sortable: true},
|
const columns = [
|
||||||
{ name: 'code', label: 'フィールドコード', align: 'left',field: 'code', sortable: true },
|
{ name: 'name', required: true, label: 'フィールド名', align: 'left', field: row => row.name, sortable: true },
|
||||||
{ name: 'type', label: 'フィールドタイプ', align: 'left',field: 'type', sortable: true }
|
{ name: 'code', label: 'フィールドコード', align: 'left', field: 'code', sortable: true },
|
||||||
]
|
{ name: 'type', label: 'フィールドタイプ', align: 'left', field: 'type', sortable: true }
|
||||||
const rows = reactive([])
|
]
|
||||||
onMounted( () => {
|
const pageSetting = ref({
|
||||||
api.get('appfields', {
|
sortBy: 'desc',
|
||||||
params:{
|
descending: false,
|
||||||
app: props.appId
|
page: 1,
|
||||||
}
|
rowsPerPage: props.not_page ? 0 : 5
|
||||||
}).then(res =>{
|
// rowsNumber: xx if getting data from a server
|
||||||
let fields = res.data.properties;
|
});
|
||||||
console.log(fields);
|
const rows = reactive([]);
|
||||||
Object.keys(fields).forEach((key) =>
|
const selected = ref(props.selectedFields && props.selectedFields.length>0?props.selectedFields:[]);
|
||||||
{
|
|
||||||
rows.push({name:fields[key].label,code:fields[key].code,type:fields[key].type});
|
onMounted(async () => {
|
||||||
|
const url = props.fieldTypes.includes('SPACER')?'api/v1/allfields':'api/v1/appfields';
|
||||||
|
const res = await api.get(url, {
|
||||||
|
params: {
|
||||||
|
app: props.appId
|
||||||
}
|
}
|
||||||
)
|
|
||||||
});
|
});
|
||||||
|
let fields = res.data.properties;
|
||||||
|
Object.keys(fields).forEach((key) => {
|
||||||
|
const fld = fields[key];
|
||||||
|
if(props.fieldTypes.length===0 || props.fieldTypes.includes(fld.type)){
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
|
||||||
|
watchEffect(()=>{
|
||||||
|
if (selected.value && selected.value[0] && props.updateSelectFields) {
|
||||||
|
props.updateSelectFields(selected)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
columns,
|
columns,
|
||||||
rows,
|
rows,
|
||||||
selected: ref([]),
|
selected,
|
||||||
|
isLoaded,
|
||||||
|
pageSetting
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="q-pa-md q-gutter-sm">
|
<!-- <div class="q-pa-md q-gutter-sm" > -->
|
||||||
<q-dialog :model-value="visible" persistent>
|
<q-dialog :model-value="visible" persistent bordered >
|
||||||
<q-card style="min-width: 350px">
|
<q-card class="" style="min-width: 40vw; max-width: 80vw; max-height: 95vh;" :style="cardStyle">
|
||||||
<q-card-section>
|
<q-toolbar class="bg-grey-4">
|
||||||
<div class="text-h6">{{ name }}選択</div>
|
<q-toolbar-title>{{ name }}</q-toolbar-title>
|
||||||
</q-card-section>
|
<q-space></q-space>
|
||||||
|
<slot name="toolbar"></slot>
|
||||||
<q-card-section class="q-pt-none">
|
<q-btn flat round dense icon="close" @click="CloseDialogue('Cancel')" />
|
||||||
|
</q-toolbar>
|
||||||
|
<q-card-section class="q-mt-md" :style="sectionStyle">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-actions align="right" class="text-primary">
|
<q-card-actions align="right" class="text-primary">
|
||||||
@@ -15,15 +17,19 @@
|
|||||||
</q-card-actions>
|
</q-card-actions>
|
||||||
</q-card>
|
</q-card>
|
||||||
</q-dialog>
|
</q-dialog>
|
||||||
</div>
|
<!-- </div> -->
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
import {computed} from 'vue'
|
||||||
export default {
|
export default {
|
||||||
name: 'ShowDialog',
|
name: 'ShowDialog',
|
||||||
props: {
|
props: {
|
||||||
name:String,
|
name:String,
|
||||||
visible: Boolean,
|
visible: Boolean,
|
||||||
|
width:String,
|
||||||
|
height:String,
|
||||||
|
minWidth:String,
|
||||||
|
minHeight:String
|
||||||
},
|
},
|
||||||
emits: [
|
emits: [
|
||||||
'close'
|
'close'
|
||||||
@@ -34,8 +40,20 @@ export default {
|
|||||||
context.emit('close', val);
|
context.emit('close', val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cardStyle = computed(() => ({
|
||||||
|
minWidth: props.minWidth,
|
||||||
|
width: props.width
|
||||||
|
}));
|
||||||
|
|
||||||
|
const sectionStyle = computed(() => ({
|
||||||
|
height: props.height,
|
||||||
|
minHeight: props.minHeight
|
||||||
|
}));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
CloseDialogue
|
CloseDialogue,
|
||||||
|
cardStyle,
|
||||||
|
sectionStyle
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
61
frontend/src/components/VariableList.vue
Normal file
61
frontend/src/components/VariableList.vue
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<template>
|
||||||
|
<div class="q-pa-md">
|
||||||
|
<q-table flat bordered row-key="id" :selection="type" :selected="modelValue" :filter="filter"
|
||||||
|
@update:selected="$emit('update:modelValue', $event)" :columns="columns" :rows="rows" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { PropType, reactive } from 'vue';
|
||||||
|
import { IActionVariable } from '../types/ActionTypes';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'VariableList',
|
||||||
|
props: {
|
||||||
|
name: String,
|
||||||
|
type: String,
|
||||||
|
vars: {
|
||||||
|
type: Array as PropType<IActionVariable[]>,
|
||||||
|
reqired: true,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
modelValue: Array,
|
||||||
|
filter: String
|
||||||
|
},
|
||||||
|
emits: [
|
||||||
|
'update:modelValue'
|
||||||
|
],
|
||||||
|
setup(props) {
|
||||||
|
const variableName = (field) => {
|
||||||
|
const name = field.name;
|
||||||
|
return name.name;
|
||||||
|
}
|
||||||
|
const columns = [
|
||||||
|
{ name: 'actionName', label: 'アクション名', align: 'left', field: 'actionName', sortable: true },
|
||||||
|
{ name: 'displayName', label: '変数表示名', align: 'left', field: 'displayName', sortable: true },
|
||||||
|
{ name: 'name', label: '変数名', align: 'left', field: variableName, required: true, sortable: true }
|
||||||
|
];
|
||||||
|
|
||||||
|
const rows = props.vars.flatMap((v) => {
|
||||||
|
if (v.name.vars && v.name.vars.length > 0) {
|
||||||
|
return v.name.vars
|
||||||
|
.filter(o => o.vName && o.logicalOperator && o.field)
|
||||||
|
.map(o => ({
|
||||||
|
id: uuidv4(),
|
||||||
|
objectType: 'variable',
|
||||||
|
name: { name: `${v.name.name}.${o.vName}` },
|
||||||
|
actionName: v.name.actionName,
|
||||||
|
displayName: v.name.displayName
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
return [{ objectType: 'variable', ...v }];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
columns,
|
||||||
|
rows: reactive(rows)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -1,11 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div class="row app-box">
|
||||||
class="row"
|
|
||||||
style="
|
|
||||||
border-radius: 2px;
|
|
||||||
box-shadow: rgba(255, 255, 255, 0.1) 0px 0px 0px 1px inset,
|
|
||||||
rgba(0, 0, 0, 0.3) 0px 0px 0px 1px;
|
|
||||||
">
|
|
||||||
<q-icon
|
<q-icon
|
||||||
class="self-center q-ma-sm"
|
class="self-center q-ma-sm"
|
||||||
name="widgets"
|
name="widgets"
|
||||||
@@ -13,7 +7,9 @@
|
|||||||
style="font-size: 2em"
|
style="font-size: 2em"
|
||||||
/>
|
/>
|
||||||
<div class="col-7 self-center ellipsis">
|
<div class="col-7 self-center ellipsis">
|
||||||
{{ selectedApp.name }}
|
<a :href="!store.appInfo?'':`${authStore.currentDomain.kintoneUrl}/k/${store.appInfo?.appId}`" target="_blank" title="Kiontoneへ">
|
||||||
|
{{ store.appInfo?.name }}
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="self-center">
|
<div class="self-center">
|
||||||
<q-btn
|
<q-btn
|
||||||
@@ -26,8 +22,15 @@
|
|||||||
></q-btn>
|
></q-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ShowDialog v-model:visible="showSelectApp" name="アプリ" @close="closeDg">
|
<ShowDialog v-model:visible="showSelectApp" name="アプリ選択" @close="closeDg" min-width="50vw" min-height="50vh" >
|
||||||
<AppSelect ref="appDg" name="アプリ" type="single"></AppSelect>
|
<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>
|
</ShowDialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -35,38 +38,37 @@
|
|||||||
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';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'AppSelector',
|
name: 'AppSelector',
|
||||||
emits:[
|
emits:[
|
||||||
"appSelected"
|
"appSelected"
|
||||||
],
|
],
|
||||||
components:{
|
components:{
|
||||||
AppSelect,
|
AppSelectBox,
|
||||||
ShowDialog
|
ShowDialog
|
||||||
},
|
},
|
||||||
setup(props, context) {
|
setup(props, context) {
|
||||||
|
|
||||||
const store = useFlowEditorStore();
|
const store = useFlowEditorStore();
|
||||||
|
const authStore=useAuthStore();
|
||||||
const appDg = ref();
|
const appDg = ref();
|
||||||
const showSelectApp=ref(false);
|
const showSelectApp=ref(false);
|
||||||
const selectedApp =ref<AppInfo>({
|
|
||||||
appId:"",
|
|
||||||
name:"",
|
|
||||||
});
|
|
||||||
const closeDg=(val :any)=>{
|
const closeDg=(val :any)=>{
|
||||||
showSelectApp.value=false;
|
showSelectApp.value=false;
|
||||||
console.log("Dialog closed->",val);
|
console.log("Dialog closed->",val);
|
||||||
if (val == 'OK') {
|
if (val == 'OK') {
|
||||||
const data = appDg.value.selected[0];
|
const data = appDg.value.selected[0];
|
||||||
console.log(data);
|
console.log(data);
|
||||||
selectedApp.value={
|
const appInfo={
|
||||||
appId:data.id ,
|
appId:data.id ,
|
||||||
name:data.name
|
name:data.name
|
||||||
};
|
};
|
||||||
store.setApp(selectedApp.value);
|
store.setApp(appInfo);
|
||||||
store.setFlow();
|
store.loadFlow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const showAppDialog=()=>{
|
const showAppDialog=()=>{
|
||||||
@@ -74,12 +76,19 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
store,
|
store,
|
||||||
selectedApp,
|
authStore,
|
||||||
showSelectApp,
|
showSelectApp,
|
||||||
showAppDialog,
|
showAppDialog,
|
||||||
closeDg,
|
closeDg,
|
||||||
appDg
|
appDg,
|
||||||
|
filter:ref('')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.app-box{
|
||||||
|
border-radius: 2px;
|
||||||
|
box-shadow: rgba(255, 255, 255, 0.1) 0px 0px 0px 1px inset,rgba(0, 0, 0, 0.3) 0px 0px 0px 1px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,89 +1,178 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="q-pa-md q-gutter-sm">
|
<!-- <div class="q-pa-md q-gutter-sm"> -->
|
||||||
<q-tree
|
<q-tree :nodes="store.eventTree.screens" node-key="eventId" children-key="events" no-connectors
|
||||||
:nodes="store.eventTree.screens"
|
v-model:expanded="store.expandedScreen" :dense="true" :ref="tree">
|
||||||
node-key="label"
|
<template v-slot:header-EVENT="prop">
|
||||||
children-key="events"
|
<div :ref="prop.node.eventId" class="row col items-center no-wrap event-node" @click="onSelected(prop.node)">
|
||||||
no-connectors
|
<q-icon v-if="prop.node.eventId" name="play_circle" :color="prop.node.hasFlow ? 'green' : 'grey'" size="16px"
|
||||||
v-model:expanded="expanded"
|
class="q-mr-sm">
|
||||||
:dense="true"
|
</q-icon>
|
||||||
>
|
<div class="no-wrap"
|
||||||
<template v-slot:default-header="prop">
|
:class="selectedEvent && prop.node.eventId === selectedEvent.eventId ? 'selected-node' : ''">{{
|
||||||
<div class="row col items-start no-wrap event-node" @click="onSelected(prop.node)">
|
prop.node.label }}</div>
|
||||||
<q-icon v-if="prop.node.eventId"
|
<q-space></q-space>
|
||||||
name="play_circle"
|
<!-- <q-icon v-if="prop.node.hasFlow" name="delete" color="negative" size="16px" class="q-mr-sm"></q-icon> -->
|
||||||
:color="prop.node.hasFlow?'green':'grey'"
|
</div>
|
||||||
size="16px" class="q-mr-sm">
|
</template>
|
||||||
</q-icon>
|
<template v-slot:header-CHANGE="prop">
|
||||||
<div class="no-wrap" :class="selectedEvent && prop.node.eventId===selectedEvent.eventId?'selected-node':''">{{ prop.node.label }}</div>
|
<div class="row col items-start no-wrap event-node">
|
||||||
</div>
|
<div class="no-wrap"
|
||||||
</template>
|
:class="selectedEvent && prop.node.eventId === selectedEvent.eventId ? 'selected-node' : ''"
|
||||||
</q-tree>
|
>{{ prop.node.label }}</div>
|
||||||
</div>
|
<q-space></q-space>
|
||||||
|
<q-icon name="add_circle" color="primary" size="16px" class="q-mr-sm"
|
||||||
|
@click="addChangeEvent(prop.node)"></q-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-slot:header-DELETABLE="prop">
|
||||||
|
<div class="row col items-start event-node" @click="onSelected(prop.node)">
|
||||||
|
<q-icon v-if="prop.node.eventId" name="play_circle" :color="prop.node.hasFlow ? 'green' : 'grey'" size="16px" class="q-mr-sm" />
|
||||||
|
<div class="no-wrap" :class="selectedEvent && prop.node.eventId === selectedEvent.eventId ? 'selected-node' : ''" >{{ prop.node.label }}</div>
|
||||||
|
<q-space></q-space>
|
||||||
|
<q-icon name="delete_forever" color="negative" size="16px" @click="deleteEvent(prop.node)"></q-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</q-tree>
|
||||||
|
<show-dialog v-model:visible="showDialog" name="フィールド選択" @close="closeDg">
|
||||||
|
<field-select ref="appDg" name="フィールド" type="single" :appId="store.appInfo?.appId"></field-select>
|
||||||
|
</show-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, computed, ref } from 'vue';
|
import { QTree, useQuasar } from 'quasar';
|
||||||
import { IKintoneEvent } from '../../types/KintoneEvents';
|
import { ActionFlow, RootAction } from 'src/types/ActionTypes';
|
||||||
import { storeToRefs } from 'pinia';
|
|
||||||
import { useFlowEditorStore } from 'stores/flowEditor';
|
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||||
import { ActionFlow, ActionNode, RootAction } from 'src/types/ActionTypes';
|
import { defineComponent, ref } from 'vue';
|
||||||
import { S } from 'app/dist/spa/assets/QTable.50486f7c';
|
import { IKintoneEvent, IKintoneEventGroup, IKintoneEventNode } from '../../types/KintoneEvents';
|
||||||
|
import FieldSelect from '../FieldSelect.vue';
|
||||||
|
import ShowDialog from '../ShowDialog.vue';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'EventTree',
|
name: 'EventTree',
|
||||||
|
components: {
|
||||||
|
ShowDialog,
|
||||||
|
FieldSelect,
|
||||||
|
},
|
||||||
setup(props, context) {
|
setup(props, context) {
|
||||||
|
const $q = useQuasar();
|
||||||
|
const appDg = ref();
|
||||||
const store = useFlowEditorStore();
|
const store = useFlowEditorStore();
|
||||||
|
const showDialog = ref(false);
|
||||||
|
const tree = ref<QTree>();
|
||||||
// const eventTree=ref(kintoneEvents);
|
// const eventTree=ref(kintoneEvents);
|
||||||
// const selectedFlow = store.currentFlow;
|
// const selectedFlow = store.currentFlow;
|
||||||
|
|
||||||
const expanded=ref([
|
// const expanded=ref();
|
||||||
store.currentFlow?.getRoot()?.title
|
const selectedEvent = ref<IKintoneEvent | null>(null);
|
||||||
]);
|
const selectedChangeEvent = ref<IKintoneEventGroup | null>(null);
|
||||||
const selectedEvent = ref<IKintoneEvent|null>(null);
|
const isFieldChange = (node: IKintoneEventNode) => {
|
||||||
const onSelected=(node:IKintoneEvent)=>{
|
return node.header == 'EVENT' && node.eventId.indexOf(".change.") > -1;
|
||||||
if(!node.eventId){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
selectedEvent.value=node;
|
|
||||||
if(store.appInfo===undefined){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const screen = store.eventTree.findScreen(node.eventId);
|
|
||||||
let flow =store.findFlowByEventId(node.eventId);
|
|
||||||
const screenName=screen!==null?screen.label:"";
|
|
||||||
if(flow!==undefined && flow!==null ){
|
|
||||||
store.selectFlow(flow);
|
|
||||||
}else{
|
|
||||||
const root = new RootAction(node.eventId,screenName,node.label)
|
|
||||||
const flow =new ActionFlow(root);
|
|
||||||
store.flows?.push(flow);
|
|
||||||
store.selectFlow(flow);
|
|
||||||
selectedEvent.value.flowData=flow;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
//フィールド値変更イベント追加
|
||||||
|
const closeDg = (val: string) => {
|
||||||
|
if (val == 'OK') {
|
||||||
|
if (!selectedChangeEvent.value) { return; }
|
||||||
|
const field = appDg.value.selected[0];
|
||||||
|
const eventid = `${selectedChangeEvent.value.eventId}.${field.code}`;
|
||||||
|
if (store.eventTree.findEventById(eventid)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectedChangeEvent.value?.events.push({
|
||||||
|
eventId: eventid,
|
||||||
|
label: field.name,
|
||||||
|
parentId: selectedChangeEvent.value.eventId,
|
||||||
|
header: 'DELETABLE'
|
||||||
|
});
|
||||||
|
tree.value?.expanded?.push(selectedChangeEvent.value.eventId);
|
||||||
|
tree.value?.expandAll();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const addChangeEvent = (node: IKintoneEventGroup) => {
|
||||||
|
if (store.appInfo === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectedChangeEvent.value = node;
|
||||||
|
showDialog.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteEvent = (node: IKintoneEvent) => {
|
||||||
|
if (!node.eventId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
store.deleteEvent(node);
|
||||||
|
store.selectFlow(undefined)
|
||||||
|
|
||||||
|
$q.notify({
|
||||||
|
type: 'positive',
|
||||||
|
caption: "通知",
|
||||||
|
message: `イベント ${node.label} 削除`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSelected = (node: IKintoneEvent) => {
|
||||||
|
if (!node.eventId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectedEvent.value = node;
|
||||||
|
if (store.appInfo === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const screen = store.eventTree.findEventById(node.parentId);
|
||||||
|
|
||||||
|
let flow = store.findFlowByEventId(node.eventId);
|
||||||
|
let screenName = screen !== null ? screen.label : "";
|
||||||
|
let nodeLabel = node.label;
|
||||||
|
// if(isFieldChange(node)){
|
||||||
|
// screenName=nodeLabel;
|
||||||
|
// nodeLabel=`${node.label}の値を変更したとき`;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (flow !== undefined && flow !== null) {
|
||||||
|
store.selectFlow(flow);
|
||||||
|
} else {
|
||||||
|
const root = new RootAction(node.eventId, screenName, nodeLabel)
|
||||||
|
const flow = new ActionFlow(root);
|
||||||
|
store.flows?.push(flow);
|
||||||
|
store.selectFlow(flow);
|
||||||
|
selectedEvent.value.flowData = flow;
|
||||||
|
}
|
||||||
|
};
|
||||||
return {
|
return {
|
||||||
// eventTree,
|
// eventTree,
|
||||||
expanded,
|
// expanded,
|
||||||
|
appDg,
|
||||||
|
tree,
|
||||||
|
showDialog,
|
||||||
|
isFieldChange,
|
||||||
onSelected,
|
onSelected,
|
||||||
selectedEvent,
|
selectedEvent,
|
||||||
|
addChangeEvent,
|
||||||
|
deleteEvent,
|
||||||
|
closeDg,
|
||||||
store
|
store
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.nowrap{
|
.nowrap {
|
||||||
flex-wrap:nowarp;
|
flex-wrap: nowarp;
|
||||||
text-wrap:nowarp;
|
text-wrap: nowarp;
|
||||||
}
|
}
|
||||||
.event-node{
|
|
||||||
cursor:pointer;
|
.event-node {
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.selected-node{
|
|
||||||
|
.selected-node {
|
||||||
color: $primary;
|
color: $primary;
|
||||||
font-weight: bolder;
|
font-weight: bolder;
|
||||||
}
|
}
|
||||||
.event-node:hover{
|
|
||||||
|
.event-node:hover {
|
||||||
background-color: $light-blue-1;
|
background-color: $light-blue-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.delete-btn {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="row justify-center" :style="{ marginLeft: node.inputPoint !== '' ? '240px' : '' }" >
|
<div class="row justify-center no-wrap" >
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<q-card class="action-node" :class="nodeStyle" :square="false" @click="onNodeClick" >
|
<q-card class="action-node" :class="nodeStyle" :square="false" @click="onNodeClick" >
|
||||||
<q-toolbar class="col" >
|
<q-toolbar class="col" >
|
||||||
@@ -8,6 +8,10 @@
|
|||||||
<q-btn flat round dense icon="more_horiz" size="sm" >
|
<q-btn flat round dense icon="more_horiz" size="sm" >
|
||||||
<q-menu auto-close anchor="top right">
|
<q-menu auto-close anchor="top right">
|
||||||
<q-list>
|
<q-list>
|
||||||
|
<q-item clickable v-if="isRoot" @click="copyFlow">
|
||||||
|
<q-item-section avatar><q-icon name="content_copy" ></q-icon></q-item-section>
|
||||||
|
<q-item-section >コピーする</q-item-section>
|
||||||
|
</q-item>
|
||||||
<q-item clickable v-if="!isRoot" @click="onEditNode">
|
<q-item clickable v-if="!isRoot" @click="onEditNode">
|
||||||
<q-item-section avatar><q-icon name="edit" ></q-icon></q-item-section>
|
<q-item-section avatar><q-icon name="edit" ></q-icon></q-item-section>
|
||||||
<q-item-section >編集する</q-item-section>
|
<q-item-section >編集する</q-item-section>
|
||||||
@@ -25,8 +29,12 @@
|
|||||||
</q-btn>
|
</q-btn>
|
||||||
</q-toolbar>
|
</q-toolbar>
|
||||||
<q-separator />
|
<q-separator />
|
||||||
<q-card-section>
|
<q-card-section class="action-title">
|
||||||
<div class="text-h7">{{ node.title }}</div>
|
<div class="row">
|
||||||
|
<span class="text-h7">{{ node.title }}</span>
|
||||||
|
<q-space></q-space>
|
||||||
|
<q-chip color="info" text-color="white" size="0.70rem" v-if="varName(node)" clickable>{{ varName(node) }}</q-chip>
|
||||||
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<template v-if="hasBranch">
|
<template v-if="hasBranch">
|
||||||
<q-separator />
|
<q-separator />
|
||||||
@@ -40,23 +48,34 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="hasBranch">
|
<template v-if="hasBranch">
|
||||||
<div class="row justify-center" :style="{ marginLeft: node.inputPoint !== '' ? '240px' : '' }">
|
<node-line :action-node="node" @addNode="addNode" :left-columns="leftColumns" :right-columns="rightColumns"></node-line>
|
||||||
<div v-for="(point, index) in node.outputPoints" :key="index">
|
<div class="row justify-center no-wrap" >
|
||||||
<node-line :action-node="node" :mode="getMode(point)" @addNode="addNode" :input-point="point"></node-line>
|
<div v-for="(point, index) in node.outputPoints" :key="index" class="column" style="min-width: 300px;">
|
||||||
|
<div class="justify-center" >
|
||||||
|
<node-item v-if="nextNode(point)!==undefined" :key="nextNode(point).id" :isSelected="nextNode(point) === store.activeNode"
|
||||||
|
:actionNode="nextNode(point)" @addNode="addNodeFromItem" @nodeSelected="onNodeSelected" @nodeEdit="onNodeEdit"
|
||||||
|
@deleteNode="onDeleteNodeFromItem" @deleteAllNextNodes="onDeleteAllNextNodes" ></node-item>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="!hasBranch">
|
<template v-if="!hasBranch">
|
||||||
<div class="row justify-center" :style="{ marginLeft: node.inputPoint !== '' ? '240px' : '' }">
|
<div class="row justify-center no-wrap" >
|
||||||
<node-line :action-node="node" :mode="getMode('')" @addNode="addNode" input-point=""></node-line>
|
<node-line :action-node="node" @addNode="addNode" ></node-line>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<node-item v-if="nextNode('')!==undefined" :key="nextNode('').id" :isSelected="nextNode('') === store.activeNode"
|
||||||
|
:actionNode="nextNode('')" @addNode="addNodeFromItem" @nodeSelected="onNodeSelected" @nodeEdit="onNodeEdit"
|
||||||
|
@deleteNode="onDeleteNodeFromItem" @deleteAllNextNodes="onDeleteAllNextNodes" ></node-item>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, computed, ref } from 'vue';
|
import { defineComponent, computed, ref } from 'vue';
|
||||||
import { IActionNode } from '../../types/ActionTypes';
|
import { IActionNode, IActionProperty } from '../../types/ActionTypes';
|
||||||
import NodeLine, { Direction } from '../main/NodeLine.vue';
|
import NodeLine, { Direction } from '../main/NodeLine.vue';
|
||||||
|
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'NodeItem',
|
name: 'NodeItem',
|
||||||
components: {
|
components: {
|
||||||
@@ -77,8 +96,10 @@ export default defineComponent({
|
|||||||
"nodeEdit",
|
"nodeEdit",
|
||||||
"deleteNode",
|
"deleteNode",
|
||||||
"deleteAllNextNodes",
|
"deleteAllNextNodes",
|
||||||
|
"copyFlow"
|
||||||
],
|
],
|
||||||
setup(props, context) {
|
setup(props, context) {
|
||||||
|
const store = useFlowEditorStore();
|
||||||
const hasBranch = computed(() => props.actionNode.outputPoints.length > 0);
|
const hasBranch = computed(() => props.actionNode.outputPoints.length > 0);
|
||||||
const nodeStyle = computed(() => {
|
const nodeStyle = computed(() => {
|
||||||
return {
|
return {
|
||||||
@@ -87,23 +108,11 @@ export default defineComponent({
|
|||||||
'selected': props.isSelected && !props.actionNode.isRoot
|
'selected': props.isSelected && !props.actionNode.isRoot
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
const getMode = (point: string) => {
|
|
||||||
if (point === '' || props.actionNode.outputPoints.length === 0) {
|
const nextNode=(point:string)=>{
|
||||||
return Direction.Default;
|
const nextId= props.actionNode.nextNodeIds.get(point);
|
||||||
}
|
if(!nextId) return undefined;
|
||||||
if (point === props.actionNode.outputPoints[0]) {
|
return store.currentFlow?.findNodeById(nextId);
|
||||||
if (props.actionNode.nextNodeIds.get(point)) {
|
|
||||||
return Direction.Left;
|
|
||||||
} else {
|
|
||||||
return Direction.LeftNotNext;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (props.actionNode.nextNodeIds.get(point)) {
|
|
||||||
return Direction.Right;
|
|
||||||
} else {
|
|
||||||
return Direction.RightNotNext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* アクションノード追加イベントを
|
* アクションノード追加イベントを
|
||||||
@@ -112,6 +121,38 @@ export default defineComponent({
|
|||||||
const addNode = (point: string) => {
|
const addNode = (point: string) => {
|
||||||
context.emit('addNode', props.actionNode, point);
|
context.emit('addNode', props.actionNode, point);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* アクションノード追加イベントを
|
||||||
|
* @param point 入力ポイント
|
||||||
|
*/
|
||||||
|
const addNodeFromItem = (node:IActionNode,point: string) => {
|
||||||
|
context.emit('addNode', node, point);
|
||||||
|
}
|
||||||
|
|
||||||
|
const leftColumns=computed(()=>{
|
||||||
|
if(!props.actionNode.outputPoints || props.actionNode.outputPoints.length<2){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
const leftNode = nextNode(props.actionNode.outputPoints[0]);
|
||||||
|
if(leftNode){
|
||||||
|
return store.currentFlow?.getColumns(leftNode);
|
||||||
|
}else{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const rightColumns=computed(()=>{
|
||||||
|
if(!props.actionNode.outputPoints || props.actionNode.outputPoints.length<2){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
const rightNode = nextNode(props.actionNode.outputPoints[1]);
|
||||||
|
if(rightNode){
|
||||||
|
return store.currentFlow?.getColumns(rightNode);
|
||||||
|
}else{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ノード選択状態
|
* ノード選択状態
|
||||||
*/
|
*/
|
||||||
@@ -119,9 +160,20 @@ export default defineComponent({
|
|||||||
context.emit('nodeSelected', props.actionNode);
|
context.emit('nodeSelected', props.actionNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const onNodeSelected = (node: IActionNode) => {
|
||||||
|
context.emit('nodeSelected', node);
|
||||||
|
}
|
||||||
|
|
||||||
const onEditNode=()=>{
|
const onEditNode=()=>{
|
||||||
context.emit('nodeEdit', props.actionNode);
|
context.emit('nodeEdit', props.actionNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onNodeEdit=(node:IActionNode)=>{
|
||||||
|
context.emit('nodeEdit', node);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ノードを削除する
|
* ノードを削除する
|
||||||
*/
|
*/
|
||||||
@@ -129,30 +181,68 @@ export default defineComponent({
|
|||||||
context.emit('deleteNode', props.actionNode);
|
context.emit('deleteNode', props.actionNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ノードを削除する
|
||||||
|
*/
|
||||||
|
const onDeleteNodeFromItem=(node:IActionNode)=>{
|
||||||
|
context.emit('deleteNode', node);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* ノードの以下すべて削除する
|
* ノードの以下すべて削除する
|
||||||
*/
|
*/
|
||||||
const onDeleteAllNode=()=>{
|
const onDeleteAllNode=()=>{
|
||||||
context.emit('deleteAllNextNodes', props.actionNode);
|
context.emit('deleteAllNextNodes', props.actionNode);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ノードの以下すべて削除する
|
||||||
|
*/
|
||||||
|
const onDeleteAllNextNodes=(node:IActionNode)=>{
|
||||||
|
context.emit('deleteAllNextNodes', node);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 変数名取得
|
||||||
|
*/
|
||||||
|
const varName =(node:IActionNode)=>{
|
||||||
|
const prop = node.actionProps.find((prop) => prop.props.name === "verName");
|
||||||
|
return prop?.props.modelValue.name;
|
||||||
|
};
|
||||||
|
const copyFlow=()=>{
|
||||||
|
context.emit('copyFlow', props.actionNode);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
store,
|
||||||
node: props.actionNode,
|
node: props.actionNode,
|
||||||
|
nextNode,
|
||||||
isRoot: props.actionNode.isRoot,
|
isRoot: props.actionNode.isRoot,
|
||||||
hasBranch,
|
hasBranch,
|
||||||
nodeStyle,
|
nodeStyle,
|
||||||
getMode,
|
// getMode,
|
||||||
addNode,
|
addNode,
|
||||||
|
addNodeFromItem,
|
||||||
onNodeClick,
|
onNodeClick,
|
||||||
|
onNodeSelected,
|
||||||
onEditNode,
|
onEditNode,
|
||||||
|
onNodeEdit,
|
||||||
onDeleteNode,
|
onDeleteNode,
|
||||||
onDeleteAllNode
|
onDeleteNodeFromItem,
|
||||||
|
onDeleteAllNode,
|
||||||
|
onDeleteAllNextNodes,
|
||||||
|
copyFlow,
|
||||||
|
varName,
|
||||||
|
leftColumns,
|
||||||
|
rightColumns
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.action-node {
|
.action-node {
|
||||||
min-width: 300px !important;
|
min-width: 280px !important;
|
||||||
|
}
|
||||||
|
.action-title{
|
||||||
|
max-width: 280px !important;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
}
|
}
|
||||||
|
|
||||||
.line {
|
.line {
|
||||||
|
|||||||
@@ -1,11 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="row justify-center">
|
||||||
<svg class="node-line">
|
<svg class="node-line" style="width:100%" :viewBox="viewBox()">
|
||||||
<polyline :points="points.linePoints" class="line" ></polyline>
|
<template v-if="!node.outputPoints || node.outputPoints.length===0" >
|
||||||
<text class="add-icon" @click="addNode(node)" :x="points.iconPoint.x" :y="points.iconPoint.y" font-family="Arial" font-size="25"
|
<polyline :points="points(getMode('')).linePoints" class="line" ></polyline>
|
||||||
text-anchor="middle" dy=".3em" style="cursor: pointer;" >
|
<text class="add-icon"
|
||||||
⊕
|
@click="addNode(node,'')"
|
||||||
</text>
|
:x="points(getMode('')).iconPoint.x"
|
||||||
|
:y="points(getMode('')).iconPoint.y"
|
||||||
|
font-family="Arial" font-size="25"
|
||||||
|
text-anchor="middle" dy=".3em" style="cursor: pointer;" >
|
||||||
|
⊕
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
<template v-for="(point, index) in node.outputPoints" :key="index" >
|
||||||
|
<polyline :points="points(getMode(point)).linePoints" class="line" ></polyline>
|
||||||
|
<text class="add-icon"
|
||||||
|
@click="addNode(node,point)"
|
||||||
|
:x="points(getMode(point)).iconPoint.x"
|
||||||
|
:y="points(getMode(point)).iconPoint.y"
|
||||||
|
font-family="Arial" font-size="25"
|
||||||
|
text-anchor="middle" dy=".3em" style="cursor: pointer;" >
|
||||||
|
⊕
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -27,55 +44,97 @@ export default defineComponent({
|
|||||||
type: Object as PropType<IActionNode>,
|
type: Object as PropType<IActionNode>,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
mode: {
|
leftColumns:{
|
||||||
type: String as PropType<Direction>,
|
type:Number,
|
||||||
required: true
|
required:false
|
||||||
},
|
},
|
||||||
inputPoint:{
|
rightColumns:{
|
||||||
type:String
|
type:Number,
|
||||||
|
required:false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['addNode'],
|
emits: ['addNode'],
|
||||||
setup(props,context) {
|
setup(props,context) {
|
||||||
const hasBranch = computed(() => props.actionNode.outputPoints.length > 0);
|
const hasBranch = computed(() => props.actionNode.outputPoints.length > 0);
|
||||||
const points = computed(() => {
|
const getMode = (point: string):Direction => {
|
||||||
switch (props.mode) {
|
if (point === '' || props.actionNode.outputPoints.length === 0) {
|
||||||
case Direction.Left:
|
return Direction.Default;
|
||||||
|
}
|
||||||
|
if (point === props.actionNode.outputPoints[0]) {
|
||||||
|
if (props.actionNode.nextNodeIds.get(point)) {
|
||||||
|
return Direction.Left;
|
||||||
|
} else {
|
||||||
|
return Direction.LeftNotNext;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (props.actionNode.nextNodeIds.get(point)) {
|
||||||
|
return Direction.Right;
|
||||||
|
} else {
|
||||||
|
return Direction.RightNotNext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const points = (mode:Direction) => {
|
||||||
|
let startX ,endX;
|
||||||
|
const leftColumn=props.leftColumns?props.leftColumns:1;
|
||||||
|
const rightColumn=props.rightColumns?props.rightColumns:1;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case Direction.Left:
|
||||||
|
startX = leftColumn*300/2.0;
|
||||||
|
endX = ((leftColumn+rightColumn)/2.0 - 0.25)*300;
|
||||||
return {
|
return {
|
||||||
linePoints: '180, 0, 180, 40, 120, 40, 120, 60',
|
linePoints: `${startX}, 60, ${startX}, 40, ${endX}, 40, ${endX}, 0`,
|
||||||
iconPoint: { x: 180, y: 20 }
|
iconPoint: { x: endX, y: 20 }
|
||||||
};
|
};
|
||||||
case Direction.Right:
|
case Direction.Right:
|
||||||
|
startX = ((leftColumn+rightColumn)/2.0 + 0.25)*300;
|
||||||
|
endX = (leftColumn+(rightColumn/2.0))*300;
|
||||||
return {
|
return {
|
||||||
linePoints: '60, 0, 60, 40, 120, 40, 120, 60',
|
linePoints: `${startX}, 0, ${startX}, 40, ${endX}, 40, ${endX}, 60`,
|
||||||
iconPoint: { x: 60, y: 20 }
|
iconPoint: { x: startX, y: 20 }
|
||||||
};
|
};
|
||||||
case Direction.LeftNotNext:
|
case Direction.LeftNotNext:
|
||||||
|
startX = ((leftColumn+rightColumn)/2.0 - 0.25)*300;
|
||||||
return {
|
return {
|
||||||
linePoints: '180, 0, 180, 40',
|
linePoints: `${startX}, 0, ${startX}, 40`,
|
||||||
iconPoint: { x: 180, y: 20 }
|
iconPoint: { x: startX, y: 20 }
|
||||||
};
|
};
|
||||||
case Direction.RightNotNext:
|
case Direction.RightNotNext:
|
||||||
|
startX = ((leftColumn+rightColumn)/2.0 + 0.25)*300;
|
||||||
return {
|
return {
|
||||||
linePoints: '60, 0, 60, 40',
|
linePoints: `${startX}, 0, ${startX}, 40`,
|
||||||
iconPoint: { x: 60, y: 30 }
|
iconPoint: { x: startX, y: 20 }
|
||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
return {
|
return {
|
||||||
linePoints: '120, 0, 120, 60',
|
linePoints: '150, 0, 150, 60',
|
||||||
iconPoint: { x: 120, y: 30 }
|
iconPoint: { x: 150, y: 30 }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
const addNode=(prveNode:IActionNode)=>{
|
|
||||||
context.emit('addNode',props.inputPoint);
|
const addNode=(prveNode:IActionNode,point:string)=>{
|
||||||
|
context.emit('addNode',point);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const viewBox=()=>{
|
||||||
|
let columns=0;
|
||||||
|
if(props.leftColumns!==undefined) columns+=props.leftColumns;
|
||||||
|
if(props.rightColumns!==undefined) columns+=props.rightColumns;
|
||||||
|
if(columns===0) columns=1;
|
||||||
|
const width= columns*300;
|
||||||
|
return `0 0 ${width} 60`;
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
node: props.actionNode,
|
node: props.actionNode,
|
||||||
|
getMode,
|
||||||
hasBranch,
|
hasBranch,
|
||||||
points,
|
points,
|
||||||
addNode
|
addNode,
|
||||||
|
viewBox
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,25 +1,27 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div v-for="(item, index) in componentData" :key="index">
|
<div v-for="(item, index) in componentData" :key="index">
|
||||||
<component :is="item.component" v-bind="item.props" v-model="item.props.modelValue"></component>
|
<component :is="item.component" v-bind="item.props" :connectProps="connectProps" v-model="item.props.modelValue"></component>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent,computed } from 'vue';
|
||||||
import InputText from '../right/InputText.vue';
|
import InputText from '../right/InputText.vue';
|
||||||
import SelectBox from '../right/SelectBox.vue';
|
import SelectBox from '../right/SelectBox.vue';
|
||||||
import DatePicker from '../right/DatePicker.vue';
|
import DatePicker from '../right/DatePicker.vue';
|
||||||
import FieldInput from '../right/FieldInput.vue';
|
import FieldInput from '../right/FieldInput.vue';
|
||||||
|
import EventSetter from '../right/EventSetter.vue';
|
||||||
|
import { IActionProperty, IProp } from 'src/types/ActionTypes';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'ActionProperty',
|
name: 'ActionProperty',
|
||||||
components: {
|
components: {
|
||||||
InputText,
|
InputText,
|
||||||
SelectBox,
|
SelectBox,
|
||||||
DatePicker,
|
DatePicker,
|
||||||
FieldInput
|
FieldInput,
|
||||||
|
EventSetter
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
jsonData: {
|
jsonData: {
|
||||||
@@ -31,27 +33,43 @@ export default defineComponent({
|
|||||||
required: false,
|
required: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
setup(props){
|
||||||
componentData() {
|
const componentData=computed<Array<IActionProperty>>(()=>{
|
||||||
return this.jsonData.elements.map((element: any) => {
|
return props.jsonData.elements.map((element: any) => {
|
||||||
if(this.jsonValue != undefined )
|
if(props.jsonValue != undefined )
|
||||||
{
|
{
|
||||||
if(this.jsonValue.hasOwnProperty(element.props.name))
|
if(props.jsonValue.hasOwnProperty(element.props.name))
|
||||||
{
|
{
|
||||||
element.props.modelValue = this.jsonValue[element.props.name];
|
element.props.modelValue = props.jsonValue[element.props.name];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
element.props.modelValue = '';
|
element.props.modelValue = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
component: element.component,
|
component: element.component,
|
||||||
props: element.props,
|
props: element.props,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
});
|
||||||
},
|
const connectProps=(props:IProp)=>{
|
||||||
|
const connProps:any={};
|
||||||
|
if(props && "connectProps" in props && props.connectProps!=undefined){
|
||||||
|
for(let connProp of props.connectProps){
|
||||||
|
let targetProp = componentData.value.find((prop)=>prop.props.name===connProp.propName);
|
||||||
|
if(targetProp){
|
||||||
|
connProps[connProp.key]=targetProp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return connProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
return{
|
||||||
|
componentData,
|
||||||
|
connectProps
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
157
frontend/src/components/right/AppFieldSelect.vue
Normal file
157
frontend/src/components/right/AppFieldSelect.vue
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
<template>
|
||||||
|
<div class="q-my-md" v-bind="$attrs">
|
||||||
|
<q-card flat>
|
||||||
|
<q-card-section class="q-pa-none q-my-sm q-mr-md">
|
||||||
|
<!-- <div class=" q-my-none ">App Field Select</div> -->
|
||||||
|
<div class="row q-mb-xs">
|
||||||
|
<div class="text-primary q-mb-xs text-caption">{{ $props.displayName }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<div class="q-mb-xs">{{ selectedField.app?.name || '未選択' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-1">
|
||||||
|
<q-btn round flat size="sm" color="primary" icon="search" @click="showDg" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</q-card-section>
|
||||||
|
<q-separator />
|
||||||
|
<q-card-section class="q-pa-none q-ma-none">
|
||||||
|
<div style="">
|
||||||
|
<div v-if="selectedField.fields && selectedField.fields.length > 0">
|
||||||
|
<q-list bordered>
|
||||||
|
<q-virtual-scroll style="max-height: 160px;" :items="selectedField.fields" separator
|
||||||
|
v-slot="{ item, index }">
|
||||||
|
<q-item :key="index" dense clickable>
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>
|
||||||
|
{{ item.label }}
|
||||||
|
</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section side>
|
||||||
|
<q-btn round flat size="sm" icon="clear" @click="removeField(index)" />
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-virtual-scroll>
|
||||||
|
</q-list>
|
||||||
|
</div>
|
||||||
|
<!-- <div v-else class="row q-mt-lg">
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
<!-- <q-separator /> -->
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-section class="q-px-none q-py-xs" v-if="selectedField.fields && selectedField.fields.length === 0">
|
||||||
|
<div class="row">
|
||||||
|
<div class="text-grey text-caption"> {{ $props.placeholder }}</div>
|
||||||
|
<!-- <q-btn flat color="grey" label="clear" @click="clear" /> -->
|
||||||
|
</div>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
<show-dialog v-model:visible="show" name="フィールド一覧" @close="closeAFBox">
|
||||||
|
<AppFieldSelectBox v-model:selectedField="selectedField" :selectType="selectType" ref="afBox" :fieldTypes="fieldTypes"/>
|
||||||
|
</show-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, ref, watchEffect } from 'vue';
|
||||||
|
import AppFieldSelectBox from '../AppFieldSelectBox.vue';
|
||||||
|
import ShowDialog from '../ShowDialog.vue';
|
||||||
|
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||||
|
|
||||||
|
export interface IApp {
|
||||||
|
id: string,
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
export interface IField {
|
||||||
|
name: string,
|
||||||
|
code: string,
|
||||||
|
type: string,
|
||||||
|
label?:string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IAppFields {
|
||||||
|
app?: IApp,
|
||||||
|
fields: IField[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
inheritAttrs: false,
|
||||||
|
name: 'AppFieldSelect',
|
||||||
|
components: {
|
||||||
|
ShowDialog,
|
||||||
|
AppFieldSelectBox
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
displayName: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
selectType: {
|
||||||
|
type: String,
|
||||||
|
default: 'single'
|
||||||
|
},
|
||||||
|
fieldTypes:{
|
||||||
|
type:Array,
|
||||||
|
default:()=>[]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const show = ref(false);
|
||||||
|
const afBox = ref();
|
||||||
|
const selectedField = ref<IAppFields>({
|
||||||
|
app: undefined,
|
||||||
|
fields: []
|
||||||
|
});
|
||||||
|
if (props.modelValue && 'app' in props.modelValue && 'fields' in props.modelValue) {
|
||||||
|
selectedField.value = props.modelValue as IAppFields;
|
||||||
|
}
|
||||||
|
const store = useFlowEditorStore();
|
||||||
|
|
||||||
|
const clear = () => {
|
||||||
|
selectedField.value = {
|
||||||
|
fields: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeField = (index: number) => {
|
||||||
|
selectedField.value.fields.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeAFBox = (val: string) => {
|
||||||
|
if (val == 'OK') {
|
||||||
|
console.log(afBox.value);
|
||||||
|
|
||||||
|
selectedField.value = afBox.value.selField;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
emit('update:modelValue', selectedField.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
store,
|
||||||
|
afBox,
|
||||||
|
show,
|
||||||
|
showDg: () => { show.value = true },
|
||||||
|
selectedField,
|
||||||
|
clear,
|
||||||
|
removeField,
|
||||||
|
closeAFBox,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
93
frontend/src/components/right/AppSelect.vue
Normal file
93
frontend/src/components/right/AppSelect.vue
Normal 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>
|
||||||
74
frontend/src/components/right/ColorPicker.vue
Normal file
74
frontend/src/components/right/ColorPicker.vue
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<template>
|
||||||
|
<div class="" v-bind="$attrs">
|
||||||
|
<q-field v-model="color" :label="displayName" labelColor="primary" :clearable="isSelected" stack-label :bottom-slots="!isSelected" >
|
||||||
|
<template v-slot:control>
|
||||||
|
<q-chip text-color="black" color="white" v-if="isSelected">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-4">
|
||||||
|
<q-avatar class="shadow-1" :style="{ background: color }" size="xs"></q-avatar>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
{{ color }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</q-chip>
|
||||||
|
</template>
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-icon name="colorize" class="cursor-pointer" color="primary" >
|
||||||
|
<q-popup-proxy cover transition-show="scale" transition-hide="scale">
|
||||||
|
<q-color no-header default-view="palette" v-model="color" />
|
||||||
|
</q-popup-proxy>
|
||||||
|
</q-icon>
|
||||||
|
</template>
|
||||||
|
<template v-slot:hint>
|
||||||
|
{{ placeholder }}
|
||||||
|
</template>
|
||||||
|
</q-field>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { computed, defineComponent, ref,watchEffect } from 'vue';
|
||||||
|
export default defineComponent({
|
||||||
|
inheritAttrs:false,
|
||||||
|
name: 'ColorPicker',
|
||||||
|
components: {
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
displayName: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
hint: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const color = ref(props.modelValue??"");
|
||||||
|
const isSelected = computed(()=>props.modelValue && props.modelValue!=="");
|
||||||
|
watchEffect(()=>{
|
||||||
|
emit('update:modelValue', color.value);
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
color,
|
||||||
|
isSelected
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
169
frontend/src/components/right/ConditionInput.vue
Normal file
169
frontend/src/components/right/ConditionInput.vue
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
<template>
|
||||||
|
<div v-bind="$attrs">
|
||||||
|
<q-field v-model="tree" :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="showDg()">クリックで設定:{{ isSetted ?
|
||||||
|
'設定済み' : '未設定' }}</q-btn>
|
||||||
|
</q-card-actions>
|
||||||
|
<q-card-section class="text-caption">
|
||||||
|
<div v-if="!isSetted">{{ placeholder }}</div>
|
||||||
|
<div v-else>{{ conditionString }}</div>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</template>
|
||||||
|
</q-field>
|
||||||
|
<condition-editor v-model:show="show" v-model:conditionTree="tree" @closed="onClosed"></condition-editor>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { ConditionNode, ConditionTree, Operator, OperatorListItem } from 'app/src/types/Conditions';
|
||||||
|
import { computed, defineComponent, provide, reactive, ref, watchEffect } from 'vue';
|
||||||
|
import ConditionEditor from '../ConditionEditor/ConditionEditor.vue';
|
||||||
|
import { IActionProperty } from 'src/types/ActionTypes';
|
||||||
|
import { } from 'src/types/';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'FieldInput',
|
||||||
|
inheritAttrs: false,
|
||||||
|
components: {
|
||||||
|
ConditionEditor
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
context: {
|
||||||
|
type: Array<IActionProperty>,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
displayName: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
hint: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
sourceType: {
|
||||||
|
type: String,
|
||||||
|
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 }) {
|
||||||
|
const source = props.context.find(element => element.props.name === 'sources')
|
||||||
|
|
||||||
|
if (source) {
|
||||||
|
if (props.sourceType === 'field') {
|
||||||
|
provide('sourceFields', computed(() => source.props?.modelValue?.fields ?? []));
|
||||||
|
} else if (props.sourceType === 'app') {
|
||||||
|
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 show = ref(false);
|
||||||
|
const tree = reactive(new ConditionTree());
|
||||||
|
if (props.modelValue && props.modelValue !== '') {
|
||||||
|
tree.fromJson(props.modelValue);
|
||||||
|
} else {
|
||||||
|
const newNode = new ConditionNode({}, (props.operatorList && props.operatorList.length > 0) ? props.operatorList[0] as OperatorListItem : Operator.Equal, '', tree.root);
|
||||||
|
tree.addNode(tree.root, newNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isSetted = ref(props.modelValue && props.modelValue !== '');
|
||||||
|
|
||||||
|
const conditionString = computed(() => {
|
||||||
|
return tree.buildConditionString(tree.root);
|
||||||
|
});
|
||||||
|
|
||||||
|
const showDg = () => {
|
||||||
|
show.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onClosed = (val: string) => {
|
||||||
|
if (val == 'OK') {
|
||||||
|
isSetted.value = true;
|
||||||
|
tree.setQuery(tree.buildConditionQueryString(tree.root));
|
||||||
|
const conditionJson = tree.toJson();
|
||||||
|
emit('update:modelValue', conditionJson);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
tree.setQuery(tree.buildConditionQueryString(tree.root));
|
||||||
|
const conditionJson = tree.toJson();
|
||||||
|
emit('update:modelValue', conditionJson);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
appDg,
|
||||||
|
isSetted,
|
||||||
|
show,
|
||||||
|
showDg,
|
||||||
|
onClosed,
|
||||||
|
tree,
|
||||||
|
conditionString,
|
||||||
|
btnDisable
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
284
frontend/src/components/right/DataMapping.vue
Normal file
284
frontend/src/components/right/DataMapping.vue
Normal 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>
|
||||||
239
frontend/src/components/right/DataProcessing.vue
Normal file
239
frontend/src/components/right/DataProcessing.vue
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<q-field :label="displayName" labelColor="primary" stack-label>
|
||||||
|
<template v-slot:control>
|
||||||
|
<q-card flat class="full-width">
|
||||||
|
<q-card-actions vertical>
|
||||||
|
<q-btn color="grey-3" text-color="black" @click="() => { dgIsShow = true }">クリックで設定</q-btn>
|
||||||
|
</q-card-actions>
|
||||||
|
<q-card-section class="text-caption">
|
||||||
|
<div v-if="processingObjectsInputDisplay && processingObjectsInputDisplay.length>0">
|
||||||
|
<div v-for="(item) in processingObjectsInputDisplay" :key="item">{{ item }}</div>
|
||||||
|
</div>
|
||||||
|
<div v-else>{{ placeholder }}</div>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</template>
|
||||||
|
</q-field>
|
||||||
|
<show-dialog v-model:visible="dgIsShow" name="集計処理" @close="closeDg" min-width="50vw" min-height="60vh">
|
||||||
|
<div class="q-mx-md q-mb-md">
|
||||||
|
<q-input v-model="processingProps.name" type="text" label-color="primary" label="集計結果の変数名"
|
||||||
|
placeholder="集計結果を格納する変数名を入力してください" stack-label />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="q-mx-md">
|
||||||
|
<div class="row q-col-gutter-x-xs flex-center">
|
||||||
|
<div class="col-5">
|
||||||
|
<div class="q-mx-xs">データソース</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-2">
|
||||||
|
<div class="q-mx-xs">集計計算</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-4">
|
||||||
|
<div class="q-mx-xs">集計結果変数名</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-1"><q-btn flat round dense icon="add" size="sm" @click="addProcessingObject" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="q-my-sm" v-for="(item, index) in processingObjects" :key="item.id">
|
||||||
|
<div class="row q-col-gutter-x-xs flex-center">
|
||||||
|
<div class="col-5">
|
||||||
|
<ConditionObject v-model="item.field" />
|
||||||
|
</div>
|
||||||
|
<div class="col-2 q-pa-sm">
|
||||||
|
<q-select v-model="item.logicalOperator" :options="logicalOperators" outlined dense></q-select>
|
||||||
|
</div>
|
||||||
|
<div class="col-4">
|
||||||
|
<q-input v-model="item.vName" type="text" outlined dense />
|
||||||
|
</div>
|
||||||
|
<div class="col-1">
|
||||||
|
<q-btn flat round dense icon="delete" size="sm" @click="() => deleteProcessingObject(index)" />
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</show-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
import { computed, defineComponent, provide, reactive, ref, watchEffect } from 'vue';
|
||||||
|
import ConditionObject from '../ConditionEditor/ConditionObject.vue';
|
||||||
|
import ShowDialog from '../ShowDialog.vue';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
props?: {
|
||||||
|
name: string;
|
||||||
|
modelValue?: {
|
||||||
|
fields: {
|
||||||
|
type: string;
|
||||||
|
label: string;
|
||||||
|
code: string;
|
||||||
|
}[]
|
||||||
|
} | string
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
type ProcessingObjectType = {
|
||||||
|
field?: {
|
||||||
|
sharedText: string;
|
||||||
|
objectType: 'field';
|
||||||
|
};
|
||||||
|
logicalOperator?: string;
|
||||||
|
vName?: string;
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type ValueType = {
|
||||||
|
name: string;
|
||||||
|
actionName: string,
|
||||||
|
displayName: string,
|
||||||
|
vars: ProcessingObjectType[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'DataProcessing',
|
||||||
|
inheritAttrs: false,
|
||||||
|
components: {
|
||||||
|
ShowDialog,
|
||||||
|
ConditionObject,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
context: {
|
||||||
|
type: Array<Props>,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
displayName: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: Object as () => ValueType,
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const source = props.context.find(element => element?.props?.name === 'sources')
|
||||||
|
|
||||||
|
if (source) {
|
||||||
|
provide('sourceFields', computed(() => {
|
||||||
|
const modelValue = source.props?.modelValue;
|
||||||
|
if (modelValue && typeof modelValue !== 'string') {
|
||||||
|
return modelValue.fields;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}));
|
||||||
|
provide('sourceApp', computed(() => source.props?.modelValue?.app?.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
const actionName = props.context.find(element => element?.props?.name === 'displayName')
|
||||||
|
|
||||||
|
const processingProps: ValueType = props.modelValue && props.modelValue.vars
|
||||||
|
? reactive(props.modelValue)
|
||||||
|
: reactive({
|
||||||
|
name: '',
|
||||||
|
actionName: actionName?.props?.modelValue as string,
|
||||||
|
displayName: '結果(戻り値)',
|
||||||
|
vars: [
|
||||||
|
{
|
||||||
|
id: uuidv4(),
|
||||||
|
field:{
|
||||||
|
objectType:'field',
|
||||||
|
sharedText:''
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
|
const closeDg = () => {
|
||||||
|
emit('update:modelValue', processingProps);
|
||||||
|
}
|
||||||
|
|
||||||
|
const processingObjects = processingProps.vars;
|
||||||
|
|
||||||
|
const deleteProcessingObject = (index: number) => {
|
||||||
|
if(processingObjects.length >0){
|
||||||
|
processingObjects.splice(index, 1);
|
||||||
|
}
|
||||||
|
if(processingObjects.length===0){
|
||||||
|
addProcessingObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const processingObjectsInputDisplay = computed(() =>
|
||||||
|
processingObjects ?
|
||||||
|
processingObjects
|
||||||
|
.filter(item => item.field && item.logicalOperator && item.vName)
|
||||||
|
.map(item => {
|
||||||
|
return`var(${processingProps.name}.${item.vName}) = ${item.field?.sharedText}`
|
||||||
|
})
|
||||||
|
: []
|
||||||
|
);
|
||||||
|
|
||||||
|
const addProcessingObject=()=>{
|
||||||
|
processingObjects.push({
|
||||||
|
id: uuidv4(),
|
||||||
|
field:{
|
||||||
|
objectType:'field',
|
||||||
|
sharedText:''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//集計処理方法
|
||||||
|
const logicalOperators = ref([
|
||||||
|
{
|
||||||
|
"operator": "",
|
||||||
|
"label": "なし"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"operator": "SUM",
|
||||||
|
"label": "合計"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"operator": "AVG",
|
||||||
|
"label": "平均"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"operator": "MAX",
|
||||||
|
"label": "最大値"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"operator": "MIN",
|
||||||
|
"label": "最小値"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"operator": "COUNT",
|
||||||
|
"label": "カウント"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"operator": "FIRST",
|
||||||
|
"label": "最初の値"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
emit('update:modelValue', processingProps);
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
uuidv4,
|
||||||
|
dgIsShow: ref(false),
|
||||||
|
closeDg,
|
||||||
|
processingObjects,
|
||||||
|
processingProps,
|
||||||
|
addProcessingObject,
|
||||||
|
deleteProcessingObject,
|
||||||
|
logicalOperators,
|
||||||
|
processingObjectsInputDisplay,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="scss"></style>
|
||||||
@@ -1,18 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<div v-bind="$attrs">
|
||||||
<q-input v-model="selectedDate" :label="placeholder" mask="date" :rules="['date']">
|
<q-input v-model="selectedDate" :label="displayName" :placeholder="placeholder" label-color="primary" mask="date" :rules="['date']" stack-label>
|
||||||
<template v-slot:append>
|
<template v-slot:append>
|
||||||
<q-icon name="event" class="cursor-pointer">
|
<q-icon name="event" class="cursor-pointer">
|
||||||
<q-popup-proxy cover transition-show="scale" transition-hide="scale">
|
<q-popup-proxy cover transition-show="scale" transition-hide="scale">
|
||||||
<q-date v-model="selectedDate">
|
<q-date v-model="selectedDate">
|
||||||
<div class="row items-center justify-end">
|
<div class="row items-center justify-end">
|
||||||
<q-btn v-close-popup label="Close" color="primary" flat />
|
<q-btn v-close-popup label="Close" color="primary" flat />
|
||||||
</div>
|
</div>
|
||||||
</q-date>
|
</q-date>
|
||||||
</q-popup-proxy>
|
</q-popup-proxy>
|
||||||
</q-icon>
|
</q-icon>
|
||||||
</template>
|
</template>
|
||||||
</q-input>
|
</q-input>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -20,11 +21,24 @@ import { defineComponent, ref ,watchEffect} from 'vue';
|
|||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'DatePicker',
|
name: 'DatePicker',
|
||||||
|
inheritAttrs:false,
|
||||||
props: {
|
props: {
|
||||||
|
displayName:{
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
name:{
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
placeholder: {
|
placeholder: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
hint:{
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
|
|||||||
83
frontend/src/components/right/EventSetter.vue
Normal file
83
frontend/src/components/right/EventSetter.vue
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
<template>
|
||||||
|
<div v-bind="$attrs">
|
||||||
|
<q-input :label="displayName" v-model="inputValue" label-color="primary" :placeholder="placeholder" stack-label>
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-btn round dense flat icon="add" @click="addButtonEvent()" />
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent,ref,watchEffect } from 'vue';
|
||||||
|
import { useFlowEditorStore } from '../../stores/flowEditor';
|
||||||
|
import { IKintoneEventGroup,kintoneEvent } from 'src/types/KintoneEvents';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'EventSetter',
|
||||||
|
inheritAttrs:false,
|
||||||
|
props: {
|
||||||
|
displayName:{
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
name:{
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
hint:{
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
connectProps:{
|
||||||
|
type:Object,
|
||||||
|
default:undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setup(props , { emit }) {
|
||||||
|
const inputValue = ref(props.modelValue);
|
||||||
|
const store = useFlowEditorStore();
|
||||||
|
const addButtonEvent=()=>{
|
||||||
|
const eventId =store.currentFlow?.getRoot()?.name;
|
||||||
|
if(eventId===undefined){return;}
|
||||||
|
let displayName = inputValue.value;
|
||||||
|
if(props.connectProps!==undefined && "displayName" in props.connectProps){
|
||||||
|
displayName =props.connectProps["displayName"].props.modelValue;
|
||||||
|
}
|
||||||
|
const customButtonId=`${eventId}.customButtonClick`;
|
||||||
|
const findedEvent = store.eventTree.findEventById(customButtonId);
|
||||||
|
if(findedEvent && "events" in findedEvent){
|
||||||
|
const customEvents = findedEvent as IKintoneEventGroup;
|
||||||
|
const addEventId = customButtonId+"." + inputValue.value;
|
||||||
|
if(store.eventTree.findEventById(addEventId)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
customEvents.events.push({
|
||||||
|
eventId: addEventId,
|
||||||
|
label: displayName,
|
||||||
|
parentId: customButtonId,
|
||||||
|
header: 'DELETABLE'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
emit('update:modelValue', inputValue.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
inputValue,
|
||||||
|
addButtonEvent
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -1,34 +1,79 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-input v-model="selectedField" :label="placeholder">
|
<div v-bind="$attrs">
|
||||||
<template v-slot:append>
|
<q-field v-model="selectedField" :label="displayName" labelColor="primary" :clearable="isSelected" stack-label
|
||||||
<q-icon name="search" class="cursor-pointer" @click="showDg"/>
|
:bottom-slots="!isSelected">
|
||||||
|
<template v-slot:control>
|
||||||
|
<q-chip color="primary" text-color="white" v-if="isSelected">
|
||||||
|
{{ selectedField.name }}
|
||||||
|
</q-chip>
|
||||||
|
</template>
|
||||||
|
<template v-slot:hint v-if="!isSelected">
|
||||||
|
{{ placeholder }}
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-icon name="search" class="cursor-pointer" color="primary" @click="showDg" />
|
||||||
|
</template>
|
||||||
|
</q-field>
|
||||||
|
<show-dialog v-model:visible="show" name="フィールド一覧" @close="closeDg" min-width="400px">
|
||||||
|
<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>
|
</template>
|
||||||
</q-input>
|
<field-select ref="appDg" name="フィールド" :type="selectType" :appId="store.appInfo?.appId" :fieldTypes="fieldTypes" :filter="filter"></field-select>
|
||||||
<show-dialog v-model:visible="show" name="フィールド一覧" @close="closeDg">
|
</show-dialog>
|
||||||
<field-select ref="appDg" name="フィールド" type="single" :appId="store.appInfo?.appId"></field-select>
|
</div>
|
||||||
</show-dialog>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, ref ,watchEffect} from 'vue';
|
import { defineComponent, ref, watchEffect, computed } from 'vue';
|
||||||
import ShowDialog from '../ShowDialog.vue';
|
import ShowDialog from '../ShowDialog.vue';
|
||||||
import FieldSelect from '../FieldSelect.vue';
|
import FieldSelect from '../FieldSelect.vue';
|
||||||
import { useFlowEditorStore } from 'stores/flowEditor';
|
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||||
|
interface IField {
|
||||||
|
name: string,
|
||||||
|
code: string,
|
||||||
|
type: string
|
||||||
|
}
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'FieldInput',
|
name: 'FieldInput',
|
||||||
|
inheritAttrs:false,
|
||||||
components: {
|
components: {
|
||||||
ShowDialog,
|
ShowDialog,
|
||||||
FieldSelect,
|
FieldSelect,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
displayName: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
placeholder: {
|
placeholder: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
modelValue: {
|
selectType:{
|
||||||
|
type:String,
|
||||||
|
default:'single'
|
||||||
|
},
|
||||||
|
fieldTypes:{
|
||||||
|
type:Array,
|
||||||
|
default:()=>[]
|
||||||
|
},
|
||||||
|
hint: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
@@ -36,14 +81,17 @@ export default defineComponent({
|
|||||||
const show = ref(false);
|
const show = ref(false);
|
||||||
const selectedField = ref(props.modelValue);
|
const selectedField = ref(props.modelValue);
|
||||||
const store = useFlowEditorStore();
|
const store = useFlowEditorStore();
|
||||||
|
const isSelected = computed(() => {
|
||||||
|
return selectedField.value !== null && typeof selectedField.value === 'object' && ('name' in selectedField.value)
|
||||||
|
});
|
||||||
|
|
||||||
const showDg = () => {
|
const showDg = () => {
|
||||||
show.value = true;
|
show.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeDg = (val:string) => {
|
const closeDg = (val: string) => {
|
||||||
if (val == 'OK') {
|
if (val == 'OK') {
|
||||||
selectedField.value = appDg.value.selected[0].name;
|
selectedField.value = appDg.value.selected[0];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -58,6 +106,8 @@ export default defineComponent({
|
|||||||
showDg,
|
showDg,
|
||||||
closeDg,
|
closeDg,
|
||||||
selectedField,
|
selectedField,
|
||||||
|
isSelected,
|
||||||
|
filter:ref(''),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,33 +1,103 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-input :label="placeholder" v-model="inputValue"/>
|
<div v-bind="$attrs">
|
||||||
|
<q-input :label="displayName" v-model="inputValue" label-color="primary" :placeholder="placeholder" stack-label
|
||||||
|
:rules="rulesExp" :maxlength="maxLength">
|
||||||
|
<template v-slot:append v-if="hint !== ''">
|
||||||
|
<q-icon name="help" size="22px" color="blue-8">
|
||||||
|
<q-tooltip class="bg-yellow-2 text-black shadow-4" anchor="bottom right">
|
||||||
|
<div class="hint-text" v-html="hint" />
|
||||||
|
</q-tooltip>
|
||||||
|
</q-icon>
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent,ref,watchEffect } from 'vue';
|
import { kMaxLength } from 'buffer';
|
||||||
|
import { defineComponent, ref, watchEffect, computed } from 'vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'InputText',
|
name: 'InputText',
|
||||||
|
inheritAttrs: false,
|
||||||
props: {
|
props: {
|
||||||
|
displayName: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
placeholder: {
|
placeholder: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
modelValue: {
|
fieldTypes:{
|
||||||
|
type:Array,
|
||||||
|
default:()=>[]
|
||||||
|
},
|
||||||
|
hint: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
maxLength: {
|
||||||
|
type: Number,
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
//例:[val=>!!val ||'入力してください']
|
||||||
|
rules: {
|
||||||
|
type: String,
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
// type: Any,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const inputValue = ref(props.modelValue);
|
const inputValue = computed({
|
||||||
|
get: () => {
|
||||||
watchEffect(() => {
|
if (props.modelValue !== null && typeof props.modelValue === 'object' && 'name' in props.modelValue) {
|
||||||
emit('update:modelValue', inputValue.value);
|
return props.modelValue.name;
|
||||||
|
} else {
|
||||||
|
return props.modelValue;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
set: (val) => {
|
||||||
|
if (props.name === 'verName') {
|
||||||
|
// return props.modelValue.name;
|
||||||
|
emit('update:modelValue', { name: val });
|
||||||
|
} else {
|
||||||
|
emit('update:modelValue', val);
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
// const inputValue = ref(props.modelValue);
|
||||||
|
const rulesExp = props.rules === undefined ? null : eval(props.rules);
|
||||||
|
|
||||||
|
// const finalValue = computed(() => {
|
||||||
|
// return props.name !== 'verName' ? inputValue.value : {
|
||||||
|
// name: inputValue.value,
|
||||||
|
// };
|
||||||
|
// });
|
||||||
|
// watchEffect(() => {
|
||||||
|
// emit('update:modelValue', finalValue);
|
||||||
|
// });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
inputValue,
|
inputValue,
|
||||||
|
showhint: ref(false),
|
||||||
|
rulesExp
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.hint-text {
|
||||||
|
white-space: always;
|
||||||
|
max-width: 450px;
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
49
frontend/src/components/right/MuiltInputText.vue
Normal file
49
frontend/src/components/right/MuiltInputText.vue
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<template>
|
||||||
|
<div v-bind="$attrs">
|
||||||
|
<q-input :label="displayName" label-color="primary" v-model="inputValue" :placeholder="placeholder" autogrow
|
||||||
|
stack-label />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, ref, watchEffect } from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'MuiltInputText',
|
||||||
|
inheritAttrs: false,
|
||||||
|
props: {
|
||||||
|
displayName: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
hint: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const inputValue = ref(props.modelValue);
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
emit('update:modelValue', inputValue.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
inputValue,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
0
frontend/src/components/right/MultiFieldInput.vue
Normal file
0
frontend/src/components/right/MultiFieldInput.vue
Normal file
87
frontend/src/components/right/NumInput.vue
Normal file
87
frontend/src/components/right/NumInput.vue
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<template>
|
||||||
|
<div class="" v-bind="$attrs">
|
||||||
|
<q-input v-model.number="numValue" type="number" :label="displayName" label-color="primary" stack-label bottom-slots
|
||||||
|
:min="min"
|
||||||
|
:max="max"
|
||||||
|
:rules="rulesExp"
|
||||||
|
>
|
||||||
|
<template v-slot:hint>
|
||||||
|
{{ placeholder }}
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { computed, defineComponent, ref, watchEffect } from 'vue';
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'NumInput',
|
||||||
|
inheritAttrs:false,
|
||||||
|
components: {
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
displayName: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
hint: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
min:{
|
||||||
|
type:Number,
|
||||||
|
default:undefined
|
||||||
|
},
|
||||||
|
max:{
|
||||||
|
type:Number,
|
||||||
|
default:undefined
|
||||||
|
},
|
||||||
|
//[val=>!!val ||'数値を入力してください',val=>val<=100 && val>=1 || '1-100の範囲内の数値を入力してください']
|
||||||
|
rules:{
|
||||||
|
type:String,
|
||||||
|
default:undefined
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [Number , String],
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const numValue = ref(props.modelValue);
|
||||||
|
const rulesExp = props.rules===undefined?null : eval(props.rules);
|
||||||
|
const isError = computed(()=>{
|
||||||
|
const val = numValue.value;
|
||||||
|
if (val === undefined) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const numVal = typeof val === "string" ? parseInt(val) : val;
|
||||||
|
// Ensure parsed value is a valid number
|
||||||
|
if (isNaN(numVal)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Check against min and max boundaries, if defined
|
||||||
|
if ((props.min !== undefined && numVal < props.min) || (props.max !== undefined && numVal > props.max)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
watchEffect(()=>{
|
||||||
|
emit("update:modelValue",numValue.value);
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
numValue,
|
||||||
|
rulesExp
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div v-for="(item, index) in properties" :key="index">
|
<div v-for="(item, index) in properties" :key="index" >
|
||||||
<component :is="item.component" v-bind="item.props" v-model="item.props.modelValue"></component>
|
<component :is="item.component" v-bind="item.props" :context="properties" :connectProps="connectProps(item.props)" v-model="item.props.modelValue"></component>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -15,7 +15,16 @@ import InputText from '../right/InputText.vue';
|
|||||||
import SelectBox from '../right/SelectBox.vue';
|
import SelectBox from '../right/SelectBox.vue';
|
||||||
import DatePicker from '../right/DatePicker.vue';
|
import DatePicker from '../right/DatePicker.vue';
|
||||||
import FieldInput from '../right/FieldInput.vue';
|
import FieldInput from '../right/FieldInput.vue';
|
||||||
import { IActionNode,IActionProperty } from 'src/types/ActionTypes';
|
import AppFieldSelect from './AppFieldSelect.vue';
|
||||||
|
import MuiltInputText from '../right/MuiltInputText.vue';
|
||||||
|
import ConditionInput from '../right/ConditionInput.vue';
|
||||||
|
import EventSetter from '../right/EventSetter.vue';
|
||||||
|
import ColorPicker from './ColorPicker.vue';
|
||||||
|
import NumInput from './NumInput.vue';
|
||||||
|
import DataProcessing from './DataProcessing.vue';
|
||||||
|
import DataMapping from './DataMapping.vue';
|
||||||
|
import AppSelect from './AppSelect.vue';
|
||||||
|
import { IActionNode,IActionProperty,IProp } from 'src/types/ActionTypes';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'PropertyList',
|
name: 'PropertyList',
|
||||||
@@ -23,7 +32,16 @@ export default defineComponent({
|
|||||||
InputText,
|
InputText,
|
||||||
SelectBox,
|
SelectBox,
|
||||||
DatePicker,
|
DatePicker,
|
||||||
FieldInput
|
FieldInput,
|
||||||
|
AppFieldSelect,
|
||||||
|
MuiltInputText,
|
||||||
|
ConditionInput,
|
||||||
|
EventSetter,
|
||||||
|
ColorPicker,
|
||||||
|
NumInput,
|
||||||
|
DataProcessing,
|
||||||
|
DataMapping,
|
||||||
|
AppSelect
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
nodeProps: {
|
nodeProps: {
|
||||||
@@ -36,10 +54,25 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
setup(props, context) {
|
setup(props, context) {
|
||||||
const properties=ref(props.nodeProps)
|
const properties=ref(props.nodeProps);
|
||||||
|
const connectProps=(props:IProp)=>{
|
||||||
|
const connProps:any={context:properties};
|
||||||
|
if(props && "connectProps" in props && props.connectProps!=undefined){
|
||||||
|
for(let connProp of props.connectProps){
|
||||||
|
let targetProp = properties.value.find((prop)=>prop.props.name===connProp.propName);
|
||||||
|
if(targetProp){
|
||||||
|
connProps[connProp.key]=targetProp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return connProps;
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
properties
|
properties,
|
||||||
|
connectProps
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -11,24 +11,24 @@
|
|||||||
elevated
|
elevated
|
||||||
overlay
|
overlay
|
||||||
>
|
>
|
||||||
<q-card class="column full-height" style="width: 300px">
|
<q-card class="column" style="max-width: 300px;min-height: 100%">
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
<div class="text-h6">プロパティ</div>
|
<div class="text-h6">{{ actionNode?.subTitle }}:設定</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-section class="col q-pt-none">
|
<q-card-section class="col q-pt-none">
|
||||||
<property-list :node-props="actionProps" v-if="showPanel" ></property-list>
|
<property-list :node-props="actionProps" v-if="showPanel" ></property-list>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
|
|
||||||
<q-card-actions align="right" class="bg-white text-teal">
|
<q-card-actions align="right" class="bg-white text-teal">
|
||||||
<q-btn flat label="Save" @click="save"/>
|
<q-btn flat label="キャンセル" @click="cancel" outline dense padding="none sm" color="primary"/>
|
||||||
<q-btn flat label="Cancel" @click="cancel" />
|
<q-btn flat label="更新" @click="save" outline dense padding="none sm" color="primary" />
|
||||||
</q-card-actions>
|
</q-card-actions>
|
||||||
</q-card>
|
</q-card>
|
||||||
</q-drawer>
|
</q-drawer>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { reactive, ref,defineComponent, defineProps,PropType ,watchEffect} from 'vue'
|
import { ref,defineComponent, PropType ,watchEffect} from 'vue'
|
||||||
import PropertyList from 'components/right/PropertyList.vue';
|
import PropertyList from 'components/right/PropertyList.vue';
|
||||||
import { IActionNode } from 'src/types/ActionTypes';
|
import { IActionNode } from 'src/types/ActionTypes';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@@ -47,24 +47,24 @@ import { IActionNode } from 'src/types/ActionTypes';
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: [
|
emits: [
|
||||||
"update:drawerRight"
|
'update:drawerRight'
|
||||||
],
|
],
|
||||||
setup(props,{emit}) {
|
setup(props,{emit}) {
|
||||||
const showPanel =ref(props.drawerRight);
|
const showPanel =ref(props.drawerRight);
|
||||||
const actionProps =ref(props.actionNode.actionProps);
|
const actionProps =ref(props.actionNode?.actionProps);
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
showPanel.value = props.drawerRight;
|
showPanel.value = props.drawerRight;
|
||||||
actionProps.value= props.actionNode.actionProps;
|
actionProps.value= props.actionNode?.actionProps;
|
||||||
});
|
});
|
||||||
|
|
||||||
const cancel = async() =>{
|
const cancel = async() =>{
|
||||||
showPanel.value = false;
|
showPanel.value = false;
|
||||||
emit("update:drawerRight",false )
|
emit('update:drawerRight',false )
|
||||||
}
|
}
|
||||||
|
|
||||||
const save = async () =>{
|
const save = async () =>{
|
||||||
showPanel.value=false;
|
showPanel.value=false;
|
||||||
emit("update:drawerRight",false )
|
emit('update:drawerRight',false )
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,13 +1,21 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-select v-model="selectedValue" :label="placeholder" :options="options"/>
|
<div v-bind="$attrs">
|
||||||
|
<q-select v-model="selectedValue" :use-chips="multiple" :label="displayName" label-color="primary" :options="options" stack-label
|
||||||
|
:multiple="multiple"/>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent,ref,watchEffect } from 'vue';
|
import { defineComponent,ref,watchEffect,computed } from 'vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'SelectBox',
|
name: 'SelectBox',
|
||||||
|
inheritAttrs:false,
|
||||||
props: {
|
props: {
|
||||||
|
displayName:{
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
placeholder: {
|
placeholder: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
@@ -16,20 +24,27 @@ export default defineComponent({
|
|||||||
type: Array,
|
type: Array,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
selectType:{
|
||||||
|
type:String,
|
||||||
|
default:'',
|
||||||
|
},
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: String,
|
type: [Array,String],
|
||||||
default: '',
|
default: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const selectedValue = ref(props.modelValue);
|
const selectedValue = ref(props.modelValue);
|
||||||
|
const multiple = computed(()=>{
|
||||||
|
return props.selectType==='multiple'
|
||||||
|
});
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
emit('update:modelValue', selectedValue.value);
|
emit('update:modelValue', selectedValue.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
selectedValue
|
selectedValue,
|
||||||
|
multiple
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
22
frontend/src/control/auth.ts
Normal file
22
frontend/src/control/auth.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { api } from 'boot/axios';
|
||||||
|
|
||||||
|
export class Auth
|
||||||
|
{
|
||||||
|
|
||||||
|
async login(user:string,pwd:string):Promise<boolean>
|
||||||
|
{
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
params.append('username', user);
|
||||||
|
params.append('password', pwd);
|
||||||
|
try{
|
||||||
|
const result = await api.post(`api/token`,params);
|
||||||
|
console.info(result);
|
||||||
|
localStorage.setItem('Token', result.data.access_token);
|
||||||
|
return true;
|
||||||
|
}catch(e)
|
||||||
|
{
|
||||||
|
console.info(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,37 +1,59 @@
|
|||||||
import { api } from 'boot/axios';
|
import { api } from 'boot/axios';
|
||||||
import { ActionFlow } from 'src/types/ActionTypes';
|
import { ActionFlow } from 'src/types/ActionTypes';
|
||||||
|
|
||||||
export class FlowCtrl
|
export class FlowCtrl {
|
||||||
{
|
async getFlows(appId: string): Promise<ActionFlow[]> {
|
||||||
|
const flows: ActionFlow[] = [];
|
||||||
|
try {
|
||||||
|
const result = await api.get(`api/flows/${appId}`);
|
||||||
|
//console.info(result.data);
|
||||||
|
if (!result.data || !Array.isArray(result.data)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
async getFlows(appId:string):Promise<ActionFlow[]>
|
for (const flow of result.data) {
|
||||||
{
|
flows.push(ActionFlow.fromJSON(flow.content));
|
||||||
const result = await api.get(`http://127.0.0.1:8000/api/flows/${appId}`);
|
}
|
||||||
//console.info(result.data);
|
return flows;
|
||||||
if(!result.data || !Array.isArray(result.data)){
|
} catch (error) {
|
||||||
return [];
|
console.error(error);
|
||||||
}
|
return flows;
|
||||||
const flows:ActionFlow[]=[];
|
}
|
||||||
for(const flow of result.data){
|
|
||||||
flows.push(ActionFlow.fromJSON(flow.content));
|
|
||||||
}
|
|
||||||
return flows;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async SaveFlow(jsonData:any):Promise<boolean>
|
async SaveFlow(jsonData: any): Promise<boolean> {
|
||||||
{
|
const result = await api.post('api/flow', jsonData);
|
||||||
const result = await api.post('http://127.0.0.1:8000/api/flow',jsonData);
|
console.info(result.data);
|
||||||
console.info(result.data)
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
/**
|
||||||
|
* フローを更新する
|
||||||
|
* @param jsonData
|
||||||
async UpdateFlow(jsonData:any):Promise<boolean>
|
* @returns
|
||||||
{
|
*/
|
||||||
const result = await api.put('http://127.0.0.1:8000/api/flow/' + jsonData.flowid,jsonData);
|
async UpdateFlow(jsonData: any): Promise<boolean> {
|
||||||
console.info(result.data)
|
const result = await api.put('api/flow/' + jsonData.flowid, jsonData);
|
||||||
|
console.info(result.data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* フローを消去する
|
||||||
|
* @param flowId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async DeleteFlow(flowId: string): Promise<boolean> {
|
||||||
|
const result = await api.delete('api/flow/' + flowId);
|
||||||
|
console.info(result.data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* デプロイ
|
||||||
|
* @param appid
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async depoly(appid: string): Promise<boolean> {
|
||||||
|
const result = await api.post(`api/v1/createjstokintone?app=${appid}`);
|
||||||
|
console.info(result.data);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1,25 @@
|
|||||||
// app global css in SCSS form
|
// app global css in SCSS form
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
height: 12px;
|
||||||
|
width: 14px;
|
||||||
|
background: transparent;
|
||||||
|
z-index: 12;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
width: 10px;
|
||||||
|
background-color: #c1c1c1;
|
||||||
|
border-radius: 10px;
|
||||||
|
z-index: 12;
|
||||||
|
border: 4px solid rgba(0, 0, 0, 0);
|
||||||
|
background-clip: padding-box;
|
||||||
|
transition: background-color .32s ease-in-out;
|
||||||
|
margin: 4px;
|
||||||
|
min-height: 32px;
|
||||||
|
min-width: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #c1c1c1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,14 +11,16 @@
|
|||||||
@click="toggleLeftDrawer"
|
@click="toggleLeftDrawer"
|
||||||
/>
|
/>
|
||||||
<q-toolbar-title>
|
<q-toolbar-title>
|
||||||
Kintone App Builder
|
{{ productName }}
|
||||||
<q-badge align="top" outline>V{{ env.version }}</q-badge>
|
<q-badge align="top" outline>V{{ version }}</q-badge>
|
||||||
</q-toolbar-title>
|
</q-toolbar-title>
|
||||||
|
<domain-selector></domain-selector>
|
||||||
|
<q-btn flat round dense icon="logout" @click="authStore.logout()"/>
|
||||||
</q-toolbar>
|
</q-toolbar>
|
||||||
</q-header>
|
</q-header>
|
||||||
|
|
||||||
<q-drawer
|
<q-drawer
|
||||||
v-model="leftDrawerOpen"
|
:model-value="authStore.toggleLeftDrawer"
|
||||||
:show-if-above="false"
|
:show-if-above="false"
|
||||||
bordered
|
bordered
|
||||||
>
|
>
|
||||||
@@ -26,7 +28,7 @@
|
|||||||
<q-item-label
|
<q-item-label
|
||||||
header
|
header
|
||||||
>
|
>
|
||||||
Essential Links
|
関連リンク
|
||||||
</q-item-label>
|
</q-item-label>
|
||||||
|
|
||||||
<EssentialLink
|
<EssentialLink
|
||||||
@@ -46,6 +48,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import EssentialLink, { EssentialLinkProps } from 'components/EssentialLink.vue';
|
import EssentialLink, { EssentialLinkProps } from 'components/EssentialLink.vue';
|
||||||
|
import DomainSelector from 'components/DomainSelector.vue';
|
||||||
|
import { useAuthStore } from 'stores/useAuthStore';
|
||||||
|
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
|
||||||
const essentialLinks: EssentialLinkProps[] = [
|
const essentialLinks: EssentialLinkProps[] = [
|
||||||
{
|
{
|
||||||
@@ -59,14 +65,14 @@ const essentialLinks: EssentialLinkProps[] = [
|
|||||||
title: 'フローエディター',
|
title: 'フローエディター',
|
||||||
caption: 'flowChart',
|
caption: 'flowChart',
|
||||||
icon: 'account_tree',
|
icon: 'account_tree',
|
||||||
link: '/#/flowEditor2',
|
link: '/#/FlowChart',
|
||||||
target:'_self'
|
target:'_self'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'FlowEditor',
|
title: '条件エディター',
|
||||||
caption: 'FlowEditor',
|
caption: 'condition',
|
||||||
icon: 'account_tree',
|
icon: 'tune',
|
||||||
link: '/#/flowEditor',
|
link: '/#/condition',
|
||||||
target:'_self'
|
target:'_self'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -145,11 +151,10 @@ const essentialLinks: EssentialLinkProps[] = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const leftDrawerOpen = ref(false)
|
const version = process.env.version;
|
||||||
|
const productName = process.env.productName;
|
||||||
const env=process.env;
|
|
||||||
|
|
||||||
function toggleLeftDrawer() {
|
function toggleLeftDrawer() {
|
||||||
leftDrawerOpen.value = !leftDrawerOpen.value
|
authStore.toggleLeftMenu();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,160 +1,274 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="q-pa-md q-gutter-sm event-tree">
|
|
||||||
<q-drawer
|
|
||||||
side="left"
|
|
||||||
overlay
|
|
||||||
bordered
|
|
||||||
v-model="drawerLeft"
|
|
||||||
:show-if-above="false"
|
|
||||||
elevated
|
|
||||||
>
|
|
||||||
<!-- <q-card class="column full-height" style="width: 300px">
|
|
||||||
<q-card-section> -->
|
|
||||||
|
|
||||||
<div class="flex-center fixd-top" >
|
|
||||||
<AppSelector />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- </q-card-section> -->
|
|
||||||
<q-separator />
|
|
||||||
<!-- <q-card-section> -->
|
|
||||||
<div class="flex-center">
|
|
||||||
<EventTree />
|
|
||||||
</div>
|
|
||||||
<!-- </q-card-section> -->
|
|
||||||
<!-- </q-card> -->
|
|
||||||
</q-drawer>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<q-page>
|
<q-page>
|
||||||
<div class="q-pa-md q-gutter-sm">
|
<q-layout container class="absolute-full shadow-2 rounded-borders">
|
||||||
<div class="flowchart" v-if="store.currentFlow">
|
<div class="q-pa-sm q-gutter-sm ">
|
||||||
<node-item v-for="(node,) in store.currentFlow.actionNodes" :key="node.id"
|
<q-drawer side="left" :overlay="true" bordered v-model="drawerLeft" :show-if-above="false" elevated>
|
||||||
:isSelected="node===state.activeNode" :actionNode="node"
|
<div class="flex-center fixed-top app-selector">
|
||||||
@addNode="addNode"
|
<AppSelector />
|
||||||
@nodeSelected="onNodeSelected"
|
</div>
|
||||||
@nodeEdit="onNodeEdit"
|
|
||||||
@deleteNode="onDeleteNode"
|
|
||||||
@deleteAllNextNodes="onDeleteAllNextNodes"
|
|
||||||
></node-item>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</q-page>
|
|
||||||
<PropertyPanel :actionNode="state.activeNode" v-model:drawerRight="drawerRight"></PropertyPanel>
|
|
||||||
<ShowDialog v-model:visible="showAddAction" name="アクション" @close="closeDg">
|
|
||||||
<action-select ref="appDg" name="model" type="single"></action-select>
|
|
||||||
</ShowDialog>
|
|
||||||
|
|
||||||
|
<div class="flex-center absolute-full" style="padding-top:65px;padding-left:15px;padding-right:15px;">
|
||||||
|
<q-scroll-area class="fit" :horizontal-thumb-style="{ opacity: '0' }">
|
||||||
|
<EventTree />
|
||||||
|
</q-scroll-area>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-center fixed-bottom bg-grey-3 q-pa-md row ">
|
||||||
|
<q-btn color="secondary" glossy label="デプロイ" @click="onDeploy" icon="sync" :loading="deployLoading" />
|
||||||
|
<q-space></q-space>
|
||||||
|
<q-btn color="primary" label="保存" @click="onSaveFlow" icon="save" :loading="saveLoading" />
|
||||||
|
</div>
|
||||||
|
</q-drawer>
|
||||||
|
</div>
|
||||||
|
<q-btn flat dense round
|
||||||
|
:icon="drawerLeft?'keyboard_double_arrow_left':'keyboard_double_arrow_right'"
|
||||||
|
:style="[drawerLeft?{'left':'300px'}:{'left':'0px'}]"
|
||||||
|
@click="drawerLeft=!drawerLeft" class="expand" />
|
||||||
|
<div class="q-pa-md q-gutter-sm" :style="{minWidth: minPanelWidth}">
|
||||||
|
<div class="flowchart" v-if="store.currentFlow" :style="[drawerLeft?{paddingLeft:'300px'}:{}]">
|
||||||
|
<node-item v-if="rootNode!==undefined" :key="rootNode.id" :isSelected="rootNode === store.activeNode"
|
||||||
|
:actionNode="rootNode" @addNode="addNode" @nodeSelected="onNodeSelected" @nodeEdit="onNodeEdit"
|
||||||
|
@deleteNode="onDeleteNode" @deleteAllNextNodes="onDeleteAllNextNodes" @copyFlow="onCopyFlow"></node-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<PropertyPanel :actionNode="store.activeNode" v-model:drawerRight="drawerRight"></PropertyPanel>
|
||||||
|
</q-layout>
|
||||||
|
<ShowDialog v-model:visible="showAddAction" name="アクション" @close="closeDg" min-width="500px" min-height="500px">
|
||||||
|
<template v-slot:toolbar>
|
||||||
|
<q-input dense debounce="200" v-model="filter" placeholder="検索" clearable>
|
||||||
|
<template v-slot:before>
|
||||||
|
<q-icon name="search" />
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</template>
|
||||||
|
<action-select ref="appDg" name="model" :filter="filter" type="single"></action-select>
|
||||||
|
</ShowDialog>
|
||||||
|
|
||||||
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {ref,reactive,computed,onMounted} from 'vue';
|
import { ref, reactive, computed, onMounted } from 'vue';
|
||||||
import {IActionNode, ActionNode, IActionFlow, ActionFlow,RootAction, IActionProperty } from 'src/types/ActionTypes';
|
import { IActionNode, ActionNode, IActionFlow, ActionFlow, RootAction, IActionProperty } from 'src/types/ActionTypes';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useFlowEditorStore } from 'stores/flowEditor';
|
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||||
|
import { useAuthStore } from 'stores/useAuthStore';
|
||||||
|
|
||||||
import NodeItem from 'src/components/main/NodeItem.vue';
|
import NodeItem from 'src/components/main/NodeItem.vue';
|
||||||
import ShowDialog from 'components/ShowDialog.vue';
|
import ShowDialog from 'components/ShowDialog.vue';
|
||||||
import ActionSelect from 'components/ActionSelect.vue';
|
import ActionSelect from 'components/ActionSelect.vue';
|
||||||
import PropertyPanel from 'components/right/PropertyPanel.vue';
|
import PropertyPanel from 'components/right/PropertyPanel.vue';
|
||||||
import AppSelector from 'components/left/AppSelector.vue';
|
import AppSelector from 'components/left/AppSelector.vue';
|
||||||
import EventTree from 'components/left/EventTree.vue';
|
import EventTree from 'components/left/EventTree.vue';
|
||||||
import {FlowCtrl } from '../control/flowctrl';
|
import { FlowCtrl } from '../control/flowctrl';
|
||||||
const drawerLeft = ref(true);
|
import { useQuasar } from 'quasar';
|
||||||
|
const deployLoading = ref(false);
|
||||||
|
const saveLoading = ref(false);
|
||||||
|
const drawerLeft = ref(false);
|
||||||
|
const $q = useQuasar();
|
||||||
const store = useFlowEditorStore();
|
const store = useFlowEditorStore();
|
||||||
// ref関数を使ってtemplateとバインド
|
const authStore = useAuthStore();
|
||||||
const state=reactive({
|
|
||||||
activeNode:{
|
|
||||||
id:""
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const appDg = ref();
|
const appDg = ref();
|
||||||
const prevNodeIfo=ref({
|
const prevNodeIfo = ref({
|
||||||
prevNode:{} as IActionNode,
|
prevNode: {} as IActionNode,
|
||||||
inputPoint:""
|
inputPoint: ""
|
||||||
});
|
});
|
||||||
const refFlow = ref<ActionFlow|null>(null);
|
// const refFlow = ref<ActionFlow|null>(null);
|
||||||
const showAddAction=ref(false);
|
const showAddAction = ref(false);
|
||||||
const drawerRight=ref(false);
|
const drawerRight = ref(false);
|
||||||
const model=ref("");
|
const filter=ref("");
|
||||||
const addActionNode=(action:IActionNode)=>{
|
const model = ref("");
|
||||||
|
const addActionNode = (action: IActionNode) => {
|
||||||
// refFlow.value?.actionNodes.push(action);
|
// refFlow.value?.actionNodes.push(action);
|
||||||
store.currentFlow?.actionNodes.push(action);
|
store.currentFlow?.actionNodes.push(action);
|
||||||
}
|
}
|
||||||
|
const rootNode = computed(()=>{
|
||||||
const addNode=(node:IActionNode,inputPoint:string)=>{
|
return store.currentFlow?.getRoot();
|
||||||
showAddAction.value=true;
|
});
|
||||||
prevNodeIfo.value.prevNode=node;
|
const minPanelWidth=computed(()=>{
|
||||||
prevNodeIfo.value.inputPoint=inputPoint;
|
const root = store.currentFlow?.getRoot();
|
||||||
}
|
if(store.currentFlow && root){
|
||||||
|
return store.currentFlow?.getColumns(root) * 300 + 'px';
|
||||||
const onNodeSelected=(node:IActionNode)=>{
|
}else{
|
||||||
//右パネルが開いている場合、自動閉じる
|
return "300px";
|
||||||
if(drawerRight.value && state.activeNode.id!==node.id){
|
|
||||||
drawerRight.value=false;
|
|
||||||
}
|
}
|
||||||
state.activeNode = node;
|
});
|
||||||
|
|
||||||
|
const addNode = (node: IActionNode, inputPoint: string) => {
|
||||||
|
if (drawerRight.value) {
|
||||||
|
drawerRight.value = false;
|
||||||
|
}
|
||||||
|
showAddAction.value = true;
|
||||||
|
prevNodeIfo.value.prevNode = node;
|
||||||
|
prevNodeIfo.value.inputPoint = inputPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
const onNodeEdit=(node:IActionNode)=>{
|
const onNodeSelected = (node: IActionNode) => {
|
||||||
state.activeNode = node;
|
//右パネルが開いている場合、自動閉じる
|
||||||
drawerRight.value=true;
|
if (drawerRight.value && store.activeNode?.id !== node.id) {
|
||||||
|
drawerRight.value = false;
|
||||||
|
}
|
||||||
|
store.setActiveNode(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
const onDeleteNode=(node:IActionNode)=>{
|
const onNodeEdit = (node: IActionNode) => {
|
||||||
if(!store.currentFlow) return;
|
store.setActiveNode(node);
|
||||||
|
drawerRight.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const onDeleteNode = (node: IActionNode) => {
|
||||||
|
if (!store.currentFlow) return;
|
||||||
|
//右パネルが開いている場合、自動閉じる
|
||||||
|
if (drawerRight.value && store.activeNode?.id === node.id) {
|
||||||
|
drawerRight.value = false;
|
||||||
|
}
|
||||||
store.currentFlow?.removeNode(node);
|
store.currentFlow?.removeNode(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
const onDeleteAllNextNodes=(node:IActionNode)=>{
|
const onDeleteAllNextNodes = (node: IActionNode) => {
|
||||||
if(!store.currentFlow) return;
|
if (!store.currentFlow) return;
|
||||||
|
//右パネルが開いている場合、自動閉じる
|
||||||
|
if (drawerRight.value) {
|
||||||
|
drawerRight.value = false;
|
||||||
|
}
|
||||||
store.currentFlow?.removeAllNext(node.id);
|
store.currentFlow?.removeAllNext(node.id);
|
||||||
}
|
}
|
||||||
const closeDg=(val :any)=>{
|
const closeDg = (val: any) => {
|
||||||
console.log("Dialog closed->",val);
|
console.log("Dialog closed->", val);
|
||||||
if (val == 'OK') {
|
if (val == 'OK') {
|
||||||
const data = appDg.value.selected[0];
|
const data = appDg.value.selected[0];
|
||||||
const actionProps=JSON.parse(data.content);
|
const actionProps = JSON.parse(data.property);
|
||||||
const action = new ActionNode(data.name,data.desc,"",[],actionProps);
|
const outputPoint = JSON.parse(data.outputPoints);
|
||||||
store.currentFlow?.addNode(action, prevNodeIfo.value.prevNode,prevNodeIfo.value.inputPoint);
|
const action = new ActionNode(data.name, data.desc, "", outputPoint, actionProps);
|
||||||
|
store.currentFlow?.addNode(action, prevNodeIfo.value.prevNode, prevNodeIfo.value.inputPoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
*フローのデータをコピーする
|
||||||
|
*/
|
||||||
|
const onCopyFlow = () => {
|
||||||
|
if (navigator.clipboard) {
|
||||||
|
const jsonData =JSON.stringify(store.currentFlow) ;
|
||||||
|
navigator.clipboard.writeText(jsonData).then(() => {
|
||||||
|
console.log('Text successfully copied to clipboard');
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
console.error('Error in copying text: ', err);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log('Clipboard API not available');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* デプロイ
|
||||||
|
*/
|
||||||
|
const onDeploy = async () => {
|
||||||
|
if (store.appInfo === undefined || store.flows?.length === 0) {
|
||||||
|
$q.notify({
|
||||||
|
type: 'negative',
|
||||||
|
caption: "エラー",
|
||||||
|
message: `設定されたフローがありません。`
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
deployLoading.value = true;
|
||||||
|
await store.deploy();
|
||||||
|
deployLoading.value = false;
|
||||||
|
$q.notify({
|
||||||
|
type: 'positive',
|
||||||
|
caption: "通知",
|
||||||
|
message: `デプロイを成功しました。`
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
deployLoading.value = false;
|
||||||
|
$q.notify({
|
||||||
|
type: 'negative',
|
||||||
|
caption: "エラー",
|
||||||
|
message: `デプロイが失敗しました。`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const fetchData= async ()=>{
|
const onSaveFlow = async () => {
|
||||||
|
const targetFlow = store.selectedFlow;
|
||||||
|
if (targetFlow === undefined) {
|
||||||
|
$q.notify({
|
||||||
|
type: 'negative',
|
||||||
|
caption: "エラー",
|
||||||
|
message: `編集中のフローがありません。`
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
saveLoading.value = true;
|
||||||
|
await store.saveFlow(targetFlow);
|
||||||
|
saveLoading.value = false;
|
||||||
|
$q.notify({
|
||||||
|
type: 'positive',
|
||||||
|
caption: "通知",
|
||||||
|
message: `${targetFlow.getRoot()?.subTitle}のフロー設定を保存しました。`
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
saveLoading.value = false;
|
||||||
|
$q.notify({
|
||||||
|
type: 'negative',
|
||||||
|
caption: "エラー",
|
||||||
|
message: `${targetFlow.getRoot()?.subTitle}のフローの設定の保存が失敗しました。`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchData = async () => {
|
||||||
|
drawerLeft.value = true;
|
||||||
|
if (store.appInfo === undefined) return;
|
||||||
const flowCtrl = new FlowCtrl();
|
const flowCtrl = new FlowCtrl();
|
||||||
if(store.appInfo===undefined) return;
|
|
||||||
const actionFlows = await flowCtrl.getFlows(store.appInfo?.appId);
|
const actionFlows = await flowCtrl.getFlows(store.appInfo?.appId);
|
||||||
if(actionFlows && actionFlows.length>0){
|
if (actionFlows && actionFlows.length > 0) {
|
||||||
store.setFlows(actionFlows);
|
store.setFlows(actionFlows);
|
||||||
}
|
}
|
||||||
if(actionFlows && actionFlows.length==1){
|
if (actionFlows && actionFlows.length == 1) {
|
||||||
store.selectFlow(actionFlows[0]);
|
store.selectFlow(actionFlows[0]);
|
||||||
}
|
}
|
||||||
refFlow.value=actionFlows[0];
|
const root = actionFlows[0].getRoot();
|
||||||
const root =refFlow.value.getRoot();
|
if (root) {
|
||||||
if(root){
|
store.setActiveNode(root);
|
||||||
state.activeNode=root;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
authStore.toggleLeftMenu();
|
||||||
fetchData();
|
fetchData();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.flowchart{
|
.app-selector {
|
||||||
padding-top: 10px;
|
padding: 15px;
|
||||||
}
|
z-index: 999;
|
||||||
.flow-toolbar{
|
}
|
||||||
|
|
||||||
|
.flowchart {
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flow-toolbar {
|
||||||
opacity: 50%;
|
opacity: 50%;
|
||||||
}
|
}
|
||||||
.flow-container{
|
|
||||||
height: 91.5dvb;
|
.event-tree .q-drawer {
|
||||||
overflow: hidden;
|
top: 50px;
|
||||||
}
|
z-index: 999;
|
||||||
.event-tree .q-drawer {
|
}
|
||||||
top:50px;
|
.expand{
|
||||||
z-index: 999;
|
position: fixed;
|
||||||
}
|
left: 0px;
|
||||||
|
top: 50%;
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</q-page>
|
</q-page>
|
||||||
<PropertyPanel :actionNode="state.activeNode" v-model:drawerRight="drawerRight"></PropertyPanel>
|
<PropertyPanel :actionNode="state.activeNode" v-model:drawerRight="drawerRight"></PropertyPanel>
|
||||||
<show-dialog v-model:visible="showAddAction" name="アクション" @close="closeDg">
|
<show-dialog v-model:visible="showAddAction" name="アクション" @close="closeDg" width="350px">
|
||||||
<action-select ref="appDg" name="アクション" type="single"></action-select>
|
<action-select ref="appDg" name="アクション" type="single"></action-select>
|
||||||
</show-dialog>
|
</show-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,117 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div >
|
|
||||||
<div class="q-ma-md">
|
|
||||||
<div class="q-gutter-xs row items-start">
|
|
||||||
<q-btn
|
|
||||||
size="md"
|
|
||||||
@click="drawerLeft = !drawerLeft"
|
|
||||||
icon="keyboard_double_arrow_right"
|
|
||||||
round
|
|
||||||
/>
|
|
||||||
|
|
||||||
<q-space />
|
|
||||||
<q-btn
|
|
||||||
color="white"
|
|
||||||
size="sm"
|
|
||||||
text-color="black"
|
|
||||||
label="キャンセル"
|
|
||||||
dense
|
|
||||||
/>
|
|
||||||
|
|
||||||
<q-btn
|
|
||||||
class="q-px-sm"
|
|
||||||
color="primary"
|
|
||||||
size="sm"
|
|
||||||
label="保存する"
|
|
||||||
@click="save()"
|
|
||||||
dense
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<q-layout
|
|
||||||
container
|
|
||||||
class="flow-container shadow-2 rounded-borders"
|
|
||||||
>
|
|
||||||
<q-drawer side="left" overlay bordered v-model="drawerLeft">
|
|
||||||
<div class="q-pa-sm fixed-right">
|
|
||||||
<q-btn
|
|
||||||
flat
|
|
||||||
round
|
|
||||||
color="primary"
|
|
||||||
icon="close"
|
|
||||||
@click="drawerLeft = !drawerLeft"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="q-mt-lg q-pa-sm">
|
|
||||||
<q-card-section>
|
|
||||||
<div class="flex-center">
|
|
||||||
<ItemSelector />
|
|
||||||
</div>
|
|
||||||
</q-card-section>
|
|
||||||
</div>
|
|
||||||
<q-separator />
|
|
||||||
<div class="q-mt-md q-pa-sm">
|
|
||||||
<q-card-section>
|
|
||||||
<ControlPanel />
|
|
||||||
</q-card-section>
|
|
||||||
</div>
|
|
||||||
<q-separator />
|
|
||||||
<q-card-actions align="right">
|
|
||||||
<div class="q-pa-sm">
|
|
||||||
<q-btn
|
|
||||||
flat
|
|
||||||
color="primary"
|
|
||||||
size="md"
|
|
||||||
@click="drawerLeft = !drawerLeft"
|
|
||||||
label="ジャンプ"
|
|
||||||
dense
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</q-card-actions>
|
|
||||||
</q-drawer>
|
|
||||||
|
|
||||||
<FlowChartTest />
|
|
||||||
</q-layout>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import FlowChartTest from 'pages/FlowChartTest.vue';
|
|
||||||
import ControlPanel from 'components/flowEditor/left/ControlPanelC.vue';
|
|
||||||
import ItemSelector from 'components/flowEditor/left/ItemSelector.vue';
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import { storeToRefs } from 'pinia';
|
|
||||||
import { useFlowEditorStore } from 'stores/flowEditor';
|
|
||||||
import { FlowCtrl } from '../control/flowctrl'
|
|
||||||
|
|
||||||
const flowCtrl = new FlowCtrl();
|
|
||||||
const actName = ref('勤怠管理 - 4');
|
|
||||||
|
|
||||||
const drawerLeft = ref(false);
|
|
||||||
const store = useFlowEditorStore();
|
|
||||||
const { flowNames1 } = storeToRefs(store);
|
|
||||||
let isNew = ref(true);
|
|
||||||
|
|
||||||
const save = () =>{
|
|
||||||
|
|
||||||
if(isNew.value)
|
|
||||||
{
|
|
||||||
flowCtrl.SaveFlow({appid:'1',flowid:'flow123',eventid:'event123',name:'test',content:'[]'});
|
|
||||||
isNew.value = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
flowCtrl.UpdateFlow({appid:'1',flowid:'flow123',eventid:'event123',name:'test',content:'[{"a":"b"}]'});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.flow-toolbar{
|
|
||||||
opacity: 50%;
|
|
||||||
}
|
|
||||||
.flow-container{
|
|
||||||
height: calc(91.5dvb - 50px);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
112
frontend/src/pages/LoginPage.vue
Normal file
112
frontend/src/pages/LoginPage.vue
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
<template>
|
||||||
|
<q-layout view="lHh Lpr fff">
|
||||||
|
<q-page-container>
|
||||||
|
<q-page class="window-height window-width row justify-center items-center">
|
||||||
|
<div class="column q-pa-lg">
|
||||||
|
<div class="row">
|
||||||
|
<q-card :square="false" class="shadow-24" style="width:400px;height:540px;">
|
||||||
|
<q-card-section class="bg-primary">
|
||||||
|
<h4 class="text-h5 text-white q-my-md">{{ title}}</h4>
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-section>
|
||||||
|
<q-form class="q-px-sm q-pt-xl" ref="loginForm">
|
||||||
|
<q-input square clearable v-model="email" type="email" lazy-rules
|
||||||
|
:rules="[required,isEmail,short]" label="メール">
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<q-icon name="email" />
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
<q-input square clearable v-model="password" :type="passwordFieldType" lazy-rules
|
||||||
|
:rules="[required, short]" label="パスワード">
|
||||||
|
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<q-icon name="lock" />
|
||||||
|
</template>
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-icon :name="visibilityIcon" @click="switchVisibility" class="cursor-pointer" />
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</q-form>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-card-actions class="q-px-lg">
|
||||||
|
<q-btn :loading="loading" unelevated size="lg" color="secondary" @click="submit" class="full-width text-white"
|
||||||
|
label="ログイン" >
|
||||||
|
<template v-slot:loading>
|
||||||
|
<q-spinner class="on-left" />
|
||||||
|
ログイン中...
|
||||||
|
</template>
|
||||||
|
</q-btn>
|
||||||
|
</q-card-actions>
|
||||||
|
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</q-page>
|
||||||
|
</q-page-container>
|
||||||
|
</q-layout>>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useQuasar } from 'quasar'
|
||||||
|
// import { useRouter } from 'vue-router';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
// import { Auth } from '../control/auth'
|
||||||
|
import { useAuthStore } from 'stores/useAuthStore';
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
const $q = useQuasar()
|
||||||
|
const loginForm = ref(null);
|
||||||
|
const loading = ref(false);
|
||||||
|
let title = ref('ログイン');
|
||||||
|
let email = ref('');
|
||||||
|
let password = ref('');
|
||||||
|
let visibility = ref(false);
|
||||||
|
let passwordFieldType = ref('password');
|
||||||
|
let visibilityIcon = ref('visibility');
|
||||||
|
const required = (val:string) => {
|
||||||
|
return (val && val.length > 0 || '必須項目')
|
||||||
|
}
|
||||||
|
const isEmail = (val:string) => {
|
||||||
|
const emailPattern = /^(?=[a-zA-Z0-9@._%+-]{6,254}$)[a-zA-Z0-9._%+-]{1,64}@(?:[a-zA-Z0-9-]{1,63}\.){1,8}[a-zA-Z]{2,63}$/
|
||||||
|
return (emailPattern.test(val) || '無効なメールアドレス')
|
||||||
|
}
|
||||||
|
const short = (val:string) => {
|
||||||
|
return (val && val.length > 3 || '値が短く過ぎる')
|
||||||
|
}
|
||||||
|
const switchVisibility = () => {
|
||||||
|
visibility.value = !visibility.value
|
||||||
|
passwordFieldType.value = visibility.value ? 'text' : 'password'
|
||||||
|
visibilityIcon.value = visibility.value ? 'visibility_off' : 'visibility'
|
||||||
|
}
|
||||||
|
const submit = async () =>{
|
||||||
|
loading.value=true;
|
||||||
|
try {
|
||||||
|
const result = await authStore.login(email.value,password.value);
|
||||||
|
loading.value=false;
|
||||||
|
if(result){
|
||||||
|
$q.notify({
|
||||||
|
icon: 'done',
|
||||||
|
color: 'positive',
|
||||||
|
message: 'ログイン成功'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$q.notify({
|
||||||
|
icon: 'error',
|
||||||
|
color: 'negative',
|
||||||
|
message: 'ログイン失敗'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
loading.value=false;
|
||||||
|
$q.notify({
|
||||||
|
icon: 'error',
|
||||||
|
color: 'negative',
|
||||||
|
message: 'ログイン失敗'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
@@ -22,9 +22,9 @@
|
|||||||
<div class="q-pa-md">
|
<div class="q-pa-md">
|
||||||
<q-select v-model="model" :options="options" label="Standard"/>
|
<q-select v-model="model" :options="options" label="Standard"/>
|
||||||
<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">
|
<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'
|
||||||
|
|||||||
206
frontend/src/pages/TenantDomain.vue
Normal file
206
frontend/src/pages/TenantDomain.vue
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
<template>
|
||||||
|
<div class="q-pa-md">
|
||||||
|
<q-table title="Treats" :rows="rows" :columns="columns" row-key="id" selection="single" :filter="filter"
|
||||||
|
:loading="loading" v-model:selected="selected">
|
||||||
|
|
||||||
|
<template v-slot:top>
|
||||||
|
<q-btn color="primary" :disable="loading" label="新規" @click="addRow" />
|
||||||
|
<q-btn class="q-ml-sm" color="primary" :disable="loading" label="編集" @click="editRow" />
|
||||||
|
<q-btn class="q-ml-sm" color="primary" :disable="loading" label="削除" @click="removeRow" />
|
||||||
|
<q-space />
|
||||||
|
<q-input borderless dense debounce="300" color="primary" v-model="filter">
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-icon name="search" />
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</q-table>
|
||||||
|
|
||||||
|
<q-dialog :model-value="show" persistent>
|
||||||
|
<q-card style="min-width: 400px">
|
||||||
|
<q-card-section>
|
||||||
|
<div class="text-h6">Kintone Account</div>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-card-section class="q-pt-none">
|
||||||
|
<q-form class="q-gutter-md">
|
||||||
|
<q-input filled v-model="tenantid" label="Tenant" hint="Tenant ID" lazy-rules
|
||||||
|
:rules="[val => val && val.length > 0 || 'Please type something']" />
|
||||||
|
|
||||||
|
<q-input filled v-model="name" label="Your name *" hint="Kintone envirment name" lazy-rules
|
||||||
|
:rules="[val => val && val.length > 0 || 'Please type something']" />
|
||||||
|
|
||||||
|
<q-input filled type="url" v-model="url" label="Kintone url" hint="Kintone domain address" lazy-rules
|
||||||
|
:rules="[val => val && val.length > 0, isDomain || 'Please type something']" />
|
||||||
|
|
||||||
|
<q-input filled v-model="kintoneuser" label="Login user " hint="Kintone user name" lazy-rules
|
||||||
|
:rules="[val => val && val.length > 0 || 'Please type something']" />
|
||||||
|
|
||||||
|
<q-input v-model="kintonepwd" filled :type="isPwd ? 'password' : 'text'" hint="Password with toggle"
|
||||||
|
label="User password">
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-icon :name="isPwd ? 'visibility_off' : 'visibility'" class="cursor-pointer" @click="isPwd = !isPwd" />
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</q-form>
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-actions align="right" class="text-primary">
|
||||||
|
<q-btn label="Save" type="submit" color="primary" @click="onSubmit" />
|
||||||
|
<q-btn label="Cancel" type="cancel" color="primary" flat class="q-ml-sm" @click="closeDg()" />
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
|
||||||
|
</q-dialog>
|
||||||
|
|
||||||
|
<q-dialog v-model="confirm" persistent>
|
||||||
|
<q-card>
|
||||||
|
<q-card-section class="row items-center">
|
||||||
|
<q-avatar icon="confirm" color="primary" text-color="white" />
|
||||||
|
<span class="q-ml-sm">削除してもよろしいですか?</span>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-card-actions align="right">
|
||||||
|
<q-btn flat label="Cancel" color="primary" v-close-popup />
|
||||||
|
<q-btn flat label="OK" color="primary" v-close-popup @click="deleteDomain()" />
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, reactive } from 'vue';
|
||||||
|
import { api } from 'boot/axios';
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{ name: 'id' },
|
||||||
|
{
|
||||||
|
name: 'tenantid',
|
||||||
|
required: true,
|
||||||
|
label: 'Tenant',
|
||||||
|
align: 'left',
|
||||||
|
field: row => row.tenantid,
|
||||||
|
format: val => `${val}`,
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{ name: 'name', align: 'center', label: 'Name', field: 'name', sortable: true },
|
||||||
|
{ name: 'url', align: 'left', label: 'URL', field: 'url', sortable: true },
|
||||||
|
{ name: 'user', label: 'Account', field: 'user' },
|
||||||
|
{ name: 'password', label: 'Password', field: 'password' }
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
const loading = ref(false);
|
||||||
|
const filter = ref('');
|
||||||
|
const rows = ref([]);
|
||||||
|
const show = ref(false);
|
||||||
|
const confirm = ref(false);
|
||||||
|
const selected = ref([]);
|
||||||
|
const tenantid = ref('');
|
||||||
|
const name = ref('');
|
||||||
|
const url = ref('');
|
||||||
|
const isPwd = ref(true);
|
||||||
|
const kintoneuser = ref('');
|
||||||
|
const kintonepwd = ref('');
|
||||||
|
|
||||||
|
let editId = ref(0);
|
||||||
|
|
||||||
|
const getDomain = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const result= await api.get(`api/domains/1`);
|
||||||
|
rows.value= result.data.map((item)=>{
|
||||||
|
return { id: item.id, tenantid: item.tenantid, name: item.name, url: item.url, user: item.kintoneuser, password: item.kintonepwd }
|
||||||
|
});
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await getDomain();
|
||||||
|
})
|
||||||
|
|
||||||
|
// emulate fetching data from server
|
||||||
|
const addRow = () => {
|
||||||
|
editId.value
|
||||||
|
show.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeRow = () => {
|
||||||
|
//loading.value = true
|
||||||
|
confirm.value = true;
|
||||||
|
let row = JSON.parse(JSON.stringify(selected.value[0]));
|
||||||
|
if (selected.value.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
editId.value = row.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteDomain = () => {
|
||||||
|
api.delete(`api/domain/${editId.value}`).then(() => {
|
||||||
|
getDomain();
|
||||||
|
})
|
||||||
|
editId.value = 0;
|
||||||
|
selected.value = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
const editRow = () => {
|
||||||
|
if (selected.value.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let row = JSON.parse(JSON.stringify(selected.value[0]));
|
||||||
|
editId.value = row.id;
|
||||||
|
tenantid.value = row.tenantid;
|
||||||
|
name.value = row.name;
|
||||||
|
url.value = row.url;
|
||||||
|
kintoneuser.value = row.user;
|
||||||
|
kintonepwd.value = row.password;
|
||||||
|
isPwd.value = true;
|
||||||
|
show.value = true;
|
||||||
|
};
|
||||||
|
const closeDg = () => {
|
||||||
|
show.value = false;
|
||||||
|
onReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSubmit = () => {
|
||||||
|
if (editId.value !== 0) {
|
||||||
|
api.put(`api/domain`, {
|
||||||
|
'id': editId.value,
|
||||||
|
'tenantid': tenantid.value,
|
||||||
|
'name': name.value,
|
||||||
|
'url': url.value,
|
||||||
|
'kintoneuser': kintoneuser.value,
|
||||||
|
'kintonepwd': kintonepwd.value
|
||||||
|
}).then(() => {
|
||||||
|
getDomain();
|
||||||
|
closeDg();
|
||||||
|
onReset();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
api.post(`api/domain`, {
|
||||||
|
'id': 0,
|
||||||
|
'tenantid': tenantid.value,
|
||||||
|
'name': name.value,
|
||||||
|
'url': url.value,
|
||||||
|
'kintoneuser': kintoneuser.value,
|
||||||
|
'kintonepwd': kintonepwd.value
|
||||||
|
}).then(() => {
|
||||||
|
getDomain();
|
||||||
|
closeDg();
|
||||||
|
onReset();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
selected.value = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const onReset = () => {
|
||||||
|
name.value = '';
|
||||||
|
url.value = '';
|
||||||
|
kintoneuser.value = '';
|
||||||
|
kintonepwd.value = '';
|
||||||
|
isPwd.value = true;
|
||||||
|
editId.value = 0;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
270
frontend/src/pages/UserDomain.vue
Normal file
270
frontend/src/pages/UserDomain.vue
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
<!-- <template>
|
||||||
|
<div class="q-pa-md" style="max-width: 400px">
|
||||||
|
|
||||||
|
<q-form
|
||||||
|
@submit="onSubmit"
|
||||||
|
@reset="onReset"
|
||||||
|
class="q-gutter-md"
|
||||||
|
>
|
||||||
|
<q-input
|
||||||
|
filled
|
||||||
|
v-model="name"
|
||||||
|
label="Your name *"
|
||||||
|
hint="Kintone envirment name"
|
||||||
|
lazy-rules
|
||||||
|
:rules="[ val => val && val.length > 0 || 'Please type something']"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<q-input
|
||||||
|
filled type="url"
|
||||||
|
v-model="url"
|
||||||
|
label="Kintone url"
|
||||||
|
hint="Kintone domain address"
|
||||||
|
lazy-rules
|
||||||
|
:rules="[ val => val && val.length > 0,isDomain || 'Please type something']"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<q-input
|
||||||
|
filled
|
||||||
|
v-model="username"
|
||||||
|
label="Login user "
|
||||||
|
hint="Kintone user name"
|
||||||
|
lazy-rules
|
||||||
|
:rules="[ val => val && val.length > 0 || 'Please type something']"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<q-input v-model="password" filled :type="isPwd ? 'password' : 'text'" hint="Password with toggle" label="User password">
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-icon
|
||||||
|
:name="isPwd ? 'visibility_off' : 'visibility'"
|
||||||
|
class="cursor-pointer"
|
||||||
|
@click="isPwd = !isPwd"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
|
||||||
|
<q-toggle v-model="accept" label="Active Domain" />
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<q-btn label="Submit" type="submit" color="primary"/>
|
||||||
|
<q-btn label="Reset" type="reset" color="primary" flat class="q-ml-sm" />
|
||||||
|
</div>
|
||||||
|
</q-form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { useQuasar } from 'quasar'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup () {
|
||||||
|
const $q = useQuasar()
|
||||||
|
|
||||||
|
const name = ref(null)
|
||||||
|
const age = ref(null)
|
||||||
|
const accept = ref(false)
|
||||||
|
const isPwd =ref(true)
|
||||||
|
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
age,
|
||||||
|
accept,
|
||||||
|
isPwd,
|
||||||
|
isDomain(val) {
|
||||||
|
const domainPattern = /^https?\/\/:([a-zA-Z] +\.){1}([a-zA-Z]+)\.([a-zA-Z]+)$/;
|
||||||
|
return (domainPattern.test(val) || '無効なURL')
|
||||||
|
},
|
||||||
|
|
||||||
|
onSubmit () {
|
||||||
|
if (accept.value !== true) {
|
||||||
|
$q.notify({
|
||||||
|
color: 'red-5',
|
||||||
|
textColor: 'white',
|
||||||
|
icon: 'warning',
|
||||||
|
message: 'You need to accept the license and terms first'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$q.notify({
|
||||||
|
color: 'green-4',
|
||||||
|
textColor: 'white',
|
||||||
|
icon: 'cloud_done',
|
||||||
|
message: 'Submitted'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onReset () {
|
||||||
|
name.value = null
|
||||||
|
age.value = null
|
||||||
|
accept.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script> -->
|
||||||
|
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="q-pa-md">
|
||||||
|
<q-table grid grid-header title="Domain" selection="single" :rows="rows" :columns="columns" v-model:selected="selected" row-key="name" :filter="filter" hide-header>
|
||||||
|
<template v-slot:top>
|
||||||
|
<div class="q-pa-md q-gutter-sm">
|
||||||
|
<q-btn color="primary" label="追加" @click="newDomain()" dense />
|
||||||
|
</div>
|
||||||
|
<q-space />
|
||||||
|
<q-input borderless dense debounce="300" v-model="filter" placeholder="Search">
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-icon name="search" />
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</template>
|
||||||
|
<template v-slot:item="props">
|
||||||
|
<div class="q-pa-xs col-xs-12 col-sm-6 col-md-4">
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<div class="q-table__grid-item-row">
|
||||||
|
<div class="q-table__grid-item-title">Domain</div>
|
||||||
|
<div class="q-table__grid-item-value">{{ props.row.name }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="q-table__grid-item-row">
|
||||||
|
<div class="q-table__grid-item-title">URL</div>
|
||||||
|
<div class="q-table__grid-item-value">{{ props.row.url }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="q-table__grid-item-row">
|
||||||
|
<div class="q-table__grid-item-title">Account</div>
|
||||||
|
<div class="q-table__grid-item-value">{{ props.row.kintoneuser }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="q-table__grid-item-row">
|
||||||
|
<div class="q-table__grid-item-value">{{isActive(props.row.id) }}</div>
|
||||||
|
</div>
|
||||||
|
</q-card-section>
|
||||||
|
<q-separator />
|
||||||
|
<q-card-actions align="right">
|
||||||
|
<q-btn flat @click = "activeDomain(props.row.id)">有効</q-btn>
|
||||||
|
<q-btn flat @click = "deleteConfirm(props.row)">削除</q-btn>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</q-table>
|
||||||
|
|
||||||
|
<show-dialog v-model:visible="show" name="ドメイン" @close="closeDg" width="350px">
|
||||||
|
<domain-select ref="domainDg" name="ドメイン" type="multiple"></domain-select>
|
||||||
|
</show-dialog>
|
||||||
|
|
||||||
|
<q-dialog v-model="confirm" persistent>
|
||||||
|
<q-card>
|
||||||
|
<q-card-section class="row items-center">
|
||||||
|
<q-avatar icon="confirm" color="primary" text-color="white" />
|
||||||
|
<span class="q-ml-sm">削除してもよろしいですか?</span>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-card-actions align="right">
|
||||||
|
<q-btn flat label="Cancel" color="primary" v-close-popup />
|
||||||
|
<q-btn flat label="OK" color="primary" v-close-popup @click = "deleteDomain()"/>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useQuasar } from 'quasar'
|
||||||
|
import { ref, onMounted, reactive } from 'vue'
|
||||||
|
import ShowDialog from 'components/ShowDialog.vue';
|
||||||
|
import DomainSelect from 'components/DomainSelect.vue';
|
||||||
|
import { useAuthStore } from 'stores/useAuthStore';
|
||||||
|
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
import { api } from 'boot/axios';
|
||||||
|
import { domain } from 'process';
|
||||||
|
|
||||||
|
const $q = useQuasar()
|
||||||
|
|
||||||
|
const domainDg = ref();
|
||||||
|
const selected = ref([])
|
||||||
|
|
||||||
|
const show = ref(false);
|
||||||
|
const confirm = ref(false)
|
||||||
|
|
||||||
|
let editId = ref(0);
|
||||||
|
let activedomainid = ref(0);
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{ name: 'id'},
|
||||||
|
{name: 'name',required: true,label: 'Name',align: 'left',field: 'name',sortable: true},
|
||||||
|
{ name: 'url', align: 'center', label: 'Domain', field: 'url', sortable: true },
|
||||||
|
{ name: 'kintoneuser', label: 'User', field: 'kintoneuser', sortable: true },
|
||||||
|
{ name: 'kintonepwd' },
|
||||||
|
{ name: 'active', field: 'active'}
|
||||||
|
]
|
||||||
|
|
||||||
|
const rows = ref([] as any[]);
|
||||||
|
|
||||||
|
const isActive = (id:number) =>{
|
||||||
|
if(id == activedomainid.value)
|
||||||
|
return "Active";
|
||||||
|
else
|
||||||
|
return "Inactive";
|
||||||
|
}
|
||||||
|
|
||||||
|
const newDomain = () => {
|
||||||
|
editId.value = 0;
|
||||||
|
show.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const activeDomain = (id:number) => {
|
||||||
|
api.put(`api/activedomain/`+ id).then(() =>{
|
||||||
|
getDomain();
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteConfirm = (row:object) => {
|
||||||
|
confirm.value = true;
|
||||||
|
editId.value = row.id;
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteDomain = () => {
|
||||||
|
api.delete(`api/domain/`+ editId.value+'/1').then(() =>{
|
||||||
|
getDomain();
|
||||||
|
})
|
||||||
|
editId.value = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeDg = (val:string) => {
|
||||||
|
if (val == 'OK') {
|
||||||
|
let dodmainids =[];
|
||||||
|
let domains = JSON.parse(JSON.stringify(domainDg.value.selected));
|
||||||
|
for(var key in domains)
|
||||||
|
{
|
||||||
|
dodmainids.push(domains[key].id);
|
||||||
|
}
|
||||||
|
api.post(`api/domain`, dodmainids).then(() =>{getDomain();});
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
const getDomain = async () => {
|
||||||
|
const resp = await api.get(`api/activedomain`);
|
||||||
|
activedomainid.value = resp.data.id;
|
||||||
|
const domainResult = await api.get(`api/domain`);
|
||||||
|
const domains = domainResult.data as any[];
|
||||||
|
rows.value=domains.map((item)=>{
|
||||||
|
return { id:item.id,name: item.name, url: item.url, kintoneuser: item.kintoneuser, kintonepwd: item.kintonepwd}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
onMounted(async () => {
|
||||||
|
await getDomain();
|
||||||
|
})
|
||||||
|
|
||||||
|
const isDomain = (val) =>{
|
||||||
|
// const domainPattern = /^https\/\/:([a-zA-Z] +\.){1}([a-zA-Z]+)\.([a-zA-Z]+)$/;
|
||||||
|
// return (domainPattern.test(val) || '無効なURL')
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
39
frontend/src/pages/conditionPage.vue
Normal file
39
frontend/src/pages/conditionPage.vue
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<template>
|
||||||
|
<q-page>
|
||||||
|
<div class="flowchart">
|
||||||
|
<q-btn @click="showCondition()" class="q-mt-md" color="primary" icon="mdi-plus">条件エディタ表示</q-btn>
|
||||||
|
</div>
|
||||||
|
<condition-editor v-model:show="show" v-model:conditionTree="tree"></condition-editor>
|
||||||
|
<q-code>{{conditionString}}</q-code>
|
||||||
|
</q-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {ref,reactive,computed} from 'vue';
|
||||||
|
import ConditionEditor from '../components/ConditionEditor/ConditionEditor.vue';
|
||||||
|
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||||
|
import { ConditionTree,GroupNode,ConditionNode,LogicalOperator,Operator } from 'app/src/types/Conditions';
|
||||||
|
|
||||||
|
const store = useFlowEditorStore();
|
||||||
|
const tree = reactive(new ConditionTree());
|
||||||
|
const newNode = new ConditionNode({},Operator.Equal,'',tree.root);
|
||||||
|
tree.addNode(tree.root,newNode);
|
||||||
|
|
||||||
|
const show =ref(false);
|
||||||
|
const showCondition=()=>{
|
||||||
|
show.value=true;
|
||||||
|
}
|
||||||
|
const conditionString = computed(()=>{
|
||||||
|
return tree.buildConditionString(tree.root);
|
||||||
|
});
|
||||||
|
store.setApp({
|
||||||
|
appId:'146',
|
||||||
|
name:'トリトン管理部日報'
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.flowchart {
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<div class="q-pa-md column content-center items-center">
|
<div class="q-pa-md column content-center items-center">
|
||||||
<div>
|
<div>
|
||||||
<q-btn label="アクション選択" color="primary" @click="showDg()" v-if="addshow" />
|
<q-btn label="アクション選択" color="primary" @click="showDg()" v-if="addshow" />
|
||||||
<show-dialog v-model:visible="show" name="アクション" @close="closeDg">
|
<show-dialog v-model:visible="show" name="アクション" @close="closeDg" width="350px">
|
||||||
<action-select ref="appDg" name="アクション" type="single"></action-select>
|
<action-select ref="appDg" name="アクション" type="single"></action-select>
|
||||||
</show-dialog>
|
</show-dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
} from 'vue-router';
|
} from 'vue-router';
|
||||||
|
|
||||||
import routes from './routes';
|
import routes from './routes';
|
||||||
|
import { useAuthStore } from 'stores/useAuthStore';
|
||||||
/*
|
/*
|
||||||
* If not building with SSR mode, you can
|
* If not building with SSR mode, you can
|
||||||
* directly export the Router instantiation;
|
* directly export the Router instantiation;
|
||||||
@@ -17,20 +17,60 @@ import routes from './routes';
|
|||||||
* with the Router instance.
|
* with the Router instance.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default route(function (/* { store, ssrContext } */) {
|
const createHistory = process.env.SERVER
|
||||||
const createHistory = process.env.SERVER
|
? createMemoryHistory
|
||||||
? createMemoryHistory
|
: (process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory);
|
||||||
: (process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory);
|
|
||||||
|
|
||||||
const Router = createRouter({
|
const routerInstance = createRouter({
|
||||||
scrollBehavior: () => ({ left: 0, top: 0 }),
|
scrollBehavior: () => ({ left: 0, top: 0 }),
|
||||||
routes,
|
routes,
|
||||||
|
|
||||||
// Leave this as is and make changes in quasar.conf.js instead!
|
// Leave this as is and make changes in quasar.conf.js instead!
|
||||||
// quasar.conf.js -> build -> vueRouterMode
|
// quasar.conf.js -> build -> vueRouterMode
|
||||||
// quasar.conf.js -> build -> publicPath
|
// quasar.conf.js -> build -> publicPath
|
||||||
history: createHistory(process.env.VUE_ROUTER_BASE),
|
history: createHistory(process.env.VUE_ROUTER_BASE),
|
||||||
});
|
|
||||||
|
|
||||||
return Router;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export default route(function (/* { store, ssrContext } */) {
|
||||||
|
|
||||||
|
routerInstance.beforeEach(async (to) => {
|
||||||
|
// clear alert on route change
|
||||||
|
//const alertStore = useAlertStore();
|
||||||
|
//alertStore.clear();
|
||||||
|
|
||||||
|
// redirect to login page if not logged in and trying to access a restricted page
|
||||||
|
const publicPages = ['/login'];
|
||||||
|
const authRequired = !publicPages.includes(to.path);
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
|
||||||
|
if (authRequired && !authStore.token) {
|
||||||
|
authStore.returnUrl = to.fullPath;
|
||||||
|
return '/login';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return routerInstance;
|
||||||
|
});
|
||||||
|
|
||||||
|
export const router = routerInstance;
|
||||||
|
|
||||||
|
|
||||||
|
// const createHistory = process.env.SERVER
|
||||||
|
// ? createMemoryHistory
|
||||||
|
// : (process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory);
|
||||||
|
|
||||||
|
// export const Router = createRouter({
|
||||||
|
// scrollBehavior: () => ({ left: 0, top: 0 }),
|
||||||
|
// routes,
|
||||||
|
|
||||||
|
// // Leave this as is and make changes in quasar.conf.js instead!
|
||||||
|
// // quasar.conf.js -> build -> vueRouterMode
|
||||||
|
// // quasar.conf.js -> build -> publicPath
|
||||||
|
// history: createHistory(process.env.VUE_ROUTER_BASE),
|
||||||
|
// });
|
||||||
|
|
||||||
|
// export default route(function (/* { store, ssrContext } */) {
|
||||||
|
// return Router;
|
||||||
|
// });
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,17 @@
|
|||||||
import { RouteRecordRaw } from 'vue-router';
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
|
|
||||||
const routes: RouteRecordRaw[] = [
|
const routes: RouteRecordRaw[] = [
|
||||||
|
{
|
||||||
|
path: '/login',
|
||||||
|
component: () => import('pages/LoginPage.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/FlowChart',
|
||||||
|
component:()=>import('layouts/MainLayout.vue'),
|
||||||
|
children:[
|
||||||
|
{path:'',component:()=>import('pages/FlowChart.vue')}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
component: () => import('layouts/MainLayout.vue'),
|
component: () => import('layouts/MainLayout.vue'),
|
||||||
@@ -9,11 +20,13 @@ const routes: RouteRecordRaw[] = [
|
|||||||
{ path: 'ruleEditor', component: () => import('pages/RuleEditor.vue') },
|
{ path: 'ruleEditor', component: () => import('pages/RuleEditor.vue') },
|
||||||
{ path: 'test', component: () => import('pages/testQursar.vue') },
|
{ path: 'test', component: () => import('pages/testQursar.vue') },
|
||||||
{ path: 'flow', component: () => import('pages/testFlow.vue') },
|
{ path: 'flow', component: () => import('pages/testFlow.vue') },
|
||||||
{ path: 'flowchart', component: () => import('pages/FlowChartTest.vue') },
|
{ path: 'FlowChartTest', component: () => import('pages/FlowChartTest.vue') },
|
||||||
{ path: 'flowEditor', component: () => import('pages/FlowEditorPage.vue') },
|
{ path: 'flowEditor', component: () => import('pages/FlowEditorPage.vue') },
|
||||||
{ path: 'flowEditor2', component: () => import('pages/FlowChart.vue') },
|
// { path: 'FlowChart', component: () => import('pages/FlowChart.vue') },
|
||||||
{ path: 'flowChart2', component: () => import('pages/FlowEditorPage2.vue') },
|
|
||||||
{ path: 'right', component: () => import('pages/testRight.vue') },
|
{ path: 'right', component: () => import('pages/testRight.vue') },
|
||||||
|
{ path: 'domain', component: () => import('pages/TenantDomain.vue') },
|
||||||
|
{ path: 'userdomain', component: () => import('pages/UserDomain.vue')},
|
||||||
|
{ path: 'condition', component: () => import('pages/conditionPage.vue') }
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// Always leave this as last one,
|
// Always leave this as last one,
|
||||||
|
|||||||
@@ -1,71 +1,142 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { AppInfo ,IActionFlow} from 'src/types/ActionTypes';
|
import { AppInfo, IActionFlow, IActionNode } from 'src/types/ActionTypes';
|
||||||
import { kintoneEvents,IKintoneEvent,KintoneEventManager } from 'src/types/KintoneEvents';
|
import { IKintoneEvent, KintoneEventManager } from 'src/types/KintoneEvents';
|
||||||
import {FlowCtrl } from '../control/flowctrl';
|
import { FlowCtrl } from '../control/flowctrl';
|
||||||
|
|
||||||
export interface FlowEditorState{
|
export interface FlowEditorState {
|
||||||
flowNames1:string;
|
flowNames1: string;
|
||||||
appInfo?:AppInfo;
|
appInfo?: AppInfo;
|
||||||
flows?:IActionFlow[];
|
flows?: IActionFlow[];
|
||||||
selectedFlow?:IActionFlow|undefined;
|
selectedFlow?: IActionFlow | undefined;
|
||||||
eventTree:KintoneEventManager;
|
activeNode: IActionNode | undefined;
|
||||||
selectedEvent:IKintoneEvent|undefined;
|
eventTree: KintoneEventManager;
|
||||||
|
selectedEvent: IKintoneEvent | undefined;
|
||||||
|
expandedScreen: any[];
|
||||||
}
|
}
|
||||||
const flowCtrl=new FlowCtrl();
|
const flowCtrl = new FlowCtrl();
|
||||||
export const useFlowEditorStore = defineStore("flowEditor",{
|
const eventTree = new KintoneEventManager();
|
||||||
state: ():FlowEditorState => ({
|
export const useFlowEditorStore = defineStore('flowEditor', {
|
||||||
flowNames1: '',
|
state: (): FlowEditorState => ({
|
||||||
appInfo:undefined,
|
flowNames1: '',
|
||||||
flows:[],
|
appInfo: undefined,
|
||||||
selectedFlow:undefined,
|
flows: [],
|
||||||
eventTree:kintoneEvents,
|
selectedFlow: undefined,
|
||||||
selectedEvent:undefined
|
activeNode: undefined,
|
||||||
}),
|
eventTree: eventTree,
|
||||||
|
selectedEvent: undefined,
|
||||||
|
expandedScreen: [],
|
||||||
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @returns 現在編集しているフロー
|
* @returns 現在編集しているフロー
|
||||||
*/
|
*/
|
||||||
currentFlow():IActionFlow|undefined{
|
currentFlow(): IActionFlow | undefined {
|
||||||
return this.selectedFlow;
|
return this.selectedFlow;
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* KintoneイベントIDから、バンドしているフローを検索する
|
* KintoneイベントIDから、バンドしているフローを検索する
|
||||||
* @param state
|
* @param state
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
findFlowByEventId(state){
|
findFlowByEventId(state) {
|
||||||
return (eventId:string)=>{
|
return (eventId: string) => {
|
||||||
return state.flows?.find((flow)=>{
|
return state.flows?.find((flow) => {
|
||||||
const root=flow.getRoot();
|
const root = flow.getRoot();
|
||||||
return root?.name===eventId
|
return root?.name === eventId;
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
}
|
},
|
||||||
|
|
||||||
|
findEventById(state) {
|
||||||
|
return (eventId: string) => {
|
||||||
|
return state.eventTree.findEventById(eventId);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
setFlows(flows:IActionFlow[]){
|
setFlows(flows: IActionFlow[]) {
|
||||||
this.flows=flows;
|
this.flows = flows;
|
||||||
},
|
},
|
||||||
selectFlow(flow:IActionFlow){
|
selectFlow(flow: IActionFlow | undefined) {
|
||||||
this.selectedFlow=flow;
|
this.selectedFlow = flow;
|
||||||
},
|
},
|
||||||
setApp(app:AppInfo){
|
setActiveNode(node: IActionNode) {
|
||||||
this.appInfo=app;
|
this.activeNode = node;
|
||||||
},
|
},
|
||||||
async setFlow(){
|
setApp(app: AppInfo) {
|
||||||
if(this.appInfo===undefined) return;
|
this.appInfo = app;
|
||||||
const actionFlows = await flowCtrl.getFlows(this.appInfo?.appId);
|
},
|
||||||
//eventTreeにバンドする
|
/**
|
||||||
this.eventTree.bindFlows(actionFlows);
|
* DBからフルーを保存する
|
||||||
if(actionFlows && actionFlows.length>0){
|
* @returns
|
||||||
this.setFlows(actionFlows);
|
*/
|
||||||
}
|
async loadFlow() {
|
||||||
if(actionFlows && actionFlows.length==1){
|
if (this.appInfo === undefined) return;
|
||||||
this.selectFlow(actionFlows[0]);
|
const actionFlows = await flowCtrl.getFlows(this.appInfo?.appId);
|
||||||
}
|
//eventTreeにバンドする
|
||||||
}
|
this.eventTree.bindFlows(actionFlows);
|
||||||
|
if (actionFlows === undefined || actionFlows.length === 0) {
|
||||||
|
this.flows = [];
|
||||||
|
this.selectedFlow = undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setFlows(actionFlows);
|
||||||
|
if (actionFlows && actionFlows.length > 0) {
|
||||||
|
this.selectFlow(actionFlows[0]);
|
||||||
|
}
|
||||||
|
const expandNames = actionFlows.map((flow) => flow.getRoot()?.title);
|
||||||
|
// const expandName =actionFlows[0].getRoot()?.title;
|
||||||
|
this.expandedScreen = expandNames;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* フローをDBに保存及び更新する
|
||||||
|
*/
|
||||||
|
async saveFlow(flow: IActionFlow) {
|
||||||
|
const root = flow.getRoot();
|
||||||
|
const isNew = flow.id === '';
|
||||||
|
const jsonData = {
|
||||||
|
flowid: isNew ? flow.createNewId() : flow.id,
|
||||||
|
appid: this.appInfo?.appId,
|
||||||
|
eventid: root?.name,
|
||||||
|
name: root?.subTitle,
|
||||||
|
content: JSON.stringify(flow),
|
||||||
|
};
|
||||||
|
|
||||||
}
|
if (isNew) {
|
||||||
|
return await flowCtrl.SaveFlow(jsonData);
|
||||||
|
} else {
|
||||||
|
return await flowCtrl.UpdateFlow(jsonData);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
async deleteEvent(event: IKintoneEvent) {
|
||||||
|
const store = useFlowEditorStore();
|
||||||
|
if (event.flowData) {
|
||||||
|
const flow = event.flowData;
|
||||||
|
if (flow.id !== '') {
|
||||||
|
await flowCtrl.DeleteFlow(flow.id)
|
||||||
|
if (this.flows) {
|
||||||
|
this.flows = this.flows.filter((f) => f.id !== flow.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eventTree.deleteEvent(event, store);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
eventTree.deleteEvent(event, store);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* デプロイする
|
||||||
|
*/
|
||||||
|
async deploy(): Promise<boolean> {
|
||||||
|
if (this.appInfo === undefined) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return await flowCtrl.depoly(this.appInfo?.appId);
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
91
frontend/src/stores/useAuthStore.ts
Normal file
91
frontend/src/stores/useAuthStore.ts
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { api } from 'boot/axios';
|
||||||
|
import {router} from 'src/router';
|
||||||
|
import {IDomainInfo} from '../types/ActionTypes';
|
||||||
|
|
||||||
|
|
||||||
|
export interface IUserState{
|
||||||
|
token?:string;
|
||||||
|
returnUrl:string;
|
||||||
|
currentDomain:IDomainInfo;
|
||||||
|
LeftDrawer:boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useAuthStore = defineStore({
|
||||||
|
id: 'auth',
|
||||||
|
state: ():IUserState =>{
|
||||||
|
const token=localStorage.getItem('token')||'';
|
||||||
|
if(token!==''){
|
||||||
|
api.defaults.headers["Authorization"]='Bearer ' + token;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
token,
|
||||||
|
returnUrl: '',
|
||||||
|
LeftDrawer:false,
|
||||||
|
currentDomain: JSON.parse(localStorage.getItem('currentDomain')||"{}")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getters:{
|
||||||
|
toggleLeftDrawer():boolean{
|
||||||
|
return this.LeftDrawer;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
toggleLeftMenu(){
|
||||||
|
this.LeftDrawer=!this.LeftDrawer;
|
||||||
|
},
|
||||||
|
async login(username:string, password:string) {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
params.append('username', username);
|
||||||
|
params.append('password', password);
|
||||||
|
try{
|
||||||
|
const result = await api.post(`api/token`,params);
|
||||||
|
console.info(result);
|
||||||
|
this.token =result.data.access_token;
|
||||||
|
localStorage.setItem('token', result.data.access_token);
|
||||||
|
api.defaults.headers["Authorization"]='Bearer ' + this.token;
|
||||||
|
this.currentDomain=await this.getCurrentDomain();
|
||||||
|
localStorage.setItem('currentDomain',JSON.stringify(this.currentDomain));
|
||||||
|
this.router.push(this.returnUrl || '/');
|
||||||
|
return true;
|
||||||
|
}catch(e)
|
||||||
|
{
|
||||||
|
console.info(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getCurrentDomain():Promise<IDomainInfo>{
|
||||||
|
const activedomain = await api.get(`api/activedomain`);
|
||||||
|
return {
|
||||||
|
id:activedomain.data.id,
|
||||||
|
domainName:activedomain.data.name,
|
||||||
|
kintoneUrl:activedomain.data.url
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getUserDomains():Promise<IDomainInfo[]>{
|
||||||
|
const resp = await api.get(`api/domain`);
|
||||||
|
const domains =resp.data as any[];
|
||||||
|
return domains.map(data=>{
|
||||||
|
return {
|
||||||
|
id:data.id,
|
||||||
|
domainName:data.name,
|
||||||
|
kintoneUrl:data.url
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
logout() {
|
||||||
|
this.token = undefined;
|
||||||
|
localStorage.removeItem('token');
|
||||||
|
localStorage.removeItem('currentDomain');
|
||||||
|
router.push('/login');
|
||||||
|
},
|
||||||
|
async setCurrentDomain(domain:IDomainInfo){
|
||||||
|
if(domain.id===this.currentDomain.id){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await api.put(`api/activedomain/${domain.id}`);
|
||||||
|
this.currentDomain=domain;
|
||||||
|
localStorage.setItem('currentDomain',JSON.stringify(this.currentDomain));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -1,12 +1,35 @@
|
|||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
export interface IDomainInfo{
|
||||||
|
id:number;
|
||||||
|
domainName:string;
|
||||||
|
kintoneUrl:string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* アプリ情報
|
* アプリ情報
|
||||||
*/
|
*/
|
||||||
export interface AppInfo {
|
export interface AppInfo {
|
||||||
appId:string;
|
appId: string;
|
||||||
code?:string;
|
code?: string;
|
||||||
name:string;
|
name: string;
|
||||||
description?:string;
|
description?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 属性項目情報
|
||||||
|
*/
|
||||||
|
export interface IProp{
|
||||||
|
//プロパティ名
|
||||||
|
name: string;
|
||||||
|
//プロパティ表示名
|
||||||
|
displayName: string;
|
||||||
|
placeholder: string;
|
||||||
|
//入力提示・説明
|
||||||
|
hint:string;
|
||||||
|
//関連属性リスト
|
||||||
|
connectProps:[{key:string,propName:string}]|undefined;
|
||||||
|
//プロパティ設定値
|
||||||
|
modelValue: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -14,34 +37,44 @@ export interface AppInfo {
|
|||||||
*/
|
*/
|
||||||
export interface IActionProperty {
|
export interface IActionProperty {
|
||||||
component: string;
|
component: string;
|
||||||
props: {
|
props: IProp;
|
||||||
//プロパティ名
|
}
|
||||||
name: string;
|
/**
|
||||||
//プロパティ表示名
|
* 変数オブジェクト
|
||||||
|
*/
|
||||||
|
export interface IActionVariable{
|
||||||
|
actionName:string;
|
||||||
|
displayName:string;
|
||||||
|
name: {
|
||||||
|
name:string;
|
||||||
|
actionName:string;
|
||||||
displayName:string;
|
displayName:string;
|
||||||
placeholder: string;
|
vars : {
|
||||||
//プロパティ設定値
|
vName:string;
|
||||||
modelValue: any;
|
logicalOperator:string;
|
||||||
|
field: object;
|
||||||
|
}[]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* アクションタイプ定義
|
* アクションタイプ定義
|
||||||
*/
|
*/
|
||||||
export interface IActionNode{
|
export interface IActionNode {
|
||||||
id:string;
|
id: string;
|
||||||
//アクション名
|
//アクション名
|
||||||
name:string;
|
name: string;
|
||||||
title:string;
|
title: string;
|
||||||
subTitle:string;
|
varName:IProp|undefined;
|
||||||
inputPoint:string;
|
subTitle: string;
|
||||||
|
inputPoint: string;
|
||||||
//出力ポイント(条件分岐以外未使用)
|
//出力ポイント(条件分岐以外未使用)
|
||||||
outputPoints:Array<string>;
|
outputPoints: Array<string>;
|
||||||
//ルートアクション(Kintone event)
|
//ルートアクション(Kintone event)
|
||||||
isRoot:boolean;
|
isRoot: boolean;
|
||||||
//アクションのプロパティ定義
|
//アクションのプロパティ定義
|
||||||
actionProps:Array<IActionProperty>;
|
actionProps: Array<IActionProperty>;
|
||||||
//アクションのプロパティ設定値抽出
|
//アクションのプロパティ設定値抽出
|
||||||
ActionValue:object
|
ActionValue: object
|
||||||
prevNodeId?: string;
|
prevNodeId?: string;
|
||||||
nextNodeIds: Map<string, string>;
|
nextNodeIds: Map<string, string>;
|
||||||
}
|
}
|
||||||
@@ -49,9 +82,17 @@ export interface IActionNode{
|
|||||||
* アクションフローの定義
|
* アクションフローの定義
|
||||||
*/
|
*/
|
||||||
export interface IActionFlow {
|
export interface IActionFlow {
|
||||||
id:string;
|
id: string;
|
||||||
actionNodes:Array<IActionNode>;
|
actionNodes: IActionNode[];
|
||||||
getRoot():IActionNode|undefined;
|
addNode(newNode: IActionNode, prevNode?: IActionNode, inputPoint?: string): IActionNode;
|
||||||
|
removeNode(targetNode: IActionNode): boolean;
|
||||||
|
removeAllNext(targetNodeId: string): void;
|
||||||
|
getVarNames(currentNode:IActionNode):IActionVariable[];
|
||||||
|
findNodeById(id: string): IActionNode | undefined;
|
||||||
|
toJSON(): any;
|
||||||
|
getRoot(): IActionNode | undefined;
|
||||||
|
createNewId(): string;
|
||||||
|
getColumns(node:IActionNode):number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,18 +100,10 @@ export interface IActionFlow {
|
|||||||
*/
|
*/
|
||||||
class ActionProperty implements IActionProperty {
|
class ActionProperty implements IActionProperty {
|
||||||
component: string;
|
component: string;
|
||||||
props: {
|
props: IProp;
|
||||||
// プロパティ名
|
|
||||||
name: string;
|
|
||||||
// プロパティ表示名
|
|
||||||
displayName: string;
|
|
||||||
placeholder: string;
|
|
||||||
// プロパティ設定値
|
|
||||||
modelValue: any;
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProperty():IActionProperty{
|
static defaultProperty(): IActionProperty {
|
||||||
return new ActionProperty('InputText','displayName','表示名','表示を入力してください','');
|
return new ActionProperty('InputText', 'displayName', '表示名', '表示を入力してください', '','');
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -78,6 +111,7 @@ class ActionProperty implements IActionProperty {
|
|||||||
name: string,
|
name: string,
|
||||||
displayName: string,
|
displayName: string,
|
||||||
placeholder: string,
|
placeholder: string,
|
||||||
|
hint:string,
|
||||||
modelValue: any
|
modelValue: any
|
||||||
) {
|
) {
|
||||||
this.component = component;
|
this.component = component;
|
||||||
@@ -85,6 +119,8 @@ class ActionProperty implements IActionProperty {
|
|||||||
name: name,
|
name: name,
|
||||||
displayName: displayName,
|
displayName: displayName,
|
||||||
placeholder: placeholder,
|
placeholder: placeholder,
|
||||||
|
hint:hint,
|
||||||
|
connectProps:undefined,
|
||||||
modelValue: modelValue
|
modelValue: modelValue
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -95,23 +131,33 @@ class ActionProperty implements IActionProperty {
|
|||||||
* IActionNodeの実装、RootActionNode以外のアクション定義
|
* IActionNodeの実装、RootActionNode以外のアクション定義
|
||||||
*/
|
*/
|
||||||
export class ActionNode implements IActionNode {
|
export class ActionNode implements IActionNode {
|
||||||
id:string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
title:string;
|
get title(): string {
|
||||||
get subTitle():string{
|
const prop = this.actionProps.find((prop) => prop.props.name === "displayName");
|
||||||
|
return prop?.props.modelValue;
|
||||||
|
};
|
||||||
|
get subTitle(): string {
|
||||||
return this.name;
|
return this.name;
|
||||||
};
|
};
|
||||||
inputPoint:string;
|
|
||||||
|
//変数名
|
||||||
|
get varName():IProp|undefined{
|
||||||
|
const prop = this.actionProps.find((prop) => prop.props.name === "verName");
|
||||||
|
return prop?.props;
|
||||||
|
}
|
||||||
|
|
||||||
|
inputPoint: string;
|
||||||
//出力ポイント(条件分岐以外未使用)
|
//出力ポイント(条件分岐以外未使用)
|
||||||
outputPoints:Array<string>;
|
outputPoints: Array<string>;
|
||||||
actionProps: Array<IActionProperty>;
|
actionProps: Array<IActionProperty>;
|
||||||
get isRoot(): boolean{
|
get isRoot(): boolean {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
get ActionValue():object{
|
get ActionValue(): object {
|
||||||
const propValue:any={};
|
const propValue: any = {};
|
||||||
this.actionProps.forEach((value)=>{
|
this.actionProps.forEach((value) => {
|
||||||
propValue[value.props.name]=value.props.modelValue
|
propValue[value.props.name] = value.props.modelValue
|
||||||
});
|
});
|
||||||
return propValue;
|
return propValue;
|
||||||
};
|
};
|
||||||
@@ -119,24 +165,23 @@ export class ActionNode implements IActionNode {
|
|||||||
nextNodeIds: Map<string, string>;
|
nextNodeIds: Map<string, string>;
|
||||||
constructor(
|
constructor(
|
||||||
name: string,
|
name: string,
|
||||||
title:string,
|
title: string,
|
||||||
inputPoint:string,
|
inputPoint: string,
|
||||||
outputPoint: Array<string> = [],
|
outputPoint: Array<string> = [],
|
||||||
actionProps: Array<IActionProperty> =[ActionProperty.defaultProperty()],
|
actionProps: Array<IActionProperty> = [ActionProperty.defaultProperty()],
|
||||||
) {
|
) {
|
||||||
this.id=uuidv4();
|
this.id = uuidv4();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.title=title;
|
this.inputPoint = inputPoint;
|
||||||
this.inputPoint=inputPoint;
|
|
||||||
this.outputPoints = outputPoint;
|
this.outputPoints = outputPoint;
|
||||||
const defProp =ActionProperty.defaultProperty();
|
const defProp = ActionProperty.defaultProperty();
|
||||||
defProp.props.displayName=title;
|
defProp.props.modelValue = title;
|
||||||
this.actionProps =actionProps;
|
this.actionProps = actionProps;
|
||||||
const prop = this.actionProps.find((prop)=>prop.props.name===defProp.props.name);
|
const prop = this.actionProps.find((prop) => prop.props.name === defProp.props.name);
|
||||||
if(prop===undefined){
|
if (prop === undefined) {
|
||||||
this.actionProps.unshift(defProp);
|
this.actionProps.unshift(defProp);
|
||||||
}
|
}
|
||||||
this.nextNodeIds=new Map<string,string>();
|
this.nextNodeIds = new Map<string, string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -144,33 +189,34 @@ export class ActionNode implements IActionNode {
|
|||||||
* ルートアクション定義
|
* ルートアクション定義
|
||||||
*/
|
*/
|
||||||
export class RootAction implements IActionNode {
|
export class RootAction implements IActionNode {
|
||||||
id:string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
title:string;
|
title: string;
|
||||||
subTitle:string;
|
subTitle: string;
|
||||||
inputPoint:string;
|
inputPoint: string;
|
||||||
|
varName: IProp | undefined=undefined;
|
||||||
//出力ポイント(条件分岐以外未使用)
|
//出力ポイント(条件分岐以外未使用)
|
||||||
outputPoints:Array<string>;
|
outputPoints: Array<string>;
|
||||||
isRoot: boolean;
|
isRoot: boolean;
|
||||||
actionProps: Array<IActionProperty>;
|
actionProps: Array<IActionProperty>;
|
||||||
ActionValue:object;
|
ActionValue: object;
|
||||||
prevNodeId?: string = undefined;
|
prevNodeId?: string = undefined;
|
||||||
nextNodeIds: Map<string, string>;
|
nextNodeIds: Map<string, string>;
|
||||||
constructor(
|
constructor(
|
||||||
name: string,
|
name: string,
|
||||||
title:string,
|
title: string,
|
||||||
subTitle:string,
|
subTitle: string,
|
||||||
) {
|
) {
|
||||||
this.id=uuidv4();
|
this.id = uuidv4();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.title=title;
|
this.title = title;
|
||||||
this.subTitle=subTitle;
|
this.subTitle = subTitle;
|
||||||
this.inputPoint='';
|
this.inputPoint = '';
|
||||||
this.outputPoints = [];
|
this.outputPoints = [];
|
||||||
this.isRoot = true;
|
this.isRoot = true;
|
||||||
this.actionProps=[];
|
this.actionProps = [];
|
||||||
this.ActionValue={};
|
this.ActionValue = {};
|
||||||
this.nextNodeIds=new Map<string,string>();
|
this.nextNodeIds = new Map<string, string>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,15 +224,16 @@ export class RootAction implements IActionNode {
|
|||||||
* アクションフローの定義
|
* アクションフローの定義
|
||||||
*/
|
*/
|
||||||
export class ActionFlow implements IActionFlow {
|
export class ActionFlow implements IActionFlow {
|
||||||
id:string;
|
id: string;
|
||||||
actionNodes:Array<IActionNode>;
|
actionNodes: Array<IActionNode>;
|
||||||
constructor(actionNodes:Array<IActionNode>|RootAction){
|
constructor(actionNodes: Array<IActionNode> | RootAction) {
|
||||||
if(actionNodes instanceof Array){
|
if (actionNodes instanceof Array) {
|
||||||
this.actionNodes=actionNodes;
|
this.actionNodes = actionNodes;
|
||||||
}else{
|
} else {
|
||||||
this.actionNodes=[actionNodes];
|
this.actionNodes = [actionNodes];
|
||||||
}
|
}
|
||||||
this.id=uuidv4();
|
this.id = '';
|
||||||
|
//this.id = uuidv4();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* ノードを追加する
|
* ノードを追加する
|
||||||
@@ -198,23 +245,22 @@ export class ActionFlow implements IActionFlow {
|
|||||||
* @returns 追加されたノード
|
* @returns 追加されたノード
|
||||||
*/
|
*/
|
||||||
addNode(
|
addNode(
|
||||||
newNode:IActionNode,
|
newNode: IActionNode,
|
||||||
prevNode?:IActionNode,
|
prevNode?: IActionNode,
|
||||||
inputPoint?:string):IActionNode
|
inputPoint?: string): IActionNode {
|
||||||
{
|
if (inputPoint !== undefined) {
|
||||||
if(inputPoint!==undefined){
|
newNode.inputPoint = inputPoint;
|
||||||
newNode.inputPoint=inputPoint;
|
|
||||||
}
|
}
|
||||||
if(prevNode!==undefined){
|
if (prevNode !== undefined) {
|
||||||
this.connectNodes(prevNode,newNode,inputPoint||'');
|
this.resetNodeRelation(prevNode, newNode, inputPoint || '');
|
||||||
}else{
|
} else {
|
||||||
prevNode=this.actionNodes[this.actionNodes.length-1];
|
prevNode = this.actionNodes[this.actionNodes.length - 1];
|
||||||
this.connectNodes(prevNode,newNode,inputPoint||'');
|
this.connectNodes(prevNode, newNode, inputPoint || '');
|
||||||
}
|
}
|
||||||
const index=this.actionNodes.findIndex(node=>node.id===prevNode?.id)
|
const index = this.actionNodes.findIndex(node => node.id === prevNode?.id)
|
||||||
if(index>=0){
|
if (index >= 0) {
|
||||||
this.actionNodes.splice(index+1,0,newNode);
|
this.actionNodes.splice(index + 1, 0, newNode);
|
||||||
}else{
|
} else {
|
||||||
this.actionNodes.push(newNode);
|
this.actionNodes.push(newNode);
|
||||||
}
|
}
|
||||||
return newNode;
|
return newNode;
|
||||||
@@ -223,124 +269,148 @@ export class ActionFlow implements IActionFlow {
|
|||||||
* ノードを削除する
|
* ノードを削除する
|
||||||
* @param delNode
|
* @param delNode
|
||||||
*/
|
*/
|
||||||
removeNode(targetNode :IActionNode):boolean{
|
removeNode(targetNode: IActionNode): boolean {
|
||||||
if (!targetNode ) {
|
if (!targetNode) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(targetNode.isRoot){
|
if (targetNode.isRoot) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this.disconnectFromPrevNode(targetNode);
|
this.disconnectFromPrevNode(targetNode);
|
||||||
this.reconnectOrRemoveNextNodes(targetNode);
|
this.reconnectOrRemoveNextNodes(targetNode);
|
||||||
this.removeFromActionNodes(targetNode.id);
|
this.removeFromActionNodes(targetNode.id);
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
/***
|
|
||||||
* 目標ノードの次のノードを全部削除する
|
|
||||||
*/
|
|
||||||
removeAllNext(targetNodeId :string){
|
|
||||||
if (!targetNodeId || targetNodeId==='') {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
const targetNode=this.findNodeById(targetNodeId);
|
/***
|
||||||
if(!targetNode){
|
* 目標ノードの次のノードを全部削除する
|
||||||
return false;
|
*/
|
||||||
|
removeAllNext(targetNodeId: string) {
|
||||||
|
if (!targetNodeId || targetNodeId === '') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const targetNode = this.findNodeById(targetNodeId);
|
||||||
|
if (!targetNode) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (targetNode.nextNodeIds.size == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (const [, id] of targetNode.nextNodeIds) {
|
||||||
|
this.removeAll(id);
|
||||||
|
}
|
||||||
|
targetNode.nextNodeIds.clear();
|
||||||
}
|
}
|
||||||
if(targetNode.nextNodeIds.size==0){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (const [, id] of targetNode.nextNodeIds) {
|
|
||||||
this.removeAllNext(id);
|
|
||||||
this.removeFromActionNodes(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 断开与前一个节点的连接
|
/***
|
||||||
disconnectFromPrevNode(targetNode: IActionNode): void {
|
* 目標ノードの次のノードを全部削除する
|
||||||
const prevNodeId = targetNode.prevNodeId;
|
*/
|
||||||
if (prevNodeId) {
|
removeAll(targetNodeId: string) {
|
||||||
const prevNode = this.findNodeById(prevNodeId);
|
if (!targetNodeId || targetNodeId === '') {
|
||||||
if (prevNode) {
|
return;
|
||||||
for (const [key, value] of prevNode.nextNodeIds) {
|
}
|
||||||
if (value === targetNode.id) {
|
const targetNode = this.findNodeById(targetNodeId);
|
||||||
prevNode.nextNodeIds.delete(key);
|
if (!targetNode) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (targetNode.nextNodeIds.size == 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for (const [, id] of targetNode.nextNodeIds) {
|
||||||
|
this.removeAll(id);
|
||||||
|
}
|
||||||
|
this.removeNode(targetNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 断开与前一个节点的连接
|
||||||
|
disconnectFromPrevNode(targetNode: IActionNode): void {
|
||||||
|
const prevNodeId = targetNode.prevNodeId;
|
||||||
|
if (prevNodeId) {
|
||||||
|
const prevNode = this.findNodeById(prevNodeId);
|
||||||
|
if (prevNode) {
|
||||||
|
for (const [key, value] of prevNode.nextNodeIds) {
|
||||||
|
if (value === targetNode.id) {
|
||||||
|
prevNode.nextNodeIds.delete(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 从 actionNodes 数组中移除节点
|
// actionNodes からノードを削除する
|
||||||
private removeFromActionNodes(targetNodeId: string): void {
|
private removeFromActionNodes(targetNodeId: string): void {
|
||||||
const index = this.actionNodes.findIndex(node => node.id === targetNodeId);
|
const index = this.actionNodes.findIndex(node => node.id === targetNodeId);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
this.actionNodes.splice(index, 1);
|
this.actionNodes.splice(index, 1);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ノード削除時、前のノードと次のノードを接続する
|
|
||||||
* @param targetNode
|
|
||||||
*/
|
|
||||||
reconnectOrRemoveNextNodes(targetNode: IActionNode): void {
|
|
||||||
if(!targetNode || !targetNode.prevNodeId ){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//前のノードを取得
|
|
||||||
const prevNode = this.findNodeById(targetNode.prevNodeId);
|
|
||||||
if(!prevNode) return;
|
|
||||||
//次のノード取得
|
|
||||||
const nextNodeIds = targetNode.nextNodeIds;
|
|
||||||
if(nextNodeIds.size==0){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//次のノード一つの場合
|
|
||||||
if(nextNodeIds.size==1){
|
|
||||||
const nextNodeId = nextNodeIds.get('');
|
|
||||||
if(!nextNodeId) return;
|
|
||||||
const nextNode = this.findNodeById(nextNodeId) ;
|
|
||||||
if(!nextNode) return;
|
|
||||||
nextNode.prevNodeId=prevNode.id;
|
|
||||||
prevNode.nextNodeIds.set(targetNode.inputPoint||'',nextNodeId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//二つ以上の場合
|
|
||||||
for(const [point,nextid] of nextNodeIds){
|
|
||||||
const nextNode = this.findNodeById(nextid);
|
|
||||||
if(!nextNode) return;
|
|
||||||
if(!this.connectNodes(prevNode,nextNode,point)){
|
|
||||||
this.removeAllNext(nextid);
|
|
||||||
this.removeFromActionNodes(nextid);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 二つノードを接続する
|
* ノード削除時、前のノードと次のノードを接続する
|
||||||
* @param prevNode
|
* @param targetNode
|
||||||
* @param nextNodeId
|
*/
|
||||||
* @param point
|
reconnectOrRemoveNextNodes(targetNode: IActionNode): void {
|
||||||
* @returns
|
if (!targetNode || !targetNode.prevNodeId) {
|
||||||
*/
|
return;
|
||||||
connectNodes(prevNode:IActionNode,nextNode:IActionNode,point:string):boolean{
|
}
|
||||||
if(!prevNode || !nextNode){
|
//前のノードを取得
|
||||||
return false;
|
const prevNode = this.findNodeById(targetNode.prevNodeId);
|
||||||
|
if (!prevNode) return;
|
||||||
|
//次のノード取得
|
||||||
|
const nextNodeIds = targetNode.nextNodeIds;
|
||||||
|
if (nextNodeIds.size == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//次のノード一つの場合
|
||||||
|
if (nextNodeIds.size == 1) {
|
||||||
|
const nextNodeId = nextNodeIds.get('');
|
||||||
|
if (!nextNodeId) return;
|
||||||
|
const nextNode = this.findNodeById(nextNodeId);
|
||||||
|
if (!nextNode) return;
|
||||||
|
this.connectNodes(prevNode,nextNode,targetNode.inputPoint || '');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//二つ以上の場合
|
||||||
|
for (const [point, nextid] of nextNodeIds) {
|
||||||
|
const nextNode = this.findNodeById(nextid);
|
||||||
|
if (!nextNode) return;
|
||||||
|
if (!this.connectNodes(prevNode, nextNode, point)) {
|
||||||
|
this.removeAllNext(nextid);
|
||||||
|
this.removeFromActionNodes(nextid);
|
||||||
}
|
}
|
||||||
if(!nextNode) return false;
|
}
|
||||||
prevNode.nextNodeIds.set(point,nextNode.id);
|
|
||||||
nextNode.prevNodeId=prevNode.id;
|
|
||||||
nextNode.inputPoint=point;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 二つノードを接続する
|
||||||
|
* @param prevNode
|
||||||
|
* @param nextNodeId
|
||||||
|
* @param point
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
connectNodes(prevNode: IActionNode, nextNode: IActionNode, point: string): boolean {
|
||||||
|
if (!prevNode || !nextNode) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!nextNode) return false;
|
||||||
|
prevNode.nextNodeIds.set(point, nextNode.id);
|
||||||
|
nextNode.prevNodeId = prevNode.id;
|
||||||
|
nextNode.inputPoint = point;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param prevNode ノード挿入時の接続をリセットする
|
||||||
|
* @param newNode
|
||||||
|
* @param inputPoint
|
||||||
|
*/
|
||||||
resetNodeRelation(prevNode: IActionNode, newNode: IActionNode, inputPoint?: string) {
|
resetNodeRelation(prevNode: IActionNode, newNode: IActionNode, inputPoint?: string) {
|
||||||
// 设置新节点和前节点的关联
|
//元の次のノードを取得
|
||||||
|
const originalNextNodeId = prevNode.nextNodeIds.get(inputPoint || '');
|
||||||
prevNode.nextNodeIds.set(inputPoint || '', newNode.id);
|
prevNode.nextNodeIds.set(inputPoint || '', newNode.id);
|
||||||
newNode.prevNodeId = prevNode.id;
|
newNode.prevNodeId = prevNode.id;
|
||||||
// 保存前节点原有的后节点ID
|
newNode.inputPoint=inputPoint||'';
|
||||||
const originalNextNodeId = prevNode.nextNodeIds.get(inputPoint || '');
|
this.setNewNodeNextId(newNode, originalNextNodeId, inputPoint);
|
||||||
this.setNewNodeNextId(newNode,originalNextNodeId,inputPoint);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -350,16 +420,19 @@ reconnectOrRemoveNextNodes(targetNode: IActionNode): void {
|
|||||||
* @param inputPoint
|
* @param inputPoint
|
||||||
*/
|
*/
|
||||||
private setNewNodeNextId(newNode: IActionNode, originalNextNodeId: string | undefined, inputPoint?: string) {
|
private setNewNodeNextId(newNode: IActionNode, originalNextNodeId: string | undefined, inputPoint?: string) {
|
||||||
// 如果原先的后节点存在
|
// 元の接続ノードが存在する
|
||||||
if (originalNextNodeId) {
|
if (!originalNextNodeId) {return;}
|
||||||
// 检查新节点的 outputPoints 是否包含该 inputPoint
|
const originNextNode = this.findNodeById(originalNextNodeId);
|
||||||
if (newNode.outputPoints.includes(inputPoint || '')) {
|
if (!originNextNode) {return;}
|
||||||
newNode.nextNodeIds.set(inputPoint || '', originalNextNodeId);
|
// 新しいノードの outputPoints に該当 inputPointが存在するか場合をチェックする
|
||||||
} else {
|
if (newNode.outputPoints.includes(inputPoint || '')) {
|
||||||
// 如果不包含,选择新节点的一个 outputPoint
|
newNode.nextNodeIds.set(inputPoint || '', originalNextNodeId);
|
||||||
const alternativeOutputPoint = newNode.outputPoints.length > 0 ? newNode.outputPoints[0] : '';
|
originNextNode.prevNodeId=newNode.id;
|
||||||
newNode.nextNodeIds.set(alternativeOutputPoint, originalNextNodeId);
|
} else {
|
||||||
}
|
// inputPointが存在しない場合、outputPointのポイントの任意ポートを選択する
|
||||||
|
const alternativeOutputPoint = newNode.outputPoints.length > 0 ? newNode.outputPoints[0] : '';
|
||||||
|
newNode.nextNodeIds.set(alternativeOutputPoint, originalNextNodeId);
|
||||||
|
originNextNode.prevNodeId=newNode.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,39 +443,93 @@ reconnectOrRemoveNextNodes(targetNode: IActionNode): void {
|
|||||||
return this.actionNodes.find((node) => node.id === id);
|
return this.actionNodes.find((node) => node.id === id);
|
||||||
}
|
}
|
||||||
|
|
||||||
toJSON() {
|
getVarNames(currentNode:IActionNode):IActionVariable[]{
|
||||||
|
let varNames:IActionVariable[]=[];
|
||||||
|
if(currentNode.prevNodeId!==undefined){
|
||||||
|
const prevNode=this.findNodeById(currentNode.prevNodeId);
|
||||||
|
if(prevNode!==undefined){
|
||||||
|
varNames = this.getPrevVarNames(prevNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return varNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
getPrevVarNames(prevNode:IActionNode):IActionVariable[]{
|
||||||
|
let varNames:IActionVariable[]=[];
|
||||||
|
if(prevNode.varName!==undefined && prevNode.varName.modelValue){
|
||||||
|
|
||||||
|
if(prevNode.varName.modelValue ==='object'){
|
||||||
|
console.log(prevNode);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
varNames.unshift({
|
||||||
|
actionName:prevNode.name,
|
||||||
|
displayName:prevNode.varName.displayName,
|
||||||
|
name:prevNode.varName.modelValue
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if(prevNode.prevNodeId!==undefined){
|
||||||
|
const prevPrevNode=this.findNodeById(prevNode.prevNodeId);
|
||||||
|
if(prevPrevNode!==undefined){
|
||||||
|
const prevVars = this.getPrevVarNames(prevPrevNode);
|
||||||
|
varNames=[...prevVars,...varNames];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return varNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
return {
|
return {
|
||||||
id:this.id,
|
id: this.id,
|
||||||
actionNodes: this.actionNodes.map(node => {
|
actionNodes: this.actionNodes.map(node => {
|
||||||
const { nextNodeIds, ...rest } = node;
|
const { nextNodeIds, ...rest } = node;
|
||||||
return {
|
return {
|
||||||
...rest,
|
...rest,
|
||||||
nextNodeIds: Array.from(nextNodeIds.entries())
|
nextNodeIds: Object.fromEntries(nextNodeIds)
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
getRoot():IActionNode|undefined{
|
getColumns(node:IActionNode):number{
|
||||||
return this.actionNodes.find(node=>node.isRoot)
|
let result= 1;
|
||||||
|
if(node.outputPoints && node.outputPoints.length>1){
|
||||||
|
result += node.outputPoints.length -1;
|
||||||
|
}
|
||||||
|
let nextNode;
|
||||||
|
for (const [key, id] of node.nextNodeIds) {
|
||||||
|
nextNode=this.findNodeById(id);
|
||||||
|
if(nextNode){
|
||||||
|
result +=this.getColumns(nextNode)-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
getRoot(): IActionNode | undefined {
|
||||||
|
return this.actionNodes.find(node => node.isRoot)
|
||||||
|
}
|
||||||
|
|
||||||
|
createNewId():string{
|
||||||
|
this.id=uuidv4();
|
||||||
|
return this.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJSON(json: string): ActionFlow {
|
static fromJSON(json: string): ActionFlow {
|
||||||
const parsedObject = JSON.parse(json);
|
const parsedObject = JSON.parse(json);
|
||||||
|
|
||||||
const actionNodes = parsedObject.actionNodes.map((node: any) => {
|
const actionNodes = parsedObject.actionNodes.map((node: any) => {
|
||||||
const nodeClass = !node.isRoot? new ActionNode(node.name,node.title,node.inputPoint,node.outputPoint,node.actionProps)
|
const nodeClass = !node.isRoot ? new ActionNode(node.name, node.title, node.inputPoint, node.outputPoints, node.actionProps)
|
||||||
:new RootAction(node.name,node.title,node.subTitle);
|
: new RootAction(node.name, node.title, node.subTitle);
|
||||||
nodeClass.nextNodeIds=new Map(node.nextNodeIds);
|
nodeClass.nextNodeIds = new Map<string,string>(Object.entries(node.nextNodeIds));
|
||||||
nodeClass.prevNodeId=node.prevNodeId;
|
nodeClass.prevNodeId = node.prevNodeId;
|
||||||
nodeClass.id=node.id;
|
nodeClass.id = node.id;
|
||||||
return nodeClass;
|
return nodeClass;
|
||||||
});
|
});
|
||||||
const actionFlow = new ActionFlow(actionNodes);
|
const actionFlow = new ActionFlow(actionNodes);
|
||||||
actionFlow.id=parsedObject.id;
|
actionFlow.id = parsedObject.id;
|
||||||
return actionFlow;
|
return actionFlow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
50
frontend/src/types/ComponentTypes.ts
Normal file
50
frontend/src/types/ComponentTypes.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
|
||||||
|
export interface IApp {
|
||||||
|
id: string,
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IField {
|
||||||
|
label?:string;
|
||||||
|
code:string;
|
||||||
|
type?:string;
|
||||||
|
required?:boolean;
|
||||||
|
options?:string;
|
||||||
|
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 選択されたフィールド
|
||||||
|
*/
|
||||||
|
export interface ISelectedField extends IField{
|
||||||
|
objectType:'Field'|'RefField';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IAppFields {
|
||||||
|
app?: IApp,
|
||||||
|
name?:string;
|
||||||
|
fields: IField[]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 条件式の入力ボタンの属性定義
|
||||||
|
*/
|
||||||
|
export interface IButtonConfig{
|
||||||
|
label: string;
|
||||||
|
color: string;
|
||||||
|
type: 'FieldAdd' | 'VariableAdd' | 'FunctionAdd';
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 条件入力項目の属性
|
||||||
|
*/
|
||||||
|
export interface IDynamicInputConfig{
|
||||||
|
canInput: boolean;
|
||||||
|
buttonsConfig: IButtonConfig[];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 条件式入力項目の属性
|
||||||
|
*/
|
||||||
|
export interface ICoditionConfig{
|
||||||
|
left:IDynamicInputConfig,
|
||||||
|
right:IDynamicInputConfig
|
||||||
|
}
|
||||||
383
frontend/src/types/Conditions.ts
Normal file
383
frontend/src/types/Conditions.ts
Normal file
@@ -0,0 +1,383 @@
|
|||||||
|
//ノード種別
|
||||||
|
export enum NodeType{
|
||||||
|
Root = 'root',
|
||||||
|
LogicGroup ='logicgroup',
|
||||||
|
Condition ='condition'
|
||||||
|
}
|
||||||
|
|
||||||
|
//ロジックオペレーター
|
||||||
|
export enum LogicalOperator{
|
||||||
|
AND = 'AND',
|
||||||
|
OR = 'OR'
|
||||||
|
}
|
||||||
|
|
||||||
|
//条件オペレーター
|
||||||
|
export enum Operator{
|
||||||
|
Equal = '=',
|
||||||
|
NotEqual='!=',
|
||||||
|
Greater = '>',
|
||||||
|
GreaterOrEqual = '>=',
|
||||||
|
Less = '<',
|
||||||
|
LessOrEqual = '<=',
|
||||||
|
Contains = 'contains',
|
||||||
|
NotContains = 'not contains',
|
||||||
|
StartWith = 'start With',
|
||||||
|
EndWith = 'end with',
|
||||||
|
NotStartWith = 'not start with',
|
||||||
|
NotEndWith = 'not end with'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// INode
|
||||||
|
export interface INode {
|
||||||
|
index:number;
|
||||||
|
type: NodeType;
|
||||||
|
header:string;
|
||||||
|
parent: INode | null;
|
||||||
|
logicalOperator:LogicalOperator
|
||||||
|
}
|
||||||
|
|
||||||
|
// ロジックノード
|
||||||
|
export class GroupNode implements INode {
|
||||||
|
index:number;
|
||||||
|
type: NodeType;
|
||||||
|
children: INode[];
|
||||||
|
parent: INode | null;
|
||||||
|
logicalOperator: LogicalOperator;
|
||||||
|
get label():string{
|
||||||
|
return this.logicalOperator;
|
||||||
|
}
|
||||||
|
get header():string{
|
||||||
|
return this.type===NodeType.Root?'root':'generic';
|
||||||
|
}
|
||||||
|
get expanded():boolean{
|
||||||
|
return this.children.length>0;
|
||||||
|
}
|
||||||
|
constructor(logicOp:LogicalOperator, parent: INode | null) {
|
||||||
|
this.index=0;
|
||||||
|
this.type = parent==null?NodeType.Root: NodeType.LogicGroup;
|
||||||
|
this.logicalOperator = logicOp;
|
||||||
|
this.parent=parent;
|
||||||
|
this.children=[];
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJSON(json: any, parent: INode | null = null): GroupNode {
|
||||||
|
const node = new GroupNode(json.logicalOperator, parent);
|
||||||
|
node.index=json.index;
|
||||||
|
node.children = json.children.map((childJson: any) => {
|
||||||
|
return childJson.type === NodeType.LogicGroup
|
||||||
|
? GroupNode.fromJSON(childJson, node)
|
||||||
|
: ConditionNode.fromJSON(childJson, node);
|
||||||
|
});
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export type OperatorListItem = {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 条件式ノード
|
||||||
|
export class ConditionNode implements INode {
|
||||||
|
index: number;
|
||||||
|
type: NodeType;
|
||||||
|
parent:INode;
|
||||||
|
get logicalOperator(): LogicalOperator{
|
||||||
|
return this.parent.logicalOperator;
|
||||||
|
};
|
||||||
|
object: any; // 比較元
|
||||||
|
operator: Operator | OperatorListItem; // 比較子
|
||||||
|
value: any;
|
||||||
|
get header():string{
|
||||||
|
return 'generic';
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(object: any, operator: Operator | OperatorListItem, value: any, parent: GroupNode) {
|
||||||
|
this.index=0;
|
||||||
|
this.type = NodeType.Condition;
|
||||||
|
this.object = object;
|
||||||
|
this.operator = operator;
|
||||||
|
this.value = value;
|
||||||
|
this.parent=parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJSON(json: any, parent: GroupNode): ConditionNode {
|
||||||
|
const node= new ConditionNode(
|
||||||
|
json.object,
|
||||||
|
json.operator,
|
||||||
|
json.value,
|
||||||
|
parent
|
||||||
|
);
|
||||||
|
node.index=json.index;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 条件式の管理クラス
|
||||||
|
export class ConditionTree {
|
||||||
|
root: GroupNode;
|
||||||
|
maxIndex:number;
|
||||||
|
queryString:string;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.maxIndex=0;
|
||||||
|
this.root = new GroupNode(LogicalOperator.AND, null);
|
||||||
|
this.queryString='';
|
||||||
|
}
|
||||||
|
|
||||||
|
// ノード追加
|
||||||
|
addNode(parent: GroupNode, node: INode): void {
|
||||||
|
this.maxIndex++;
|
||||||
|
node.index=this.maxIndex;
|
||||||
|
parent.children.push(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ノード削除
|
||||||
|
removeNode(node: INode): void {
|
||||||
|
if (node.parent === null) {
|
||||||
|
throw new Error('ルートノード削除できません');
|
||||||
|
} else {
|
||||||
|
const parent = node.parent as GroupNode;
|
||||||
|
const index = parent.children.indexOf(node);
|
||||||
|
if (index > -1) {
|
||||||
|
parent.children.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
findByIndex(index:number):INode|undefined{
|
||||||
|
return this.findChildren(this.root,index);
|
||||||
|
}
|
||||||
|
|
||||||
|
findChildren(parent: GroupNode, index: number): INode | undefined {
|
||||||
|
if (parent.index === index) {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
for (const node of parent.children) {
|
||||||
|
if (node.index === index) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
if (node.type !== NodeType.Condition) {
|
||||||
|
const foundNode = this.findChildren(node as GroupNode, index);
|
||||||
|
if (foundNode) {
|
||||||
|
return foundNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
getMaxIndex(node:INode):number{
|
||||||
|
let maxIndex:number=node.index;
|
||||||
|
if(node.type!==NodeType.Condition){
|
||||||
|
const groupNode = node as GroupNode;
|
||||||
|
groupNode.children.forEach((child)=>{
|
||||||
|
const childMax = this.getMaxIndex(child);
|
||||||
|
if(childMax>maxIndex){
|
||||||
|
maxIndex=childMax;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return maxIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
//条件式を表示する
|
||||||
|
buildConditionString(node:INode){
|
||||||
|
if (node.type !== NodeType.Condition) {
|
||||||
|
let conditionString = '(';
|
||||||
|
const groupNode = node as GroupNode;
|
||||||
|
for (let i = 0; i < groupNode.children.length; i++) {
|
||||||
|
const childConditionString = this.buildConditionString(groupNode.children[i]);
|
||||||
|
if (childConditionString !== '') {
|
||||||
|
conditionString += childConditionString;
|
||||||
|
if (i < groupNode.children.length - 1) {
|
||||||
|
conditionString += ` ${groupNode.logicalOperator} `;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conditionString += ')';
|
||||||
|
return conditionString;
|
||||||
|
} else {
|
||||||
|
const condNode=node as ConditionNode;
|
||||||
|
if (condNode.object && condNode.operator ) {
|
||||||
|
// let value=condNode.value;
|
||||||
|
// if(value && typeof value ==='object' && ('label' in value)){
|
||||||
|
// value =condNode.value.label;
|
||||||
|
// }
|
||||||
|
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 {
|
||||||
|
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 direction
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
moveNode(node:INode, direction: 'up' | 'down'): void {
|
||||||
|
if (!node || !node.parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parent = node.parent as GroupNode;
|
||||||
|
const currentIndex = parent.children.findIndex(child => child === node);
|
||||||
|
if (currentIndex === -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newIndex = direction === 'up' ? currentIndex - 1 : currentIndex + 1;
|
||||||
|
|
||||||
|
// 範囲外のインデックスの処理
|
||||||
|
if (newIndex >= 0 && newIndex < parent.children.length) {
|
||||||
|
// ノードの位置を入れ替える
|
||||||
|
[parent.children[currentIndex], parent.children[newIndex]] = [parent.children[newIndex], parent.children[currentIndex]];
|
||||||
|
return; // 範囲外なら移動しない
|
||||||
|
}else if(newIndex<0 && parent.parent){
|
||||||
|
this.removeNode(node);
|
||||||
|
const parentIndex = (parent.parent as GroupNode).children.findIndex(child => child === parent);
|
||||||
|
(parent.parent as GroupNode).children.splice(parentIndex, 0, node);
|
||||||
|
node.parent = parent.parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getGroups(parent:GroupNode):number[]{
|
||||||
|
const groups:number[]=[];
|
||||||
|
groups.push(parent.index);
|
||||||
|
parent.children.forEach((node)=>{
|
||||||
|
if(node.type!==NodeType.Condition){
|
||||||
|
groups.push(...this.getGroups(node as GroupNode));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 条件ノードをグループ化
|
||||||
|
* @param nodes 結合ノードを選択する
|
||||||
|
* @param logicOp
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
createGroupNode(firstNode:INode,nodes: INode[], logicOp: LogicalOperator): GroupNode | null {
|
||||||
|
if (nodes.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 最初のノードの親ノードを取得
|
||||||
|
const parent = firstNode.parent as GroupNode;
|
||||||
|
if (!parent) {
|
||||||
|
throw new Error('ルートノードをグループ化できません');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 親ノードを取得
|
||||||
|
const filteredNodes = nodes.filter(node => node.parent === parent);
|
||||||
|
|
||||||
|
// 新しいグループノードを作成
|
||||||
|
const newGroup = new GroupNode(logicOp, parent);
|
||||||
|
this.maxIndex++;
|
||||||
|
newGroup.index = this.maxIndex;
|
||||||
|
|
||||||
|
// 新しいグループノードの挿入位置を取得
|
||||||
|
let firstNodeIndex = parent.children.length;
|
||||||
|
if (filteredNodes.length > 0) {
|
||||||
|
firstNodeIndex = parent.children.indexOf(filteredNodes[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
filteredNodes.forEach(node => {
|
||||||
|
// 元の親ノードから削除する
|
||||||
|
const nodeIndex = parent.children.indexOf(node);
|
||||||
|
parent.children.splice(nodeIndex, 1);
|
||||||
|
|
||||||
|
// 新しいグループに追加
|
||||||
|
node.parent = newGroup;
|
||||||
|
newGroup.children.push(node);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 新しいGroupNodeを挿入する
|
||||||
|
parent.children.splice(firstNodeIndex, 0, newGroup);
|
||||||
|
return newGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GroupNodeを解散する
|
||||||
|
* @param groupNode 対象グループノード
|
||||||
|
*/
|
||||||
|
dissolveGroupNode(groupNode: GroupNode): void {
|
||||||
|
if (groupNode.parent === null || groupNode.type !== NodeType.LogicGroup) {
|
||||||
|
throw new Error('ルートノードと非グループノードを解散することができません');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 親ノードを取得
|
||||||
|
const parent = groupNode.parent as GroupNode;
|
||||||
|
const groupIndex = parent.children.indexOf(groupNode);
|
||||||
|
|
||||||
|
// 子ノードをリセットする
|
||||||
|
groupNode.children.forEach(child => {
|
||||||
|
child.parent = parent;
|
||||||
|
parent.children.splice(groupIndex, 0, child);
|
||||||
|
});
|
||||||
|
|
||||||
|
//グループノードを削除する
|
||||||
|
parent.children.splice(groupIndex + groupNode.children.length, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jsonから復元
|
||||||
|
fromJson(jsonString: string): INode {
|
||||||
|
const json = JSON.parse(jsonString);
|
||||||
|
this.root = GroupNode.fromJSON(json) as GroupNode;
|
||||||
|
this.maxIndex=this.getMaxIndex(this.root);
|
||||||
|
return this.root;
|
||||||
|
}
|
||||||
|
|
||||||
|
toJson():string{
|
||||||
|
return JSON.stringify({queryString :this.queryString, ...this.root}, (key, value) => {
|
||||||
|
if (key === 'parent') {
|
||||||
|
return value ? value.type : null;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setQuery(queryString:string){
|
||||||
|
this.queryString=queryString;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,112 +1,338 @@
|
|||||||
import { publicDecrypt } from 'crypto';
|
import { useFlowEditorStore } from 'src/stores/flowEditor';
|
||||||
import {IActionFlow} from './ActionTypes';
|
import { IActionFlow } from './ActionTypes';
|
||||||
export interface TreeNode {
|
export interface IKintoneEventNode {
|
||||||
label: string;
|
label: string;
|
||||||
|
header: string;
|
||||||
|
eventId: string;
|
||||||
|
parentId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IKintoneEvent extends TreeNode {
|
export interface IKintoneEvent extends IKintoneEventNode {
|
||||||
eventId: string;
|
|
||||||
hasFlow: boolean;
|
hasFlow: boolean;
|
||||||
flowData?: IActionFlow;
|
flowData?: IActionFlow;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IKintoneScreen extends TreeNode {
|
export interface IKintoneEventGroup extends IKintoneEventNode {
|
||||||
label: string;
|
events: IKintoneEventNode[];
|
||||||
events: IKintoneEvent[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class kintoneEvent implements IKintoneEvent{
|
export class kintoneEvent implements IKintoneEvent {
|
||||||
eventId: string;
|
eventId: string;
|
||||||
get hasFlow(): boolean{
|
parentId: string;
|
||||||
return this.flowData!==undefined && this.flowData.actionNodes.length>1
|
get hasFlow(): boolean {
|
||||||
};
|
return this.flowData !== undefined && this.flowData.actionNodes.length > 1;
|
||||||
|
}
|
||||||
flowData?: IActionFlow | undefined;
|
flowData?: IActionFlow | undefined;
|
||||||
label: string;
|
label: string;
|
||||||
constructor({eventId,label}:{eventId:string,label:string}){
|
header = 'EVENT';
|
||||||
this.eventId=eventId;
|
constructor(label: string, eventId: string, parentId: string) {
|
||||||
this.label=label;
|
this.eventId = eventId;
|
||||||
|
this.label = label;
|
||||||
|
this.parentId = parentId;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class kintoneEventGroup implements IKintoneEventGroup {
|
||||||
|
eventId: string;
|
||||||
|
parentId: string;
|
||||||
|
label: string;
|
||||||
|
events: IKintoneEventNode[];
|
||||||
|
get header(): string {
|
||||||
|
return 'EVENTGROUP';
|
||||||
|
}
|
||||||
|
constructor(
|
||||||
|
eventId: string,
|
||||||
|
label: string,
|
||||||
|
events: IKintoneEventNode[],
|
||||||
|
parentId: string
|
||||||
|
) {
|
||||||
|
this.eventId = eventId;
|
||||||
|
this.label = label;
|
||||||
|
this.events = events;
|
||||||
|
this.parentId = parentId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class kintoneEventForChange implements IKintoneEventGroup {
|
||||||
|
eventId: string;
|
||||||
|
parentId: string;
|
||||||
|
label: string;
|
||||||
|
events: IKintoneEventNode[];
|
||||||
|
get header(): string {
|
||||||
|
return 'CHANGE';
|
||||||
|
}
|
||||||
|
constructor(
|
||||||
|
eventId: string,
|
||||||
|
label: string,
|
||||||
|
events: IKintoneEventNode[],
|
||||||
|
parentId: string
|
||||||
|
) {
|
||||||
|
this.eventId = eventId;
|
||||||
|
this.label = label;
|
||||||
|
this.events = events;
|
||||||
|
this.parentId = parentId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class KintoneEventManager {
|
export class KintoneEventManager {
|
||||||
public screens: IKintoneScreen[];
|
public screens: IKintoneEventGroup[];
|
||||||
|
|
||||||
constructor(screens: IKintoneScreen[]) {
|
constructor() {
|
||||||
this.screens = screens;
|
this.screens = this.getKintoneEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bindFlows(flows:IActionFlow[]){
|
public bindFlows(flows: IActionFlow[]) {
|
||||||
for (const screen of this.screens) {
|
this.screens = this.getKintoneEvents();
|
||||||
screen.events.forEach((ev)=>ev.flowData=undefined);
|
for (const flow of flows) {
|
||||||
}
|
const eventId = flow.getRoot()?.name;
|
||||||
for (const flow of flows){
|
if (eventId !== undefined) {
|
||||||
const eventId =flow.getRoot()?.name;
|
const eventNode = this.findEventById(eventId);
|
||||||
if(eventId!==undefined){
|
if (eventNode !== null && eventNode.header === 'EVENT') {
|
||||||
const event = this.findEventById(eventId);
|
const event = eventNode as kintoneEvent;
|
||||||
if(event!==null){
|
event.flowData = flow;
|
||||||
event.flowData=flow;
|
} else {
|
||||||
|
//EventGroupのIDを取得
|
||||||
|
const lastIndex = eventId.lastIndexOf('.');
|
||||||
|
const groupId = eventId.substring(0, lastIndex);
|
||||||
|
const eventNode = this.findEventById(groupId);
|
||||||
|
if (eventNode && (eventNode.header === 'EVENTGROUP' || eventNode.header === 'CHANGE')) {
|
||||||
|
const groupEvent = eventNode as kintoneEventGroup;
|
||||||
|
|
||||||
|
const newEvent = {
|
||||||
|
label: flow.getRoot()?.subTitle || '',
|
||||||
|
eventId: eventId,
|
||||||
|
parentId: groupId,
|
||||||
|
header: 'DELETABLE',
|
||||||
|
hasFlow: true,
|
||||||
|
flowData: flow,
|
||||||
|
};
|
||||||
|
|
||||||
|
groupEvent.events.push(newEvent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public findEventById(eventId: string): IKintoneEvent | null {
|
public findEventById(eventId: string): IKintoneEventNode | null {
|
||||||
|
const screen = this.findScreen(eventId);
|
||||||
|
if (screen) {
|
||||||
|
return screen;
|
||||||
|
}
|
||||||
for (const screen of this.screens) {
|
for (const screen of this.screens) {
|
||||||
for (const event of screen.events) {
|
for (const event of screen.events) {
|
||||||
if (event.eventId === eventId) {
|
if (event.eventId === eventId) {
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
if (event.header === 'EVENTGROUP' || event.header === 'CHANGE') {
|
||||||
|
const eventGroup = event as IKintoneEventGroup;
|
||||||
|
const targetEvent = eventGroup.events.find((ev) => {
|
||||||
|
return ev.eventId === eventId;
|
||||||
|
});
|
||||||
|
if (targetEvent) {
|
||||||
|
return targetEvent;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public findScreen(eventId:string):IKintoneScreen|null{
|
public findScreen(eventId: string): IKintoneEventGroup | undefined {
|
||||||
for (const screen of this.screens) {
|
return this.screens.find((screen) => screen.eventId == eventId);
|
||||||
if(screen.events.some((ev:IKintoneEvent)=>ev.eventId===eventId)){
|
}
|
||||||
return screen;
|
|
||||||
}
|
public deleteEvent(
|
||||||
|
event: kintoneEvent,
|
||||||
|
store: ReturnType<typeof useFlowEditorStore>
|
||||||
|
) {
|
||||||
|
if (event.header !== 'DELETABLE') {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
const parent = store.findEventById(event.parentId);
|
||||||
|
if (parent?.header !== 'CHANGE' && parent?.header !== 'EVENTGROUP') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const realParent = parent as kintoneEventForChange;
|
||||||
|
|
||||||
|
const index = realParent.events.findIndex(
|
||||||
|
(e) => e.eventId === event.eventId
|
||||||
|
);
|
||||||
|
|
||||||
|
if (index !== -1) {
|
||||||
|
realParent.events.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getKintoneEvents(): IKintoneEventGroup[] {
|
||||||
|
return [
|
||||||
|
new kintoneEventGroup(
|
||||||
|
'app.record.create',
|
||||||
|
'レコード追加画面',
|
||||||
|
[
|
||||||
|
new kintoneEvent(
|
||||||
|
'レコード追加画面を表示した後',
|
||||||
|
'app.record.create.show',
|
||||||
|
'app.record.create'
|
||||||
|
),
|
||||||
|
new kintoneEvent(
|
||||||
|
'保存をクリックしたとき',
|
||||||
|
'app.record.create.submit',
|
||||||
|
'app.record.create'
|
||||||
|
),
|
||||||
|
new kintoneEvent(
|
||||||
|
'保存が成功したとき',
|
||||||
|
'app.record.create.submit.success',
|
||||||
|
'app.record.create'
|
||||||
|
),
|
||||||
|
new kintoneEventForChange(
|
||||||
|
'app.record.create.change',
|
||||||
|
'フィールドの値を変更したとき',
|
||||||
|
[],
|
||||||
|
'app.record.create'
|
||||||
|
),
|
||||||
|
new kintoneEventGroup(
|
||||||
|
'app.record.create.show.customButtonClick',
|
||||||
|
'ボタンをクリックした時',
|
||||||
|
[],
|
||||||
|
'app.record.create'
|
||||||
|
),
|
||||||
|
],
|
||||||
|
''
|
||||||
|
),
|
||||||
|
new kintoneEventGroup(
|
||||||
|
'app.record.detail',
|
||||||
|
'レコード詳細画面',
|
||||||
|
[
|
||||||
|
new kintoneEvent(
|
||||||
|
'レコード詳細画面を表示した後',
|
||||||
|
'app.record.detail.show',
|
||||||
|
'app.record.detail'
|
||||||
|
),
|
||||||
|
new kintoneEvent(
|
||||||
|
'レコードを削除するとき',
|
||||||
|
'app.record.detail.delete.submit',
|
||||||
|
'app.record.detail'
|
||||||
|
),
|
||||||
|
new kintoneEvent(
|
||||||
|
'プロセス管理のアクションを実行したとき',
|
||||||
|
'app.record.detail.process.proceed',
|
||||||
|
'app.record.detail'
|
||||||
|
),
|
||||||
|
new kintoneEventGroup(
|
||||||
|
'app.record.detail.show.customButtonClick',
|
||||||
|
'ボタンをクリックした時',
|
||||||
|
[],
|
||||||
|
'app.record.detail'
|
||||||
|
),
|
||||||
|
],
|
||||||
|
''
|
||||||
|
),
|
||||||
|
new kintoneEventGroup(
|
||||||
|
'app.record.edit',
|
||||||
|
'レコード編集画面',
|
||||||
|
[
|
||||||
|
new kintoneEvent(
|
||||||
|
'レコード編集画面を表示した後',
|
||||||
|
'app.record.edit.show',
|
||||||
|
'app.record.edit'
|
||||||
|
),
|
||||||
|
new kintoneEvent(
|
||||||
|
'保存をクリックしたとき',
|
||||||
|
'app.record.edit.submit',
|
||||||
|
'app.record.edit'
|
||||||
|
),
|
||||||
|
new kintoneEvent(
|
||||||
|
'保存が成功したとき',
|
||||||
|
'app.record.edit.submit.success',
|
||||||
|
'app.record.edit'
|
||||||
|
),
|
||||||
|
new kintoneEventForChange(
|
||||||
|
'app.record.edit.change',
|
||||||
|
'フィールドの値を変更したとき',
|
||||||
|
[],
|
||||||
|
'app.record.edit'
|
||||||
|
),
|
||||||
|
new kintoneEventGroup(
|
||||||
|
'app.record.edit.show.customButtonClick',
|
||||||
|
'ボタンをクリックした時',
|
||||||
|
[],
|
||||||
|
'app.record.edit'
|
||||||
|
),
|
||||||
|
],
|
||||||
|
''
|
||||||
|
),
|
||||||
|
new kintoneEventGroup(
|
||||||
|
'app.record.index',
|
||||||
|
'レコード一覧画面',
|
||||||
|
[
|
||||||
|
new kintoneEvent(
|
||||||
|
'一覧画面を表示した後',
|
||||||
|
'app.record.index.show',
|
||||||
|
'app.record.index'
|
||||||
|
),
|
||||||
|
new kintoneEvent(
|
||||||
|
'インライン編集を開始したとき',
|
||||||
|
'app.record.index.edit.show',
|
||||||
|
'app.record.index'
|
||||||
|
),
|
||||||
|
new kintoneEvent(
|
||||||
|
'インライン編集の【保存】をクリックしたとき',
|
||||||
|
'app.record.index.edit.submit',
|
||||||
|
'app.record.index'
|
||||||
|
),
|
||||||
|
new kintoneEvent(
|
||||||
|
'インライン編集の保存が成功したとき',
|
||||||
|
'app.record.index.edit.submit.success',
|
||||||
|
'app.record.index'
|
||||||
|
),
|
||||||
|
new kintoneEventForChange(
|
||||||
|
'app.record.index.edit.change',
|
||||||
|
'インライン編集のフィールド値を変更したとき',
|
||||||
|
[],
|
||||||
|
'app.record.index'
|
||||||
|
),
|
||||||
|
new kintoneEventGroup(
|
||||||
|
'app.record.detail.show.customButtonClick',
|
||||||
|
'ボタンをクリックした時',
|
||||||
|
[],
|
||||||
|
'app.record.index'
|
||||||
|
),
|
||||||
|
],
|
||||||
|
''
|
||||||
|
),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const kintoneEvents:KintoneEventManager = new KintoneEventManager([
|
// export const kintoneEvents:KintoneEventManager = new KintoneEventManager([
|
||||||
{
|
// new kintoneEventGroup("app.record.create","レコード追加画面",[
|
||||||
label:"レコード追加画面",
|
// new kintoneEvent('レコード追加画面を表示した後','app.record.create.show',"app.record.create"),
|
||||||
events:[
|
// new kintoneEvent('保存をクリックしたとき','app.record.create.submit',"app.record.create"),
|
||||||
new kintoneEvent({label:"レコード追加画面を表示した後",eventId:"app.record.create.show"}),
|
// new kintoneEvent('保存が成功したとき','app.record.create.submit.success',"app.record.create"),
|
||||||
new kintoneEvent({label:"保存をクリックしたとき",eventId:"app.record.create.submit"}),
|
// new kintoneEventForChange('app.record.create.change','フィールドの値を変更したとき',[],"app.record.create"),
|
||||||
new kintoneEvent({label:"保存が成功したとき",eventId:"app.record.create.submit.success"}),
|
// new kintoneEventGroup('app.record.create.customButtonClick','ボタンをクリックした時',[],"app.record.create")
|
||||||
new kintoneEvent({label:"フィールドの値を変更したとき",eventId:"app.record.create.change"}),
|
// ],""),
|
||||||
]
|
// new kintoneEventGroup("app.record.detail","レコード詳細画面",[
|
||||||
},
|
// new kintoneEvent('レコード詳細画面を表示した後','app.record.detail.show',"app.record.detail"),
|
||||||
{
|
// new kintoneEvent('レコードを削除するとき','app.record.detail.delete.submit',"app.record.detail"),
|
||||||
label:"レコード詳細画面",
|
// new kintoneEvent('プロセス管理のアクションを実行したとき','app.record.detail.process.proceed',"app.record.detail"),
|
||||||
events:[
|
// new kintoneEventGroup('app.record.detail.customButtonClick','ボタンをクリックした時',[],"app.record.detail"),
|
||||||
new kintoneEvent({label:"レコード詳細画面を表示した後",eventId:"app.record.detail.show"}),
|
// ],""),
|
||||||
new kintoneEvent({label:"レコードを削除するとき",eventId:"app.record.detail.delete.submit"}),
|
// new kintoneEventGroup("app.record.edit","レコード編集画面",[
|
||||||
new kintoneEvent({label:"プロセス管理のアクションを実行したとき",eventId:"app.record.detail.process.proceed"}),
|
// new kintoneEvent('レコード編集画面を表示した後','app.record.edit.show',"app.record.edit"),
|
||||||
]
|
// new kintoneEvent('保存をクリックしたとき','app.record.edit.submit',"app.record.edit"),
|
||||||
},
|
// new kintoneEvent('保存が成功したとき','app.record.edit.submit.success',"app.record.edit"),
|
||||||
{
|
// new kintoneEventForChange('app.record.edit.change','フィールドの値を変更したとき',[],"app.record.edit"),
|
||||||
label:"レコード編集画面",
|
// new kintoneEventGroup('app.record.edit.customButtonClick','ボタンをクリックした時',[],"app.record.edit"),
|
||||||
events:[new kintoneEvent({label:"レコード編集画面を表示した後",eventId:"app.record.edit.show"}),
|
// ],""),
|
||||||
new kintoneEvent({label:"保存をクリックしたとき",eventId:"app.record.edit.submit"}),
|
// new kintoneEventGroup("app.record.index","レコード一覧画面",[
|
||||||
new kintoneEvent({label:"保存が成功したとき",eventId:"app.record.edit.submit.success"}),
|
// new kintoneEvent('一覧画面を表示した後', 'app.record.index.show',"app.record.index"),
|
||||||
new kintoneEvent({label:"フィールドの値を変更したとき",eventId:"app.record.edit.change"}),
|
// new kintoneEvent('インライン編集を開始したとき','app.record.index.edit.show',"app.record.index"),
|
||||||
]
|
// new kintoneEvent('インライン編集の【保存】をクリックしたとき','app.record.index.edit.submit',"app.record.index"),
|
||||||
},
|
// new kintoneEvent('インライン編集の保存が成功したとき', 'app.record.index.edit.submit.success',"app.record.index"),
|
||||||
{
|
// new kintoneEventForChange('app.record.index.edit.change','インライン編集のフィールド値を変更したとき' ,[],"app.record.index"),
|
||||||
label:"レコード一覧画面",
|
// new kintoneEventGroup('app.record.detail.customButtonClick','ボタンをクリックした時',[],"app.record.index"),
|
||||||
events:[
|
// ],"")
|
||||||
new kintoneEvent({label:"一覧画面を表示した後", eventId:"app.record.index.show"}),
|
// ]);
|
||||||
new kintoneEvent({label:"インライン編集を開始したとき",eventId:"app.record.index.edit.show"}),
|
|
||||||
new kintoneEvent({label:"インライン編集のフィールド値を変更したとき", eventId:"app.record.index.edit.change"}),
|
|
||||||
new kintoneEvent({label:"インライン編集の【保存】をクリックしたとき",eventId:"app.record.index.edit.submit"}),
|
|
||||||
new kintoneEvent({label:"インライン編集の保存が成功したとき", eventId:"app.record.index.edit.submit.success"}),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@
|
|||||||
"@nodelib/fs.stat" "2.0.5"
|
"@nodelib/fs.stat" "2.0.5"
|
||||||
run-parallel "^1.1.9"
|
run-parallel "^1.1.9"
|
||||||
|
|
||||||
"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5":
|
"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
|
||||||
version "2.0.5"
|
version "2.0.5"
|
||||||
resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
|
resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
|
||||||
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
|
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
|
||||||
@@ -299,7 +299,7 @@
|
|||||||
semver "^7.3.7"
|
semver "^7.3.7"
|
||||||
tsutils "^3.21.0"
|
tsutils "^3.21.0"
|
||||||
|
|
||||||
"@typescript-eslint/parser@^5.0.0", "@typescript-eslint/parser@^5.10.0":
|
"@typescript-eslint/parser@^5.10.0":
|
||||||
version "5.61.0"
|
version "5.61.0"
|
||||||
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.61.0.tgz"
|
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.61.0.tgz"
|
||||||
integrity sha512-yGr4Sgyh8uO6fSi9hw3jAFXNBHbCtKKFMdX2IkT3ZqpKmtAq3lHS4ixB/COFuAIJpwl9/AqF7j72ZDWYKmIfvg==
|
integrity sha512-yGr4Sgyh8uO6fSi9hw3jAFXNBHbCtKKFMdX2IkT3ZqpKmtAq3lHS4ixB/COFuAIJpwl9/AqF7j72ZDWYKmIfvg==
|
||||||
@@ -367,7 +367,7 @@
|
|||||||
"@typescript-eslint/types" "5.61.0"
|
"@typescript-eslint/types" "5.61.0"
|
||||||
eslint-visitor-keys "^3.3.0"
|
eslint-visitor-keys "^3.3.0"
|
||||||
|
|
||||||
"@vitejs/plugin-vue@^2.0.0 || ^3.0.0 || ^4.0.0", "@vitejs/plugin-vue@^2.2.0":
|
"@vitejs/plugin-vue@^2.2.0":
|
||||||
version "2.3.4"
|
version "2.3.4"
|
||||||
resolved "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-2.3.4.tgz"
|
resolved "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-2.3.4.tgz"
|
||||||
integrity sha512-IfFNbtkbIm36O9KB8QodlwwYvTEsJb4Lll4c2IwB3VHc2gie2mSPtSzL0eYay7X2jd/2WX02FjSGTWR6OPr/zg==
|
integrity sha512-IfFNbtkbIm36O9KB8QodlwwYvTEsJb4Lll4c2IwB3VHc2gie2mSPtSzL0eYay7X2jd/2WX02FjSGTWR6OPr/zg==
|
||||||
@@ -480,22 +480,12 @@ acorn-jsx@^5.3.2:
|
|||||||
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
|
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
|
||||||
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
|
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
|
||||||
|
|
||||||
"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.9.0:
|
acorn@^8.9.0:
|
||||||
version "8.10.0"
|
version "8.10.0"
|
||||||
resolved "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz"
|
resolved "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz"
|
||||||
integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==
|
integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==
|
||||||
|
|
||||||
ajv@^6.10.0:
|
ajv@^6.10.0, ajv@^6.12.4:
|
||||||
version "6.12.6"
|
|
||||||
resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz"
|
|
||||||
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
|
|
||||||
dependencies:
|
|
||||||
fast-deep-equal "^3.1.1"
|
|
||||||
fast-json-stable-stringify "^2.0.0"
|
|
||||||
json-schema-traverse "^0.4.1"
|
|
||||||
uri-js "^4.2.2"
|
|
||||||
|
|
||||||
ajv@^6.12.4:
|
|
||||||
version "6.12.6"
|
version "6.12.6"
|
||||||
resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz"
|
resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz"
|
||||||
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
|
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
|
||||||
@@ -691,7 +681,7 @@ braces@^3.0.2, braces@~3.0.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
fill-range "^7.0.1"
|
fill-range "^7.0.1"
|
||||||
|
|
||||||
browserslist@^4.21.5, "browserslist@>= 4.21.0":
|
browserslist@^4.21.5:
|
||||||
version "4.21.9"
|
version "4.21.9"
|
||||||
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz"
|
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz"
|
||||||
integrity sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==
|
integrity sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==
|
||||||
@@ -763,7 +753,7 @@ chardet@^0.7.0:
|
|||||||
resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz"
|
resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz"
|
||||||
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
|
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
|
||||||
|
|
||||||
chokidar@^3.5.3, "chokidar@>=3.0.0 <4.0.0":
|
"chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.3:
|
||||||
version "3.5.3"
|
version "3.5.3"
|
||||||
resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz"
|
resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz"
|
||||||
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
|
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
|
||||||
@@ -948,27 +938,6 @@ csstype@^3.1.1:
|
|||||||
resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz"
|
resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz"
|
||||||
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
|
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
|
||||||
|
|
||||||
debug@^4.1.1:
|
|
||||||
version "4.3.4"
|
|
||||||
resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
|
|
||||||
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
|
||||||
dependencies:
|
|
||||||
ms "2.1.2"
|
|
||||||
|
|
||||||
debug@^4.3.2:
|
|
||||||
version "4.3.4"
|
|
||||||
resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
|
|
||||||
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
|
||||||
dependencies:
|
|
||||||
ms "2.1.2"
|
|
||||||
|
|
||||||
debug@^4.3.4:
|
|
||||||
version "4.3.4"
|
|
||||||
resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
|
|
||||||
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
|
||||||
dependencies:
|
|
||||||
ms "2.1.2"
|
|
||||||
|
|
||||||
debug@2.6.9:
|
debug@2.6.9:
|
||||||
version "2.6.9"
|
version "2.6.9"
|
||||||
resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
|
resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
|
||||||
@@ -976,6 +945,13 @@ debug@2.6.9:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ms "2.0.0"
|
ms "2.0.0"
|
||||||
|
|
||||||
|
debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
|
||||||
|
version "4.3.4"
|
||||||
|
resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
|
||||||
|
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
||||||
|
dependencies:
|
||||||
|
ms "2.1.2"
|
||||||
|
|
||||||
deep-is@^0.1.3:
|
deep-is@^0.1.3:
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz"
|
resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz"
|
||||||
@@ -1068,12 +1044,107 @@ end-of-stream@^1.4.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
once "^1.4.0"
|
once "^1.4.0"
|
||||||
|
|
||||||
|
esbuild-android-64@0.14.51:
|
||||||
|
version "0.14.51"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.51.tgz#414a087cb0de8db1e347ecca6c8320513de433db"
|
||||||
|
integrity sha512-6FOuKTHnC86dtrKDmdSj2CkcKF8PnqkaIXqvgydqfJmqBazCPdw+relrMlhGjkvVdiiGV70rpdnyFmA65ekBCQ==
|
||||||
|
|
||||||
|
esbuild-android-arm64@0.14.51:
|
||||||
|
version "0.14.51"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.51.tgz#55de3bce2aab72bcd2b606da4318ad00fb9c8151"
|
||||||
|
integrity sha512-vBtp//5VVkZWmYYvHsqBRCMMi1MzKuMIn5XDScmnykMTu9+TD9v0NMEDqQxvtFToeYmojdo5UCV2vzMQWJcJ4A==
|
||||||
|
|
||||||
|
esbuild-darwin-64@0.14.51:
|
||||||
|
version "0.14.51"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.51.tgz#4259f23ed6b4cea2ec8a28d87b7fb9801f093754"
|
||||||
|
integrity sha512-YFmXPIOvuagDcwCejMRtCDjgPfnDu+bNeh5FU2Ryi68ADDVlWEpbtpAbrtf/lvFTWPexbgyKgzppNgsmLPr8PA==
|
||||||
|
|
||||||
|
esbuild-darwin-arm64@0.14.51:
|
||||||
|
version "0.14.51"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.51.tgz#d77b4366a71d84e530ba019d540b538b295d494a"
|
||||||
|
integrity sha512-juYD0QnSKwAMfzwKdIF6YbueXzS6N7y4GXPDeDkApz/1RzlT42mvX9jgNmyOlWKN7YzQAYbcUEJmZJYQGdf2ow==
|
||||||
|
|
||||||
|
esbuild-freebsd-64@0.14.51:
|
||||||
|
version "0.14.51"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.51.tgz#27b6587b3639f10519c65e07219d249b01f2ad38"
|
||||||
|
integrity sha512-cLEI/aXjb6vo5O2Y8rvVSQ7smgLldwYY5xMxqh/dQGfWO+R1NJOFsiax3IS4Ng300SVp7Gz3czxT6d6qf2cw0g==
|
||||||
|
|
||||||
|
esbuild-freebsd-arm64@0.14.51:
|
||||||
|
version "0.14.51"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.51.tgz#63c435917e566808c71fafddc600aca4d78be1ec"
|
||||||
|
integrity sha512-TcWVw/rCL2F+jUgRkgLa3qltd5gzKjIMGhkVybkjk6PJadYInPtgtUBp1/hG+mxyigaT7ib+od1Xb84b+L+1Mg==
|
||||||
|
|
||||||
|
esbuild-linux-32@0.14.51:
|
||||||
|
version "0.14.51"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.51.tgz#c3da774143a37e7f11559b9369d98f11f997a5d9"
|
||||||
|
integrity sha512-RFqpyC5ChyWrjx8Xj2K0EC1aN0A37H6OJfmUXIASEqJoHcntuV3j2Efr9RNmUhMfNE6yEj2VpYuDteZLGDMr0w==
|
||||||
|
|
||||||
|
esbuild-linux-64@0.14.51:
|
||||||
|
version "0.14.51"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.51.tgz#5d92b67f674e02ae0b4a9de9a757ba482115c4ae"
|
||||||
|
integrity sha512-dxjhrqo5i7Rq6DXwz5v+MEHVs9VNFItJmHBe1CxROWNf4miOGoQhqSG8StStbDkQ1Mtobg6ng+4fwByOhoQoeA==
|
||||||
|
|
||||||
|
esbuild-linux-arm64@0.14.51:
|
||||||
|
version "0.14.51"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.51.tgz#dac84740516e859d8b14e1ecc478dd5241b10c93"
|
||||||
|
integrity sha512-D9rFxGutoqQX3xJPxqd6o+kvYKeIbM0ifW2y0bgKk5HPgQQOo2k9/2Vpto3ybGYaFPCE5qTGtqQta9PoP6ZEzw==
|
||||||
|
|
||||||
|
esbuild-linux-arm@0.14.51:
|
||||||
|
version "0.14.51"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.51.tgz#b3ae7000696cd53ed95b2b458554ff543a60e106"
|
||||||
|
integrity sha512-LsJynDxYF6Neg7ZC7748yweCDD+N8ByCv22/7IAZglIEniEkqdF4HCaa49JNDLw1UQGlYuhOB8ZT/MmcSWzcWg==
|
||||||
|
|
||||||
|
esbuild-linux-mips64le@0.14.51:
|
||||||
|
version "0.14.51"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.51.tgz#dad10770fac94efa092b5a0643821c955a9dd385"
|
||||||
|
integrity sha512-vS54wQjy4IinLSlb5EIlLoln8buh1yDgliP4CuEHumrPk4PvvP4kTRIG4SzMXm6t19N0rIfT4bNdAxzJLg2k6A==
|
||||||
|
|
||||||
|
esbuild-linux-ppc64le@0.14.51:
|
||||||
|
version "0.14.51"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.51.tgz#b68c2f8294d012a16a88073d67e976edd4850ae0"
|
||||||
|
integrity sha512-xcdd62Y3VfGoyphNP/aIV9LP+RzFw5M5Z7ja+zdpQHHvokJM7d0rlDRMN+iSSwvUymQkqZO+G/xjb4/75du8BQ==
|
||||||
|
|
||||||
|
esbuild-linux-riscv64@0.14.51:
|
||||||
|
version "0.14.51"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.51.tgz#608a318b8697123e44c1e185cdf6708e3df50b93"
|
||||||
|
integrity sha512-syXHGak9wkAnFz0gMmRBoy44JV0rp4kVCEA36P5MCeZcxFq8+fllBC2t6sKI23w3qd8Vwo9pTADCgjTSf3L3rA==
|
||||||
|
|
||||||
|
esbuild-linux-s390x@0.14.51:
|
||||||
|
version "0.14.51"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.51.tgz#c9e7791170a3295dba79b93aa452beb9838a8625"
|
||||||
|
integrity sha512-kFAJY3dv+Wq8o28K/C7xkZk/X34rgTwhknSsElIqoEo8armCOjMJ6NsMxm48KaWY2h2RUYGtQmr+RGuUPKBhyw==
|
||||||
|
|
||||||
|
esbuild-netbsd-64@0.14.51:
|
||||||
|
version "0.14.51"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.51.tgz#0abd40b8c2e37fda6f5cc41a04cb2b690823d891"
|
||||||
|
integrity sha512-ZZBI7qrR1FevdPBVHz/1GSk1x5GDL/iy42Zy8+neEm/HA7ma+hH/bwPEjeHXKWUDvM36CZpSL/fn1/y9/Hb+1A==
|
||||||
|
|
||||||
|
esbuild-openbsd-64@0.14.51:
|
||||||
|
version "0.14.51"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.51.tgz#4adba0b7ea7eb1428bb00d8e94c199a949b130e8"
|
||||||
|
integrity sha512-7R1/p39M+LSVQVgDVlcY1KKm6kFKjERSX1lipMG51NPcspJD1tmiZSmmBXoY5jhHIu6JL1QkFDTx94gMYK6vfA==
|
||||||
|
|
||||||
|
esbuild-sunos-64@0.14.51:
|
||||||
|
version "0.14.51"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.51.tgz#4b8a6d97dfedda30a6e39607393c5c90ebf63891"
|
||||||
|
integrity sha512-HoHaCswHxLEYN8eBTtyO0bFEWvA3Kdb++hSQ/lLG7TyKF69TeSG0RNoBRAs45x/oCeWaTDntEZlYwAfQlhEtJA==
|
||||||
|
|
||||||
|
esbuild-windows-32@0.14.51:
|
||||||
|
version "0.14.51"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.51.tgz#d31d8ca0c1d314fb1edea163685a423b62e9ac17"
|
||||||
|
integrity sha512-4rtwSAM35A07CBt1/X8RWieDj3ZUHQqUOaEo5ZBs69rt5WAFjP4aqCIobdqOy4FdhYw1yF8Z0xFBTyc9lgPtEg==
|
||||||
|
|
||||||
esbuild-windows-64@0.14.51:
|
esbuild-windows-64@0.14.51:
|
||||||
version "0.14.51"
|
version "0.14.51"
|
||||||
resolved "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.51.tgz"
|
resolved "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.51.tgz"
|
||||||
integrity sha512-HoN/5HGRXJpWODprGCgKbdMvrC3A2gqvzewu2eECRw2sYxOUoh2TV1tS+G7bHNapPGI79woQJGV6pFH7GH7qnA==
|
integrity sha512-HoN/5HGRXJpWODprGCgKbdMvrC3A2gqvzewu2eECRw2sYxOUoh2TV1tS+G7bHNapPGI79woQJGV6pFH7GH7qnA==
|
||||||
|
|
||||||
esbuild@^0.14.27, esbuild@0.14.51:
|
esbuild-windows-arm64@0.14.51:
|
||||||
|
version "0.14.51"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.51.tgz#0220d2304bfdc11bc27e19b2aaf56edf183e4ae9"
|
||||||
|
integrity sha512-JQDqPjuOH7o+BsKMSddMfmVJXrnYZxXDHsoLHc0xgmAZkOOCflRmC43q31pk79F9xuyWY45jDBPolb5ZgGOf9g==
|
||||||
|
|
||||||
|
esbuild@0.14.51, esbuild@^0.14.27:
|
||||||
version "0.14.51"
|
version "0.14.51"
|
||||||
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.14.51.tgz"
|
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.14.51.tgz"
|
||||||
integrity sha512-+CvnDitD7Q5sT7F+FM65sWkF8wJRf+j9fPcprxYV4j+ohmzVj2W7caUqH2s5kCaCJAfcAICjSlKhDCcvDpU7nw==
|
integrity sha512-+CvnDitD7Q5sT7F+FM65sWkF8wJRf+j9fPcprxYV4j+ohmzVj2W7caUqH2s5kCaCJAfcAICjSlKhDCcvDpU7nw==
|
||||||
@@ -1145,15 +1216,7 @@ eslint-scope@^5.1.1:
|
|||||||
esrecurse "^4.3.0"
|
esrecurse "^4.3.0"
|
||||||
estraverse "^4.1.1"
|
estraverse "^4.1.1"
|
||||||
|
|
||||||
eslint-scope@^7.1.1:
|
eslint-scope@^7.1.1, eslint-scope@^7.2.0:
|
||||||
version "7.2.0"
|
|
||||||
resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz"
|
|
||||||
integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==
|
|
||||||
dependencies:
|
|
||||||
esrecurse "^4.3.0"
|
|
||||||
estraverse "^5.2.0"
|
|
||||||
|
|
||||||
eslint-scope@^7.2.0:
|
|
||||||
version "7.2.0"
|
version "7.2.0"
|
||||||
resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz"
|
resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz"
|
||||||
integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==
|
integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==
|
||||||
@@ -1166,7 +1229,7 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1:
|
|||||||
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz"
|
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz"
|
||||||
integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==
|
integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==
|
||||||
|
|
||||||
eslint@*, "eslint@^6.0.0 || ^7.0.0 || ^8.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^6.2.0 || ^7.0.0 || ^8.0.0", eslint@^8.10.0, eslint@^8.11.0, eslint@>=6.0.0, eslint@>=7.0.0:
|
eslint@^8.10.0:
|
||||||
version "8.44.0"
|
version "8.44.0"
|
||||||
resolved "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz"
|
resolved "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz"
|
||||||
integrity sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==
|
integrity sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==
|
||||||
@@ -1239,12 +1302,7 @@ estraverse@^4.1.1:
|
|||||||
resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz"
|
resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz"
|
||||||
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
|
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
|
||||||
|
|
||||||
estraverse@^5.1.0:
|
estraverse@^5.1.0, estraverse@^5.2.0:
|
||||||
version "5.3.0"
|
|
||||||
resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz"
|
|
||||||
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
|
|
||||||
|
|
||||||
estraverse@^5.2.0:
|
|
||||||
version "5.3.0"
|
version "5.3.0"
|
||||||
resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz"
|
resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz"
|
||||||
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
|
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
|
||||||
@@ -1315,7 +1373,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
|
|||||||
resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz"
|
resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz"
|
||||||
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
|
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
|
||||||
|
|
||||||
fast-glob@^3.2.9, fast-glob@3.2.12:
|
fast-glob@3.2.12, fast-glob@^3.2.9:
|
||||||
version "3.2.12"
|
version "3.2.12"
|
||||||
resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz"
|
resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz"
|
||||||
integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==
|
integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==
|
||||||
@@ -1446,6 +1504,11 @@ fs.realpath@^1.0.0:
|
|||||||
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
|
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
|
||||||
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
||||||
|
|
||||||
|
fsevents@~2.3.2:
|
||||||
|
version "2.3.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
|
||||||
|
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
|
||||||
|
|
||||||
function-bind@^1.1.1:
|
function-bind@^1.1.1:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
|
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
|
||||||
@@ -1572,7 +1635,7 @@ http-errors@2.0.0:
|
|||||||
statuses "2.0.1"
|
statuses "2.0.1"
|
||||||
toidentifier "1.0.1"
|
toidentifier "1.0.1"
|
||||||
|
|
||||||
iconv-lite@^0.4.24, iconv-lite@0.4.24:
|
iconv-lite@0.4.24, iconv-lite@^0.4.24:
|
||||||
version "0.4.24"
|
version "0.4.24"
|
||||||
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz"
|
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz"
|
||||||
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
|
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
|
||||||
@@ -1610,7 +1673,7 @@ inflight@^1.0.4:
|
|||||||
once "^1.3.0"
|
once "^1.3.0"
|
||||||
wrappy "1"
|
wrappy "1"
|
||||||
|
|
||||||
inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3, inherits@2, inherits@2.0.4:
|
inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
|
||||||
version "2.0.4"
|
version "2.0.4"
|
||||||
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
|
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
|
||||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||||
@@ -1894,7 +1957,7 @@ micromatch@^4.0.4:
|
|||||||
braces "^3.0.2"
|
braces "^3.0.2"
|
||||||
picomatch "^2.3.1"
|
picomatch "^2.3.1"
|
||||||
|
|
||||||
"mime-db@>= 1.43.0 < 2", mime-db@1.52.0:
|
mime-db@1.52.0, "mime-db@>= 1.43.0 < 2":
|
||||||
version "1.52.0"
|
version "1.52.0"
|
||||||
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz"
|
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz"
|
||||||
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
|
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
|
||||||
@@ -2149,7 +2212,7 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, 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==
|
||||||
|
|
||||||
pinia@^2.0.0, pinia@^2.1.6:
|
pinia@^2.1.6:
|
||||||
version "2.1.6"
|
version "2.1.6"
|
||||||
resolved "https://registry.npmjs.org/pinia/-/pinia-2.1.6.tgz"
|
resolved "https://registry.npmjs.org/pinia/-/pinia-2.1.6.tgz"
|
||||||
integrity sha512-bIU6QuE5qZviMmct5XwCesXelb5VavdOWKWaB17ggk++NUwQWWbP5YnsONTk3b752QkW9sACiR81rorpeOMSvQ==
|
integrity sha512-bIU6QuE5qZviMmct5XwCesXelb5VavdOWKWaB17ggk++NUwQWWbP5YnsONTk3b752QkW9sACiR81rorpeOMSvQ==
|
||||||
@@ -2170,7 +2233,7 @@ postcss-value-parser@^4.2.0:
|
|||||||
resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz"
|
resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz"
|
||||||
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
|
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
|
||||||
|
|
||||||
postcss@^8.1.0, postcss@^8.1.10, postcss@^8.4.13:
|
postcss@^8.1.10, postcss@^8.4.13:
|
||||||
version "8.4.25"
|
version "8.4.25"
|
||||||
resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz"
|
resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz"
|
||||||
integrity sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw==
|
integrity sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw==
|
||||||
@@ -2219,7 +2282,7 @@ qs@6.11.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
side-channel "^1.0.4"
|
side-channel "^1.0.4"
|
||||||
|
|
||||||
quasar@^2.6.0, quasar@^2.8.0:
|
quasar@^2.6.0:
|
||||||
version "2.12.2"
|
version "2.12.2"
|
||||||
resolved "https://registry.npmjs.org/quasar/-/quasar-2.12.2.tgz"
|
resolved "https://registry.npmjs.org/quasar/-/quasar-2.12.2.tgz"
|
||||||
integrity sha512-UB+J1cN6b9FrRphUuMvW1Pt1uaOPH2XJMAZagQlYzVUmltKCXQ0sby+ANgGRYa8w/tsekMySmN9QvkQ3+hYv/g==
|
integrity sha512-UB+J1cN6b9FrRphUuMvW1Pt1uaOPH2XJMAZagQlYzVUmltKCXQ0sby+ANgGRYa8w/tsekMySmN9QvkQ3+hYv/g==
|
||||||
@@ -2251,20 +2314,7 @@ raw-body@2.5.1:
|
|||||||
iconv-lite "0.4.24"
|
iconv-lite "0.4.24"
|
||||||
unpipe "1.0.0"
|
unpipe "1.0.0"
|
||||||
|
|
||||||
readable-stream@^2.0.0:
|
readable-stream@^2.0.0, readable-stream@^2.0.5:
|
||||||
version "2.3.8"
|
|
||||||
resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz"
|
|
||||||
integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==
|
|
||||||
dependencies:
|
|
||||||
core-util-is "~1.0.0"
|
|
||||||
inherits "~2.0.3"
|
|
||||||
isarray "~1.0.0"
|
|
||||||
process-nextick-args "~2.0.0"
|
|
||||||
safe-buffer "~5.1.1"
|
|
||||||
string_decoder "~1.1.1"
|
|
||||||
util-deprecate "~1.0.1"
|
|
||||||
|
|
||||||
readable-stream@^2.0.5:
|
|
||||||
version "2.3.8"
|
version "2.3.8"
|
||||||
resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz"
|
resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz"
|
||||||
integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==
|
integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==
|
||||||
@@ -2364,7 +2414,7 @@ rollup-plugin-visualizer@^5.5.4:
|
|||||||
source-map "^0.7.4"
|
source-map "^0.7.4"
|
||||||
yargs "^17.5.1"
|
yargs "^17.5.1"
|
||||||
|
|
||||||
"rollup@>=2.59.0 <2.78.0", "rollup@2.x || 3.x":
|
"rollup@>=2.59.0 <2.78.0":
|
||||||
version "2.77.3"
|
version "2.77.3"
|
||||||
resolved "https://registry.npmjs.org/rollup/-/rollup-2.77.3.tgz"
|
resolved "https://registry.npmjs.org/rollup/-/rollup-2.77.3.tgz"
|
||||||
integrity sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==
|
integrity sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==
|
||||||
@@ -2390,7 +2440,7 @@ rxjs@^7.5.5:
|
|||||||
dependencies:
|
dependencies:
|
||||||
tslib "^2.1.0"
|
tslib "^2.1.0"
|
||||||
|
|
||||||
safe-buffer@^5.1.0, safe-buffer@~5.1.0, safe-buffer@~5.1.1, safe-buffer@5.1.2:
|
safe-buffer@5.1.2, safe-buffer@^5.1.0, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||||
version "5.1.2"
|
version "5.1.2"
|
||||||
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz"
|
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz"
|
||||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||||
@@ -2405,7 +2455,7 @@ safe-buffer@5.2.1:
|
|||||||
resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
|
resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
|
||||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||||
|
|
||||||
sass@*, sass@1.32.12:
|
sass@1.32.12:
|
||||||
version "1.32.12"
|
version "1.32.12"
|
||||||
resolved "https://registry.npmjs.org/sass/-/sass-1.32.12.tgz"
|
resolved "https://registry.npmjs.org/sass/-/sass-1.32.12.tgz"
|
||||||
integrity sha512-zmXn03k3hN0KaiVTjohgkg98C3UowhL1/VSGdj4/VAAiMKGQOE80PFPxFP2Kyq0OUskPKcY5lImkhBKEHlypJA==
|
integrity sha512-zmXn03k3hN0KaiVTjohgkg98C3UowhL1/VSGdj4/VAAiMKGQOE80PFPxFP2Kyq0OUskPKcY5lImkhBKEHlypJA==
|
||||||
@@ -2537,13 +2587,6 @@ statuses@2.0.1:
|
|||||||
resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz"
|
resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz"
|
||||||
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
|
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
|
||||||
|
|
||||||
string_decoder@^1.1.1, string_decoder@~1.1.1:
|
|
||||||
version "1.1.1"
|
|
||||||
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz"
|
|
||||||
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
|
|
||||||
dependencies:
|
|
||||||
safe-buffer "~5.1.0"
|
|
||||||
|
|
||||||
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||||
version "4.2.3"
|
version "4.2.3"
|
||||||
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
|
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
|
||||||
@@ -2553,6 +2596,13 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
|||||||
is-fullwidth-code-point "^3.0.0"
|
is-fullwidth-code-point "^3.0.0"
|
||||||
strip-ansi "^6.0.1"
|
strip-ansi "^6.0.1"
|
||||||
|
|
||||||
|
string_decoder@^1.1.1, string_decoder@~1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz"
|
||||||
|
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
|
||||||
|
dependencies:
|
||||||
|
safe-buffer "~5.1.0"
|
||||||
|
|
||||||
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||||
version "6.0.1"
|
version "6.0.1"
|
||||||
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
|
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
|
||||||
@@ -2670,7 +2720,7 @@ type-is@~1.6.18:
|
|||||||
media-typer "0.3.0"
|
media-typer "0.3.0"
|
||||||
mime-types "~2.1.24"
|
mime-types "~2.1.24"
|
||||||
|
|
||||||
typescript@^4.5.4, "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta", typescript@>=4.4.4:
|
typescript@^4.5.4:
|
||||||
version "4.9.5"
|
version "4.9.5"
|
||||||
resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz"
|
resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz"
|
||||||
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
|
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
|
||||||
@@ -2685,7 +2735,7 @@ universalify@^2.0.0:
|
|||||||
resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz"
|
resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz"
|
||||||
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
|
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
|
||||||
|
|
||||||
unpipe@~1.0.0, unpipe@1.0.0:
|
unpipe@1.0.0, unpipe@~1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz"
|
resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz"
|
||||||
integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
|
integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
|
||||||
@@ -2730,7 +2780,7 @@ vary@~1.1.2:
|
|||||||
resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz"
|
resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz"
|
||||||
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
|
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
|
||||||
|
|
||||||
"vite@^2.0.0 || ^3.0.0 || ^4.0.0", vite@^2.5.10, vite@^2.9.13:
|
vite@^2.9.13:
|
||||||
version "2.9.16"
|
version "2.9.16"
|
||||||
resolved "https://registry.npmjs.org/vite/-/vite-2.9.16.tgz"
|
resolved "https://registry.npmjs.org/vite/-/vite-2.9.16.tgz"
|
||||||
integrity sha512-X+6q8KPyeuBvTQV8AVSnKDvXoBMnTx8zxh54sOwmmuOdxkjMmEJXH2UEchA+vTMps1xw9vL64uwJOWryULg7nA==
|
integrity sha512-X+6q8KPyeuBvTQV8AVSnKDvXoBMnTx8zxh54sOwmmuOdxkjMmEJXH2UEchA+vTMps1xw9vL64uwJOWryULg7nA==
|
||||||
@@ -2760,14 +2810,14 @@ vue-eslint-parser@^9.3.0:
|
|||||||
lodash "^4.17.21"
|
lodash "^4.17.21"
|
||||||
semver "^7.3.6"
|
semver "^7.3.6"
|
||||||
|
|
||||||
vue-router@^4.0.0, vue-router@^4.0.12:
|
vue-router@^4.0.0:
|
||||||
version "4.2.4"
|
version "4.2.4"
|
||||||
resolved "https://registry.npmjs.org/vue-router/-/vue-router-4.2.4.tgz"
|
resolved "https://registry.npmjs.org/vue-router/-/vue-router-4.2.4.tgz"
|
||||||
integrity sha512-9PISkmaCO02OzPVOMq2w82ilty6+xJmQrarYZDkjZBfl4RvYAlt4PKnEX21oW4KTtWfa9OuO/b3qk1Od3AEdCQ==
|
integrity sha512-9PISkmaCO02OzPVOMq2w82ilty6+xJmQrarYZDkjZBfl4RvYAlt4PKnEX21oW4KTtWfa9OuO/b3qk1Od3AEdCQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@vue/devtools-api" "^6.5.0"
|
"@vue/devtools-api" "^6.5.0"
|
||||||
|
|
||||||
"vue@^2.6.14 || ^3.3.0", vue@^3.0.0, "vue@^3.0.0-0 || ^2.6.0", vue@^3.2.0, vue@^3.2.25, vue@^3.2.29, vue@3.3.4:
|
vue@^3.0.0:
|
||||||
version "3.3.4"
|
version "3.3.4"
|
||||||
resolved "https://registry.npmjs.org/vue/-/vue-3.3.4.tgz"
|
resolved "https://registry.npmjs.org/vue/-/vue-3.3.4.tgz"
|
||||||
integrity sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==
|
integrity sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==
|
||||||
|
|||||||
6
node_modules/.package-lock.json
generated
vendored
Normal file
6
node_modules/.package-lock.json
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "App Builder for kintone",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {}
|
||||||
|
}
|
||||||
15
node_modules/.yarn-integrity
generated
vendored
Normal file
15
node_modules/.yarn-integrity
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"systemParams": "win32-x64-108",
|
||||||
|
"modulesFolders": [
|
||||||
|
"node_modules"
|
||||||
|
],
|
||||||
|
"flags": [],
|
||||||
|
"linkedModules": [
|
||||||
|
"@quasar\\quasar-ui-qactivity",
|
||||||
|
"docs"
|
||||||
|
],
|
||||||
|
"topLevelPatterns": [],
|
||||||
|
"lockfileEntries": {},
|
||||||
|
"files": [],
|
||||||
|
"artifacts": {}
|
||||||
|
}
|
||||||
2
plugin/kintone-addins/.env.dev
Normal file
2
plugin/kintone-addins/.env.dev
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
VITE_SOURCE_MAP = inline
|
||||||
|
VITE_PORT = 4173
|
||||||
2
plugin/kintone-addins/.env.production
Normal file
2
plugin/kintone-addins/.env.production
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
VITE_SOURCE_MAP = false
|
||||||
|
VITE_PORT = 4173
|
||||||
24
plugin/kintone-addins/.gitignore
vendored
Normal file
24
plugin/kintone-addins/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
814
plugin/kintone-addins/package-lock.json
generated
Normal file
814
plugin/kintone-addins/package-lock.json
generated
Normal file
@@ -0,0 +1,814 @@
|
|||||||
|
{
|
||||||
|
"name": "kintone-addins",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "kintone-addins",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"dependencies": {
|
||||||
|
"jquery": "^3.7.1",
|
||||||
|
"yarn": "^1.22.22"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/jquery": "^3.5.24",
|
||||||
|
"@types/node": "^20.8.9",
|
||||||
|
"sass": "^1.69.5",
|
||||||
|
"typescript": "^5.0.2",
|
||||||
|
"vite": "^4.4.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/android-arm": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/android-arm64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/android-x64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/darwin-arm64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/darwin-x64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/freebsd-arm64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/freebsd-x64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-arm": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-arm64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-ia32": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-loong64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==",
|
||||||
|
"cpu": [
|
||||||
|
"loong64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-mips64el": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==",
|
||||||
|
"cpu": [
|
||||||
|
"mips64el"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-ppc64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==",
|
||||||
|
"cpu": [
|
||||||
|
"ppc64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-riscv64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==",
|
||||||
|
"cpu": [
|
||||||
|
"riscv64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-s390x": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==",
|
||||||
|
"cpu": [
|
||||||
|
"s390x"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-x64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/netbsd-x64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"netbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/openbsd-x64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"openbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/sunos-x64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"sunos"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/win32-arm64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/win32-ia32": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/win32-x64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/jquery": {
|
||||||
|
"version": "3.5.24",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.24.tgz",
|
||||||
|
"integrity": "sha512-V/TG69ge5amcr8Ap7vY3SObqKfZlV7ttqcYnNcYnndI77ySIRi05+3GjvfwRtE2qalAC2ySLIL1ker512sI20g==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/sizzle": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "20.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.0.tgz",
|
||||||
|
"integrity": "sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~5.26.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/sizzle": {
|
||||||
|
"version": "2.3.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.5.tgz",
|
||||||
|
"integrity": "sha512-tAe4Q+OLFOA/AMD+0lq8ovp8t3ysxAOeaScnfNdZpUxaGl51ZMDEITxkvFl1STudQ58mz6gzVGl9VhMKhwRnZQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/anymatch": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"normalize-path": "^3.0.0",
|
||||||
|
"picomatch": "^2.0.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/binary-extensions": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/braces": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"fill-range": "^7.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/chokidar": {
|
||||||
|
"version": "3.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||||
|
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://paulmillr.com/funding/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"anymatch": "~3.1.2",
|
||||||
|
"braces": "~3.0.2",
|
||||||
|
"glob-parent": "~5.1.2",
|
||||||
|
"is-binary-path": "~2.1.0",
|
||||||
|
"is-glob": "~4.0.1",
|
||||||
|
"normalize-path": "~3.0.0",
|
||||||
|
"readdirp": "~3.6.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8.10.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"fsevents": "~2.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/esbuild": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"bin": {
|
||||||
|
"esbuild": "bin/esbuild"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@esbuild/android-arm": "0.18.20",
|
||||||
|
"@esbuild/android-arm64": "0.18.20",
|
||||||
|
"@esbuild/android-x64": "0.18.20",
|
||||||
|
"@esbuild/darwin-arm64": "0.18.20",
|
||||||
|
"@esbuild/darwin-x64": "0.18.20",
|
||||||
|
"@esbuild/freebsd-arm64": "0.18.20",
|
||||||
|
"@esbuild/freebsd-x64": "0.18.20",
|
||||||
|
"@esbuild/linux-arm": "0.18.20",
|
||||||
|
"@esbuild/linux-arm64": "0.18.20",
|
||||||
|
"@esbuild/linux-ia32": "0.18.20",
|
||||||
|
"@esbuild/linux-loong64": "0.18.20",
|
||||||
|
"@esbuild/linux-mips64el": "0.18.20",
|
||||||
|
"@esbuild/linux-ppc64": "0.18.20",
|
||||||
|
"@esbuild/linux-riscv64": "0.18.20",
|
||||||
|
"@esbuild/linux-s390x": "0.18.20",
|
||||||
|
"@esbuild/linux-x64": "0.18.20",
|
||||||
|
"@esbuild/netbsd-x64": "0.18.20",
|
||||||
|
"@esbuild/openbsd-x64": "0.18.20",
|
||||||
|
"@esbuild/sunos-x64": "0.18.20",
|
||||||
|
"@esbuild/win32-arm64": "0.18.20",
|
||||||
|
"@esbuild/win32-ia32": "0.18.20",
|
||||||
|
"@esbuild/win32-x64": "0.18.20"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fill-range": {
|
||||||
|
"version": "7.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||||
|
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"to-regex-range": "^5.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fsevents": {
|
||||||
|
"version": "2.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
|
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/glob-parent": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"is-glob": "^4.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/immutable": {
|
||||||
|
"version": "4.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz",
|
||||||
|
"integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/is-binary-path": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"binary-extensions": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-extglob": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-glob": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"is-extglob": "^2.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-number": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jquery": {
|
||||||
|
"version": "3.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
|
||||||
|
"integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg=="
|
||||||
|
},
|
||||||
|
"node_modules/nanoid": {
|
||||||
|
"version": "3.3.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
||||||
|
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bin": {
|
||||||
|
"nanoid": "bin/nanoid.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/normalize-path": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/picocolors": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/picomatch": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postcss": {
|
||||||
|
"version": "8.4.31",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
|
||||||
|
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "tidelift",
|
||||||
|
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"nanoid": "^3.3.6",
|
||||||
|
"picocolors": "^1.0.0",
|
||||||
|
"source-map-js": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || >=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/readdirp": {
|
||||||
|
"version": "3.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||||
|
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"picomatch": "^2.2.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/rollup": {
|
||||||
|
"version": "3.29.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
|
||||||
|
"integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"rollup": "dist/bin/rollup"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.18.0",
|
||||||
|
"npm": ">=8.0.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"fsevents": "~2.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sass": {
|
||||||
|
"version": "1.69.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/sass/-/sass-1.69.7.tgz",
|
||||||
|
"integrity": "sha512-rzj2soDeZ8wtE2egyLXgOOHQvaC2iosZrkF6v3EUG+tBwEvhqUCzm0VP3k9gHF9LXbSrRhT5SksoI56Iw8NPnQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"chokidar": ">=3.0.0 <4.0.0",
|
||||||
|
"immutable": "^4.0.0",
|
||||||
|
"source-map-js": ">=0.6.2 <2.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"sass": "sass.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/source-map-js": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/to-regex-range": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"is-number": "^7.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/typescript": {
|
||||||
|
"version": "5.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
|
||||||
|
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"tsc": "bin/tsc",
|
||||||
|
"tsserver": "bin/tsserver"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "5.26.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/vite": {
|
||||||
|
"version": "4.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz",
|
||||||
|
"integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"esbuild": "^0.18.10",
|
||||||
|
"postcss": "^8.4.27",
|
||||||
|
"rollup": "^3.27.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"vite": "bin/vite.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.18.0 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/vitejs/vite?sponsor=1"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"fsevents": "~2.3.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/node": ">= 14",
|
||||||
|
"less": "*",
|
||||||
|
"lightningcss": "^1.21.0",
|
||||||
|
"sass": "*",
|
||||||
|
"stylus": "*",
|
||||||
|
"sugarss": "*",
|
||||||
|
"terser": "^5.4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/node": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"less": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"lightningcss": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"sass": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"stylus": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"sugarss": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"terser": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/yarn": {
|
||||||
|
"version": "1.22.22",
|
||||||
|
"resolved": "https://registry.npmjs.org/yarn/-/yarn-1.22.22.tgz",
|
||||||
|
"integrity": "sha512-prL3kGtyG7o9Z9Sv8IPfBNrWTDmXB4Qbes8A9rEzt6wkJV8mUvoirjU0Mp3GGAU06Y0XQyA3/2/RQFVuK7MTfg==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"bin": {
|
||||||
|
"yarn": "bin/yarn.js",
|
||||||
|
"yarnpkg": "bin/yarn.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user