Compare commits
109 Commits
mvp-step1
...
mvp_step2_
| Author | SHA1 | Date | |
|---|---|---|---|
| 58e22dc55f | |||
| f861955b51 | |||
| 1e7d553bd6 | |||
| 35ae2539cb | |||
|
|
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 | |||
| 9e72acf84b | |||
| 52f4af759e | |||
| 76457b6667 | |||
| e1f2afa942 | |||
| 8d5dff60f1 | |||
| 461cd26690 | |||
| 4c6b2ea844 | |||
| 418f45f997 | |||
| 51ebe99d1c | |||
| 2f1f8a60fc | |||
| 64795a80c7 | |||
| 94a17073dd | |||
| 7f7d625fdd | |||
| 6902079866 | |||
| 6aa057e590 | |||
| 2721cd60d1 | |||
| 1f8d079d4d | |||
|
|
f34dec1054 | ||
|
|
01b64f1aba | ||
|
|
3367ada343 | ||
|
|
f4ea3eaccb | ||
|
|
4adb8401d6 | ||
| df59bff6ae | |||
| 3ae685a0e2 | |||
|
|
fce56e43c3 | ||
|
|
42618602f4 | ||
| c1e50736e8 | |||
|
|
e02131846b | ||
|
|
2c3b27d9de | ||
|
|
6ccc833f7d | ||
|
|
a0ecc2eee3 | ||
| 59e6d33656 | |||
| b641c729c2 | |||
| 142cdcda38 | |||
| fc2669dabf | |||
| 8e095b51e3 | |||
| ff03490209 | |||
| 40cd9998d0 | |||
| 973ba159b4 | |||
| 063a5af822 | |||
|
|
6a06c71104 | ||
| cccff1d16d | |||
|
|
100d8de54f | ||
|
|
7c667660c0 | ||
|
|
4eb56372a5 | ||
|
|
16edd398be | ||
|
|
4e08159e6d |
3
backend/.gitignore
vendored
3
backend/.gitignore
vendored
@@ -125,4 +125,5 @@ cython_debug/
|
||||
# VS Code settings
|
||||
.vscode/
|
||||
|
||||
*.lock
|
||||
*.lock
|
||||
Temp/
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
FROM python:3.8
|
||||
FROM python:3.11.4
|
||||
|
||||
RUN mkdir /app
|
||||
WORKDIR /app
|
||||
|
||||
14
backend/Temp/alc_runtime.js
Normal file
14
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:
|
||||
permissions = "user"
|
||||
access_token = security.create_access_token(
|
||||
data={"sub": user.email, "permissions": permissions},
|
||||
data={"sub": user.id, "permissions": permissions},
|
||||
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")
|
||||
async def signup(
|
||||
firstname:str, lastname:str,
|
||||
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:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_409_CONFLICT,
|
||||
@@ -56,8 +57,8 @@ async def signup(
|
||||
else:
|
||||
permissions = "user"
|
||||
access_token = security.create_access_token(
|
||||
data={"sub": user.email, "permissions": permissions},
|
||||
data={"sub": user.id, "permissions": permissions},
|
||||
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,152 @@ import pandas as pd
|
||||
import json
|
||||
import httpx
|
||||
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()
|
||||
|
||||
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):
|
||||
if(type(value) == str):
|
||||
value = value.replace("\"","⊡⊡")
|
||||
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]
|
||||
col=[]
|
||||
for row in range(5,len(df)):
|
||||
if pd.isna(df.iloc[row,1]):
|
||||
for row in range(startrow,len(df)):
|
||||
if pd.isna(df.iloc[row,startcolumn]):
|
||||
break
|
||||
if not df.iloc[row,3] in c.KINTONE_FIELD_TYPE:
|
||||
if not df.iloc[row,typecolumn] in config.KINTONE_FIELD_TYPE:
|
||||
continue
|
||||
p=[]
|
||||
for column in range(1,7):
|
||||
for column in range(startcolumn,startcolumn + len(property)):
|
||||
if(not pd.isna(df.iloc[row,column])):
|
||||
if(property[column-1]=="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"\"{property[column-1]}\":{{{','.join(o)}}}")
|
||||
elif(property[column-1]=="required"):
|
||||
p.append(f"\"{property[column-1]}\":{df.iloc[row,column]}")
|
||||
propertyname =property[column-1]
|
||||
if(propertyname.find("[") == 0):
|
||||
continue
|
||||
elif (propertyname =="remark"):
|
||||
if (df.iloc[row,column].find("|") !=-1):
|
||||
propertyname = "options"
|
||||
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:
|
||||
p.append(f"\"{property[column-1]}\":\"{df.iloc[row,column]}\"")
|
||||
col.append(f"\"{df.iloc[row,2]}\":{{{','.join(p)}}}")
|
||||
fields = ",".join(col).replace("False","false").replace("True","true")
|
||||
p = p + createkintonefields(propertyname, df.iloc[row,column],trueformat)
|
||||
|
||||
# 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("\\", "\\\\").replace("⊡⊡","\\\"")
|
||||
return json.loads(f"{{{fields}}}")
|
||||
|
||||
def getsettingfromexcel(df):
|
||||
@@ -39,10 +158,10 @@ def getsettingfromexcel(df):
|
||||
des = df.iloc[2,2]
|
||||
return {"name":appname,"description":des}
|
||||
|
||||
def getsettingfromkintone(app:str):
|
||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||
def getsettingfromkintone(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}{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)
|
||||
return r.json()
|
||||
|
||||
@@ -54,24 +173,24 @@ def analysesettings(excel,kintone):
|
||||
updatesettings[key] = excel[key]
|
||||
return updatesettings
|
||||
|
||||
def createkintoneapp(name:str):
|
||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
||||
def createkintoneapp(name:str,c:config.KINTONE_ENV):
|
||||
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
||||
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))
|
||||
return r.json()
|
||||
|
||||
def updateappsettingstokintone(app:str,updates:dict):
|
||||
headers={c.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"
|
||||
def updateappsettingstokintone(app:str,updates:dict,c:config.KINTONE_ENV):
|
||||
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/settings.json"
|
||||
data = {"app":app}
|
||||
data.update(updates)
|
||||
r = httpx.put(url,headers=headers,data=json.dumps(data))
|
||||
return r.json()
|
||||
|
||||
def addfieldstokintone(app:str,fields:dict,revision:str = None):
|
||||
headers={c.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"
|
||||
def addfieldstokintone(app:str,fields:dict,c:config.KINTONE_ENV,revision:str = None):
|
||||
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/form/fields.json"
|
||||
if revision != None:
|
||||
data = {"app":app,"revision":revision,"properties":fields}
|
||||
else:
|
||||
@@ -79,32 +198,32 @@ def addfieldstokintone(app:str,fields:dict,revision:str = None):
|
||||
r = httpx.post(url,headers=headers,data=json.dumps(data))
|
||||
return r.json()
|
||||
|
||||
def updatefieldstokintone(app:str,revision:str,fields:dict):
|
||||
headers={c.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"
|
||||
def updatefieldstokintone(app:str,revision:str,fields:dict,c:config.KINTONE_ENV):
|
||||
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/form/fields.json"
|
||||
data = {"app":app,"properties":fields}
|
||||
r = httpx.put(url,headers=headers,data=json.dumps(data))
|
||||
return r.json()
|
||||
|
||||
def deletefieldsfromkintone(app:str,revision:str,fields:dict):
|
||||
headers={c.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"
|
||||
def deletefieldsfromkintone(app:str,revision:str,fields:dict,c:config.KINTONE_ENV):
|
||||
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/form/fields.json"
|
||||
params = {"app":app,"revision":revision,"fields":fields}
|
||||
#r = httpx.delete(url,headers=headers,content=json.dumps(params))
|
||||
r = httpx.request(method="DELETE",url=url,headers=headers,content=json.dumps(params))
|
||||
return r.json()
|
||||
|
||||
def deoployappfromkintone(app:str,revision:str):
|
||||
headers={c.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"
|
||||
def deoployappfromkintone(app:str,revision:str,c:config.KINTONE_ENV):
|
||||
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/deploy.json"
|
||||
data = {"apps":[{"app":app,"revision":revision}],"revert": False}
|
||||
r = httpx.post(url,headers=headers,data=json.dumps(data))
|
||||
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}
|
||||
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)
|
||||
return r.json()
|
||||
|
||||
@@ -116,22 +235,22 @@ def analysefields(excel,kintone):
|
||||
adds = excel.keys() - kintone.keys()
|
||||
dels = kintone.keys() - excel.keys()
|
||||
for key in updates:
|
||||
for p in property:
|
||||
if excel[key].get(p) != None and kintone[key][p] != excel[key][p]:
|
||||
for p in config.KINTONE_FIELD_PROPERTY:
|
||||
if excel[key].get(p) != None and kintone[key].get(p) != None and kintone[key][p] != excel[key][p]:
|
||||
updatefields[key] = excel[key]
|
||||
break
|
||||
for key in adds:
|
||||
addfields[key] = excel[key]
|
||||
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)
|
||||
|
||||
return {"update":updatefields,"add":addfields,"del":delfields}
|
||||
|
||||
def getprocessfromkintone(app:str):
|
||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||
def getprocessfromkintone(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}{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)
|
||||
return r.json()
|
||||
|
||||
@@ -195,27 +314,75 @@ def analysprocess(excel,kintone):
|
||||
# return True
|
||||
return diff
|
||||
|
||||
def updateprocesstokintone(app:str,process:dict):
|
||||
headers={c.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"
|
||||
def updateprocesstokintone(app:str,process:dict,c:config.KINTONE_ENV):
|
||||
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/status.json"
|
||||
data = {"app":app,"enable":True}
|
||||
data.update(process)
|
||||
r = httpx.put(url,headers=headers,data=json.dumps(data))
|
||||
return r.json()
|
||||
|
||||
def getkintoneusers():
|
||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||
def getkintoneusers(c:config.KINTONE_ENV):
|
||||
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||
url = f"{c.BASE_URL}/v1/users.json"
|
||||
r = httpx.get(url,headers=headers)
|
||||
return r.json()
|
||||
|
||||
def getkintoneorgs():
|
||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||
def getkintoneorgs(c:config.KINTONE_ENV):
|
||||
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||
params = {"code":c.KINTONE_USER}
|
||||
url = f"{c.BASE_URL}/v1/user/organizations.json"
|
||||
r = httpx.get(url,headers=headers,params=params)
|
||||
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 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")
|
||||
print(rootdir)
|
||||
print(fpath)
|
||||
with open(fpath,'w') as file:
|
||||
file.write(js)
|
||||
return fpath
|
||||
|
||||
@r.post("/test",)
|
||||
async def test(file:UploadFile= File(...),app:str=None):
|
||||
if file.filename.endswith('.xlsx'):
|
||||
@@ -233,15 +400,26 @@ async def test(file:UploadFile= File(...),app:str=None):
|
||||
# kintone = getfieldsfromkintone(app)
|
||||
# fields = analysefields(excel,kintone["properties"])
|
||||
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:
|
||||
raise HTTPException(status_code=400, detail=f"File {file.filename} is not an Excel file")
|
||||
|
||||
return test
|
||||
|
||||
|
||||
@r.post("/upload",)
|
||||
async def upload(files:t.List[UploadFile] = File(...)):
|
||||
@r.post("/download",)
|
||||
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 = []
|
||||
for file in files:
|
||||
if file.filename.endswith('.xlsx'):
|
||||
@@ -251,61 +429,103 @@ async def upload(files:t.List[UploadFile] = File(...)):
|
||||
print(df)
|
||||
dataframes.append(df)
|
||||
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:
|
||||
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]}
|
||||
|
||||
@r.get("/allapps",)
|
||||
async def allapps():
|
||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||
url = f"{c.BASE_URL}{c.API_V1_STR}/apps.json"
|
||||
r = httpx.get(url,headers=headers)
|
||||
return r.json()
|
||||
@r.post("/updatejscss")
|
||||
async def jscss(request:Request,app:str,files:t.List[UploadFile] = File(...),env = Depends(getkintoneenv)):
|
||||
try:
|
||||
jscs=[]
|
||||
for file in files:
|
||||
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(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()
|
||||
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()
|
||||
except Exception as e:
|
||||
raise APIException('kintone:app',request.url._url, f"Error occurred while get app({c.DOMAIN_NAM}->{app}):",e)
|
||||
|
||||
@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_NAM}):",e)
|
||||
|
||||
@r.get("/appfields")
|
||||
async def appfields(app:str):
|
||||
return getfieldsfromkintone(app)
|
||||
async def appfields(request:Request,app:str,env = Depends(getkintoneenv)):
|
||||
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_NAM}->{app}):",e)
|
||||
|
||||
@r.get("/appprocess")
|
||||
async def appprocess(app:str):
|
||||
return getprocessfromkintone(app)
|
||||
async def appprocess(request:Request,app:str,env = Depends(getkintoneenv)):
|
||||
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_NAM}->{app}):",e)
|
||||
|
||||
@r.get("/alljscs")
|
||||
async def alljscs(app:str):
|
||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||
url = f"{c.BASE_URL}{c.API_V1_STR}/app/customize.json"
|
||||
params = {"app":app}
|
||||
r = httpx.get(url,headers=headers,params=params)
|
||||
return r.json()
|
||||
@r.get("/alljscss")
|
||||
async def alljscs(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/customize.json"
|
||||
params = {"app":app}
|
||||
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_NAM}->{app}):",e)
|
||||
|
||||
@r.post("/createapp",)
|
||||
async def createapp(name:str):
|
||||
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
||||
data = {"name":name}
|
||||
url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app.json"
|
||||
r = httpx.post(url,headers=headers,data=json.dumps(data))
|
||||
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}
|
||||
async def createapp(request:Request,name:str,c:config.KINTONE_ENV=Depends(getkintoneenv)):
|
||||
try:
|
||||
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
||||
data = {"name":name}
|
||||
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app.json"
|
||||
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_NAM}->{name}):",e)
|
||||
|
||||
property=["label","code","type","required","defaultValue","options"]
|
||||
|
||||
@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:
|
||||
if file.filename.endswith('.xlsx'):
|
||||
try:
|
||||
@@ -315,87 +535,90 @@ async def createappfromexcel(files:t.List[UploadFile] = File(...)):
|
||||
appname = df.iloc[0,2]
|
||||
desc = df.iloc[2,2]
|
||||
result = {"app":0,"revision":0,"msg":""}
|
||||
fields = getfieldsfromexcel(df)
|
||||
users = getkintoneusers()
|
||||
orgs = getkintoneorgs()
|
||||
fields = getfieldsfromexcel(df,mapping)
|
||||
users = getkintoneusers(env)
|
||||
orgs = getkintoneorgs(env)
|
||||
processes = getprocessfromexcel(df,users["users"], orgs["organizationTitles"])
|
||||
app = createkintoneapp(appname)
|
||||
app = createkintoneapp(appname,env)
|
||||
if app.get("app") != None:
|
||||
result["app"] = app["app"]
|
||||
app = updateappsettingstokintone(result["app"],{"description":desc})
|
||||
app = updateappsettingstokintone(result["app"],{"description":desc},env)
|
||||
if app.get("revision") != None:
|
||||
result["revision"] = app["revision"]
|
||||
app = addfieldstokintone(result["app"],fields)
|
||||
if len(processes)> 0:
|
||||
app = updateprocesstokintone(result["app"],processes)
|
||||
app = addfieldstokintone(result["app"],fields,env)
|
||||
if len(processes["states"])> 0:
|
||||
app = updateprocesstokintone(result["app"],processes,env)
|
||||
if app.get("revision") != None:
|
||||
result["revision"] = app["revision"]
|
||||
deoployappfromkintone(result["app"],result["revision"])
|
||||
deoployappfromkintone(result["app"],result["revision"],env)
|
||||
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:
|
||||
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
|
||||
|
||||
|
||||
@r.post("/updateappfromexcel",)
|
||||
async def updateappfromexcel(app:str,files:t.List[UploadFile] = File(...)):
|
||||
@r.post("/updateappfromexcel")
|
||||
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:
|
||||
if file.filename.endswith('.xlsx'):
|
||||
try:
|
||||
content = await file.read()
|
||||
df = pd.read_excel(BytesIO(content))
|
||||
excel = getsettingfromexcel(df)
|
||||
kintone= getsettingfromkintone(app)
|
||||
kintone= getsettingfromkintone(app,env)
|
||||
settings = analysesettings(excel,kintone)
|
||||
excel = getfieldsfromexcel(df)
|
||||
kintone = getfieldsfromkintone(app)
|
||||
users = getkintoneusers()
|
||||
orgs = getkintoneorgs()
|
||||
excel = getfieldsfromexcel(df,mapping)
|
||||
kintone = getfieldsfromkintone(app,env)
|
||||
users = getkintoneusers(env)
|
||||
orgs = getkintoneorgs(env)
|
||||
exp = getprocessfromexcel(df,users["users"], orgs["organizationTitles"])
|
||||
#exp = getprocessfromexcel(df)
|
||||
kinp = getprocessfromkintone(app)
|
||||
kinp = getprocessfromkintone(app,env)
|
||||
process = analysprocess(exp,kinp)
|
||||
revision = kintone["revision"]
|
||||
fields = analysefields(excel,kintone["properties"])
|
||||
result = {"app":app,"revision":revision,"msg":"No Update"}
|
||||
deploy = False
|
||||
if len(fields["update"]) > 0:
|
||||
result = updatefieldstokintone(app,revision,fields["update"])
|
||||
result = updatefieldstokintone(app,revision,fields["update"],env)
|
||||
revision = result["revision"]
|
||||
deploy = True
|
||||
if len(fields["add"]) > 0:
|
||||
result = addfieldstokintone(app,fields["add"],revision)
|
||||
result = addfieldstokintone(app,fields["add"],env,revision)
|
||||
revision = result["revision"]
|
||||
deploy = True
|
||||
if len(fields["del"]) > 0:
|
||||
result = deletefieldsfromkintone(app,revision,fields["del"])
|
||||
result = deletefieldsfromkintone(app,revision,fields["del"],env)
|
||||
revision = result["revision"]
|
||||
deploy = True
|
||||
if len(settings) > 0:
|
||||
result = updateappsettingstokintone(app,settings)
|
||||
result = updateappsettingstokintone(app,settings,env)
|
||||
revision = result["revision"]
|
||||
deploy = True
|
||||
if len(process)>0:
|
||||
result = updateprocesstokintone(app,exp)
|
||||
result = updateprocesstokintone(app,exp,env)
|
||||
revision = result["revision"]
|
||||
deploy = True
|
||||
if deploy:
|
||||
result = deoployappfromkintone(app,revision)
|
||||
result = deoployappfromkintone(app,revision,env)
|
||||
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:
|
||||
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
|
||||
|
||||
@r.post("/updateprocessfromexcel",)
|
||||
async def updateprocessfromexcel(app:str):
|
||||
async def updateprocessfromexcel(request:Request,app:str,env = Depends(getkintoneenv)):
|
||||
|
||||
try:
|
||||
excel = getprocessfromexcel()
|
||||
kintone = getprocessfromkintone(app)
|
||||
kintone = getprocessfromkintone(app,env)
|
||||
revision = kintone["revision"]
|
||||
#fields = analysefields(excel,kintone["properties"])
|
||||
result = {"app":app,"revision":revision,"msg":"No Update"}
|
||||
@@ -416,14 +639,31 @@ async def updateprocessfromexcel(app:str):
|
||||
# result = updateappsettingstokintone(app,settings)
|
||||
# revision = result["revision"]
|
||||
# deploy = True
|
||||
result = updateprocesstokintone(app,excel)
|
||||
result = updateprocesstokintone(app,excel,env)
|
||||
revision = result["revision"]
|
||||
deploy = True
|
||||
if deploy:
|
||||
result = deoployappfromkintone(app,revision)
|
||||
result = deoployappfromkintone(app,revision,env)
|
||||
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_NAM}->{app}):",e)
|
||||
|
||||
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('Temp\\alc_runtime.js')
|
||||
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_NAM}->{app}):",e)
|
||||
|
||||
@@ -2,7 +2,10 @@ from fastapi import Request,Depends, APIRouter, UploadFile,HTTPException,File
|
||||
from app.db import Base,engine
|
||||
from app.db.session import get_db
|
||||
from app.db.crud import *
|
||||
from app.db.schemas import AppBase, AppEdit, App,Kintone
|
||||
from app.db.schemas import *
|
||||
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()
|
||||
|
||||
@@ -16,9 +19,11 @@ async def appsetting_details(
|
||||
id: int,
|
||||
db=Depends(get_db),
|
||||
):
|
||||
app = get_appsetting(db, id)
|
||||
return app
|
||||
|
||||
try:
|
||||
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)
|
||||
async def appsetting_create(
|
||||
@@ -26,7 +31,10 @@ async def appsetting_create(
|
||||
app: AppBase,
|
||||
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(
|
||||
@@ -38,7 +46,10 @@ async def appsetting_edit(
|
||||
app: AppEdit,
|
||||
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(
|
||||
@@ -49,8 +60,10 @@ async def appsettings_delete(
|
||||
id: int,
|
||||
db=Depends(get_db),
|
||||
):
|
||||
|
||||
return delete_appsetting(db, id)
|
||||
try:
|
||||
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(
|
||||
@@ -63,5 +76,270 @@ async def kintone_data(
|
||||
type: int,
|
||||
db=Depends(get_db),
|
||||
):
|
||||
kintone = get_kintones(db, type)
|
||||
return kintone
|
||||
try:
|
||||
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(
|
||||
"/actions",
|
||||
response_model=t.List[Action],
|
||||
response_model_exclude={"id"},
|
||||
response_model_exclude_none=True,
|
||||
)
|
||||
async def action_data(
|
||||
request: Request,
|
||||
db=Depends(get_db),
|
||||
):
|
||||
try:
|
||||
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(
|
||||
"/flow/{flowid}",
|
||||
response_model=Flow,
|
||||
response_model_exclude_none=True,
|
||||
)
|
||||
async def flow_details(
|
||||
request: Request,
|
||||
flowid: str,
|
||||
db=Depends(get_db),
|
||||
):
|
||||
try:
|
||||
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(
|
||||
"/flows/{appid}",
|
||||
response_model=List[Flow],
|
||||
response_model_exclude_none=True,
|
||||
)
|
||||
async def flow_list(
|
||||
request: Request,
|
||||
appid: str,
|
||||
user=Depends(get_current_user),
|
||||
db=Depends(get_db),
|
||||
):
|
||||
try:
|
||||
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)
|
||||
async def flow_create(
|
||||
request: Request,
|
||||
flow: FlowBase,
|
||||
user=Depends(get_current_user),
|
||||
db=Depends(get_db),
|
||||
):
|
||||
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(
|
||||
"/flow/{flowid}", response_model=Flow, response_model_exclude_none=True
|
||||
)
|
||||
async def flow_edit(
|
||||
request: Request,
|
||||
flow: FlowBase,
|
||||
db=Depends(get_db),
|
||||
):
|
||||
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(
|
||||
"/flow/{flowid}", response_model=Flow, response_model_exclude_none=True
|
||||
)
|
||||
async def flow_delete(
|
||||
request: Request,
|
||||
flowid: str,
|
||||
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)
|
||||
|
||||
@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 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
|
||||
|
||||
|
||||
@@ -19,14 +19,14 @@ async def get_current_user(
|
||||
payload = jwt.decode(
|
||||
token, security.SECRET_KEY, algorithms=[security.ALGORITHM]
|
||||
)
|
||||
email: str = payload.get("sub")
|
||||
if email is None:
|
||||
id: int = payload.get("sub")
|
||||
if id is None:
|
||||
raise credentials_exception
|
||||
permissions: str = payload.get("permissions")
|
||||
token_data = schemas.TokenData(email=email, permissions=permissions)
|
||||
token_data = schemas.TokenData(id = id, permissions=permissions)
|
||||
except PyJWTError:
|
||||
raise credentials_exception
|
||||
user = get_user_by_email(db, token_data.email)
|
||||
user = get_user(db, token_data.id)
|
||||
if user is None:
|
||||
raise credentials_exception
|
||||
return user
|
||||
@@ -58,7 +58,7 @@ def authenticate_user(db, email: str, password: str):
|
||||
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)
|
||||
if user:
|
||||
return False # User already exists
|
||||
@@ -67,6 +67,8 @@ def sign_up_new_user(db, email: str, password: str):
|
||||
schemas.UserCreate(
|
||||
email=email,
|
||||
password=password,
|
||||
first_name = firstname,
|
||||
last_name = lastname,
|
||||
is_active=True,
|
||||
is_superuser=False,
|
||||
),
|
||||
|
||||
@@ -1,18 +1,38 @@
|
||||
import os
|
||||
import base64
|
||||
|
||||
PROJECT_NAME = "KintoneAppBuilder"
|
||||
|
||||
SQLALCHEMY_DATABASE_URI = "mssql+pymssql://maxz64@maxzdb:m@xz1205@maxzdb.database.windows.net/alloc"
|
||||
|
||||
BASE_URL = "https://mfu07rkgnb7c.cybozu.com"
|
||||
#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"
|
||||
|
||||
API_V1_STR = "/k/v1"
|
||||
|
||||
API_V1_AUTH_KEY = "X-Cybozu-Authorization"
|
||||
|
||||
API_V1_AUTH_VALUE = "TVhaOm1heHoxMjA1"
|
||||
DEPLOY_MODE = "DEV" #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_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"))
|
||||
@@ -25,7 +25,7 @@ def create_access_token(*, data: dict, expires_delta: timedelta = None):
|
||||
if expires_delta:
|
||||
expire = datetime.utcnow() + expires_delta
|
||||
else:
|
||||
expire = datetime.utcnow() + timedelta(minutes=15)
|
||||
expire = datetime.utcnow() + timedelta(minutes=2880)
|
||||
to_encode.update({"exp": expire})
|
||||
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
|
||||
return encoded_jwt
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from fastapi import HTTPException, status
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import and_
|
||||
import typing as t
|
||||
|
||||
from . import models, schemas
|
||||
@@ -115,4 +116,182 @@ def get_kintones(db: Session, type: int):
|
||||
kintones = db.query(models.Kintone).filter(models.Kintone.type == type).all()
|
||||
if not kintones:
|
||||
raise HTTPException(status_code=404, detail="Data not found")
|
||||
return kintones
|
||||
return kintones
|
||||
|
||||
def get_actions(db: Session):
|
||||
actions = db.query(models.Action).all()
|
||||
if not actions:
|
||||
raise HTTPException(status_code=404, detail="Data not found")
|
||||
return actions
|
||||
|
||||
|
||||
def create_flow(db: Session, domainid: int, flow: schemas.FlowBase):
|
||||
db_flow = models.Flow(
|
||||
flowid=flow.flowid,
|
||||
appid=flow.appid,
|
||||
eventid=flow.eventid,
|
||||
domainid=domainid,
|
||||
name=flow.name,
|
||||
content=flow.content
|
||||
)
|
||||
db.add(db_flow)
|
||||
db.commit()
|
||||
db.refresh(db_flow)
|
||||
return db_flow
|
||||
|
||||
def delete_flow(db: Session, flowid: str):
|
||||
flow = get_flow(db, flowid)
|
||||
if not flow:
|
||||
raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Flow not found")
|
||||
db.delete(flow)
|
||||
db.commit()
|
||||
return flow
|
||||
|
||||
|
||||
def edit_flow(
|
||||
db: Session, flow: schemas.FlowBase
|
||||
) -> schemas.Flow:
|
||||
db_flow = get_flow(db, flow.flowid)
|
||||
if not db_flow:
|
||||
raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Flow not found")
|
||||
update_data = flow.dict(exclude_unset=True)
|
||||
|
||||
for key, value in update_data.items():
|
||||
setattr(db_flow, key, value)
|
||||
|
||||
db.add(db_flow)
|
||||
db.commit()
|
||||
db.refresh(db_flow)
|
||||
return db_flow
|
||||
|
||||
|
||||
def get_flows(db: Session, flowid: str):
|
||||
flows = db.query(models.Flow).all()
|
||||
if not flows:
|
||||
raise HTTPException(status_code=404, detail="Data not found")
|
||||
return flows
|
||||
|
||||
def get_flow(db: Session, flowid: str):
|
||||
flow = db.query(models.Flow).filter(models.Flow.flowid == flowid).first()
|
||||
if not flow:
|
||||
raise HTTPException(status_code=404, detail="Data not found")
|
||||
return flow
|
||||
|
||||
def get_flows_by_app(db: Session, domainid: int, appid: str):
|
||||
flows = db.query(models.Flow).filter(and_(models.Flow.domainid == domainid,models.Flow.appid == appid)).all()
|
||||
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")
|
||||
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()
|
||||
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,12 +1,16 @@
|
||||
from sqlalchemy import Boolean, Column, Integer, String
|
||||
|
||||
from .session import Base
|
||||
from sqlalchemy import Boolean, Column, Integer, String, DateTime,ForeignKey
|
||||
from sqlalchemy.ext.declarative import as_declarative
|
||||
from datetime import datetime
|
||||
|
||||
@as_declarative()
|
||||
class Base:
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
create_time = Column(DateTime, default=datetime.now)
|
||||
update_time = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = "user"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
email = Column(String(50), unique=True, index=True, nullable=False)
|
||||
first_name = Column(String(100))
|
||||
last_name = Column(String(100))
|
||||
@@ -17,15 +21,92 @@ class User(Base):
|
||||
class AppSetting(Base):
|
||||
__tablename__ = "appsetting"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
appid = Column(String(100), index=True, nullable=False)
|
||||
setting = Column(String(1000))
|
||||
|
||||
class Kintone(Base):
|
||||
__tablename__ = "kintone"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
type = Column(Integer, index=True, nullable=False)
|
||||
name = Column(String(100), nullable=False)
|
||||
desc = Column(String)
|
||||
content = Column(String)
|
||||
content = Column(String)
|
||||
|
||||
class Action(Base):
|
||||
__tablename__ = "action"
|
||||
|
||||
name = Column(String(100), index=True, nullable=False)
|
||||
title = Column(String(200))
|
||||
subtitle = Column(String(500))
|
||||
outputpoints = Column(String)
|
||||
property = Column(String)
|
||||
|
||||
class Flow(Base):
|
||||
__tablename__ = "flow"
|
||||
|
||||
flowid = Column(String(100), index=True, nullable=False)
|
||||
appid = 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))
|
||||
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)
|
||||
|
||||
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))
|
||||
@@ -1,7 +1,12 @@
|
||||
from pydantic import BaseModel
|
||||
from datetime import datetime
|
||||
import typing as t
|
||||
|
||||
|
||||
class Base(BaseModel):
|
||||
create_time: datetime
|
||||
update_time: datetime
|
||||
|
||||
class UserBase(BaseModel):
|
||||
email: str
|
||||
is_active: bool = True
|
||||
@@ -15,7 +20,12 @@ class UserOut(UserBase):
|
||||
|
||||
|
||||
class UserCreate(UserBase):
|
||||
email:str
|
||||
password: str
|
||||
first_name: str
|
||||
last_name: str
|
||||
is_active:bool
|
||||
is_superuser:bool
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
@@ -41,6 +51,7 @@ class Token(BaseModel):
|
||||
|
||||
|
||||
class TokenData(BaseModel):
|
||||
id:int = 0
|
||||
email: str = None
|
||||
permissions: str = "user"
|
||||
|
||||
@@ -68,4 +79,69 @@ class Kintone(BaseModel):
|
||||
content: str = None
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
orm_mode = True
|
||||
|
||||
class Action(BaseModel):
|
||||
id: int
|
||||
name: str = None
|
||||
title: str = None
|
||||
subtitle: str = None
|
||||
outputpoints: str = None
|
||||
property: str = None
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
class FlowBase(BaseModel):
|
||||
flowid: str
|
||||
appid: str
|
||||
eventid: str
|
||||
name: str = None
|
||||
content: str = None
|
||||
|
||||
class Flow(Base):
|
||||
id: int
|
||||
flowid: str
|
||||
appid: str
|
||||
eventid: str
|
||||
domainid: int
|
||||
name: str = None
|
||||
content: str = None
|
||||
|
||||
class Config:
|
||||
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
|
||||
|
||||
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 starlette.requests import Request
|
||||
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 import tasks
|
||||
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)
|
||||
|
||||
@@ -19,9 +25,7 @@ app = FastAPI(
|
||||
)
|
||||
|
||||
origins = [
|
||||
"http://localhost:9000",
|
||||
"http://localhost",
|
||||
"http://localhost:8080",
|
||||
"*"
|
||||
]
|
||||
|
||||
app.add_middleware(
|
||||
@@ -39,6 +43,25 @@ app.add_middleware(
|
||||
# request.state.db.close()
|
||||
# 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")
|
||||
async def root():
|
||||
|
||||
@@ -20,4 +20,5 @@ pyjwt==1.7.1
|
||||
pandas==2.0.3
|
||||
openpyxl==3.1.2
|
||||
deepdiff==6.3.1
|
||||
pymssql==2.2.7
|
||||
pymssql==2.2.7
|
||||
psycopg2==2.9.8
|
||||
845
document/ALCKintone_20231012.drawio
Normal file
845
document/ALCKintone_20231012.drawio
Normal file
@@ -0,0 +1,845 @@
|
||||
<mxfile host="65bd71144e" pages="3">
|
||||
<diagram name="Page-1" id="efa7a0a1-bf9b-a30e-e6df-94a7791c09e9">
|
||||
<mxGraphModel dx="1073" dy="518" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="826" pageHeight="1169" background="none" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
<mxCell id="ZIlfFuTIaODnUzWRKW0w-114" value="<p style="margin: 0px; margin-top: 4px; text-align: center; text-decoration: underline;"><strong>User</strong></p><p style="margin: 0px; margin-left: 8px;"><br></p><p style="margin: 0px; margin-left: 8px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;strokeColor=#003366;shadow=1;fillColor=#D4E1F5;fontColor=#003366" parent="1" vertex="1">
|
||||
<mxGeometry x="40" y="21.64" width="160" height="78.36" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="ZIlfFuTIaODnUzWRKW0w-116" value="" style="endArrow=open;endSize=12;startArrow=diamondThin;startSize=14;startFill=0;edgeStyle=orthogonalEdgeStyle;entryX=1;entryY=0.5;entryDx=0;entryDy=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" parent="1" target="ZIlfFuTIaODnUzWRKW0w-114" edge="1">
|
||||
<mxGeometry x="389.35999999999996" y="350" as="geometry">
|
||||
<mxPoint x="350" y="60.820000000000164" as="sourcePoint"/>
|
||||
<mxPoint x="671" y="532" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="ZIlfFuTIaODnUzWRKW0w-117" value="0..n" style="resizable=0;align=left;verticalAlign=top;labelBackgroundColor=#ffffff;fontSize=10;strokeColor=#003366;shadow=1;fillColor=#D4E1F5;fontColor=#003366" parent="ZIlfFuTIaODnUzWRKW0w-116" connectable="0" vertex="1">
|
||||
<mxGeometry x="-1" relative="1" as="geometry">
|
||||
<mxPoint x="-30" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="ZIlfFuTIaODnUzWRKW0w-118" value="1" style="resizable=0;align=right;verticalAlign=top;labelBackgroundColor=#ffffff;fontSize=10;strokeColor=#003366;shadow=1;fillColor=#D4E1F5;fontColor=#003366" parent="ZIlfFuTIaODnUzWRKW0w-116" connectable="0" vertex="1">
|
||||
<mxGeometry x="1" relative="1" as="geometry">
|
||||
<mxPoint x="18.919999999999582" y="-21.960000000000644" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="ZIlfFuTIaODnUzWRKW0w-119" value="<p style="margin: 0px; margin-top: 4px; text-align: center; text-decoration: underline;"><strong>UserApp</strong></p><hr><p style="margin: 0px; margin-left: 8px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;strokeColor=#003366;shadow=1;fillColor=#D4E1F5;fontColor=#003366" parent="1" vertex="1">
|
||||
<mxGeometry x="350" y="250" width="160" height="78.36" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="ZIlfFuTIaODnUzWRKW0w-120" value="" style="endArrow=open;endSize=12;startArrow=diamondThin;startSize=14;startFill=0;edgeStyle=orthogonalEdgeStyle;entryX=0.5;entryY=1;entryDx=0;entryDy=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;" parent="1" source="ZIlfFuTIaODnUzWRKW0w-119" edge="1">
|
||||
<mxGeometry x="399.35999999999996" y="360" as="geometry">
|
||||
<mxPoint x="360" y="71" as="sourcePoint"/>
|
||||
<mxPoint x="430" y="100.00000000000023" as="targetPoint"/>
|
||||
<Array as="points">
|
||||
<mxPoint x="430" y="140"/>
|
||||
<mxPoint x="430" y="140"/>
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="ZIlfFuTIaODnUzWRKW0w-121" value="0..n" style="resizable=0;align=left;verticalAlign=top;labelBackgroundColor=#ffffff;fontSize=10;strokeColor=#003366;shadow=1;fillColor=#D4E1F5;fontColor=#003366" parent="ZIlfFuTIaODnUzWRKW0w-120" connectable="0" vertex="1">
|
||||
<mxGeometry x="-1" relative="1" as="geometry">
|
||||
<mxPoint x="9" y="-20" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="ZIlfFuTIaODnUzWRKW0w-122" value="1" style="resizable=0;align=right;verticalAlign=top;labelBackgroundColor=#ffffff;fontSize=10;strokeColor=#003366;shadow=1;fillColor=#D4E1F5;fontColor=#003366" parent="ZIlfFuTIaODnUzWRKW0w-120" connectable="0" vertex="1">
|
||||
<mxGeometry x="1" relative="1" as="geometry">
|
||||
<mxPoint x="18.919999999999582" y="-21.960000000000644" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="ZIlfFuTIaODnUzWRKW0w-123" value="<p style="margin: 0px; margin-top: 4px; text-align: center; text-decoration: underline;"><strong>UserDomain</strong></p><hr><p style="margin: 0px; margin-left: 8px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;strokeColor=#003366;shadow=1;fillColor=#D4E1F5;fontColor=#003366" parent="1" vertex="1">
|
||||
<mxGeometry x="350" y="21.64" width="160" height="78.36" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="ZIlfFuTIaODnUzWRKW0w-124" value="<p style="margin: 0px; margin-top: 4px; text-align: center; text-decoration: underline;"><b>Action</b></p><hr><p style="margin: 0px; margin-left: 8px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;strokeColor=#003366;shadow=1;fillColor=#D4E1F5;fontColor=#003366" parent="1" vertex="1">
|
||||
<mxGeometry x="30" y="440" width="160" height="78.36" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="ZIlfFuTIaODnUzWRKW0w-125" value="<p style="margin: 0px; margin-top: 4px; text-align: center; text-decoration: underline;"><strong>AppAction</strong></p><hr><p style="margin: 0px; margin-left: 8px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;strokeColor=#003366;shadow=1;fillColor=#D4E1F5;fontColor=#003366" parent="1" vertex="1">
|
||||
<mxGeometry x="350" y="440" width="160" height="78.36" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="ZIlfFuTIaODnUzWRKW0w-130" value="" style="endArrow=open;endSize=12;startArrow=diamondThin;startSize=14;startFill=0;edgeStyle=orthogonalEdgeStyle;entryX=1;entryY=0.5;entryDx=0;entryDy=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="ZIlfFuTIaODnUzWRKW0w-125" target="ZIlfFuTIaODnUzWRKW0w-124" edge="1">
|
||||
<mxGeometry x="209.35999999999999" y="733" as="geometry">
|
||||
<mxPoint x="240.59" y="584.64" as="sourcePoint"/>
|
||||
<mxPoint x="240.00000000000003" y="473.0000000000002" as="targetPoint"/>
|
||||
<Array as="points">
|
||||
<mxPoint x="241" y="479"/>
|
||||
<mxPoint x="200" y="480"/>
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="ZIlfFuTIaODnUzWRKW0w-131" value="0..n" style="resizable=0;align=left;verticalAlign=top;labelBackgroundColor=#ffffff;fontSize=10;strokeColor=#003366;shadow=1;fillColor=#D4E1F5;fontColor=#003366" parent="ZIlfFuTIaODnUzWRKW0w-130" connectable="0" vertex="1">
|
||||
<mxGeometry x="-1" relative="1" as="geometry">
|
||||
<mxPoint x="-30" y="-29" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="ZIlfFuTIaODnUzWRKW0w-132" value="1" style="resizable=0;align=right;verticalAlign=top;labelBackgroundColor=#ffffff;fontSize=10;strokeColor=#003366;shadow=1;fillColor=#D4E1F5;fontColor=#003366" parent="ZIlfFuTIaODnUzWRKW0w-130" connectable="0" vertex="1">
|
||||
<mxGeometry x="1" relative="1" as="geometry">
|
||||
<mxPoint x="18.919999999999582" y="-21.960000000000644" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="ZIlfFuTIaODnUzWRKW0w-133" value="<p style="margin: 0px; margin-top: 4px; text-align: center; text-decoration: underline;"><b>Flow</b></p><hr><p style="margin: 0px; margin-left: 8px;"><br></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;strokeColor=#003366;shadow=1;fillColor=#D4E1F5;fontColor=#003366" parent="1" vertex="1">
|
||||
<mxGeometry x="630" y="250" width="160" height="78.36" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="ZIlfFuTIaODnUzWRKW0w-134" value="" style="endArrow=open;endSize=12;startArrow=diamondThin;startSize=14;startFill=0;edgeStyle=orthogonalEdgeStyle;entryX=1;entryY=0.5;entryDx=0;entryDy=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="ZIlfFuTIaODnUzWRKW0w-133" target="ZIlfFuTIaODnUzWRKW0w-119" edge="1">
|
||||
<mxGeometry x="408.77" y="598.36" as="geometry">
|
||||
<mxPoint x="440" y="450" as="sourcePoint"/>
|
||||
<mxPoint x="439.41" y="338.36000000000024" as="targetPoint"/>
|
||||
<Array as="points">
|
||||
<mxPoint x="570" y="290"/>
|
||||
<mxPoint x="570" y="290"/>
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="ZIlfFuTIaODnUzWRKW0w-135" value="0..n" style="resizable=0;align=left;verticalAlign=top;labelBackgroundColor=#ffffff;fontSize=10;strokeColor=#003366;shadow=1;fillColor=#D4E1F5;fontColor=#003366" parent="ZIlfFuTIaODnUzWRKW0w-134" connectable="0" vertex="1">
|
||||
<mxGeometry x="-1" relative="1" as="geometry">
|
||||
<mxPoint x="-30" y="-20" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="ZIlfFuTIaODnUzWRKW0w-136" value="1" style="resizable=0;align=right;verticalAlign=top;labelBackgroundColor=#ffffff;fontSize=10;strokeColor=#003366;shadow=1;fillColor=#D4E1F5;fontColor=#003366" parent="ZIlfFuTIaODnUzWRKW0w-134" connectable="0" vertex="1">
|
||||
<mxGeometry x="1" relative="1" as="geometry">
|
||||
<mxPoint x="18.919999999999582" y="-21.960000000000644" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="ZIlfFuTIaODnUzWRKW0w-140" value="1" style="resizable=0;align=right;verticalAlign=top;labelBackgroundColor=#ffffff;fontSize=10;strokeColor=#003366;shadow=1;fillColor=#D4E1F5;fontColor=#003366" parent="1" connectable="0" vertex="1">
|
||||
<mxGeometry x="420.00000020761206" y="99.99999999998707" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="Z9b4y0bF-qkiY6ReSsG3-1" value="<p style="margin: 0px; margin-top: 4px; text-align: center; text-decoration: underline;"><b>Tenant</b></p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;strokeColor=#003366;shadow=1;fillColor=#D4E1F5;fontColor=#003366" parent="1" vertex="1">
|
||||
<mxGeometry x="40" y="250" width="160" height="78.36" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="Z9b4y0bF-qkiY6ReSsG3-2" value="" style="endArrow=open;endSize=12;startArrow=diamondThin;startSize=14;startFill=0;edgeStyle=orthogonalEdgeStyle;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" parent="1" source="ZIlfFuTIaODnUzWRKW0w-114" target="Z9b4y0bF-qkiY6ReSsG3-1" edge="1">
|
||||
<mxGeometry x="209.35999999999999" y="733" as="geometry">
|
||||
<mxPoint x="230" y="220" as="sourcePoint"/>
|
||||
<mxPoint x="70" y="220" as="targetPoint"/>
|
||||
<Array as="points">
|
||||
<mxPoint x="120" y="220"/>
|
||||
<mxPoint x="121" y="220"/>
|
||||
<mxPoint x="110" y="221"/>
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="Z9b4y0bF-qkiY6ReSsG3-3" value="0..n" style="resizable=0;align=left;verticalAlign=top;labelBackgroundColor=#ffffff;fontSize=10;strokeColor=#003366;shadow=1;fillColor=#D4E1F5;fontColor=#003366" parent="Z9b4y0bF-qkiY6ReSsG3-2" connectable="0" vertex="1">
|
||||
<mxGeometry x="-1" relative="1" as="geometry">
|
||||
<mxPoint x="450" y="-100" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="Z9b4y0bF-qkiY6ReSsG3-4" value="1" style="resizable=0;align=right;verticalAlign=top;labelBackgroundColor=#ffffff;fontSize=10;strokeColor=#003366;shadow=1;fillColor=#D4E1F5;fontColor=#003366" parent="Z9b4y0bF-qkiY6ReSsG3-2" connectable="0" vertex="1">
|
||||
<mxGeometry x="1" relative="1" as="geometry">
|
||||
<mxPoint x="18.919999999999582" y="-21.960000000000644" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="lCZzTbn_7m8qK95pbvvS" name="ER図">
|
||||
<mxGraphModel dx="1900" dy="518" 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="inIyfaXWTM6ArMeTnGn6-1" value="User" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1">
|
||||
<mxGeometry x="420" y="20" width="180" height="180" as="geometry">
|
||||
<mxRectangle x="310" y="60" width="110" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="inIyfaXWTM6ArMeTnGn6-2" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="inIyfaXWTM6ArMeTnGn6-1" vertex="1">
|
||||
<mxGeometry y="30" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="inIyfaXWTM6ArMeTnGn6-3" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="inIyfaXWTM6ArMeTnGn6-2" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="inIyfaXWTM6ArMeTnGn6-4" value="id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="inIyfaXWTM6ArMeTnGn6-2" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="inIyfaXWTM6ArMeTnGn6-5" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="inIyfaXWTM6ArMeTnGn6-1" vertex="1">
|
||||
<mxGeometry y="60" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="inIyfaXWTM6ArMeTnGn6-6" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="inIyfaXWTM6ArMeTnGn6-5" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="inIyfaXWTM6ArMeTnGn6-7" value="<b style="border-color: var(--border-color); text-align: center; color: rgb(0, 51, 102);">Tenant_id</b>" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="inIyfaXWTM6ArMeTnGn6-5" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="inIyfaXWTM6ArMeTnGn6-8" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="inIyfaXWTM6ArMeTnGn6-1" vertex="1">
|
||||
<mxGeometry y="90" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="inIyfaXWTM6ArMeTnGn6-9" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="inIyfaXWTM6ArMeTnGn6-8" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="inIyfaXWTM6ArMeTnGn6-10" value="ユーザー名" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="inIyfaXWTM6ArMeTnGn6-8" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="inIyfaXWTM6ArMeTnGn6-11" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="inIyfaXWTM6ArMeTnGn6-1" vertex="1">
|
||||
<mxGeometry y="120" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="inIyfaXWTM6ArMeTnGn6-12" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="inIyfaXWTM6ArMeTnGn6-11" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="inIyfaXWTM6ArMeTnGn6-13" value="パスワード(暗号化)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="inIyfaXWTM6ArMeTnGn6-11" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-1" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="inIyfaXWTM6ArMeTnGn6-1" vertex="1">
|
||||
<mxGeometry y="150" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-2" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" parent="NCbWPNvujZOKFJAbQVH6-1" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-3" value="その他情報" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" parent="NCbWPNvujZOKFJAbQVH6-1" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="inIyfaXWTM6ArMeTnGn6-14" value="Domain" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1">
|
||||
<mxGeometry x="420" y="240" width="180" height="180" as="geometry">
|
||||
<mxRectangle x="590" y="60" width="100" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="inIyfaXWTM6ArMeTnGn6-15" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="inIyfaXWTM6ArMeTnGn6-14" vertex="1">
|
||||
<mxGeometry y="30" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="inIyfaXWTM6ArMeTnGn6-16" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="inIyfaXWTM6ArMeTnGn6-15" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="inIyfaXWTM6ArMeTnGn6-17" value="id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="inIyfaXWTM6ArMeTnGn6-15" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="inIyfaXWTM6ArMeTnGn6-24" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="inIyfaXWTM6ArMeTnGn6-14" vertex="1">
|
||||
<mxGeometry y="60" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="inIyfaXWTM6ArMeTnGn6-25" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="inIyfaXWTM6ArMeTnGn6-24" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="inIyfaXWTM6ArMeTnGn6-26" value="domain_url" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="inIyfaXWTM6ArMeTnGn6-24" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-31" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="inIyfaXWTM6ArMeTnGn6-14" vertex="1">
|
||||
<mxGeometry y="90" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-32" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" parent="GH2g80-cBXHe62XdPV4N-31" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-33" value="kintoneユーザーID" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" parent="GH2g80-cBXHe62XdPV4N-31" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-34" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="inIyfaXWTM6ArMeTnGn6-14" vertex="1">
|
||||
<mxGeometry y="120" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-35" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" parent="GH2g80-cBXHe62XdPV4N-34" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-36" value="kintoneパスワード" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" parent="GH2g80-cBXHe62XdPV4N-34" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-4" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="inIyfaXWTM6ArMeTnGn6-14" vertex="1">
|
||||
<mxGeometry y="150" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-5" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" parent="NCbWPNvujZOKFJAbQVH6-4" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-6" value="API_Key" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" parent="NCbWPNvujZOKFJAbQVH6-4" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="QUGX19b9cPh8sdE7zjoR-1" value="<b style="border-color: var(--border-color); color: rgb(0, 51, 102);">Tenant</b>" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1">
|
||||
<mxGeometry x="130" y="20" width="180" height="180" as="geometry">
|
||||
<mxRectangle x="40" y="60" width="100" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="QUGX19b9cPh8sdE7zjoR-2" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="QUGX19b9cPh8sdE7zjoR-1" vertex="1">
|
||||
<mxGeometry y="30" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="QUGX19b9cPh8sdE7zjoR-3" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="QUGX19b9cPh8sdE7zjoR-2" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="QUGX19b9cPh8sdE7zjoR-4" value="id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="QUGX19b9cPh8sdE7zjoR-2" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="QUGX19b9cPh8sdE7zjoR-5" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="QUGX19b9cPh8sdE7zjoR-1" vertex="1">
|
||||
<mxGeometry y="60" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="QUGX19b9cPh8sdE7zjoR-6" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="QUGX19b9cPh8sdE7zjoR-5" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="QUGX19b9cPh8sdE7zjoR-7" value="名前" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="QUGX19b9cPh8sdE7zjoR-5" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="QUGX19b9cPh8sdE7zjoR-8" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="QUGX19b9cPh8sdE7zjoR-1" vertex="1">
|
||||
<mxGeometry y="90" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="QUGX19b9cPh8sdE7zjoR-9" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="QUGX19b9cPh8sdE7zjoR-8" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="QUGX19b9cPh8sdE7zjoR-10" value="ライセンスキー" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="QUGX19b9cPh8sdE7zjoR-8" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="QUGX19b9cPh8sdE7zjoR-11" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="QUGX19b9cPh8sdE7zjoR-1" vertex="1">
|
||||
<mxGeometry y="120" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="QUGX19b9cPh8sdE7zjoR-12" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="QUGX19b9cPh8sdE7zjoR-11" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="QUGX19b9cPh8sdE7zjoR-13" value="利用期限" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="QUGX19b9cPh8sdE7zjoR-11" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="xY3sbCmQmCiIU-0kb39k-5" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="QUGX19b9cPh8sdE7zjoR-1" vertex="1">
|
||||
<mxGeometry y="150" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="xY3sbCmQmCiIU-0kb39k-6" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" parent="xY3sbCmQmCiIU-0kb39k-5" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="xY3sbCmQmCiIU-0kb39k-7" value="その他情報" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" parent="xY3sbCmQmCiIU-0kb39k-5" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="8Zu1yShcSHxMs68hy39H-1" value="Flow" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
|
||||
<mxGeometry x="420" y="480" width="180" height="210" as="geometry">
|
||||
<mxRectangle x="320" y="370" width="60" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="8Zu1yShcSHxMs68hy39H-2" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="8Zu1yShcSHxMs68hy39H-1" vertex="1">
|
||||
<mxGeometry y="30" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="8Zu1yShcSHxMs68hy39H-3" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8Zu1yShcSHxMs68hy39H-2" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="8Zu1yShcSHxMs68hy39H-4" value="id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8Zu1yShcSHxMs68hy39H-2" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-56" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8Zu1yShcSHxMs68hy39H-1" vertex="1">
|
||||
<mxGeometry y="60" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-57" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=0;overflow=hidden;whiteSpace=wrap;html=1;" parent="NCbWPNvujZOKFJAbQVH6-56" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-58" value="domain_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=0;overflow=hidden;whiteSpace=wrap;html=1;" parent="NCbWPNvujZOKFJAbQVH6-56" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="8Zu1yShcSHxMs68hy39H-5" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8Zu1yShcSHxMs68hy39H-1" vertex="1">
|
||||
<mxGeometry y="90" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="8Zu1yShcSHxMs68hy39H-6" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8Zu1yShcSHxMs68hy39H-5" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="8Zu1yShcSHxMs68hy39H-7" value="app_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8Zu1yShcSHxMs68hy39H-5" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="8Zu1yShcSHxMs68hy39H-8" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8Zu1yShcSHxMs68hy39H-1" vertex="1">
|
||||
<mxGeometry y="120" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="8Zu1yShcSHxMs68hy39H-9" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8Zu1yShcSHxMs68hy39H-8" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="8Zu1yShcSHxMs68hy39H-10" value="spaceid" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8Zu1yShcSHxMs68hy39H-8" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="XZEu5LJmFrV2HCpzu9aW-12" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8Zu1yShcSHxMs68hy39H-1" vertex="1">
|
||||
<mxGeometry y="150" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="XZEu5LJmFrV2HCpzu9aW-13" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" parent="XZEu5LJmFrV2HCpzu9aW-12" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="XZEu5LJmFrV2HCpzu9aW-14" value="content(json)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" parent="XZEu5LJmFrV2HCpzu9aW-12" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-14" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8Zu1yShcSHxMs68hy39H-1" vertex="1">
|
||||
<mxGeometry y="180" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-15" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" parent="GH2g80-cBXHe62XdPV4N-14" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-16" value="event_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" parent="GH2g80-cBXHe62XdPV4N-14" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-1" value="Event" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1">
|
||||
<mxGeometry x="130" y="480" width="180" height="150" as="geometry">
|
||||
<mxRectangle x="40" y="390" width="70" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-2" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="GH2g80-cBXHe62XdPV4N-1" vertex="1">
|
||||
<mxGeometry y="30" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-3" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="GH2g80-cBXHe62XdPV4N-2" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-4" value="id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="GH2g80-cBXHe62XdPV4N-2" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-5" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="GH2g80-cBXHe62XdPV4N-1" vertex="1">
|
||||
<mxGeometry y="60" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-6" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="GH2g80-cBXHe62XdPV4N-5" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-7" value="画面名" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="GH2g80-cBXHe62XdPV4N-5" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-8" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="GH2g80-cBXHe62XdPV4N-1" vertex="1">
|
||||
<mxGeometry y="90" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-9" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="GH2g80-cBXHe62XdPV4N-8" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-10" value="イベント名" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="GH2g80-cBXHe62XdPV4N-8" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-11" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="GH2g80-cBXHe62XdPV4N-1" vertex="1">
|
||||
<mxGeometry y="120" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-12" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="GH2g80-cBXHe62XdPV4N-11" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-13" value="モバイル使用可能か" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="GH2g80-cBXHe62XdPV4N-11" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-17" value="" style="edgeStyle=entityRelationEdgeStyle;fontSize=12;html=1;endArrow=ERoneToMany;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;curved=1;" parent="1" source="GH2g80-cBXHe62XdPV4N-2" target="GH2g80-cBXHe62XdPV4N-14" edge="1">
|
||||
<mxGeometry width="100" height="100" relative="1" as="geometry">
|
||||
<mxPoint x="630" y="845" as="sourcePoint"/>
|
||||
<mxPoint x="530" y="1085" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-18" value="App" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
|
||||
<mxGeometry x="710" y="280" width="180" height="150" as="geometry">
|
||||
<mxRectangle x="600" y="370" width="60" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-34" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="GH2g80-cBXHe62XdPV4N-18" vertex="1">
|
||||
<mxGeometry y="30" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-35" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="NCbWPNvujZOKFJAbQVH6-34" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-36" value="id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="NCbWPNvujZOKFJAbQVH6-34" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-51" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="GH2g80-cBXHe62XdPV4N-18" vertex="1">
|
||||
<mxGeometry y="60" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-52" value="UK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="NCbWPNvujZOKFJAbQVH6-51" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-53" value="domain_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="NCbWPNvujZOKFJAbQVH6-51" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-25" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="GH2g80-cBXHe62XdPV4N-18" vertex="1">
|
||||
<mxGeometry y="90" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-26" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="GH2g80-cBXHe62XdPV4N-25" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-27" value="app_name" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="GH2g80-cBXHe62XdPV4N-25" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-28" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="GH2g80-cBXHe62XdPV4N-18" vertex="1">
|
||||
<mxGeometry y="120" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-29" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="GH2g80-cBXHe62XdPV4N-28" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="GH2g80-cBXHe62XdPV4N-30" value="update_date" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="GH2g80-cBXHe62XdPV4N-28" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-1" value="Flow_History" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
|
||||
<mxGeometry x="710" y="480" width="180" height="240" as="geometry">
|
||||
<mxRectangle x="320" y="670" width="110" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-23" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="AJLbZMHdl7kzV18ppMoM-1" vertex="1">
|
||||
<mxGeometry y="30" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-24" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="AJLbZMHdl7kzV18ppMoM-23" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-25" value="id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="AJLbZMHdl7kzV18ppMoM-23" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-2" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="AJLbZMHdl7kzV18ppMoM-1" vertex="1">
|
||||
<mxGeometry y="60" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-3" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="AJLbZMHdl7kzV18ppMoM-2" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-4" value="flow_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="AJLbZMHdl7kzV18ppMoM-2" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-5" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="AJLbZMHdl7kzV18ppMoM-1" vertex="1">
|
||||
<mxGeometry y="90" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-6" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="AJLbZMHdl7kzV18ppMoM-5" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-7" value="domain_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="AJLbZMHdl7kzV18ppMoM-5" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-8" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="AJLbZMHdl7kzV18ppMoM-1" vertex="1">
|
||||
<mxGeometry y="120" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-9" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="AJLbZMHdl7kzV18ppMoM-8" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-10" value="spaceid" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="AJLbZMHdl7kzV18ppMoM-8" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-11" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="AJLbZMHdl7kzV18ppMoM-1" vertex="1">
|
||||
<mxGeometry y="150" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-12" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="AJLbZMHdl7kzV18ppMoM-11" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-13" value="appid" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="AJLbZMHdl7kzV18ppMoM-11" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-17" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="AJLbZMHdl7kzV18ppMoM-1" vertex="1">
|
||||
<mxGeometry y="180" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-18" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" parent="AJLbZMHdl7kzV18ppMoM-17" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-19" value="event_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" parent="AJLbZMHdl7kzV18ppMoM-17" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-14" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="AJLbZMHdl7kzV18ppMoM-1" vertex="1">
|
||||
<mxGeometry y="210" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-15" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" parent="AJLbZMHdl7kzV18ppMoM-14" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-16" value="content" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" parent="AJLbZMHdl7kzV18ppMoM-14" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-40" value="Action" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1">
|
||||
<mxGeometry x="130" y="720" width="180" height="150" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-41" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="AJLbZMHdl7kzV18ppMoM-40" vertex="1">
|
||||
<mxGeometry y="30" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-42" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="AJLbZMHdl7kzV18ppMoM-41" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-43" value="id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="AJLbZMHdl7kzV18ppMoM-41" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-44" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="AJLbZMHdl7kzV18ppMoM-40" vertex="1">
|
||||
<mxGeometry y="60" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-45" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="AJLbZMHdl7kzV18ppMoM-44" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-46" value="アクション名" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="AJLbZMHdl7kzV18ppMoM-44" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-47" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="AJLbZMHdl7kzV18ppMoM-40" vertex="1">
|
||||
<mxGeometry y="90" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-48" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="AJLbZMHdl7kzV18ppMoM-47" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-49" value="説明" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="AJLbZMHdl7kzV18ppMoM-47" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-50" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="AJLbZMHdl7kzV18ppMoM-40" vertex="1">
|
||||
<mxGeometry y="120" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-51" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="AJLbZMHdl7kzV18ppMoM-50" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="AJLbZMHdl7kzV18ppMoM-52" value="属性定義(json)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="AJLbZMHdl7kzV18ppMoM-50" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-7" value="UserDomain" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1">
|
||||
<mxGeometry x="710" y="100" width="180" height="120" as="geometry">
|
||||
<mxRectangle x="590" y="60" width="100" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-8" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="NCbWPNvujZOKFJAbQVH6-7" vertex="1">
|
||||
<mxGeometry y="30" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-9" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="NCbWPNvujZOKFJAbQVH6-8" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-10" value="id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="NCbWPNvujZOKFJAbQVH6-8" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-11" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="NCbWPNvujZOKFJAbQVH6-7" vertex="1">
|
||||
<mxGeometry y="60" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-12" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="NCbWPNvujZOKFJAbQVH6-11" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-13" value="user_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="NCbWPNvujZOKFJAbQVH6-11" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-44" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="NCbWPNvujZOKFJAbQVH6-7" vertex="1">
|
||||
<mxGeometry y="90" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-45" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=0;overflow=hidden;whiteSpace=wrap;html=1;" parent="NCbWPNvujZOKFJAbQVH6-44" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-46" value="domain_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=0;overflow=hidden;whiteSpace=wrap;html=1;" parent="NCbWPNvujZOKFJAbQVH6-44" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-42" value="" style="edgeStyle=entityRelationEdgeStyle;fontSize=12;html=1;endArrow=ERzeroToMany;endFill=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;curved=1;" parent="1" source="QUGX19b9cPh8sdE7zjoR-2" target="inIyfaXWTM6ArMeTnGn6-2" edge="1">
|
||||
<mxGeometry width="100" height="100" relative="1" as="geometry">
|
||||
<mxPoint x="160" y="350" as="sourcePoint"/>
|
||||
<mxPoint x="260" y="250" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-47" value="" style="edgeStyle=entityRelationEdgeStyle;fontSize=12;html=1;endArrow=ERmandOne;startArrow=ERmandOne;rounded=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="NCbWPNvujZOKFJAbQVH6-11" target="inIyfaXWTM6ArMeTnGn6-2" edge="1">
|
||||
<mxGeometry width="100" height="100" relative="1" as="geometry">
|
||||
<mxPoint x="230" y="390" as="sourcePoint"/>
|
||||
<mxPoint x="330" y="290" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-49" value="" style="edgeStyle=entityRelationEdgeStyle;fontSize=12;html=1;endArrow=ERmandOne;startArrow=ERmandOne;rounded=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="inIyfaXWTM6ArMeTnGn6-15" target="NCbWPNvujZOKFJAbQVH6-44" edge="1">
|
||||
<mxGeometry width="100" height="100" relative="1" as="geometry">
|
||||
<mxPoint x="200" y="400" as="sourcePoint"/>
|
||||
<mxPoint x="300" y="300" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-50" value="" style="edgeStyle=entityRelationEdgeStyle;fontSize=12;html=1;endArrow=ERzeroToMany;endFill=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;curved=1;" parent="1" source="inIyfaXWTM6ArMeTnGn6-15" target="NCbWPNvujZOKFJAbQVH6-51" edge="1">
|
||||
<mxGeometry width="100" height="100" relative="1" as="geometry">
|
||||
<mxPoint x="140" y="430" as="sourcePoint"/>
|
||||
<mxPoint x="740" y="445" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-54" value="" style="edgeStyle=entityRelationEdgeStyle;fontSize=12;html=1;endArrow=ERzeroToMany;endFill=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;curved=1;" parent="1" source="NCbWPNvujZOKFJAbQVH6-51" target="8Zu1yShcSHxMs68hy39H-5" edge="1">
|
||||
<mxGeometry width="100" height="100" relative="1" as="geometry">
|
||||
<mxPoint x="210" y="450" as="sourcePoint"/>
|
||||
<mxPoint x="310" y="350" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NCbWPNvujZOKFJAbQVH6-55" value="" style="edgeStyle=entityRelationEdgeStyle;fontSize=12;html=1;endArrow=ERzeroToMany;endFill=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;curved=1;" parent="1" source="8Zu1yShcSHxMs68hy39H-2" target="AJLbZMHdl7kzV18ppMoM-2" edge="1">
|
||||
<mxGeometry width="100" height="100" relative="1" as="geometry">
|
||||
<mxPoint x="270" y="470" as="sourcePoint"/>
|
||||
<mxPoint x="370" y="370" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="dFNVox72oq8u18PzFUgJ-1" value="EventAction" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1">
|
||||
<mxGeometry x="-110" y="570" width="180" height="120" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="dFNVox72oq8u18PzFUgJ-2" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="dFNVox72oq8u18PzFUgJ-1" vertex="1">
|
||||
<mxGeometry y="30" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="dFNVox72oq8u18PzFUgJ-3" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="dFNVox72oq8u18PzFUgJ-2" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="dFNVox72oq8u18PzFUgJ-4" value="id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="dFNVox72oq8u18PzFUgJ-2" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="dFNVox72oq8u18PzFUgJ-5" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="dFNVox72oq8u18PzFUgJ-1" vertex="1">
|
||||
<mxGeometry y="60" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="dFNVox72oq8u18PzFUgJ-6" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="dFNVox72oq8u18PzFUgJ-5" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="dFNVox72oq8u18PzFUgJ-7" value="event_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="dFNVox72oq8u18PzFUgJ-5" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="dFNVox72oq8u18PzFUgJ-8" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="dFNVox72oq8u18PzFUgJ-1" vertex="1">
|
||||
<mxGeometry y="90" width="180" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="dFNVox72oq8u18PzFUgJ-9" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="dFNVox72oq8u18PzFUgJ-8" vertex="1">
|
||||
<mxGeometry width="30" height="30" as="geometry">
|
||||
<mxRectangle width="30" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="dFNVox72oq8u18PzFUgJ-10" value="action_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="dFNVox72oq8u18PzFUgJ-8" vertex="1">
|
||||
<mxGeometry x="30" width="150" height="30" as="geometry">
|
||||
<mxRectangle width="150" height="30" as="alternateBounds"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="dFNVox72oq8u18PzFUgJ-16" value="" style="edgeStyle=entityRelationEdgeStyle;fontSize=12;html=1;endArrow=ERmandOne;startArrow=ERmandOne;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;curved=1;" parent="1" source="dFNVox72oq8u18PzFUgJ-5" target="GH2g80-cBXHe62XdPV4N-2" edge="1">
|
||||
<mxGeometry width="100" height="100" relative="1" as="geometry">
|
||||
<mxPoint x="290" y="800" as="sourcePoint"/>
|
||||
<mxPoint x="390" y="700" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="dFNVox72oq8u18PzFUgJ-17" value="" style="edgeStyle=entityRelationEdgeStyle;fontSize=12;html=1;endArrow=ERmandOne;startArrow=ERmandOne;rounded=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="AJLbZMHdl7kzV18ppMoM-41" target="dFNVox72oq8u18PzFUgJ-8" edge="1">
|
||||
<mxGeometry width="100" height="100" relative="1" as="geometry">
|
||||
<mxPoint x="-100" y="900" as="sourcePoint"/>
|
||||
<mxPoint y="800" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="yu2qkxLoxjZt0KdZdE3U" name="ページ3">
|
||||
<mxGraphModel dx="1434" dy="884" 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"/>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
@@ -1,10 +0,0 @@
|
||||
<mxfile host="65bd71144e">
|
||||
<diagram id="UMFNb7zEleFpzTH4EAp9" name="ページ1">
|
||||
<mxGraphModel dx="1202" dy="612" 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"/>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
BIN
document/Kintone自動作成ツールのプラグインについて.xlsx
Normal file
BIN
document/Kintone自動作成ツールのプラグインについて.xlsx
Normal file
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
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 |
BIN
document/kintone開発自動化ツール UIデザイン案.pptx
Normal file
BIN
document/kintone開発自動化ツール UIデザイン案.pptx
Normal file
Binary file not shown.
@@ -1,2 +1,3 @@
|
||||
KAB_BACKEND_URL="http://127.0.0.1:8000/api/v1/"
|
||||
KAB_BACKEND_URL="https://kab-backend.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/"
|
||||
|
||||
3
frontend/.gitignore
vendored
3
frontend/.gitignore
vendored
@@ -35,3 +35,6 @@ yarn-error.log*
|
||||
|
||||
# local .env files
|
||||
.env.local*
|
||||
|
||||
# pnpm
|
||||
pnpm-lock.yaml
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="ja-jp">
|
||||
<head>
|
||||
<title><%= productName %></title>
|
||||
|
||||
|
||||
72
frontend/package-lock.json
generated
72
frontend/package-lock.json
generated
@@ -10,13 +10,16 @@
|
||||
"dependencies": {
|
||||
"@quasar/extras": "^1.16.4",
|
||||
"axios": "^1.4.0",
|
||||
"pinia": "^2.1.6",
|
||||
"quasar": "^2.6.0",
|
||||
"uuid": "^9.0.0",
|
||||
"vue": "^3.0.0",
|
||||
"vue-router": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@quasar/app-vite": "^1.3.0",
|
||||
"@types/node": "^12.20.21",
|
||||
"@types/uuid": "^9.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.10.0",
|
||||
"@typescript-eslint/parser": "^5.10.0",
|
||||
"autoprefixer": "^10.4.2",
|
||||
@@ -28,8 +31,9 @@
|
||||
"typescript": "^4.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18 || ^16 || ^14.19",
|
||||
"node": "^20 ||^18 || ^16 || ^14.19",
|
||||
"npm": ">= 6.13.4",
|
||||
"pnpm": ">=8.6.0",
|
||||
"yarn": ">= 1.21.1"
|
||||
}
|
||||
},
|
||||
@@ -544,6 +548,12 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/uuid": {
|
||||
"version": "9.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.3.tgz",
|
||||
"integrity": "sha512-taHQQH/3ZyI3zP8M/puluDEIEvtQHVYcC6y3N8ijFtAd28+Ey/G4sg1u2gB01S8MwybLOKAp9/yCMu/uR5l3Ug==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.61.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.61.0.tgz",
|
||||
@@ -4070,6 +4080,56 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/pinia": {
|
||||
"version": "2.1.6",
|
||||
"resolved": "https://registry.npmjs.org/pinia/-/pinia-2.1.6.tgz",
|
||||
"integrity": "sha512-bIU6QuE5qZviMmct5XwCesXelb5VavdOWKWaB17ggk++NUwQWWbP5YnsONTk3b752QkW9sACiR81rorpeOMSvQ==",
|
||||
"dependencies": {
|
||||
"@vue/devtools-api": "^6.5.0",
|
||||
"vue-demi": ">=0.14.5"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/posva"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vue/composition-api": "^1.4.0",
|
||||
"typescript": ">=4.4.4",
|
||||
"vue": "^2.6.14 || ^3.3.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vue/composition-api": {
|
||||
"optional": true
|
||||
},
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/pinia/node_modules/vue-demi": {
|
||||
"version": "0.14.6",
|
||||
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz",
|
||||
"integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==",
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"vue-demi-fix": "bin/vue-demi-fix.js",
|
||||
"vue-demi-switch": "bin/vue-demi-switch.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vue/composition-api": "^1.0.0-rc.1",
|
||||
"vue": "^3.0.0-0 || ^2.6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vue/composition-api": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.25",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz",
|
||||
@@ -4946,7 +5006,7 @@
|
||||
"version": "4.9.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
||||
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -5045,6 +5105,14 @@
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
|
||||
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "kintone-app-builder",
|
||||
"version": "0.0.1",
|
||||
"name": "kintone-automate",
|
||||
"version": "0.2.0",
|
||||
"description": "Kintoneアプリの自動生成とデプロイを支援ツールです",
|
||||
"productName": "Kintone App Builder",
|
||||
"productName": "Kintone Automate",
|
||||
"author": "maxiaozhe@alicorns.co.jp <maxiaozhe@alicorns.co.jp>",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@@ -10,18 +10,24 @@
|
||||
"format": "prettier --write \"**/*.{js,ts,vue,scss,html,md,json}\" --ignore-path .gitignore",
|
||||
"test": "echo \"No test specified\" && exit 0",
|
||||
"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": {
|
||||
"@quasar/extras": "^1.16.4",
|
||||
"axios": "^1.4.0",
|
||||
"pinia": "^2.1.6",
|
||||
"quasar": "^2.6.0",
|
||||
"uuid": "^9.0.0",
|
||||
"vue": "^3.0.0",
|
||||
"vue-router": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@quasar/app-vite": "^1.3.0",
|
||||
"@types/node": "^12.20.21",
|
||||
"@types/uuid": "^9.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.10.0",
|
||||
"@typescript-eslint/parser": "^5.10.0",
|
||||
"autoprefixer": "^10.4.2",
|
||||
@@ -33,8 +39,9 @@
|
||||
"typescript": "^4.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18 || ^16 || ^14.19",
|
||||
"node": "^20 ||^18 || ^16 || ^14.19",
|
||||
"npm": ">= 6.13.4",
|
||||
"yarn": ">= 1.21.1"
|
||||
"yarn": ">= 1.21.1",
|
||||
"pnpm": ">=8.6.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 dotenv = require('dotenv').config().parsed;
|
||||
const package = require('./package.json');
|
||||
const envPath = process.env.LOCAL==='true'?'.env.development':'.env';
|
||||
const dotenv = require('dotenv').config({path:envPath}).parsed;
|
||||
console.log('dotenv=>',dotenv);
|
||||
// const package = require('./package.json');
|
||||
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 */) {
|
||||
return {
|
||||
eslint: {
|
||||
@@ -49,7 +53,6 @@ module.exports = configure(function (/* ctx */) {
|
||||
// 'themify',
|
||||
// 'line-awesome',
|
||||
// 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
|
||||
|
||||
'roboto-font', // optional, you are not bound to it
|
||||
'material-icons', // optional, you are not bound to it
|
||||
],
|
||||
@@ -60,6 +63,7 @@ module.exports = configure(function (/* ctx */) {
|
||||
browser: ['es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1'],
|
||||
node: 'node16'
|
||||
},
|
||||
sourcemap:process.env.SOURCE_MAP === 'true',
|
||||
|
||||
vueRouterMode: 'hash', // available values: 'hash', 'history'
|
||||
// vueRouterBase,
|
||||
@@ -70,7 +74,7 @@ module.exports = configure(function (/* ctx */) {
|
||||
|
||||
// publicPath: '/',
|
||||
// analyze: true,
|
||||
env: { ...dotenv, version },
|
||||
env: { ...dotenv, version ,productName},
|
||||
// rawDefine: {}
|
||||
// ignorePublicFolder: true,
|
||||
// minify: false,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { boot } from 'quasar/wrappers';
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import {router} from 'src/router';
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
interface ComponentCustomProperties {
|
||||
@@ -15,7 +16,28 @@ declare module '@vue/runtime-core' {
|
||||
// "export default () => {}" function below (which runs individually
|
||||
// for each client)
|
||||
const api:AxiosInstance = axios.create({ baseURL: process.env.KAB_BACKEND_URL });
|
||||
|
||||
const token=localStorage.getItem('token')||'';
|
||||
if(token!==''){
|
||||
api.defaults.headers["Authorization"]='Bearer ' + token;
|
||||
}
|
||||
api.interceptors.response.use(
|
||||
(response)=>response,
|
||||
(error)=>{
|
||||
const orgReq=error.config;
|
||||
if(error.response && error.response.status===401){
|
||||
console.error("401エラー");
|
||||
localStorage.removeItem('token');
|
||||
router.replace({
|
||||
path:"/login",
|
||||
query:{redirect:router.currentRoute.value.fullPath}
|
||||
});
|
||||
// router.push({
|
||||
// path:"/login",
|
||||
// query:{redirect:router.currentRoute.value.fullPath}
|
||||
// });
|
||||
}
|
||||
}
|
||||
)
|
||||
export default boot(({ app }) => {
|
||||
// for use inside Vue files (Options API) through this.$axios and this.$api
|
||||
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
<template>
|
||||
<div class="q-pa-md" style="max-width: 350px">
|
||||
<q-expansion-item
|
||||
class="shadow-1 overflow-hidden"
|
||||
style="border-radius: 30px"
|
||||
icon="explore"
|
||||
label="Counter"
|
||||
@show="startCounting"
|
||||
@hide="stopCounting"
|
||||
header-class="bg-primary text-white"
|
||||
expand-icon-class="text-white"
|
||||
>
|
||||
<q-card>
|
||||
<q-card-section>
|
||||
Counting: <q-badge color="secondary">{{ counter }}</q-badge>.
|
||||
Will only count when opened, using the show/hide events to control count timer.
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-expansion-item>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent} from "vue"
|
||||
export default defineComponent({
|
||||
props:{
|
||||
icon:String,
|
||||
|
||||
},
|
||||
setup() {
|
||||
return {
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="">
|
||||
|
||||
</style>
|
||||
@@ -1,30 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {defineComponent,reactive} from 'vue';
|
||||
import {KintoneEvent} from "../models/kintone";
|
||||
export default defineComponent({
|
||||
setup(props, ctx) {
|
||||
const events = reactive<KintoneEvent[]>(
|
||||
[
|
||||
{
|
||||
screen:"レコード追加画面",
|
||||
type:"app.record.create.show",
|
||||
name:"レコード追加画面を表示した後"
|
||||
},
|
||||
{
|
||||
screen:"レコード追加画面",
|
||||
type:"app.record.create.show",
|
||||
name:"レコード追加画面を表示した後"
|
||||
}
|
||||
]
|
||||
);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
||||
@@ -1,6 +1,15 @@
|
||||
<template>
|
||||
<div class="q-pa-md">
|
||||
<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 v-else row-key="name" :selection="type" v-model:selected="selected" :columns="columns" :rows="rows"
|
||||
class="action-table"
|
||||
flat bordered
|
||||
virtual-scroll
|
||||
:pagination="pagination"
|
||||
:rows-per-page-options="[0]"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
@@ -14,27 +23,36 @@ export default {
|
||||
type: String
|
||||
},
|
||||
setup() {
|
||||
const columns = [
|
||||
{ name: 'name', required: true,label: 'アクション名',align: 'left',field: 'name',sortable: true},
|
||||
{ name: 'desc', align: 'left', label: '説明', field: 'desc', sortable: true },
|
||||
{ name: 'content', label: '内容', field: 'content', sortable: true }
|
||||
]
|
||||
const rows = reactive([])
|
||||
const isLoaded=ref(false);
|
||||
const columns = [
|
||||
{ name: 'name', required: true,label: 'アクション名',align: 'left',field: 'name',sortable: true},
|
||||
{ name: 'desc', align: 'left', label: '説明', field: 'desc', sortable: true },
|
||||
// { name: 'content', label: '内容', field: 'content', sortable: true }
|
||||
];
|
||||
const rows = reactive([])
|
||||
onMounted(async () => {
|
||||
await api.get('http://127.0.0.1:8000/api/kintone/2').then(res =>{
|
||||
res.data.forEach((item) =>
|
||||
const res =await api.get('api/actions');
|
||||
res.data.forEach((item) =>
|
||||
{
|
||||
rows.push({name:item.name,desc:item.desc,content:item.content});
|
||||
}
|
||||
)
|
||||
});
|
||||
rows.push({name:item.name,desc:item.title,outputPoints:item.outputpoints,property:item.property});
|
||||
});
|
||||
isLoaded.value=true;
|
||||
});
|
||||
return {
|
||||
columns,
|
||||
rows,
|
||||
selected: ref([]),
|
||||
pagination:ref({
|
||||
rowsPerPage:0
|
||||
}),
|
||||
isLoaded,
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.action-table{
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
import { AppInfo, AppSeed } from './models';
|
||||
import { ref, defineComponent, watch, onMounted , toRefs } from 'vue';
|
||||
import { api } from 'boot/axios';
|
||||
import { promises } from 'dns';
|
||||
import { useAuthStore } from 'src/stores/useAuthStore';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
@@ -44,12 +44,13 @@ export default defineComponent({
|
||||
},
|
||||
setup(props) {
|
||||
const { app } = toRefs(props);
|
||||
const authStore = useAuthStore();
|
||||
const appinfo = ref<AppInfo>({
|
||||
appId: "",
|
||||
name: "",
|
||||
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) => {
|
||||
if(!appId){
|
||||
return;
|
||||
@@ -59,7 +60,7 @@ export default defineComponent({
|
||||
let retry =0;
|
||||
while(retry<=3 && result && result.appId!==appId){
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
const response = await api.get('app', {
|
||||
const response = await api.get('api/v1/app', {
|
||||
params:{
|
||||
app: appId
|
||||
}
|
||||
@@ -73,7 +74,7 @@ export default defineComponent({
|
||||
|
||||
watch(app, async (newApp) => {
|
||||
appinfo.value = await getAppInfo(newApp);
|
||||
link.value = 'https://mfu07rkgnb7c.cybozu.com/k/' + newApp;
|
||||
link.value = `${authStore.currentDomain.kintoneUrl}/k/${newApp}`;
|
||||
}, { immediate: true });
|
||||
|
||||
const linkClick=(ev : MouseEvent)=>{
|
||||
@@ -82,7 +83,7 @@ export default defineComponent({
|
||||
};
|
||||
onMounted(async ()=>{
|
||||
appinfo.value = await getAppInfo(app.value);
|
||||
link.value = 'https://mfu07rkgnb7c.cybozu.com/k/' + app.value;
|
||||
link.value = `${authStore.currentDomain.kintoneUrl}/k/${app.value}`;
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,41 +1,84 @@
|
||||
<template>
|
||||
<div class="q-pa-md">
|
||||
<q-table :title="name+'一覧'" :selection="type" v-model:selected="selected" :columns="columns" :rows="rows" />
|
||||
<div class="q-pa-md" >
|
||||
<div v-if="!isLoaded" class="spinner flex flex-center">
|
||||
<q-spinner color="primary" size="3em" />
|
||||
</div>
|
||||
<q-table v-else :selection="type" v-model:selected="selected" :columns="columns" :rows="rows" >
|
||||
<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>
|
||||
<script lang="ts">
|
||||
import { ref,onMounted,reactive } from 'vue'
|
||||
import { api } from 'boot/axios';
|
||||
import { LeftDataBus } from './flowEditor/left/DataBus';
|
||||
|
||||
export default {
|
||||
name: 'appSelect',
|
||||
name: 'AppSelect',
|
||||
props: {
|
||||
name: String,
|
||||
type: String
|
||||
},
|
||||
setup() {
|
||||
const columns = [
|
||||
{ name: 'id', required: true,label: 'アプリID',align: 'left',field: 'id',sortable: true},
|
||||
{ name: 'name', align: 'center', label: 'アプリ名', field: 'name', sortable: true },
|
||||
{ name: 'creator', label: '作成者', field: 'creator', sortable: true },
|
||||
{ name: 'createdate', label: '作成日時', field: 'createdate' }
|
||||
{ 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 rows = reactive([])
|
||||
const isLoaded=ref(false);
|
||||
const rows :any[]= reactive([]);
|
||||
onMounted( () => {
|
||||
api.get('allapps').then(res =>{
|
||||
res.data.apps.forEach((item) =>
|
||||
{
|
||||
rows.push({id:item.appId,name:item.name,creator:item.creator.name,createdate:item.createdAt});
|
||||
}
|
||||
)
|
||||
});
|
||||
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: ref([]),
|
||||
isLoaded
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
</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" width="60vw" 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>
|
||||
79
frontend/src/components/ConditionEditor/ConditionObject.vue
Normal file
79
frontend/src/components/ConditionEditor/ConditionObject.vue
Normal file
@@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<q-field v-model="selectedField" labelColor="primary" class="condition-object"
|
||||
:clearable="isSelected" stack-label :dense="true" :outlined="true" >
|
||||
<template v-slot:control >
|
||||
<q-chip color="primary" text-color="white" v-if="isSelected" :dense="true" class="selected-obj">
|
||||
{{ selectedField.name }}
|
||||
</q-chip>
|
||||
</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" widht="400px">
|
||||
<condition-objects ref="appDg" name="フィールド" type="single" :appId="store.appInfo?.appId"></condition-objects>
|
||||
</show-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref ,watchEffect,computed} from 'vue';
|
||||
import ShowDialog from '../ShowDialog.vue';
|
||||
import ConditionObjects from '../ConditionObjects.vue';
|
||||
import { useFlowEditorStore } from '../../stores/flowEditor';
|
||||
export default defineComponent({
|
||||
name: 'ConditionObject',
|
||||
components: {
|
||||
ShowDialog,
|
||||
ConditionObjects,
|
||||
},
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const appDg = ref();
|
||||
const show = ref(false);
|
||||
const selectedField = ref(props.modelValue);
|
||||
const store = useFlowEditorStore();
|
||||
const isSelected = computed(()=>{
|
||||
return selectedField.value!==null && typeof selectedField.value === 'object' && ('name' in selectedField.value)
|
||||
});
|
||||
|
||||
const showDg = () => {
|
||||
show.value = true;
|
||||
};
|
||||
|
||||
const closeDg = (val:string) => {
|
||||
if (val == 'OK') {
|
||||
selectedField.value = appDg.value.selected[0];
|
||||
}
|
||||
};
|
||||
|
||||
watchEffect(() => {
|
||||
emit('update:modelValue', selectedField.value);
|
||||
});
|
||||
|
||||
return {
|
||||
store,
|
||||
appDg,
|
||||
show,
|
||||
showDg,
|
||||
closeDg,
|
||||
selectedField,
|
||||
isSelected
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.condition-object{
|
||||
min-width: 200px;
|
||||
max-height: 40px;
|
||||
padding: 2px;
|
||||
}
|
||||
.selected-obj{
|
||||
margin: 0px;
|
||||
}
|
||||
</style>
|
||||
273
frontend/src/components/ConditionEditor/NodeCondition.vue
Normal file
273
frontend/src/components/ConditionEditor/NodeCondition.vue
Normal file
@@ -0,0 +1,273 @@
|
||||
<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">
|
||||
<ConditionObject v-bind="prop.node" v-model="prop.node.object" class="col-4"></ConditionObject>
|
||||
<q-select v-model="prop.node.operator" :options="operators" class="operator" :outlined="true" :dense="true"></q-select>
|
||||
<q-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-btn @click="addCondition(tree.root)" class="q-mt-md" color="primary" icon="mdi-plus">Add Condition</q-btn> -->
|
||||
<!-- <q-btn @click="getConditionString()" class="q-mt-md" color="primary" icon="mdi-plus">Show Condtion</q-btn>
|
||||
<q-btn @click="getConditionJson()" class="q-mt-md" color="primary" icon="mdi-plus">Show Condtion data</q-btn>
|
||||
<q-btn @click="LoadCondition()" class="q-mt-md" color="primary" icon="mdi-plus">Load Condition</q-btn> -->
|
||||
<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 } from 'vue';
|
||||
import { INode,ConditionTree,GroupNode,ConditionNode, LogicalOperator,Operator,NodeType } from '../../types/Conditions';
|
||||
import ConditionObject from './ConditionObject.vue';
|
||||
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 operators =computed(()=>{
|
||||
const opts=[];
|
||||
for(const op in Operator){
|
||||
opts.push(Operator[op as keyof typeof Operator]);
|
||||
}
|
||||
return opts;
|
||||
});
|
||||
const tree = reactive(props.conditionTree);
|
||||
|
||||
const conditionString = computed(()=>{
|
||||
return tree.buildConditionString(tree.root);
|
||||
});
|
||||
|
||||
const objectValueOptions=(options:any):any[]=>{
|
||||
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);
|
||||
|
||||
return {
|
||||
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;
|
||||
padding: 2px;
|
||||
}
|
||||
.operator{
|
||||
min-width: 150px;
|
||||
max-height: 40px;
|
||||
padding: 2px;
|
||||
text-align: center;
|
||||
font-size: 12pt;
|
||||
}
|
||||
</style>
|
||||
54
frontend/src/components/ConditionObjects.vue
Normal file
54
frontend/src/components/ConditionObjects.vue
Normal file
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<div class="q-pa-md">
|
||||
<div v-if="!isLoaded" class="spinner flex flex-center">
|
||||
<q-spinner color="primary" size="3em" />
|
||||
</div>
|
||||
<q-table v-else row-key="name" :selection="type" v-model:selected="selected" :columns="columns" :rows="rows" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { ref,onMounted,reactive } from 'vue'
|
||||
import { api } from 'boot/axios';
|
||||
|
||||
export default {
|
||||
name: 'ConditionObjects',
|
||||
props: {
|
||||
name: String,
|
||||
type: String,
|
||||
appId:Number
|
||||
},
|
||||
setup(props) {
|
||||
const isLoaded=ref(false);
|
||||
const columns = [
|
||||
{ name: 'name', required: true,label: 'フィールド名',align: 'left',field: row=>row.name,sortable: true},
|
||||
{ name: 'code', label: 'フィールドコード', align: 'left',field: 'code', sortable: true },
|
||||
{ name: 'type', label: 'フィールドタイプ', align: 'left',field: 'type', sortable: true }
|
||||
]
|
||||
const rows = reactive([])
|
||||
onMounted( async () => {
|
||||
const res = await api.get('api/v1/appfields', {
|
||||
params:{
|
||||
app: props.appId
|
||||
}
|
||||
});
|
||||
let fields = res.data.properties;
|
||||
console.log(fields);
|
||||
Object.keys(fields).forEach((key) =>
|
||||
{
|
||||
const fld=fields[key];
|
||||
// rows.push({name:fields[key].label,code:fields[key].code,type:fields[key].type});
|
||||
rows.push({name:fld.label,objectType:'field',...fld});
|
||||
});
|
||||
isLoaded.value=true;
|
||||
});
|
||||
|
||||
return {
|
||||
columns,
|
||||
rows,
|
||||
selected: ref([]),
|
||||
isLoaded
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
@@ -4,6 +4,7 @@
|
||||
style="max-width: 400px"
|
||||
:url="uploadUrl"
|
||||
:label="title"
|
||||
:headers="headers"
|
||||
accept=".csv,.xlsx"
|
||||
v-on:rejected="onRejected"
|
||||
v-on:uploaded="onUploadFinished"
|
||||
@@ -15,7 +16,10 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { createUploaderComponent, useQuasar } from 'quasar';
|
||||
import { useAuthStore } from 'src/stores/useAuthStore';
|
||||
import { ref } from 'vue';
|
||||
const $q=useQuasar();
|
||||
const authStore = useAuthStore();
|
||||
const emit =defineEmits(['uploaded']);
|
||||
/**
|
||||
* ファイルアップロードを拒否する時の処理
|
||||
@@ -67,9 +71,12 @@
|
||||
title: string;
|
||||
uploadUrl:string;
|
||||
}
|
||||
|
||||
const headers = ref([{name:"Authorization",value:'Bearer ' + authStore.token}]);
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
title:"設計書から導入する(csv or excel)",
|
||||
uploadUrl: `${process.env.KAB_BACKEND_URL}createappfromexcel`
|
||||
uploadUrl: `${process.env.KAB_BACKEND_URL}api/v1/createappfromexcel`
|
||||
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
|
||||
42
frontend/src/components/DomainSelect.vue
Normal file
42
frontend/src/components/DomainSelect.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<div class="q-pa-md">
|
||||
<q-table :title="name+'一覧'" :selection="type" v-model:selected="selected" :columns="columns" :rows="rows" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { ref,onMounted,reactive } from 'vue'
|
||||
import { api } from 'boot/axios';
|
||||
|
||||
export default {
|
||||
name: 'DomainSelect',
|
||||
props: {
|
||||
name: String,
|
||||
type: String
|
||||
},
|
||||
setup() {
|
||||
const columns = [
|
||||
{ name: 'id'},
|
||||
{ name: 'tenantid', required: true,label: 'テナント',align: 'left',field: 'tenantid',sortable: true},
|
||||
{ name: 'name', align: 'center', label: 'ドメイン', field: 'name', sortable: true },
|
||||
{ name: 'url', label: 'URL', field: 'url', sortable: true },
|
||||
{ name: 'kintoneuser', label: 'アカウント', field: 'kintoneuser' }
|
||||
]
|
||||
const rows = reactive([])
|
||||
onMounted( () => {
|
||||
api.get(`api/domains/1`).then(res =>{
|
||||
res.data.forEach((item) =>
|
||||
{
|
||||
rows.push({id:item.id,tenantid:item.tenantid,name:item.name,url:item.url,kintoneuser:item.kintoneuser});
|
||||
}
|
||||
)
|
||||
});
|
||||
});
|
||||
return {
|
||||
columns,
|
||||
rows,
|
||||
selected: ref([]),
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
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>
|
||||
@@ -1,6 +1,9 @@
|
||||
<template>
|
||||
<div class="q-pa-md">
|
||||
<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 v-else row-key="name" :selection="type" v-model:selected="selected" :columns="columns" :rows="rows" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
@@ -15,32 +18,36 @@ export default {
|
||||
appId:Number
|
||||
},
|
||||
setup(props) {
|
||||
const columns = [
|
||||
{ name: 'name', required: true,label: 'フィールド名',align: 'left',field: row=>row.name,sortable: true},
|
||||
{ name: 'code', label: 'フィールドコード', align: 'left',field: 'code', sortable: true },
|
||||
{ name: 'type', label: 'フィールドタイプ', align: 'left',field: 'type', sortable: true }
|
||||
]
|
||||
const rows = reactive([])
|
||||
onMounted( () => {
|
||||
api.get('appfields', {
|
||||
params:{
|
||||
app: props.appId
|
||||
}
|
||||
}).then(res =>{
|
||||
let fields = res.data.properties;
|
||||
console.log(fields);
|
||||
Object.keys(fields).forEach((key) =>
|
||||
{
|
||||
rows.push({name:fields[key].label,code:fields[key].code,type:fields[key].type});
|
||||
}
|
||||
)
|
||||
});
|
||||
});
|
||||
return {
|
||||
columns,
|
||||
rows,
|
||||
selected: ref([]),
|
||||
}
|
||||
const isLoaded=ref(false);
|
||||
const columns = [
|
||||
{ name: 'name', required: true,label: 'フィールド名',align: 'left',field: row=>row.name,sortable: true},
|
||||
{ name: 'code', label: 'フィールドコード', align: 'left',field: 'code', sortable: true },
|
||||
{ name: 'type', label: 'フィールドタイプ', align: 'left',field: 'type', sortable: true }
|
||||
]
|
||||
const rows = reactive([])
|
||||
onMounted( async () => {
|
||||
const res = await api.get('api/v1/appfields', {
|
||||
params:{
|
||||
app: props.appId
|
||||
}
|
||||
});
|
||||
let fields = res.data.properties;
|
||||
console.log(fields);
|
||||
Object.keys(fields).forEach((key) =>
|
||||
{
|
||||
const fld=fields[key];
|
||||
// rows.push({name:fields[key].label,code:fields[key].code,type:fields[key].type});
|
||||
rows.push({name:fld.label,...fld});
|
||||
});
|
||||
isLoaded.value=true;
|
||||
});
|
||||
|
||||
return {
|
||||
columns,
|
||||
rows,
|
||||
selected: ref([]),
|
||||
isLoaded
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
<style lang="">
|
||||
|
||||
</style>
|
||||
@@ -1,9 +0,0 @@
|
||||
export interface Rule{
|
||||
id:number;
|
||||
name:string;
|
||||
condtion:CondtionTree
|
||||
}
|
||||
|
||||
export interface CondtionTree{
|
||||
|
||||
}
|
||||
@@ -1,12 +1,17 @@
|
||||
<template>
|
||||
<div class="q-pa-md q-gutter-sm">
|
||||
<q-dialog :model-value="visible" persistent>
|
||||
<q-card style="min-width: 350px">
|
||||
<!-- <div class="q-pa-md q-gutter-sm" > -->
|
||||
<q-dialog :model-value="visible" persistent bordered>
|
||||
<q-card :style="{minWidth : width}" >
|
||||
<q-toolbar class="bg-grey-4">
|
||||
<q-toolbar-title>{{ name }}</q-toolbar-title>
|
||||
<q-space></q-space>
|
||||
<slot name="toolbar"></slot>
|
||||
<q-btn flat round dense icon="close" @click="CloseDialogue('Cancel')" />
|
||||
</q-toolbar>
|
||||
<q-card-section>
|
||||
<div class="text-h6">{{ name }}選択</div>
|
||||
<!-- <div class="text-h6">{{ name }}</div> -->
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section class="q-pt-none">
|
||||
<q-card-section class="q-pt-none" :style="{...(height? {minHeight:height}:{}) }">
|
||||
<slot></slot>
|
||||
</q-card-section>
|
||||
<q-card-actions align="right" class="text-primary">
|
||||
@@ -15,15 +20,17 @@
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</div>
|
||||
<!-- </div> -->
|
||||
</template>
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'showDialog',
|
||||
name: 'ShowDialog',
|
||||
props: {
|
||||
name:String,
|
||||
visible: Boolean,
|
||||
width:String,
|
||||
height:String
|
||||
},
|
||||
emits: [
|
||||
'close'
|
||||
|
||||
29
frontend/src/components/flowEditor/left/ControlPanelC.vue
Normal file
29
frontend/src/components/flowEditor/left/ControlPanelC.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<div class="q-py-md">
|
||||
<q-tree
|
||||
no-connectors
|
||||
selected-color="primary"
|
||||
default-expand-all
|
||||
:nodes="LeftDataBus.root"
|
||||
v-model:selected="flowNames1"
|
||||
node-key="label"
|
||||
>
|
||||
</q-tree>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
LeftDataBus,
|
||||
setControlPanelE,
|
||||
} from 'components/flowEditor/left/DataBus';
|
||||
import { ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||
|
||||
// 应该在page中用网络请求获取值并初始化组件
|
||||
// 然后在page中执行setControlPane设置databus
|
||||
const store = useFlowEditorStore();
|
||||
const { flowNames1 } = storeToRefs(store);
|
||||
setControlPanelE();
|
||||
</script>
|
||||
72
frontend/src/components/flowEditor/left/DataBus.ts
Normal file
72
frontend/src/components/flowEditor/left/DataBus.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { reactive } from 'vue'
|
||||
|
||||
export const LeftDataBus = reactive<LeftData>({})
|
||||
|
||||
const defaultData = {
|
||||
root: [
|
||||
{
|
||||
label: 'レコードを追加画面',
|
||||
children: [
|
||||
{
|
||||
label: '追加画面表示した時',
|
||||
header: 'rg',
|
||||
value: '1-1',
|
||||
group: 'g1',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
label: '保存をクリックした時',
|
||||
header: 'rg',
|
||||
value: '1-2',
|
||||
group: 'g1',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
label: '保存成功した時',
|
||||
header: 'rg',
|
||||
value: '1-3',
|
||||
group: 'g1',
|
||||
children: []
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'レコード編集画面',
|
||||
},
|
||||
{
|
||||
label: 'レコード詳細画面',
|
||||
},
|
||||
{
|
||||
label: 'レコード一覧画面',
|
||||
},
|
||||
],
|
||||
data: new Map([['g1', '1-1']])
|
||||
}
|
||||
|
||||
export const setControlPanel = (rootData: LeftData) => {
|
||||
const { root: dr, data: dd } = defaultData
|
||||
LeftDataBus.title = rootData.title
|
||||
LeftDataBus.root = rootData.root ?? dr
|
||||
LeftDataBus.data = rootData.data ?? dd
|
||||
}
|
||||
|
||||
export const setControlPanelE = () => {
|
||||
const { root: dr, data: dd } = defaultData
|
||||
// LeftDataBus.title = rootData.title
|
||||
LeftDataBus.root = dr
|
||||
LeftDataBus.data = dd
|
||||
}
|
||||
|
||||
export interface LeftData {
|
||||
title?: string
|
||||
root?: ControlPanelData[]
|
||||
data?: Map<string, string>
|
||||
}
|
||||
|
||||
export interface ControlPanelData {
|
||||
label: string,
|
||||
header?: string,
|
||||
value?: string,
|
||||
group?: string,
|
||||
children?: ControlPanelData[]
|
||||
}
|
||||
42
frontend/src/components/flowEditor/left/ItemSelector.vue
Normal file
42
frontend/src/components/flowEditor/left/ItemSelector.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<div
|
||||
class="row"
|
||||
style="
|
||||
border-radius: 2px;
|
||||
box-shadow: rgba(255, 255, 255, 0.1) 0px 0px 0px 1px inset,
|
||||
rgba(0, 0, 0, 0.3) 0px 0px 0px 1px;
|
||||
"
|
||||
>
|
||||
<q-icon
|
||||
class="self-center q-ma-sm"
|
||||
name="widgets"
|
||||
color="grey-9"
|
||||
style="font-size: 2em"
|
||||
/>
|
||||
|
||||
<div class="col-7 self-center ellipsis">
|
||||
{{ actName }}
|
||||
</div>
|
||||
|
||||
<div class="self-center">
|
||||
<q-btn
|
||||
outline
|
||||
dense
|
||||
label="変 更"
|
||||
padding="none sm"
|
||||
color="primary"
|
||||
></q-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { computed } from 'vue';
|
||||
|
||||
export default {
|
||||
props: ['actName'],
|
||||
setup(props) {
|
||||
const actName = computed(() => props.actName);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
86
frontend/src/components/left/AppSelector.vue
Normal file
86
frontend/src/components/left/AppSelector.vue
Normal file
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<div class="row app-box">
|
||||
<q-icon
|
||||
class="self-center q-ma-sm"
|
||||
name="widgets"
|
||||
color="grey-9"
|
||||
style="font-size: 2em"
|
||||
/>
|
||||
<div class="col-7 self-center ellipsis">
|
||||
<a :href="!store.appInfo?'':`${authStore.currentDomain.kintoneUrl}/k/${store.appInfo?.appId}`" target="_blank" title="Kiontoneへ">
|
||||
{{ store.appInfo?.name }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="self-center">
|
||||
<q-btn
|
||||
outline
|
||||
dense
|
||||
label="変 更"
|
||||
padding="none sm"
|
||||
color="primary"
|
||||
@click="showAppDialog"
|
||||
></q-btn>
|
||||
</div>
|
||||
</div>
|
||||
<ShowDialog v-model:visible="showSelectApp" name="アプリ選択" @close="closeDg" width="600px" >
|
||||
<AppSelect ref="appDg" name="アプリ" type="single"></AppSelect>
|
||||
</ShowDialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent,ref } from 'vue';
|
||||
import {AppInfo} from '../../types/ActionTypes'
|
||||
import ShowDialog from '../../components/ShowDialog.vue';
|
||||
import AppSelect from '../../components/AppSelect.vue';
|
||||
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||
import { useAuthStore } from 'src/stores/useAuthStore';
|
||||
export default defineComponent({
|
||||
name: 'AppSelector',
|
||||
emits:[
|
||||
"appSelected"
|
||||
],
|
||||
components:{
|
||||
AppSelect,
|
||||
ShowDialog
|
||||
},
|
||||
setup(props, context) {
|
||||
|
||||
const store = useFlowEditorStore();
|
||||
const authStore=useAuthStore();
|
||||
const appDg = ref();
|
||||
const showSelectApp=ref(false);
|
||||
|
||||
const closeDg=(val :any)=>{
|
||||
showSelectApp.value=false;
|
||||
console.log("Dialog closed->",val);
|
||||
if (val == 'OK') {
|
||||
const data = appDg.value.selected[0];
|
||||
console.log(data);
|
||||
const appInfo={
|
||||
appId:data.id ,
|
||||
name:data.name
|
||||
};
|
||||
store.setApp(appInfo);
|
||||
store.loadFlow();
|
||||
}
|
||||
}
|
||||
const showAppDialog=()=>{
|
||||
showSelectApp.value=true;
|
||||
}
|
||||
return {
|
||||
store,
|
||||
authStore,
|
||||
showSelectApp,
|
||||
showAppDialog,
|
||||
closeDg,
|
||||
appDg
|
||||
}
|
||||
}
|
||||
});
|
||||
</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>
|
||||
86
frontend/src/components/left/EventTree.vue
Normal file
86
frontend/src/components/left/EventTree.vue
Normal file
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<!-- <div class="q-pa-md q-gutter-sm"> -->
|
||||
<q-tree
|
||||
:nodes="store.eventTree.screens"
|
||||
node-key="label"
|
||||
children-key="events"
|
||||
no-connectors
|
||||
v-model:expanded="store.expandedScreen"
|
||||
:dense="true"
|
||||
>
|
||||
<template v-slot:default-header="prop">
|
||||
<div class="row col items-start no-wrap 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">
|
||||
</q-icon>
|
||||
<div class="no-wrap" :class="selectedEvent && prop.node.eventId===selectedEvent.eventId?'selected-node':''">{{ prop.node.label }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</q-tree>
|
||||
<!-- </div> -->
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, ref } from 'vue';
|
||||
import { IKintoneEvent } from '../../types/KintoneEvents';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||
import { ActionFlow, ActionNode, RootAction } from 'src/types/ActionTypes';
|
||||
export default defineComponent({
|
||||
name: 'EventTree',
|
||||
setup(props, context) {
|
||||
const store = useFlowEditorStore();
|
||||
// const eventTree=ref(kintoneEvents);
|
||||
// const selectedFlow = store.currentFlow;
|
||||
|
||||
// const expanded=ref();
|
||||
const selectedEvent = ref<IKintoneEvent|null>(null);
|
||||
const onSelected=(node:IKintoneEvent)=>{
|
||||
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;
|
||||
}
|
||||
}
|
||||
return {
|
||||
// eventTree,
|
||||
// expanded,
|
||||
onSelected,
|
||||
selectedEvent,
|
||||
store
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.nowrap{
|
||||
flex-wrap:nowarp;
|
||||
text-wrap:nowarp;
|
||||
}
|
||||
.event-node{
|
||||
cursor:pointer;
|
||||
}
|
||||
.selected-node{
|
||||
color: $primary;
|
||||
font-weight: bolder;
|
||||
}
|
||||
.event-node:hover{
|
||||
background-color: $light-blue-1;
|
||||
}
|
||||
</style>
|
||||
198
frontend/src/components/main/NodeItem.vue
Normal file
198
frontend/src/components/main/NodeItem.vue
Normal file
@@ -0,0 +1,198 @@
|
||||
<template>
|
||||
<div class="row justify-center" :style="{ marginLeft: node.inputPoint !== '' ? '240px' : '' }" >
|
||||
<div class="row">
|
||||
<q-card class="action-node" :class="nodeStyle" :square="false" @click="onNodeClick" >
|
||||
<q-toolbar class="col" >
|
||||
<div class="text-subtitle2">{{ node.subTitle }}</div>
|
||||
<q-space></q-space>
|
||||
<q-btn flat round dense icon="more_horiz" size="sm" >
|
||||
<q-menu auto-close anchor="top right">
|
||||
<q-list>
|
||||
<q-item clickable v-if="!isRoot" @click="onEditNode">
|
||||
<q-item-section avatar><q-icon name="edit" ></q-icon></q-item-section>
|
||||
<q-item-section >編集する</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable v-if="!isRoot" @click="onDeleteNode">
|
||||
<q-item-section avatar><q-icon name="delete" ></q-icon></q-item-section>
|
||||
<q-item-section>削除する</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable @click="onDeleteAllNode">
|
||||
<q-item-section avatar><q-icon name="delete_sweep" ></q-icon></q-item-section>
|
||||
<q-item-section >以下すべて削除する</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-menu>
|
||||
</q-btn>
|
||||
</q-toolbar>
|
||||
<q-separator />
|
||||
<q-card-section>
|
||||
<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>
|
||||
<template v-if="hasBranch">
|
||||
<q-separator />
|
||||
<q-card-actions align="around">
|
||||
<q-btn flat v-for="(point, index) in node.outputPoints" :key="index">
|
||||
{{ point }}
|
||||
</q-btn>
|
||||
</q-card-actions>
|
||||
</template>
|
||||
</q-card>
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="hasBranch">
|
||||
<div class="row justify-center" :style="{ marginLeft: node.inputPoint !== '' ? '240px' : '' }">
|
||||
<div v-for="(point, index) in node.outputPoints" :key="index">
|
||||
<node-line :action-node="node" :mode="getMode(point)" @addNode="addNode" :input-point="point"></node-line>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="!hasBranch">
|
||||
<div class="row justify-center" :style="{ marginLeft: node.inputPoint !== '' ? '240px' : '' }">
|
||||
<node-line :action-node="node" :mode="getMode('')" @addNode="addNode" input-point=""></node-line>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, ref } from 'vue';
|
||||
import { IActionNode } from '../../types/ActionTypes';
|
||||
import NodeLine, { Direction } from '../main/NodeLine.vue';
|
||||
export default defineComponent({
|
||||
name: 'NodeItem',
|
||||
components: {
|
||||
NodeLine
|
||||
},
|
||||
props: {
|
||||
actionNode: {
|
||||
type: Object as () => IActionNode,
|
||||
required: true
|
||||
},
|
||||
isSelected: {
|
||||
type: Boolean
|
||||
}
|
||||
},
|
||||
emits: [
|
||||
'addNode',
|
||||
"nodeSelected",
|
||||
"nodeEdit",
|
||||
"deleteNode",
|
||||
"deleteAllNextNodes",
|
||||
],
|
||||
setup(props, context) {
|
||||
const hasBranch = computed(() => props.actionNode.outputPoints.length > 0);
|
||||
const nodeStyle = computed(() => {
|
||||
return {
|
||||
'root-node': props.actionNode.isRoot,
|
||||
'text-white': props.actionNode.isRoot,
|
||||
'selected': props.isSelected && !props.actionNode.isRoot
|
||||
};
|
||||
});
|
||||
const getMode = (point: string) => {
|
||||
if (point === '' || props.actionNode.outputPoints.length === 0) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* アクションノード追加イベントを
|
||||
* @param point 入力ポイント
|
||||
*/
|
||||
const addNode = (point: string) => {
|
||||
context.emit('addNode', props.actionNode, point);
|
||||
}
|
||||
/**
|
||||
* ノード選択状態
|
||||
*/
|
||||
const onNodeClick = () => {
|
||||
context.emit('nodeSelected', props.actionNode);
|
||||
}
|
||||
|
||||
const onEditNode=()=>{
|
||||
context.emit('nodeEdit', props.actionNode);
|
||||
}
|
||||
/**
|
||||
* ノードを削除する
|
||||
*/
|
||||
const onDeleteNode=()=>{
|
||||
context.emit('deleteNode', props.actionNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* ノードの以下すべて削除する
|
||||
*/
|
||||
const onDeleteAllNode=()=>{
|
||||
context.emit('deleteAllNextNodes', props.actionNode);
|
||||
};
|
||||
/**
|
||||
* 変数名取得
|
||||
*/
|
||||
const varName =(node:IActionNode)=>{
|
||||
const prop = node.actionProps.find((prop) => prop.props.name === "verName");
|
||||
return prop?.props.modelValue;
|
||||
};
|
||||
return {
|
||||
node: props.actionNode,
|
||||
isRoot: props.actionNode.isRoot,
|
||||
hasBranch,
|
||||
nodeStyle,
|
||||
getMode,
|
||||
addNode,
|
||||
onNodeClick,
|
||||
onEditNode,
|
||||
onDeleteNode,
|
||||
onDeleteAllNode,
|
||||
varName
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.action-node {
|
||||
min-width: 300px !important;
|
||||
}
|
||||
|
||||
.line {
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.line:after {
|
||||
content: '';
|
||||
background-color: $blue-7;
|
||||
display: block;
|
||||
width: 3px;
|
||||
}
|
||||
|
||||
.add-icon {
|
||||
font-size: 2em;
|
||||
color: $blue-7;
|
||||
}
|
||||
|
||||
.root-node {
|
||||
background-color: $blue-7;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.action-node:not(.root-node):hover{
|
||||
background-color: $light-blue-1;
|
||||
}
|
||||
|
||||
.selected{
|
||||
background-color: $yellow-1;
|
||||
}
|
||||
</style>
|
||||
109
frontend/src/components/main/NodeLine.vue
Normal file
109
frontend/src/components/main/NodeLine.vue
Normal file
@@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<div>
|
||||
<svg class="node-line">
|
||||
<polyline :points="points.linePoints" class="line" ></polyline>
|
||||
<text class="add-icon" @click="addNode(node)" :x="points.iconPoint.x" :y="points.iconPoint.y" font-family="Arial" font-size="25"
|
||||
text-anchor="middle" dy=".3em" style="cursor: pointer;" >
|
||||
⊕
|
||||
</text>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { ref, defineComponent, computed, PropType } from 'vue';
|
||||
import { IActionNode, ActionNode, ActionFlow, RootAction } from '../../types/ActionTypes';
|
||||
export enum Direction {
|
||||
Default = "None",
|
||||
Left = "LEFT",
|
||||
Right = "RIGHT",
|
||||
LeftNotNext = "LEFTNOTNEXT",
|
||||
RightNotNext = "RIGHTNOTNEXT",
|
||||
}
|
||||
export default defineComponent({
|
||||
name: 'NodeLine',
|
||||
props: {
|
||||
actionNode: {
|
||||
type: Object as PropType<IActionNode>,
|
||||
required: true
|
||||
},
|
||||
mode: {
|
||||
type: String as PropType<Direction>,
|
||||
required: true
|
||||
},
|
||||
inputPoint:{
|
||||
type:String
|
||||
}
|
||||
},
|
||||
emits: ['addNode'],
|
||||
setup(props,context) {
|
||||
const hasBranch = computed(() => props.actionNode.outputPoints.length > 0);
|
||||
const points = computed(() => {
|
||||
switch (props.mode) {
|
||||
case Direction.Left:
|
||||
return {
|
||||
linePoints: '180, 0, 180, 40, 120, 40, 120, 60',
|
||||
iconPoint: { x: 180, y: 20 }
|
||||
};
|
||||
case Direction.Right:
|
||||
return {
|
||||
linePoints: '60, 0, 60, 40, 120, 40, 120, 60',
|
||||
iconPoint: { x: 60, y: 20 }
|
||||
};
|
||||
case Direction.LeftNotNext:
|
||||
return {
|
||||
linePoints: '180, 0, 180, 40',
|
||||
iconPoint: { x: 180, y: 20 }
|
||||
};
|
||||
case Direction.RightNotNext:
|
||||
return {
|
||||
linePoints: '60, 0, 60, 40',
|
||||
iconPoint: { x: 60, y: 30 }
|
||||
};
|
||||
default:
|
||||
return {
|
||||
linePoints: '120, 0, 120, 60',
|
||||
iconPoint: { x: 120, y: 30 }
|
||||
};
|
||||
}
|
||||
});
|
||||
const addNode=(prveNode:IActionNode)=>{
|
||||
context.emit('addNode',props.inputPoint);
|
||||
}
|
||||
|
||||
return {
|
||||
node: props.actionNode,
|
||||
hasBranch,
|
||||
points,
|
||||
addNode
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.node-line {
|
||||
height: 60px;
|
||||
width: 240px;
|
||||
}
|
||||
|
||||
.line {
|
||||
stroke: $blue-7;
|
||||
fill: none;
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
.add-icon {
|
||||
stroke: $blue-8;
|
||||
fill: $blue-8;
|
||||
font-family: Arial;
|
||||
pointer-events: all;
|
||||
font-size: 2.0em;
|
||||
}
|
||||
|
||||
.add-icon:hover{
|
||||
stroke: $blue-8;
|
||||
fill:$blue-8;
|
||||
font-weight: bold;
|
||||
font-size: 2.4em;
|
||||
}
|
||||
</style>
|
||||
@@ -32,4 +32,3 @@ export interface AppInfo {
|
||||
creator?:User;
|
||||
modifier?:User;
|
||||
}
|
||||
|
||||
|
||||
57
frontend/src/components/right/ActionProperty.vue
Normal file
57
frontend/src/components/right/ActionProperty.vue
Normal file
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-for="(item, index) in componentData" :key="index">
|
||||
<component :is="item.component" v-bind="item.props" v-model="item.props.modelValue"></component>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import InputText from '../right/InputText.vue';
|
||||
import SelectBox from '../right/SelectBox.vue';
|
||||
import DatePicker from '../right/DatePicker.vue';
|
||||
import FieldInput from '../right/FieldInput.vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ActionProperty',
|
||||
components: {
|
||||
InputText,
|
||||
SelectBox,
|
||||
DatePicker,
|
||||
FieldInput
|
||||
},
|
||||
props: {
|
||||
jsonData: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
jsonValue:{
|
||||
type: Object,
|
||||
required: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
componentData() {
|
||||
return this.jsonData.elements.map((element: any) => {
|
||||
if(this.jsonValue != undefined )
|
||||
{
|
||||
if(this.jsonValue.hasOwnProperty(element.props.name))
|
||||
{
|
||||
element.props.modelValue = this.jsonValue[element.props.name];
|
||||
}
|
||||
else
|
||||
{
|
||||
element.props.modelValue = '';
|
||||
}
|
||||
|
||||
}
|
||||
return {
|
||||
component: element.component,
|
||||
props: element.props,
|
||||
};
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
95
frontend/src/components/right/ConditionInput.vue
Normal file
95
frontend/src/components/right/ConditionInput.vue
Normal file
@@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<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" @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>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref ,watchEffect,computed,reactive} from 'vue';
|
||||
import { ConditionTree,GroupNode,ConditionNode,LogicalOperator,Operator } from 'app/src/types/Conditions';
|
||||
import ConditionEditor from '../ConditionEditor/ConditionEditor.vue'
|
||||
export default defineComponent({
|
||||
name: 'FieldInput',
|
||||
components: {
|
||||
ConditionEditor
|
||||
},
|
||||
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 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({},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') {
|
||||
const conditionJson = tree.toJson();
|
||||
isSetted.value=true;
|
||||
emit('update:modelValue', conditionJson);
|
||||
}
|
||||
};
|
||||
|
||||
watchEffect(() => {
|
||||
const conditionJson = tree.toJson();
|
||||
emit('update:modelValue', conditionJson);
|
||||
});
|
||||
|
||||
return {
|
||||
appDg,
|
||||
isSetted,
|
||||
show,
|
||||
showDg,
|
||||
onClosed,
|
||||
tree,
|
||||
conditionString
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
57
frontend/src/components/right/DatePicker.vue
Normal file
57
frontend/src/components/right/DatePicker.vue
Normal file
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
|
||||
<q-input v-model="selectedDate" :label="displayName" :placeholder="placeholder" label-color="primary" mask="date" :rules="['date']" stack-label>
|
||||
<template v-slot:append>
|
||||
<q-icon name="event" class="cursor-pointer">
|
||||
<q-popup-proxy cover transition-show="scale" transition-hide="scale">
|
||||
<q-date v-model="selectedDate">
|
||||
<div class="row items-center justify-end">
|
||||
<q-btn v-close-popup label="Close" color="primary" flat />
|
||||
</div>
|
||||
</q-date>
|
||||
</q-popup-proxy>
|
||||
</q-icon>
|
||||
</template>
|
||||
</q-input>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref ,watchEffect} from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'DatePicker',
|
||||
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 selectedDate = ref(props.modelValue);
|
||||
|
||||
watchEffect(() => {
|
||||
emit('update:modelValue', selectedDate.value);
|
||||
});
|
||||
|
||||
return {
|
||||
selectedDate
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
98
frontend/src/components/right/FieldInput.vue
Normal file
98
frontend/src/components/right/FieldInput.vue
Normal file
@@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<q-field v-model="selectedField" :label="displayName" labelColor="primary"
|
||||
:clearable="isSelected" stack-label :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">
|
||||
<div> 項目コード:<q-chip size="sm" outline color="secondary" text-color="white">{{selectedField.code}}</q-chip></div>
|
||||
</template> -->
|
||||
<template v-slot:hint v-if="!isSelected">
|
||||
{{ placeholder }}
|
||||
</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" widht="400px">
|
||||
<field-select ref="appDg" name="フィールド" type="single" :appId="store.appInfo?.appId"></field-select>
|
||||
</show-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref ,watchEffect,computed} from 'vue';
|
||||
import ShowDialog from '../ShowDialog.vue';
|
||||
import FieldSelect from '../FieldSelect.vue';
|
||||
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||
interface IField{
|
||||
name:string,
|
||||
code:string,
|
||||
type:string
|
||||
}
|
||||
export default defineComponent({
|
||||
name: 'FieldInput',
|
||||
components: {
|
||||
ShowDialog,
|
||||
FieldSelect,
|
||||
},
|
||||
props: {
|
||||
displayName:{
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
name:{
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
hint:{
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
modelValue: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
},
|
||||
|
||||
setup(props, { emit }) {
|
||||
const appDg = ref();
|
||||
const show = ref(false);
|
||||
const selectedField = ref(props.modelValue);
|
||||
const store = useFlowEditorStore();
|
||||
const isSelected = computed(()=>{
|
||||
return selectedField.value!==null && typeof selectedField.value === 'object' && ('name' in selectedField.value)
|
||||
});
|
||||
|
||||
const showDg = () => {
|
||||
show.value = true;
|
||||
};
|
||||
|
||||
const closeDg = (val:string) => {
|
||||
if (val == 'OK') {
|
||||
selectedField.value = appDg.value.selected[0];
|
||||
}
|
||||
};
|
||||
|
||||
watchEffect(() => {
|
||||
emit('update:modelValue', selectedField.value);
|
||||
});
|
||||
|
||||
return {
|
||||
store,
|
||||
appDg,
|
||||
show,
|
||||
showDg,
|
||||
closeDg,
|
||||
selectedField,
|
||||
isSelected
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
45
frontend/src/components/right/InputText.vue
Normal file
45
frontend/src/components/right/InputText.vue
Normal file
@@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<q-input :label="displayName" v-model="inputValue" label-color="primary" :placeholder="placeholder" stack-label/>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent,ref,watchEffect } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'InputText',
|
||||
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>
|
||||
45
frontend/src/components/right/MuiltInputText.vue
Normal file
45
frontend/src/components/right/MuiltInputText.vue
Normal file
@@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<q-input :label="displayName" label-color="primary" v-model="inputValue" :placeholder="placeholder" autogrow stack-label/>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent,ref,watchEffect } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MuiltInputText',
|
||||
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>
|
||||
51
frontend/src/components/right/PropertyList.vue
Normal file
51
frontend/src/components/right/PropertyList.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-for="(item, index) in properties" :key="index" >
|
||||
<component :is="item.component" v-bind="item.props" v-model="item.props.modelValue"></component>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
/**
|
||||
* プロパティ属性設定生成する
|
||||
*/
|
||||
import { PropType, defineComponent,ref } from 'vue';
|
||||
import InputText from '../right/InputText.vue';
|
||||
import SelectBox from '../right/SelectBox.vue';
|
||||
import DatePicker from '../right/DatePicker.vue';
|
||||
import FieldInput from '../right/FieldInput.vue';
|
||||
import MuiltInputText from '../right/MuiltInputText.vue';
|
||||
import ConditionInput from '../right/ConditionInput.vue';
|
||||
import { IActionNode,IActionProperty } from 'src/types/ActionTypes';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'PropertyList',
|
||||
components: {
|
||||
InputText,
|
||||
SelectBox,
|
||||
DatePicker,
|
||||
FieldInput,
|
||||
MuiltInputText,
|
||||
ConditionInput
|
||||
},
|
||||
props: {
|
||||
nodeProps: {
|
||||
type: Object as PropType<Array<IActionProperty>>,
|
||||
required: true,
|
||||
},
|
||||
jsonValue:{
|
||||
type: Object,
|
||||
required: false,
|
||||
}
|
||||
},
|
||||
setup(props, context) {
|
||||
const properties=ref(props.nodeProps)
|
||||
return {
|
||||
properties
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
</style>
|
||||
80
frontend/src/components/right/PropertyPanel.vue
Normal file
80
frontend/src/components/right/PropertyPanel.vue
Normal file
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<div class="q-pa-md q-gutter-sm">
|
||||
<q-drawer
|
||||
side="right"
|
||||
:show-if-above="false"
|
||||
bordered
|
||||
:width="301"
|
||||
:breakpoint="500"
|
||||
class="bg-grey-3"
|
||||
:model-value="showPanel"
|
||||
elevated
|
||||
overlay
|
||||
>
|
||||
<q-card class="column full-height" style="width: 300px">
|
||||
<q-card-section>
|
||||
<div class="text-h6">{{ actionNode.subTitle }}:設定</div>
|
||||
</q-card-section>
|
||||
<q-card-section class="col q-pt-none">
|
||||
<property-list :node-props="actionProps" v-if="showPanel" ></property-list>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions align="right" class="bg-white text-teal">
|
||||
<q-btn flat label="キャンセル" @click="cancel" outline dense padding="none sm" color="primary"/>
|
||||
<q-btn flat label="更新" @click="save" outline dense padding="none sm" color="primary" />
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-drawer>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { ref,defineComponent, PropType ,watchEffect} from 'vue'
|
||||
import PropertyList from 'components/right/PropertyList.vue';
|
||||
import { IActionNode } from 'src/types/ActionTypes';
|
||||
export default defineComponent({
|
||||
name: 'PropertyPanel',
|
||||
components: {
|
||||
PropertyList
|
||||
},
|
||||
props: {
|
||||
actionNode:{
|
||||
type:Object as PropType<IActionNode>,
|
||||
required:true
|
||||
},
|
||||
drawerRight:{
|
||||
type:Boolean,
|
||||
required:true
|
||||
}
|
||||
},
|
||||
emits: [
|
||||
'update:drawerRight'
|
||||
],
|
||||
setup(props,{emit}) {
|
||||
const showPanel =ref(props.drawerRight);
|
||||
const actionProps =ref(props.actionNode.actionProps);
|
||||
watchEffect(() => {
|
||||
showPanel.value = props.drawerRight;
|
||||
actionProps.value= props.actionNode.actionProps;
|
||||
});
|
||||
|
||||
const cancel = async() =>{
|
||||
showPanel.value = false;
|
||||
emit('update:drawerRight',false )
|
||||
}
|
||||
|
||||
const save = async () =>{
|
||||
showPanel.value=false;
|
||||
emit('update:drawerRight',false )
|
||||
}
|
||||
|
||||
return {
|
||||
cancel,
|
||||
save,
|
||||
actionProps,
|
||||
showPanel
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
</style>
|
||||
40
frontend/src/components/right/SelectBox.vue
Normal file
40
frontend/src/components/right/SelectBox.vue
Normal file
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<q-select v-model="selectedValue" :label="displayName" :options="options"/>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent,ref,watchEffect } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SelectBox',
|
||||
props: {
|
||||
displayName:{
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
options: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const selectedValue = ref(props.modelValue);
|
||||
|
||||
watchEffect(() => {
|
||||
emit('update:modelValue', selectedValue.value);
|
||||
});
|
||||
|
||||
return {
|
||||
selectedValue
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
57
frontend/src/control/flowctrl.ts
Normal file
57
frontend/src/control/flowctrl.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { api } from 'boot/axios';
|
||||
import { ActionFlow } from 'src/types/ActionTypes';
|
||||
|
||||
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 [];
|
||||
}
|
||||
|
||||
for(const flow of result.data){
|
||||
flows.push(ActionFlow.fromJSON(flow.content));
|
||||
}
|
||||
return flows;
|
||||
}catch(error){
|
||||
console.error(error);
|
||||
return flows;
|
||||
}
|
||||
}
|
||||
|
||||
async SaveFlow(jsonData:any):Promise<boolean>
|
||||
{
|
||||
const result = await api.post('api/flow',jsonData);
|
||||
console.info(result.data)
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* フローを更新する
|
||||
* @param jsonData
|
||||
* @returns
|
||||
*/
|
||||
async UpdateFlow(jsonData:any):Promise<boolean>
|
||||
{
|
||||
const result = await api.put('api/flow/' + jsonData.flowid,jsonData);
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,9 +11,11 @@
|
||||
@click="toggleLeftDrawer"
|
||||
/>
|
||||
<q-toolbar-title>
|
||||
Kintone App Builder
|
||||
<q-badge align="top" outline>V{{ env.version }}</q-badge>
|
||||
{{ productName }}
|
||||
<q-badge align="top" outline>V{{ version }}</q-badge>
|
||||
</q-toolbar-title>
|
||||
<domain-selector></domain-selector>
|
||||
<q-btn flat round dense icon="logout" @click="authStore.logout()"/>
|
||||
</q-toolbar>
|
||||
</q-header>
|
||||
|
||||
@@ -26,7 +28,7 @@
|
||||
<q-item-label
|
||||
header
|
||||
>
|
||||
Essential Links
|
||||
関連リンク
|
||||
</q-item-label>
|
||||
|
||||
<EssentialLink
|
||||
@@ -46,6 +48,10 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from '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[] = [
|
||||
{
|
||||
@@ -56,10 +62,17 @@ const essentialLinks: EssentialLinkProps[] = [
|
||||
target:'_self'
|
||||
},
|
||||
{
|
||||
title: 'ルールエディター',
|
||||
caption: 'rule',
|
||||
icon: 'rule',
|
||||
link: '/#/ruleEditor',
|
||||
title: 'フローエディター',
|
||||
caption: 'flowChart',
|
||||
icon: 'account_tree',
|
||||
link: '/#/FlowChart',
|
||||
target:'_self'
|
||||
},
|
||||
{
|
||||
title: '条件エディター',
|
||||
caption: 'condition',
|
||||
icon: 'tune',
|
||||
link: '/#/condition',
|
||||
target:'_self'
|
||||
},
|
||||
{
|
||||
@@ -139,8 +152,8 @@ const essentialLinks: EssentialLinkProps[] = [
|
||||
];
|
||||
|
||||
const leftDrawerOpen = ref(false)
|
||||
|
||||
const env=process.env;
|
||||
const version = process.env.version;
|
||||
const productName = process.env.productName;
|
||||
|
||||
function toggleLeftDrawer() {
|
||||
leftDrawerOpen.value = !leftDrawerOpen.value
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
|
||||
|
||||
export interface KintoneEvent{
|
||||
screen:string,
|
||||
type:string,
|
||||
name:string
|
||||
}
|
||||
|
||||
246
frontend/src/pages/FlowChart.vue
Normal file
246
frontend/src/pages/FlowChart.vue
Normal file
@@ -0,0 +1,246 @@
|
||||
<template>
|
||||
<q-page>
|
||||
<q-layout
|
||||
container
|
||||
class="absolute-full shadow-2 rounded-borders"
|
||||
>
|
||||
<div class="q-pa-sm q-gutter-sm ">
|
||||
<q-drawer
|
||||
side="left"
|
||||
:overlay="true"
|
||||
bordered
|
||||
v-model="drawerLeft"
|
||||
:show-if-above="false"
|
||||
elevated
|
||||
>
|
||||
<div class="flex-center fixed-top app-selector" >
|
||||
<AppSelector />
|
||||
</div>
|
||||
|
||||
<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>
|
||||
<div class="q-pa-md q-gutter-sm">
|
||||
<div class="flowchart" v-if="store.currentFlow">
|
||||
<node-item v-for="(node,) in store.currentFlow.actionNodes" :key="node.id"
|
||||
:isSelected="node===state.activeNode" :actionNode="node"
|
||||
@addNode="addNode"
|
||||
@nodeSelected="onNodeSelected"
|
||||
@nodeEdit="onNodeEdit"
|
||||
@deleteNode="onDeleteNode"
|
||||
@deleteAllNextNodes="onDeleteAllNextNodes"
|
||||
></node-item>
|
||||
</div>
|
||||
</div>
|
||||
<PropertyPanel :actionNode="state.activeNode" v-model:drawerRight="drawerRight"></PropertyPanel>
|
||||
</q-layout>
|
||||
<ShowDialog v-model:visible="showAddAction" name="アクション" @close="closeDg" width="350px">
|
||||
<action-select ref="appDg" name="model" type="single"></action-select>
|
||||
</ShowDialog>
|
||||
|
||||
</q-page>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {ref,reactive,computed,onMounted} from 'vue';
|
||||
import {IActionNode, ActionNode, IActionFlow, ActionFlow,RootAction, IActionProperty } from 'src/types/ActionTypes';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||
import NodeItem from 'src/components/main/NodeItem.vue';
|
||||
import ShowDialog from 'components/ShowDialog.vue';
|
||||
import ActionSelect from 'components/ActionSelect.vue';
|
||||
import PropertyPanel from 'components/right/PropertyPanel.vue';
|
||||
import AppSelector from 'components/left/AppSelector.vue';
|
||||
import EventTree from 'components/left/EventTree.vue';
|
||||
import {FlowCtrl } from '../control/flowctrl';
|
||||
import { useQuasar } from 'quasar';
|
||||
const deployLoading = ref(false);
|
||||
const saveLoading = ref(false);
|
||||
|
||||
const drawerLeft = ref(false);
|
||||
const $q=useQuasar();
|
||||
const store = useFlowEditorStore();
|
||||
// ref関数を使ってtemplateとバインド
|
||||
const state=reactive({
|
||||
activeNode:{
|
||||
id:""
|
||||
},
|
||||
})
|
||||
const appDg = ref();
|
||||
const prevNodeIfo=ref({
|
||||
prevNode:{} as IActionNode,
|
||||
inputPoint:""
|
||||
});
|
||||
// const refFlow = ref<ActionFlow|null>(null);
|
||||
const showAddAction=ref(false);
|
||||
const drawerRight=ref(false);
|
||||
const model=ref("");
|
||||
const addActionNode=(action:IActionNode)=>{
|
||||
// refFlow.value?.actionNodes.push(action);
|
||||
store.currentFlow?.actionNodes.push(action);
|
||||
}
|
||||
|
||||
const addNode=(node:IActionNode,inputPoint:string)=>{
|
||||
if(drawerRight.value){
|
||||
drawerRight.value=false;
|
||||
}
|
||||
showAddAction.value=true;
|
||||
prevNodeIfo.value.prevNode=node;
|
||||
prevNodeIfo.value.inputPoint=inputPoint;
|
||||
}
|
||||
|
||||
const onNodeSelected=(node:IActionNode)=>{
|
||||
//右パネルが開いている場合、自動閉じる
|
||||
if(drawerRight.value && state.activeNode.id!==node.id){
|
||||
drawerRight.value=false;
|
||||
}
|
||||
state.activeNode = node;
|
||||
}
|
||||
|
||||
const onNodeEdit=(node:IActionNode)=>{
|
||||
state.activeNode = node;
|
||||
drawerRight.value=true;
|
||||
}
|
||||
|
||||
const onDeleteNode=(node:IActionNode)=>{
|
||||
if(!store.currentFlow) return;
|
||||
//右パネルが開いている場合、自動閉じる
|
||||
if(drawerRight.value && state.activeNode.id===node.id){
|
||||
drawerRight.value=false;
|
||||
}
|
||||
store.currentFlow?.removeNode(node);
|
||||
}
|
||||
|
||||
const onDeleteAllNextNodes=(node:IActionNode)=>{
|
||||
if(!store.currentFlow) return;
|
||||
//右パネルが開いている場合、自動閉じる
|
||||
if(drawerRight.value){
|
||||
drawerRight.value=false;
|
||||
}
|
||||
store.currentFlow?.removeAllNext(node.id);
|
||||
}
|
||||
const closeDg=(val :any)=>{
|
||||
console.log("Dialog closed->",val);
|
||||
if (val == 'OK') {
|
||||
const data = appDg.value.selected[0];
|
||||
const actionProps=JSON.parse(data.property);
|
||||
const outputPoint =JSON.parse(data.outputPoints);
|
||||
const action = new ActionNode(data.name,data.desc,"",outputPoint,actionProps);
|
||||
store.currentFlow?.addNode(action, prevNodeIfo.value.prevNode,prevNodeIfo.value.inputPoint);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* デプロイ
|
||||
*/
|
||||
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 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 actionFlows = await flowCtrl.getFlows(store.appInfo?.appId);
|
||||
if(actionFlows && actionFlows.length>0){
|
||||
store.setFlows(actionFlows);
|
||||
}
|
||||
if(actionFlows && actionFlows.length==1){
|
||||
store.selectFlow(actionFlows[0]);
|
||||
}
|
||||
const root =actionFlows[0].getRoot();
|
||||
if(root){
|
||||
state.activeNode=root;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.app-selector{
|
||||
padding:15px;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.flowchart{
|
||||
padding-top: 10px;
|
||||
}
|
||||
.flow-toolbar{
|
||||
opacity: 50%;
|
||||
}
|
||||
|
||||
.event-tree .q-drawer {
|
||||
top:50px;
|
||||
z-index: 999;
|
||||
}
|
||||
</style>
|
||||
102
frontend/src/pages/FlowChartTest.vue
Normal file
102
frontend/src/pages/FlowChartTest.vue
Normal file
@@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<q-page>
|
||||
|
||||
<div class="flowchart">
|
||||
<node-item v-for="(node,) in refFlow.actionNodes" :key="node.id"
|
||||
:isSelected="node===state.activeNode" :actionNode="node"
|
||||
@addNode="addNode"
|
||||
@nodeSelected="onNodeSelected"
|
||||
@nodeEdit="onNodeEdit"
|
||||
@deleteNode="onDeleteNode"
|
||||
@deleteAllNextNodes="onDeleteAllNextNodes"
|
||||
></node-item>
|
||||
</div>
|
||||
</q-page>
|
||||
<PropertyPanel :actionNode="state.activeNode" v-model:drawerRight="drawerRight"></PropertyPanel>
|
||||
<show-dialog v-model:visible="showAddAction" name="アクション" @close="closeDg" width="350px">
|
||||
<action-select ref="appDg" name="アクション" type="single"></action-select>
|
||||
</show-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {ref,reactive,computed} from 'vue';
|
||||
import {IActionNode, ActionNode, IActionFlow, ActionFlow,RootAction, IActionProperty } from 'src/types/ActionTypes';
|
||||
import NodeItem from 'src/components/main/NodeItem.vue';
|
||||
import ShowDialog from 'components/ShowDialog.vue';
|
||||
import ActionSelect from 'components/ActionSelect.vue';
|
||||
import PropertyPanel from 'components/right/PropertyPanel.vue';
|
||||
|
||||
|
||||
const rootNode:RootAction =new RootAction("app.record.create.submit","レコード追加画面","保存するとき");
|
||||
const actionFlow: ActionFlow = new ActionFlow(rootNode);
|
||||
const saibanProps:IActionProperty[]=[{
|
||||
component:"InputText",
|
||||
props:{
|
||||
displayName:"フォーマット",
|
||||
modelValue:"",
|
||||
name:"format",
|
||||
placeholder:"フォーマットを入力してください",
|
||||
}
|
||||
},{
|
||||
component:"FieldInput",
|
||||
props:{
|
||||
displayName:"採番項目",
|
||||
modelValue:"",
|
||||
name:"field",
|
||||
placeholder:"採番項目を選択してください",
|
||||
}
|
||||
}];
|
||||
|
||||
actionFlow.addNode(new ActionNode('自動採番','文書番号を自動採番する','',[],saibanProps));
|
||||
actionFlow.addNode(new ActionNode('入力データ取得','電話番号を取得する',''));
|
||||
const branchNode = actionFlow.addNode(new ActionNode('条件分岐','電話番号入力形式チャック','',['はい','いいえ'] ));
|
||||
// actionFlow.addNode(new ActionNode('入力データ取得','住所を取得する',''),branchNode,'はい');
|
||||
actionFlow.addNode(new ActionNode('エラー表示','エラー表示して保存しない',''),branchNode,'いいえ' );
|
||||
|
||||
// ref関数を使ってtemplateとバインド
|
||||
const state=reactive({
|
||||
activeNode:rootNode,
|
||||
})
|
||||
|
||||
const refFlow = ref(actionFlow);
|
||||
const showAddAction=ref(false);
|
||||
const drawerRight=ref(false);
|
||||
|
||||
const addActionNode=(action:IActionNode)=>{
|
||||
refFlow.value.actionNodes.push(action);
|
||||
}
|
||||
|
||||
const addNode=(node:IActionNode,inputPoint:string)=>{
|
||||
showAddAction.value=true;
|
||||
}
|
||||
|
||||
const onNodeSelected=(node:IActionNode)=>{
|
||||
//右パネルが開いている場合、自動閉じる
|
||||
if(drawerRight.value && state.activeNode.id!==node.id){
|
||||
drawerRight.value=false;
|
||||
}
|
||||
state.activeNode = node;
|
||||
}
|
||||
|
||||
const onNodeEdit=(node:IActionNode)=>{
|
||||
state.activeNode = node;
|
||||
drawerRight.value=true;
|
||||
}
|
||||
|
||||
const onDeleteNode=(node:IActionNode)=>{
|
||||
refFlow.value.removeNode(node);
|
||||
}
|
||||
|
||||
const onDeleteAllNextNodes=(node:IActionNode)=>{
|
||||
refFlow.value.removeAllNext(node.id);
|
||||
}
|
||||
const closeDg=(val :any)=>{
|
||||
console.log("Dialog closed->",val);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.flowchart{
|
||||
padding-top: 10px;
|
||||
}
|
||||
</style>
|
||||
122
frontend/src/pages/FlowEditorPage.vue
Normal file
122
frontend/src/pages/FlowEditorPage.vue
Normal file
@@ -0,0 +1,122 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="q-ma-md">
|
||||
<div class="q-gutter-xs row items-start">
|
||||
<q-breadcrumbs class="q-pt-xs q-mr-sm" active-color="black">
|
||||
<q-breadcrumbs-el icon="home" />
|
||||
<q-breadcrumbs-el :label="actName" />
|
||||
<q-breadcrumbs-el
|
||||
v-for="flowName in flowNames"
|
||||
:key="flowName"
|
||||
:label="flowName"
|
||||
/>
|
||||
|
||||
<q-breadcrumbs-el :label="flowNames1" />
|
||||
</q-breadcrumbs>
|
||||
<q-separator vertical class="q-mr-xs" />
|
||||
<q-btn
|
||||
unelevated
|
||||
class="q-py-sm"
|
||||
padding="none md none sm"
|
||||
color="blue-1"
|
||||
text-color="primary"
|
||||
size="md"
|
||||
@click="drawerLeft = !drawerLeft"
|
||||
label="変 更"
|
||||
icon="expand_more"
|
||||
dense
|
||||
/>
|
||||
|
||||
<q-space />
|
||||
<q-btn
|
||||
class="q-px-sm q-mr-sm"
|
||||
color="white"
|
||||
size="sm"
|
||||
text-color="black"
|
||||
label="キャンセル"
|
||||
dense
|
||||
/>
|
||||
|
||||
<q-btn
|
||||
class="q-px-sm"
|
||||
color="primary"
|
||||
size="sm"
|
||||
label="保存する"
|
||||
dense
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<q-layout
|
||||
container
|
||||
style="height: 91.5dvb"
|
||||
class="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">
|
||||
<div class="row q-pl-md">
|
||||
<p class="text-h6">アクション選択</p>
|
||||
</div>
|
||||
<ItemSelector :actName="actName" />
|
||||
</div>
|
||||
</q-card-section>
|
||||
</div>
|
||||
<q-separator />
|
||||
<div class="q-mt-md q-pa-sm">
|
||||
<q-card-section>
|
||||
<p class="text-h6 q-pl-md q-mb-none">フロー選択</p>
|
||||
<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';
|
||||
|
||||
const actName = ref('勤怠管理 - 4');
|
||||
const flowNames = ref(['レコードを追加画面', '保存をクリックした時']);
|
||||
|
||||
const drawerLeft = ref(false);
|
||||
const store = useFlowEditorStore();
|
||||
const { flowNames1 } = storeToRefs(store);
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="sass"></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>
|
||||
@@ -9,7 +9,7 @@
|
||||
</div>
|
||||
<div style="min-height: 100vh;">
|
||||
<div class="q-pa-md">
|
||||
<!-- <q-btn-dropdown split color="primary" label="ルール新規作成" size="lg">
|
||||
<q-btn-dropdown split color="primary" label="ルール新規作成" size="lg">
|
||||
<q-list>
|
||||
<q-item v-for="action in actions" clickable v-close-popup @click="onItemClick" :key="action">
|
||||
<q-item-section>
|
||||
@@ -17,12 +17,12 @@
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-btn-dropdown> -->
|
||||
</q-btn-dropdown>
|
||||
</div>
|
||||
<div class="q-pa-md">
|
||||
<q-select v-model="model" :options="options" label="ダイアログ選択"/>
|
||||
<q-select v-model="model" :options="options" label="Standard"/>
|
||||
<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=='アプリ'">
|
||||
<app-select ref="appDg" :name="model" type="single"></app-select>
|
||||
</template>
|
||||
|
||||
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>
|
||||
96
frontend/src/pages/testFlow.vue
Normal file
96
frontend/src/pages/testFlow.vue
Normal file
@@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<div class="q-pa-md q-gutter-sm">
|
||||
<q-btn label="プロパティ" icon="keyboard_arrow_right" color="primary" @click="open('right')" />
|
||||
<!-- <q-btn label="Readプロパティ" icon="keyboard_arrow_right" color="primary" @click="write('right')" /> -->
|
||||
|
||||
<q-dialog v-model="dialog" :position="position">
|
||||
<q-card class="column full-height" style="width: 300px">
|
||||
<q-card-section>
|
||||
<div class="text-h6">プロパティ</div>
|
||||
</q-card-section>
|
||||
|
||||
|
||||
<q-card-section class="col q-pt-none">
|
||||
<ActionProperty :jsonData="jsonData" :jsonValue="jsonValue"/>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions align="right" class="bg-white text-teal">
|
||||
<q-btn flat label="Save" v-close-popup @click="save"/>
|
||||
<q-btn flat label="Cancel" v-close-popup />
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref,onMounted } from 'vue'
|
||||
import ActionProperty from 'components/right/ActionProperty.vue';
|
||||
const dialog = ref(false)
|
||||
const position = ref('top')
|
||||
|
||||
const jsonData = {
|
||||
elements: [
|
||||
{
|
||||
component: 'InputText',
|
||||
props: {
|
||||
name:'1',
|
||||
placeholder: 'Enter some text',
|
||||
modelValue: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'SelectBox',
|
||||
props: {
|
||||
name:'2',
|
||||
placeholder: 'Choose an option',
|
||||
modelValue: '',
|
||||
options: [
|
||||
'option1',
|
||||
'option2',
|
||||
'option3'
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'DatePicker',
|
||||
props: {
|
||||
name:'3',
|
||||
placeholder: 'Choose a date',
|
||||
modelValue: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'FieldInput',
|
||||
props: {
|
||||
name:'4',
|
||||
placeholder: 'Choose a field',
|
||||
modelValue: '',
|
||||
},
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
let jsonValue = {
|
||||
1:'abc',
|
||||
2:'option2',
|
||||
3:'2023/09/04',
|
||||
4:'6666'
|
||||
};
|
||||
|
||||
const open = (pos:string) => {
|
||||
position.value = pos
|
||||
dialog.value = true
|
||||
};
|
||||
|
||||
const save = async () =>{
|
||||
|
||||
jsonData.elements.forEach(property => {
|
||||
if(jsonValue != undefined)
|
||||
{
|
||||
jsonValue[property.props.name] = property.props.modelValue;
|
||||
}
|
||||
});
|
||||
console.log(jsonValue);
|
||||
|
||||
}
|
||||
</script>
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="q-pa-md column content-center items-center">
|
||||
<div>
|
||||
<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>
|
||||
</show-dialog>
|
||||
</div>
|
||||
|
||||
101
frontend/src/pages/testRight.vue
Normal file
101
frontend/src/pages/testRight.vue
Normal file
@@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<div class="q-pa-md q-gutter-sm">
|
||||
<q-btn label="プロパティ" icon="keyboard_arrow_right" color="primary" @click="drawerRight = !drawerRight" />
|
||||
<!-- <q-btn label="Readプロパティ" icon="keyboard_arrow_right" color="primary" @click="write('right')" /> -->
|
||||
<q-drawer
|
||||
side="right"
|
||||
v-model="drawerRight"
|
||||
show-if-above
|
||||
bordered
|
||||
:width="301"
|
||||
:breakpoint="500"
|
||||
class="bg-grey-3"
|
||||
>
|
||||
<q-card class="column full-height" style="width: 300px">
|
||||
<q-card-section>
|
||||
<div class="text-h6">プロパティ</div>
|
||||
</q-card-section>
|
||||
|
||||
|
||||
<q-card-section class="col q-pt-none">
|
||||
<ActionProperty :jsonData="jsonData" :jsonValue="jsonValue" v-if="drawerRight"/>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions align="right" class="bg-white text-teal">
|
||||
<q-btn flat label="Save" @click="save"/>
|
||||
<q-btn flat label="Cancel" @click="cancel" />
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-drawer>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref } from 'vue'
|
||||
import ActionProperty from 'components/right/ActionProperty.vue';
|
||||
const drawerRight = ref(false);
|
||||
const jsonData = {
|
||||
elements: [
|
||||
{
|
||||
component: 'InputText',
|
||||
props: {
|
||||
name:'1',
|
||||
placeholder: 'Enter some text',
|
||||
modelValue: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'SelectBox',
|
||||
props: {
|
||||
name:'2',
|
||||
placeholder: 'Choose an option',
|
||||
modelValue: '',
|
||||
options: [
|
||||
'option1',
|
||||
'option2',
|
||||
'option3'
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'DatePicker',
|
||||
props: {
|
||||
name:'3',
|
||||
placeholder: 'Choose a date',
|
||||
modelValue: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'FieldInput',
|
||||
props: {
|
||||
name:'4',
|
||||
placeholder: 'Choose a field',
|
||||
modelValue: '',
|
||||
},
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
let jsonValue = {
|
||||
1:'abc',
|
||||
2:'option2',
|
||||
3:'2023/09/04',
|
||||
4:'6666'
|
||||
};
|
||||
|
||||
const cancel = async() =>{
|
||||
drawerRight.value = false;
|
||||
}
|
||||
|
||||
const save = async () =>{
|
||||
|
||||
jsonData.elements.forEach(property => {
|
||||
if(jsonValue != undefined)
|
||||
{
|
||||
jsonValue[property.props.name] = property.props.modelValue;
|
||||
}
|
||||
});
|
||||
console.log(jsonValue);
|
||||
drawerRight.value=false;
|
||||
|
||||
}
|
||||
</script>
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
} from 'vue-router';
|
||||
|
||||
import routes from './routes';
|
||||
|
||||
import { useAuthStore } from 'stores/useAuthStore';
|
||||
/*
|
||||
* If not building with SSR mode, you can
|
||||
* directly export the Router instantiation;
|
||||
@@ -17,20 +17,60 @@ import routes from './routes';
|
||||
* with the Router instance.
|
||||
*/
|
||||
|
||||
export default route(function (/* { store, ssrContext } */) {
|
||||
const createHistory = process.env.SERVER
|
||||
? createMemoryHistory
|
||||
: (process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory);
|
||||
const createHistory = process.env.SERVER
|
||||
? createMemoryHistory
|
||||
: (process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory);
|
||||
|
||||
const Router = createRouter({
|
||||
scrollBehavior: () => ({ left: 0, top: 0 }),
|
||||
routes,
|
||||
const routerInstance = 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),
|
||||
});
|
||||
|
||||
return Router;
|
||||
// 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 } */) {
|
||||
|
||||
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;
|
||||
// });
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,21 +2,27 @@ import { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: '/',
|
||||
component: () => import('layouts/MainLayout.vue'),
|
||||
children: [{ path: '', component: () => import('pages/IndexPage.vue') }],
|
||||
},
|
||||
{
|
||||
path: '/ruleEditor/',
|
||||
component: () => import('layouts/MainLayout.vue'),
|
||||
children: [{ path: '', component: () => import('pages/RuleEditor.vue') }],
|
||||
},
|
||||
{
|
||||
path: '/test/',
|
||||
component: () => import('layouts/MainLayout.vue'),
|
||||
children: [{ path: '', component: () => import('pages/testQursar.vue') }],
|
||||
path: '/login',
|
||||
component: () => import('pages/LoginPage.vue')
|
||||
},
|
||||
|
||||
{
|
||||
path: '/',
|
||||
component: () => import('layouts/MainLayout.vue'),
|
||||
children: [
|
||||
{ path: '', component: () => import('pages/IndexPage.vue') },
|
||||
{ path: 'ruleEditor', component: () => import('pages/RuleEditor.vue') },
|
||||
{ path: 'test', component: () => import('pages/testQursar.vue') },
|
||||
{ path: 'flow', component: () => import('pages/testFlow.vue') },
|
||||
{ path: 'FlowChartTest', component: () => import('pages/FlowChartTest.vue') },
|
||||
{ path: 'flowEditor', component: () => import('pages/FlowEditorPage.vue') },
|
||||
{ path: 'FlowChart', component: () => import('pages/FlowChart.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,
|
||||
// but you can also remove it
|
||||
{
|
||||
|
||||
112
frontend/src/stores/flowEditor.ts
Normal file
112
frontend/src/stores/flowEditor.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { AppInfo ,IActionFlow} from 'src/types/ActionTypes';
|
||||
import { kintoneEvents,IKintoneEvent,KintoneEventManager } from 'src/types/KintoneEvents';
|
||||
import {FlowCtrl } from '../control/flowctrl';
|
||||
|
||||
export interface FlowEditorState{
|
||||
flowNames1:string;
|
||||
appInfo?:AppInfo;
|
||||
flows?:IActionFlow[];
|
||||
selectedFlow?:IActionFlow|undefined;
|
||||
eventTree:KintoneEventManager;
|
||||
selectedEvent:IKintoneEvent|undefined;
|
||||
expandedScreen:any[];
|
||||
}
|
||||
const flowCtrl=new FlowCtrl();
|
||||
export const useFlowEditorStore = defineStore("flowEditor",{
|
||||
state: ():FlowEditorState => ({
|
||||
flowNames1: '',
|
||||
appInfo:undefined,
|
||||
flows:[],
|
||||
selectedFlow:undefined,
|
||||
eventTree:kintoneEvents,
|
||||
selectedEvent:undefined,
|
||||
expandedScreen:[]
|
||||
}),
|
||||
getters: {
|
||||
/**
|
||||
*
|
||||
* @returns 現在編集しているフロー
|
||||
*/
|
||||
currentFlow():IActionFlow|undefined{
|
||||
return this.selectedFlow;
|
||||
},
|
||||
/**
|
||||
* KintoneイベントIDから、バンドしているフローを検索する
|
||||
* @param state
|
||||
* @returns
|
||||
*/
|
||||
findFlowByEventId(state){
|
||||
return (eventId:string)=>{
|
||||
return state.flows?.find((flow)=>{
|
||||
const root=flow.getRoot();
|
||||
return root?.name===eventId
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
setFlows(flows:IActionFlow[]){
|
||||
this.flows=flows;
|
||||
},
|
||||
selectFlow(flow:IActionFlow){
|
||||
this.selectedFlow=flow;
|
||||
},
|
||||
setApp(app:AppInfo){
|
||||
this.appInfo=app;
|
||||
},
|
||||
/**
|
||||
* DBからフルーを保存する
|
||||
* @returns
|
||||
*/
|
||||
async loadFlow(){
|
||||
if(this.appInfo===undefined) return;
|
||||
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 deploy():Promise<boolean>{
|
||||
if(this.appInfo===undefined){
|
||||
return false;
|
||||
}
|
||||
return await flowCtrl.depoly(this.appInfo?.appId);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
32
frontend/src/stores/index.ts
Normal file
32
frontend/src/stores/index.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { store } from 'quasar/wrappers'
|
||||
import { createPinia } from 'pinia'
|
||||
import { Router } from 'vue-router';
|
||||
|
||||
/*
|
||||
* When adding new properties to stores, you should also
|
||||
* extend the `PiniaCustomProperties` interface.
|
||||
* @see https://pinia.vuejs.org/core-concepts/plugins.html#typing-new-store-properties
|
||||
*/
|
||||
declare module 'pinia' {
|
||||
export interface PiniaCustomProperties {
|
||||
readonly router: Router;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If not building with SSR mode, you can
|
||||
* directly export the Store instantiation;
|
||||
*
|
||||
* The function below can be async too; either use
|
||||
* async/await or return a Promise which resolves
|
||||
* with the Store instance.
|
||||
*/
|
||||
|
||||
export default store((/* { ssrContext } */) => {
|
||||
const pinia = createPinia()
|
||||
|
||||
// You can add Pinia plugins here
|
||||
// pinia.use(SomePiniaPlugin)
|
||||
|
||||
return pinia
|
||||
})
|
||||
10
frontend/src/stores/store-flag.d.ts
vendored
Normal file
10
frontend/src/stores/store-flag.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/* eslint-disable */
|
||||
// THIS FEATURE-FLAG FILE IS AUTOGENERATED,
|
||||
// REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING
|
||||
import "quasar/dist/types/feature-flag";
|
||||
|
||||
declare module "quasar/dist/types/feature-flag" {
|
||||
interface QuasarFeatureFlags {
|
||||
store: true;
|
||||
}
|
||||
}
|
||||
19
frontend/src/stores/testStore.ts
Normal file
19
frontend/src/stores/testStore.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { defineStore } from 'pinia';
|
||||
|
||||
export const useCounterStore = defineStore('counter', {
|
||||
state: () => ({
|
||||
counter: 0
|
||||
}),
|
||||
|
||||
getters: {
|
||||
doubleCount (state) {
|
||||
return state.counter * 2;
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
increment () {
|
||||
this.counter++;
|
||||
}
|
||||
}
|
||||
});
|
||||
81
frontend/src/stores/useAuthStore.ts
Normal file
81
frontend/src/stores/useAuthStore.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
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;
|
||||
}
|
||||
|
||||
export const useAuthStore = defineStore({
|
||||
id: 'auth',
|
||||
state: ():IUserState =>{
|
||||
const token=localStorage.getItem('token')||'';
|
||||
if(token!==''){
|
||||
api.defaults.headers["Authorization"]='Bearer ' + token;
|
||||
}
|
||||
return {
|
||||
token,
|
||||
returnUrl: '',
|
||||
currentDomain: JSON.parse(localStorage.getItem('currentDomain')||"{}")
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
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));
|
||||
}
|
||||
}
|
||||
});
|
||||
434
frontend/src/types/ActionTypes.ts
Normal file
434
frontend/src/types/ActionTypes.ts
Normal file
@@ -0,0 +1,434 @@
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
export interface IDomainInfo{
|
||||
id:number;
|
||||
domainName:string;
|
||||
kintoneUrl:string;
|
||||
}
|
||||
|
||||
/**
|
||||
* アプリ情報
|
||||
*/
|
||||
export interface AppInfo {
|
||||
appId: string;
|
||||
code?: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* アクションのプロパティ定義
|
||||
*/
|
||||
export interface IActionProperty {
|
||||
component: string;
|
||||
props: {
|
||||
//プロパティ名
|
||||
name: string;
|
||||
//プロパティ表示名
|
||||
displayName: string;
|
||||
placeholder: string;
|
||||
//入力提示・説明
|
||||
hint:string;
|
||||
//プロパティ設定値
|
||||
modelValue: any;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* アクションタイプ定義
|
||||
*/
|
||||
export interface IActionNode {
|
||||
id: string;
|
||||
//アクション名
|
||||
name: string;
|
||||
title: string;
|
||||
subTitle: string;
|
||||
inputPoint: string;
|
||||
//出力ポイント(条件分岐以外未使用)
|
||||
outputPoints: Array<string>;
|
||||
//ルートアクション(Kintone event)
|
||||
isRoot: boolean;
|
||||
//アクションのプロパティ定義
|
||||
actionProps: Array<IActionProperty>;
|
||||
//アクションのプロパティ設定値抽出
|
||||
ActionValue: object
|
||||
prevNodeId?: string;
|
||||
nextNodeIds: Map<string, string>;
|
||||
}
|
||||
/**
|
||||
* アクションフローの定義
|
||||
*/
|
||||
export interface IActionFlow {
|
||||
id: string;
|
||||
actionNodes: IActionNode[];
|
||||
addNode(newNode: IActionNode, prevNode?: IActionNode, inputPoint?: string): IActionNode;
|
||||
removeNode(targetNode: IActionNode): boolean;
|
||||
removeAllNext(targetNodeId: string): void;
|
||||
findNodeById(id: string): IActionNode | undefined;
|
||||
toJSON(): any;
|
||||
getRoot(): IActionNode | undefined;
|
||||
createNewId(): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* アクションのプロパティ定義に基づいたクラス
|
||||
*/
|
||||
class ActionProperty implements IActionProperty {
|
||||
component: string;
|
||||
props: {
|
||||
// プロパティ名
|
||||
name: string;
|
||||
// プロパティ表示名
|
||||
displayName: string;
|
||||
placeholder: string;
|
||||
hint:string;
|
||||
// プロパティ設定値
|
||||
modelValue: any;
|
||||
};
|
||||
|
||||
static defaultProperty(): IActionProperty {
|
||||
return new ActionProperty('InputText', 'displayName', '表示名', '表示を入力してください', '','');
|
||||
};
|
||||
|
||||
constructor(
|
||||
component: string,
|
||||
name: string,
|
||||
displayName: string,
|
||||
placeholder: string,
|
||||
hint:string,
|
||||
modelValue: any
|
||||
) {
|
||||
this.component = component;
|
||||
this.props = {
|
||||
name: name,
|
||||
displayName: displayName,
|
||||
placeholder: placeholder,
|
||||
hint:hint,
|
||||
modelValue: modelValue
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* IActionNodeの実装、RootActionNode以外のアクション定義
|
||||
*/
|
||||
export class ActionNode implements IActionNode {
|
||||
id: string;
|
||||
name: string;
|
||||
get title(): string {
|
||||
const prop = this.actionProps.find((prop) => prop.props.name === "displayName");
|
||||
return prop?.props.modelValue;
|
||||
};
|
||||
get subTitle(): string {
|
||||
return this.name;
|
||||
};
|
||||
inputPoint: string;
|
||||
//出力ポイント(条件分岐以外未使用)
|
||||
outputPoints: Array<string>;
|
||||
actionProps: Array<IActionProperty>;
|
||||
get isRoot(): boolean {
|
||||
return false;
|
||||
};
|
||||
get ActionValue(): object {
|
||||
const propValue: any = {};
|
||||
this.actionProps.forEach((value) => {
|
||||
propValue[value.props.name] = value.props.modelValue
|
||||
});
|
||||
return propValue;
|
||||
};
|
||||
prevNodeId?: string;
|
||||
nextNodeIds: Map<string, string>;
|
||||
constructor(
|
||||
name: string,
|
||||
title: string,
|
||||
inputPoint: string,
|
||||
outputPoint: Array<string> = [],
|
||||
actionProps: Array<IActionProperty> = [ActionProperty.defaultProperty()],
|
||||
) {
|
||||
this.id = uuidv4();
|
||||
this.name = name;
|
||||
this.inputPoint = inputPoint;
|
||||
this.outputPoints = outputPoint;
|
||||
const defProp = ActionProperty.defaultProperty();
|
||||
defProp.props.modelValue = title;
|
||||
this.actionProps = actionProps;
|
||||
const prop = this.actionProps.find((prop) => prop.props.name === defProp.props.name);
|
||||
if (prop === undefined) {
|
||||
this.actionProps.unshift(defProp);
|
||||
}
|
||||
this.nextNodeIds = new Map<string, string>();
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* ルートアクション定義
|
||||
*/
|
||||
export class RootAction implements IActionNode {
|
||||
id: string;
|
||||
name: string;
|
||||
title: string;
|
||||
subTitle: string;
|
||||
inputPoint: string;
|
||||
//出力ポイント(条件分岐以外未使用)
|
||||
outputPoints: Array<string>;
|
||||
isRoot: boolean;
|
||||
actionProps: Array<IActionProperty>;
|
||||
ActionValue: object;
|
||||
prevNodeId?: string = undefined;
|
||||
nextNodeIds: Map<string, string>;
|
||||
constructor(
|
||||
name: string,
|
||||
title: string,
|
||||
subTitle: string,
|
||||
) {
|
||||
this.id = uuidv4();
|
||||
this.name = name;
|
||||
this.title = title;
|
||||
this.subTitle = subTitle;
|
||||
this.inputPoint = '';
|
||||
this.outputPoints = [];
|
||||
this.isRoot = true;
|
||||
this.actionProps = [];
|
||||
this.ActionValue = {};
|
||||
this.nextNodeIds = new Map<string, string>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* アクションフローの定義
|
||||
*/
|
||||
export class ActionFlow implements IActionFlow {
|
||||
id: string;
|
||||
actionNodes: Array<IActionNode>;
|
||||
constructor(actionNodes: Array<IActionNode> | RootAction) {
|
||||
if (actionNodes instanceof Array) {
|
||||
this.actionNodes = actionNodes;
|
||||
} else {
|
||||
this.actionNodes = [actionNodes];
|
||||
}
|
||||
this.id = '';
|
||||
//this.id = uuidv4();
|
||||
}
|
||||
/**
|
||||
* ノードを追加する
|
||||
* 1.ID採番する
|
||||
* 2.前のノードを関連付け
|
||||
* @param newNode 新規追加するノード
|
||||
* @param prevNode 前のノード
|
||||
* @param inputPoint 入力ポイント
|
||||
* @returns 追加されたノード
|
||||
*/
|
||||
addNode(
|
||||
newNode: IActionNode,
|
||||
prevNode?: IActionNode,
|
||||
inputPoint?: string): IActionNode {
|
||||
if (inputPoint !== undefined) {
|
||||
newNode.inputPoint = inputPoint;
|
||||
}
|
||||
if (prevNode !== undefined) {
|
||||
this.connectNodes(prevNode, newNode, inputPoint || '');
|
||||
} else {
|
||||
prevNode = this.actionNodes[this.actionNodes.length - 1];
|
||||
this.connectNodes(prevNode, newNode, inputPoint || '');
|
||||
}
|
||||
const index = this.actionNodes.findIndex(node => node.id === prevNode?.id)
|
||||
if (index >= 0) {
|
||||
this.actionNodes.splice(index + 1, 0, newNode);
|
||||
} else {
|
||||
this.actionNodes.push(newNode);
|
||||
}
|
||||
return newNode;
|
||||
}
|
||||
/**
|
||||
* ノードを削除する
|
||||
* @param delNode
|
||||
*/
|
||||
removeNode(targetNode: IActionNode): boolean {
|
||||
if (!targetNode) {
|
||||
return false;
|
||||
}
|
||||
if (targetNode.isRoot) {
|
||||
return false;
|
||||
}
|
||||
this.disconnectFromPrevNode(targetNode);
|
||||
this.reconnectOrRemoveNextNodes(targetNode);
|
||||
this.removeFromActionNodes(targetNode.id);
|
||||
return true;
|
||||
}
|
||||
/***
|
||||
* 目標ノードの次のノードを全部削除する
|
||||
*/
|
||||
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.removeAllNext(id);
|
||||
this.removeFromActionNodes(id);
|
||||
}
|
||||
}
|
||||
|
||||
// 断开与前一个节点的连接
|
||||
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 からノードを削除する
|
||||
private removeFromActionNodes(targetNodeId: string): void {
|
||||
const index = this.actionNodes.findIndex(node => node.id === targetNodeId);
|
||||
if (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 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) {
|
||||
//
|
||||
prevNode.nextNodeIds.set(inputPoint || '', newNode.id);
|
||||
newNode.prevNodeId = prevNode.id;
|
||||
const originalNextNodeId = prevNode.nextNodeIds.get(inputPoint || '');
|
||||
this.setNewNodeNextId(newNode, originalNextNodeId, inputPoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* 後ノードと新ノードの関連付け
|
||||
* @param newNode
|
||||
* @param originalNextNodeId
|
||||
* @param inputPoint
|
||||
*/
|
||||
private setNewNodeNextId(newNode: IActionNode, originalNextNodeId: string | undefined, inputPoint?: string) {
|
||||
// 元の接続ノードが存在する
|
||||
if (originalNextNodeId) {
|
||||
// 新しいノードの outputPoints に該当 inputPointが存在するか場合をチェックする
|
||||
if (newNode.outputPoints.includes(inputPoint || '')) {
|
||||
newNode.nextNodeIds.set(inputPoint || '', originalNextNodeId);
|
||||
} else {
|
||||
// inputPointが存在しない場合、outputPointのポイントの任意ポートを選択する
|
||||
const alternativeOutputPoint = newNode.outputPoints.length > 0 ? newNode.outputPoints[0] : '';
|
||||
newNode.nextNodeIds.set(alternativeOutputPoint, originalNextNodeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* IDでActionNodeを取得する
|
||||
*/
|
||||
findNodeById(id: string): IActionNode | undefined {
|
||||
return this.actionNodes.find((node) => node.id === id);
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
id: this.id,
|
||||
actionNodes: this.actionNodes.map(node => {
|
||||
const { nextNodeIds, ...rest } = node;
|
||||
return {
|
||||
...rest,
|
||||
nextNodeIds: Array.from(nextNodeIds.entries())
|
||||
};
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
getRoot(): IActionNode | undefined {
|
||||
return this.actionNodes.find(node => node.isRoot)
|
||||
}
|
||||
|
||||
createNewId():string{
|
||||
this.id=uuidv4();
|
||||
return this.id;
|
||||
}
|
||||
|
||||
static fromJSON(json: string): ActionFlow {
|
||||
const parsedObject = JSON.parse(json);
|
||||
|
||||
const actionNodes = parsedObject.actionNodes.map((node: any) => {
|
||||
const nodeClass = !node.isRoot ? new ActionNode(node.name, node.title, node.inputPoint, node.outputPoint, node.actionProps)
|
||||
: new RootAction(node.name, node.title, node.subTitle);
|
||||
nodeClass.nextNodeIds = new Map(node.nextNodeIds);
|
||||
nodeClass.prevNodeId = node.prevNodeId;
|
||||
nodeClass.id = node.id;
|
||||
return nodeClass;
|
||||
});
|
||||
const actionFlow = new ActionFlow(actionNodes);
|
||||
actionFlow.id = parsedObject.id;
|
||||
return actionFlow;
|
||||
}
|
||||
}
|
||||
|
||||
336
frontend/src/types/Conditions.ts
Normal file
336
frontend/src/types/Conditions.ts
Normal file
@@ -0,0 +1,336 @@
|
||||
//ノード種別
|
||||
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 class ConditionNode implements INode {
|
||||
index: number;
|
||||
type: NodeType;
|
||||
parent:INode;
|
||||
get logicalOperator(): LogicalOperator{
|
||||
return this.parent.logicalOperator;
|
||||
};
|
||||
object: any; // 比較元
|
||||
operator: Operator; // 比較子
|
||||
value: any;
|
||||
get header():string{
|
||||
return 'generic';
|
||||
}
|
||||
|
||||
constructor(object: any, operator: Operator, 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;
|
||||
|
||||
constructor() {
|
||||
this.maxIndex=0;
|
||||
this.root = new GroupNode(LogicalOperator.AND, null);
|
||||
}
|
||||
|
||||
// ノード追加
|
||||
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.name} ${condNode.operator} '${value}'`;
|
||||
} 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(this.root, (key, value) => {
|
||||
if (key === 'parent') {
|
||||
return value ? value.type : null;
|
||||
}
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
112
frontend/src/types/KintoneEvents.ts
Normal file
112
frontend/src/types/KintoneEvents.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import { publicDecrypt } from 'crypto';
|
||||
import {IActionFlow} from './ActionTypes';
|
||||
export interface TreeNode {
|
||||
label: string;
|
||||
}
|
||||
|
||||
export interface IKintoneEvent extends TreeNode {
|
||||
eventId: string;
|
||||
hasFlow: boolean;
|
||||
flowData?: IActionFlow;
|
||||
}
|
||||
|
||||
export interface IKintoneScreen extends TreeNode {
|
||||
label: string;
|
||||
events: IKintoneEvent[];
|
||||
}
|
||||
|
||||
export class kintoneEvent implements IKintoneEvent{
|
||||
eventId: string;
|
||||
get hasFlow(): boolean{
|
||||
return this.flowData!==undefined && this.flowData.actionNodes.length>1
|
||||
};
|
||||
flowData?: IActionFlow | undefined;
|
||||
label: string;
|
||||
constructor({eventId,label}:{eventId:string,label:string}){
|
||||
this.eventId=eventId;
|
||||
this.label=label;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class KintoneEventManager {
|
||||
public screens: IKintoneScreen[];
|
||||
|
||||
constructor(screens: IKintoneScreen[]) {
|
||||
this.screens = screens;
|
||||
}
|
||||
|
||||
public bindFlows(flows:IActionFlow[]){
|
||||
for (const screen of this.screens) {
|
||||
screen.events.forEach((ev)=>ev.flowData=undefined);
|
||||
}
|
||||
for (const flow of flows){
|
||||
const eventId =flow.getRoot()?.name;
|
||||
if(eventId!==undefined){
|
||||
const event = this.findEventById(eventId);
|
||||
if(event!==null){
|
||||
event.flowData=flow;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public findEventById(eventId: string): IKintoneEvent | null {
|
||||
for (const screen of this.screens) {
|
||||
for (const event of screen.events) {
|
||||
if (event.eventId === eventId) {
|
||||
return event;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public findScreen(eventId:string):IKintoneScreen|null{
|
||||
for (const screen of this.screens) {
|
||||
if(screen.events.some((ev:IKintoneEvent)=>ev.eventId===eventId)){
|
||||
return screen;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export const kintoneEvents:KintoneEventManager = new KintoneEventManager([
|
||||
{
|
||||
label:'レコード追加画面',
|
||||
events:[
|
||||
new kintoneEvent({label:'レコード追加画面を表示した後',eventId:'app.record.create.show'}),
|
||||
new kintoneEvent({label:'保存をクリックしたとき',eventId:'app.record.create.submit'}),
|
||||
new kintoneEvent({label:'保存が成功したとき',eventId:'app.record.create.submit.success'}),
|
||||
new kintoneEvent({label:'フィールドの値を変更したとき',eventId:'app.record.create.change'}),
|
||||
]
|
||||
},
|
||||
{
|
||||
label:'レコード詳細画面',
|
||||
events:[
|
||||
new kintoneEvent({label:'レコード詳細画面を表示した後',eventId:'app.record.detail.show'}),
|
||||
new kintoneEvent({label:'レコードを削除するとき',eventId:'app.record.detail.delete.submit'}),
|
||||
new kintoneEvent({label:'プロセス管理のアクションを実行したとき',eventId:'app.record.detail.process.proceed'}),
|
||||
]
|
||||
},
|
||||
{
|
||||
label:'レコード編集画面',
|
||||
events:[new kintoneEvent({label:'レコード編集画面を表示した後',eventId:'app.record.edit.show'}),
|
||||
new kintoneEvent({label:'保存をクリックしたとき',eventId:'app.record.edit.submit'}),
|
||||
new kintoneEvent({label:'保存が成功したとき',eventId:'app.record.edit.submit.success'}),
|
||||
new kintoneEvent({label:'フィールドの値を変更したとき',eventId:'app.record.edit.change'}),
|
||||
]
|
||||
},
|
||||
{
|
||||
label:'レコード一覧画面',
|
||||
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'}),
|
||||
]
|
||||
}
|
||||
]);
|
||||
@@ -1,17 +1,6 @@
|
||||
{
|
||||
"extends": "@quasar/app-vite/tsconfig-preset",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"src/*": ["src/*"],
|
||||
"app/*": ["*"],
|
||||
"components/*": ["src/components/*"],
|
||||
"layouts/*": ["src/layouts/*"],
|
||||
"pages/*": ["src/pages/*"],
|
||||
"assets/*": ["src/assets/*"],
|
||||
"boot/*": ["src/boot/*"],
|
||||
"stores/*": ["src/stores/*"],
|
||||
"models/*":["scr/models/*"]
|
||||
}
|
||||
"baseUrl": "."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,7 @@
|
||||
"@nodelib/fs.stat" "2.0.5"
|
||||
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"
|
||||
resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
|
||||
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
|
||||
@@ -278,6 +278,11 @@
|
||||
"@types/mime" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/uuid@^9.0.3":
|
||||
version "9.0.3"
|
||||
resolved "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.3.tgz"
|
||||
integrity sha512-taHQQH/3ZyI3zP8M/puluDEIEvtQHVYcC6y3N8ijFtAd28+Ey/G4sg1u2gB01S8MwybLOKAp9/yCMu/uR5l3Ug==
|
||||
|
||||
"@typescript-eslint/eslint-plugin@^5.10.0":
|
||||
version "5.61.0"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.61.0.tgz"
|
||||
@@ -294,7 +299,7 @@
|
||||
semver "^7.3.7"
|
||||
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"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.61.0.tgz"
|
||||
integrity sha512-yGr4Sgyh8uO6fSi9hw3jAFXNBHbCtKKFMdX2IkT3ZqpKmtAq3lHS4ixB/COFuAIJpwl9/AqF7j72ZDWYKmIfvg==
|
||||
@@ -362,7 +367,7 @@
|
||||
"@typescript-eslint/types" "5.61.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"
|
||||
resolved "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-2.3.4.tgz"
|
||||
integrity sha512-IfFNbtkbIm36O9KB8QodlwwYvTEsJb4Lll4c2IwB3VHc2gie2mSPtSzL0eYay7X2jd/2WX02FjSGTWR6OPr/zg==
|
||||
@@ -475,22 +480,12 @@ acorn-jsx@^5.3.2:
|
||||
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
|
||||
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"
|
||||
resolved "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz"
|
||||
integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==
|
||||
|
||||
ajv@^6.10.0:
|
||||
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:
|
||||
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==
|
||||
@@ -686,7 +681,7 @@ braces@^3.0.2, braces@~3.0.2:
|
||||
dependencies:
|
||||
fill-range "^7.0.1"
|
||||
|
||||
browserslist@^4.21.5, "browserslist@>= 4.21.0":
|
||||
browserslist@^4.21.5:
|
||||
version "4.21.9"
|
||||
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz"
|
||||
integrity sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==
|
||||
@@ -758,7 +753,7 @@ chardet@^0.7.0:
|
||||
resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz"
|
||||
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"
|
||||
resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz"
|
||||
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
|
||||
@@ -943,27 +938,6 @@ csstype@^3.1.1:
|
||||
resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz"
|
||||
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:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
|
||||
@@ -971,6 +945,13 @@ debug@2.6.9:
|
||||
dependencies:
|
||||
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:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz"
|
||||
@@ -1063,12 +1044,107 @@ end-of-stream@^1.4.1:
|
||||
dependencies:
|
||||
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:
|
||||
version "0.14.51"
|
||||
resolved "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.51.tgz"
|
||||
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"
|
||||
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.14.51.tgz"
|
||||
integrity sha512-+CvnDitD7Q5sT7F+FM65sWkF8wJRf+j9fPcprxYV4j+ohmzVj2W7caUqH2s5kCaCJAfcAICjSlKhDCcvDpU7nw==
|
||||
@@ -1140,15 +1216,7 @@ eslint-scope@^5.1.1:
|
||||
esrecurse "^4.3.0"
|
||||
estraverse "^4.1.1"
|
||||
|
||||
eslint-scope@^7.1.1:
|
||||
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:
|
||||
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==
|
||||
@@ -1161,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"
|
||||
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"
|
||||
resolved "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz"
|
||||
integrity sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==
|
||||
@@ -1234,12 +1302,7 @@ estraverse@^4.1.1:
|
||||
resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz"
|
||||
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
|
||||
|
||||
estraverse@^5.1.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:
|
||||
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==
|
||||
@@ -1310,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"
|
||||
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"
|
||||
resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz"
|
||||
integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==
|
||||
@@ -1441,6 +1504,11 @@ fs.realpath@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
|
||||
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:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
|
||||
@@ -1567,7 +1635,7 @@ http-errors@2.0.0:
|
||||
statuses "2.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"
|
||||
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz"
|
||||
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
|
||||
@@ -1605,7 +1673,7 @@ inflight@^1.0.4:
|
||||
once "^1.3.0"
|
||||
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"
|
||||
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
@@ -1889,7 +1957,7 @@ micromatch@^4.0.4:
|
||||
braces "^3.0.2"
|
||||
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"
|
||||
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz"
|
||||
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
|
||||
@@ -2144,6 +2212,14 @@ 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"
|
||||
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||
|
||||
pinia@^2.1.6:
|
||||
version "2.1.6"
|
||||
resolved "https://registry.npmjs.org/pinia/-/pinia-2.1.6.tgz"
|
||||
integrity sha512-bIU6QuE5qZviMmct5XwCesXelb5VavdOWKWaB17ggk++NUwQWWbP5YnsONTk3b752QkW9sACiR81rorpeOMSvQ==
|
||||
dependencies:
|
||||
"@vue/devtools-api" "^6.5.0"
|
||||
vue-demi ">=0.14.5"
|
||||
|
||||
postcss-selector-parser@^6.0.9:
|
||||
version "6.0.13"
|
||||
resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz"
|
||||
@@ -2157,7 +2233,7 @@ postcss-value-parser@^4.2.0:
|
||||
resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz"
|
||||
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"
|
||||
resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz"
|
||||
integrity sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw==
|
||||
@@ -2206,7 +2282,7 @@ qs@6.11.0:
|
||||
dependencies:
|
||||
side-channel "^1.0.4"
|
||||
|
||||
quasar@^2.6.0, quasar@^2.8.0:
|
||||
quasar@^2.6.0:
|
||||
version "2.12.2"
|
||||
resolved "https://registry.npmjs.org/quasar/-/quasar-2.12.2.tgz"
|
||||
integrity sha512-UB+J1cN6b9FrRphUuMvW1Pt1uaOPH2XJMAZagQlYzVUmltKCXQ0sby+ANgGRYa8w/tsekMySmN9QvkQ3+hYv/g==
|
||||
@@ -2238,20 +2314,7 @@ raw-body@2.5.1:
|
||||
iconv-lite "0.4.24"
|
||||
unpipe "1.0.0"
|
||||
|
||||
readable-stream@^2.0.0:
|
||||
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:
|
||||
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==
|
||||
@@ -2351,7 +2414,7 @@ rollup-plugin-visualizer@^5.5.4:
|
||||
source-map "^0.7.4"
|
||||
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"
|
||||
resolved "https://registry.npmjs.org/rollup/-/rollup-2.77.3.tgz"
|
||||
integrity sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==
|
||||
@@ -2377,7 +2440,7 @@ rxjs@^7.5.5:
|
||||
dependencies:
|
||||
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"
|
||||
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz"
|
||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
@@ -2392,7 +2455,7 @@ safe-buffer@5.2.1:
|
||||
resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
sass@*, sass@1.32.12:
|
||||
sass@1.32.12:
|
||||
version "1.32.12"
|
||||
resolved "https://registry.npmjs.org/sass/-/sass-1.32.12.tgz"
|
||||
integrity sha512-zmXn03k3hN0KaiVTjohgkg98C3UowhL1/VSGdj4/VAAiMKGQOE80PFPxFP2Kyq0OUskPKcY5lImkhBKEHlypJA==
|
||||
@@ -2524,13 +2587,6 @@ statuses@2.0.1:
|
||||
resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz"
|
||||
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:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
|
||||
@@ -2540,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"
|
||||
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:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
|
||||
@@ -2657,7 +2720,7 @@ type-is@~1.6.18:
|
||||
media-typer "0.3.0"
|
||||
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.5.4:
|
||||
version "4.9.5"
|
||||
resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz"
|
||||
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
|
||||
@@ -2672,7 +2735,7 @@ universalify@^2.0.0:
|
||||
resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz"
|
||||
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
|
||||
|
||||
unpipe@~1.0.0, unpipe@1.0.0:
|
||||
unpipe@1.0.0, unpipe@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz"
|
||||
integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
|
||||
@@ -2707,12 +2770,17 @@ utils-merge@1.0.1:
|
||||
resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz"
|
||||
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
|
||||
|
||||
uuid@^9.0.0:
|
||||
version "9.0.0"
|
||||
resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz"
|
||||
integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==
|
||||
|
||||
vary@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz"
|
||||
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"
|
||||
resolved "https://registry.npmjs.org/vite/-/vite-2.9.16.tgz"
|
||||
integrity sha512-X+6q8KPyeuBvTQV8AVSnKDvXoBMnTx8zxh54sOwmmuOdxkjMmEJXH2UEchA+vTMps1xw9vL64uwJOWryULg7nA==
|
||||
@@ -2724,6 +2792,11 @@ vary@~1.1.2:
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
vue-demi@>=0.14.5:
|
||||
version "0.14.6"
|
||||
resolved "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz"
|
||||
integrity sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==
|
||||
|
||||
vue-eslint-parser@^9.3.0:
|
||||
version "9.3.1"
|
||||
resolved "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.3.1.tgz"
|
||||
@@ -2737,14 +2810,14 @@ vue-eslint-parser@^9.3.0:
|
||||
lodash "^4.17.21"
|
||||
semver "^7.3.6"
|
||||
|
||||
vue-router@^4.0.0, vue-router@^4.0.12:
|
||||
vue-router@^4.0.0:
|
||||
version "4.2.4"
|
||||
resolved "https://registry.npmjs.org/vue-router/-/vue-router-4.2.4.tgz"
|
||||
integrity sha512-9PISkmaCO02OzPVOMq2w82ilty6+xJmQrarYZDkjZBfl4RvYAlt4PKnEX21oW4KTtWfa9OuO/b3qk1Od3AEdCQ==
|
||||
dependencies:
|
||||
"@vue/devtools-api" "^6.5.0"
|
||||
|
||||
vue@^3.0.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"
|
||||
resolved "https://registry.npmjs.org/vue/-/vue-3.3.4.tgz"
|
||||
integrity sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==
|
||||
|
||||
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?
|
||||
800
plugin/kintone-addins/package-lock.json
generated
Normal file
800
plugin/kintone-addins/package-lock.json
generated
Normal file
@@ -0,0 +1,800 @@
|
||||
{
|
||||
"name": "kintone-addins",
|
||||
"version": "0.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "kintone-addins",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"jquery": "^3.7.1"
|
||||
},
|
||||
"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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
plugin/kintone-addins/package.json
Normal file
22
plugin/kintone-addins/package.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "kintone-addins",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build && xcopy dist\\*.js ..\\..\\backend\\Temp\\ /E /I /Y",
|
||||
"build:dev":"tsc && set \"SOURCE_MAP=true\" && vite build && xcopy dist\\*.js ..\\..\\backend\\Temp\\ /E /I /Y",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jquery": "^3.5.24",
|
||||
"@types/node": "^20.8.9",
|
||||
"sass": "^1.69.5",
|
||||
"typescript": "^5.0.2",
|
||||
"vite": "^4.4.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"jquery": "^3.7.1"
|
||||
}
|
||||
}
|
||||
1
plugin/kintone-addins/public/vite.svg
Normal file
1
plugin/kintone-addins/public/vite.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
266
plugin/kintone-addins/readme.md
Normal file
266
plugin/kintone-addins/readme.md
Normal file
@@ -0,0 +1,266 @@
|
||||
# kintone自動化開発ツールのアクションのアドイン開発手順
|
||||
|
||||
## 1. アクションの登録
|
||||
|
||||
アクションプラグインをシステムに登録するためには、以下の情報をデータベースの`action`表に挿入する必要があります。
|
||||
|
||||
|列名 | 項目 | 説明 |
|
||||
|----- |-------------|-------------------------------------------|
|
||||
|name | 名前 | アクションプラグイン名(ユニークな名前が必要) |
|
||||
|title |タイトル | タイトル (20文字以内) |
|
||||
|subtitle|サブタイトル | サブタイトル |
|
||||
|outputpoint|出力ポイント | 出力値に分岐がある場合の接続点 |
|
||||
|property|プロパティ | アクションプラグインの属性(json形式) |
|
||||
|
||||
### 登録の例
|
||||
|
||||
以下は「表示/非表示」アクションプラグインを登録する例です。
|
||||
|
||||
- name: "表示/非表示"
|
||||
- title: "指定項目の表示・非表示を設定する"
|
||||
- subtitle: "表示/非表示"
|
||||
- outputpoint: "[]"
|
||||
- property:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"component": "FieldInput",
|
||||
"props": {
|
||||
"displayName": "フィールド",
|
||||
"modelValue": {},
|
||||
"name": "field",
|
||||
"placeholder": "対象項目を選択してください"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "SelectBox",
|
||||
"props": {
|
||||
"displayName": "表示/非表示",
|
||||
"options": ["表示", "非表示"],
|
||||
"modelValue": "",
|
||||
"name": "show",
|
||||
"placeholder": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "ConditionInput",
|
||||
"props": {
|
||||
"displayName": "条件",
|
||||
"modelValue": "",
|
||||
"name": "condition",
|
||||
"placeholder": "条件式を設定してください"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### プロパティ属性設定画面
|
||||

|
||||
|
||||
|
||||
### 属性UIコンポーネントの共通属性
|
||||
| 属性 | 設定値の例 | 説明 |
|
||||
|-------------|--------------------|----------------------------------------------------------------------------|
|
||||
| component | InputText | コンポーネントの種類を示しており、この場合は選択リストを意味します。<br>使用可能なコンポーネントを参照|
|
||||
| displayName | 表示/非表示 | ユーザーに対して表示されるコンポーネントの名前です。 |
|
||||
| options | ["表示", "非表示"] | ユーザーが選択できるオプションの配列です。<br>SelectBoxのみ使用可能 |
|
||||
| modelValue | 空文字 | コンポーネントの初期値を設定します。<br>初期設定ないの場合は空文字で設定する。
|
||||
| name | field | 属性の設定値の名前です。 |
|
||||
| placeholder | 対象項目を選択してください| 入力フィールドに表示されるプレースホルダーのテキストです。この場合は設定されていません。 |
|
||||
|
||||
### 使用可能なコンポーネント
|
||||
| No. | コンポーネント名 | コンポーネントタイプ | 説明 |
|
||||
|-----|------------------|------------------|-----------------------------------------|
|
||||
| 1 | テキストボックス | InputText | 一行のテキスト入力が可能なフィールドです。 |
|
||||
| 2 | テキストボックス(改行可能) | MuiltInputText | 複数行のテキスト入力が可能なテキストエリアです。 |
|
||||
| 3 | 日付 | DatePicker | 日付を選択するためのカレンダーコンポーネントです。 |
|
||||
| 4 | フィールド選択 | FieldInput | システムのフィールドを選択するための入力コンポーネントです。 |
|
||||
| 5 | 選択リスト | SelectBox | 複数のオプションから選択するためのドロップダウンリストです。 |
|
||||
| 6 | 条件式設定 | ConditionInput | 条件式やロジックを入力するためのコンポーネントです。 |
|
||||
| 7 | 色選択 | ColorPicker | 色を設定する(追加予定中) |
|
||||
| 8 | 他のアプリのフィールド選択 | AppFieldPicker | 他のアプリのフィールドを選択する(追加予定中) |
|
||||
| 9 |ユーザー選択 | UserPicker | ユーザーを選択する(追加予定中) |
|
||||
|
||||
## 2.アクションアドインの開発
|
||||
|
||||
### 1. Action pluginファイルの追加
|
||||
アクションプラグインを作成するためには、以下のディレクトリ構造に`TypeScript`ファイルを追加します。
|
||||
```
|
||||
KintoneAppBuilder
|
||||
└─ plugin
|
||||
└─ kintone-addins
|
||||
└─ src
|
||||
└─ actions
|
||||
└─ your-action.ts // ここにアクションプラグインのtsファイルを追加
|
||||
```
|
||||
### 2. アクションクラスの実装手順
|
||||
`IAction` インターフェースに従ってアクションクラスを実装します。
|
||||
```typescript
|
||||
|
||||
/**
|
||||
* アクションのインターフェース
|
||||
*/
|
||||
export interface IAction{
|
||||
// アクションのユニークな名前
|
||||
name:string;
|
||||
//属性設定情報
|
||||
actionProps: Array<IActionProperty>;
|
||||
//アクションのプロセス実行関数
|
||||
process(prop:IActionNode,event:any,context:IContext):Promise<IActionResult>;
|
||||
//アクションの登録関数
|
||||
register():void;
|
||||
}
|
||||
```
|
||||
#### サンプルコード
|
||||
```ts
|
||||
// アクションの属性定義
|
||||
interface IShownProps{
|
||||
field:IField;
|
||||
show:string;
|
||||
condition:string;
|
||||
}
|
||||
|
||||
// 表示/非表示アクション
|
||||
export class FieldShownAction implements IAction{
|
||||
name: string;
|
||||
actionProps: IActionProperty[];
|
||||
props:IShownProps;
|
||||
constructor(){
|
||||
this.name="表示/非表示"; // DBに登録したアクション名一致する必要があり
|
||||
this.actionProps=[];
|
||||
//プロパティ属性の初期化
|
||||
this.props={
|
||||
field:{code:''},
|
||||
show:'',
|
||||
condition:''
|
||||
}
|
||||
//アクションの自動登録
|
||||
this.register();
|
||||
}
|
||||
/**
|
||||
* アクションの実行を呼び出す
|
||||
* @param actionNode
|
||||
* @param event
|
||||
* @returns
|
||||
*/
|
||||
async process(actionNode:IActionNode,event:any,context:IContext):Promise<IActionResult> {
|
||||
// ... (アクション処理の実装)
|
||||
}
|
||||
|
||||
register(): void {
|
||||
actionAddins[this.name]=this;
|
||||
}
|
||||
}
|
||||
new FieldShownAction();
|
||||
|
||||
```
|
||||
アクションプラグインを実装するには、`IAction`インターフェースの定義に従って、必要なメソッドとプロパティをクラスに実装します。
|
||||
以下に、`IAction`インターフェースを用いて`表示/非表示`アクションを実装する手順を説明します。
|
||||
1. **アクションの属性定義**
|
||||
|
||||
2. **アクションクラスの作成**:
|
||||
- `IAction`インターフェースを実装する新しいクラス`FieldShownAction`を作成します。
|
||||
|
||||
3. **コンストラクタの定義**:
|
||||
- アクション名や初期プロパティを設定します。
|
||||
- このクラスのインスタンスが作成された際に、自動的にアクションが登録されるように、コンストラクタ内で`register`メソッドを呼び出します。
|
||||
|
||||
4. **プロセス実行関数の実装** (`process`):
|
||||
- `process`メソッドは、アクションの主要なロジックを含み、アクションの実行時に呼び出されます。
|
||||
|
||||
|
||||
- * 以下は`process`関数のパラメータとその用途を説明します。
|
||||
|
||||
| パラメータ名 | 型 | 用途 |
|
||||
|----------|----------------|------------------------------------------------------------------------------------------------|
|
||||
| actionNode | `IActionNode` | Kintone自動化ツールのアクションの設定やプロパティ情報を保持します。 |
|
||||
| event |kintoneのイベント情報| レコードやエラー制御で使用します |
|
||||
| context | `IContext` | 現在のレコード情報や変数など、実行に必要なデータへのアクセスを提供します。 |
|
||||
|
||||
- このメソッド内で、アクションに必要な処理を行います。
|
||||
- 1. アクションプロパティの取得:
|
||||
`Kitone自動化ツール`を設定したプロパティの値を取得する
|
||||
|
||||
```ts
|
||||
//プロパティ設定を取得する
|
||||
this.actionProps=actionNode.actionProps;
|
||||
//プロパティ設定のデータ型は必要な情報が含めますか
|
||||
if (!('field' in actionNode.ActionValue) && !('show' in actionNode.ActionValue)) {
|
||||
return result
|
||||
}
|
||||
//既定のプロパティのインターフェースへ変換する
|
||||
this.props = actionNode.ActionValue as IShownProps;
|
||||
```
|
||||
|
||||
- 2. 条件式の評価
|
||||
getConditionResult関数を呼び出して条件式を評価します。この関数は、現在のコンテキストに基づいて条件式が真か偽かを返します。
|
||||
```ts
|
||||
//条件式の計算結果を取得
|
||||
const conditionResult = this.getConditionResult(context);
|
||||
/**
|
||||
*
|
||||
* @param context 条件式を実行する
|
||||
* @returns
|
||||
*/
|
||||
getConditionResult(context:any):boolean{
|
||||
//プロパティ`condition`から条件ツリーを取得する
|
||||
const tree =this.getCondition(this.props.condition);
|
||||
if(!tree){
|
||||
//条件を設定されていません
|
||||
return true;
|
||||
}
|
||||
return tree.evaluate(tree.root,context);
|
||||
}
|
||||
```
|
||||
- 3. Kintone APIを使用して、フィールドの表示/非表示の制御
|
||||
```ts
|
||||
//条件式の計算結果を取得
|
||||
const conditionResult = this.getConditionResult(context);
|
||||
if(conditionResult){
|
||||
if(this.props.show==='表示'){
|
||||
kintone.app.record.setFieldShown(this.props.field.code,true);
|
||||
}else if (this.props.show==='非表示'){
|
||||
kintone.app.record.setFieldShown(this.props.field.code,false);
|
||||
}
|
||||
}
|
||||
```
|
||||
5. **登録関数の実装** (`register`):
|
||||
- アクションをアドインシステムに登録するための`register`メソッドを実装します。
|
||||
|
||||
6. **アクションプロセス`ActionProcess`に参照追加**
|
||||
```ts
|
||||
import { actionAddins } from "../actions";
|
||||
import '../actions/must-input';
|
||||
import '../actions/auto-numbering';
|
||||
import '../actions/field-shown';
|
||||
import '../actions/your-action'; //ここに新規のアクションの参照を追加する
|
||||
...
|
||||
```
|
||||
### 3. デプロイ
|
||||
1. **プロジェクトをビルドする**
|
||||
- 本番環境にデプロイする場合
|
||||
```bash
|
||||
cd plug\kintone-addins\
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
- 開発環境にデプロイする場合(ソースマップ出力ます)
|
||||
```bash
|
||||
cd plug\kintone-addins\
|
||||
npm install
|
||||
npm run build:dev
|
||||
```
|
||||
2. **Azureにデプロイする**
|
||||
- Azure 拡張機能のインストール:
|
||||
VSCode の拡張機能ペインで`Azure Tools`を検索し、インストールします。
|
||||
|
||||
- Azure にログイン:
|
||||
- Azure Account 拡張機能を使用して Azure にログインします。
|
||||
|
||||
- Azure へのデプロイ:
|
||||
- 「Deploy to Web App」オプションを使用し、デプロイするファイルやフォルダを指定します。
|
||||
|
||||
- デプロイの確認:
|
||||
- Azure App Service 拡張機能でデプロイが完了したことを確認します。
|
||||
- ka-addin の URL にアクセスしてアプリケーションが正常に動作しているか確認します。
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user