Compare commits

..

1 Commits

Author SHA1 Message Date
xue jiahao
e362c80e98 show domain page for all user
1. show ドメイン管理
2. hide ドメイン適用
3. force redirect to domain page if user no domain exist
2024-11-06 21:56:14 +08:00
26 changed files with 281 additions and 1039 deletions

4
.gitignore vendored
View File

@@ -1,7 +1,3 @@
.vscode
.mypy_cache
docker-stack.yml
backend/pyvenv.cfg
backend/Include/
backend/Scripts/

View File

@@ -25,15 +25,11 @@ async def login(
minutes=security.ACCESS_TOKEN_EXPIRE_MINUTES
)
if user.is_superuser:
roles = "super"
permissions = "ALL"
permissions = "admin"
else:
roles = ";".join(role.name for role in user.roles)
perlst = [perm.privilege for role in user.roles for perm in role.permissions]
permissions =";".join(list(set(perlst)))
permissions = "user"
access_token = security.create_access_token(
data={"sub": user.id, "roles":roles,"permissions": permissions ,},
data={"sub": user.id, "permissions": permissions},
expires_delta=access_token_expires,
)

View File

@@ -156,10 +156,10 @@ def getsettingfromexcel(df):
des = df.iloc[2,2]
return {"name":appname,"description":des}
def getsettingfromkintone(app:str,env:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:env.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"{env.BASE_URL}{config.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()
@@ -171,24 +171,24 @@ def analysesettings(excel,kintone):
updatesettings[key] = excel[key]
return updatesettings
def createkintoneapp(name:str,env:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:env.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"{env.BASE_URL}{config.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,env:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
url = f"{env.BASE_URL}{config.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,env:config.KINTONE_ENV,revision:str = None):
headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
url = f"{env.BASE_URL}{config.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:
@@ -197,43 +197,43 @@ def addfieldstokintone(app:str,fields:dict,env:config.KINTONE_ENV,revision:str =
r.raise_for_status()
return r.json()
def updatefieldstokintone(app:str,revision:str,fields:dict,env:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
url = f"{env.BASE_URL}{config.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,env:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
url = f"{env.BASE_URL}{config.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,env:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
url = f"{env.BASE_URL}{config.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:str,env:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:env.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"{env.BASE_URL}{config.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()
# フォームに配置するフィールドのみ取得する
# スペース、枠線、ラベルも含める
def getformfromkintone(app:str,env:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE}
def getformfromkintone(app:str,c:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
params = {"app":app}
url = f"{env.BASE_URL}{config.API_V1_STR}/form.json"
url = f"{c.BASE_URL}{config.API_V1_STR}/form.json"
r = httpx.get(url,headers=headers,params=params)
return r.json()
@@ -286,10 +286,10 @@ def analysefields(excel,kintone):
return {"update":updatefields,"add":addfields,"del":delfields}
def getprocessfromkintone(app:str,env:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:env.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"{env.BASE_URL}{config.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()
@@ -374,24 +374,24 @@ def getkintoneorgs(c:config.KINTONE_ENV):
r = httpx.get(url,headers=headers,params=params)
return r.json()
def uploadkintonefiles(file,env:config.KINTONE_ENV):
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:env.API_V1_AUTH_VALUE}
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
data ={'name':'file','filename':os.path.basename(file)}
url = f"{env.BASE_URL}/k/v1/file.json"
url = f"{c.BASE_URL}/k/v1/file.json"
r = httpx.post(url,headers=headers,data=data,files=upload_files)
#{"name":data['filename'],'fileKey':r['fileKey']}
return r.json()
def updateappjscss(app,uploads,env:config.KINTONE_ENV):
def updateappjscss(app,uploads,c:config.KINTONE_ENV):
dsjs = []
dscss = []
#mobile側
mbjs = []
mbcss = []
customize = getappcustomize(app, env)
customize = getappcustomize(app, c)
current_js = customize['desktop'].get('js', [])
current_css = customize['desktop'].get('css', [])
current_mobile_js = customize['mobile'].get('js', [])
@@ -430,16 +430,16 @@ def updateappjscss(app,uploads,env:config.KINTONE_ENV):
ds ={'js':dsjs,'css':dscss}
mb ={'js':mbjs,'css':mbcss}
data = {'app':app,'scope':'ALL','desktop':ds,'mobile':mb,'revision':customize["revision"]}
headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
url = f"{env.BASE_URL}{config.API_V1_STR}/preview/app/customize.json"
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(json.dumps(data))
r = httpx.put(url,headers=headers,data=json.dumps(data))
return r.json()
#kintone カスタマイズ情報
def getappcustomize(app,env:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE}
url = f"{env.BASE_URL}{config.API_V1_STR}/preview/app/customize.json"
def getappcustomize(app,c:config.KINTONE_ENV):
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
url = f"{c.BASE_URL}{config.API_V1_STR}/preview/app/customize.json"
params = {"app":app}
r = httpx.get(url,headers=headers,params=params)
return r.json()
@@ -451,9 +451,9 @@ def getTempPath(filename):
fpath = os.path.join(rootdir,"Temp",filename)
return fpath
def createappjs(domain_url,app):
def createappjs(domainid,app):
db = SessionLocal()
flows = get_flows_by_app(db,domain_url,app)
flows = get_flows_by_app(db,domainid,app)
db.close()
content={}
for flow in flows:
@@ -521,7 +521,7 @@ async def upload(request:Request,files:t.List[UploadFile] = File(...)):
return {"files": [file.filename for file in files]}
@r.post("/updatejscss")
async def jscss(request:Request,app:str,files:t.List[UploadFile] = File(...),env:config.KINTONE_ENV = Depends(getkintoneenv)):
async def jscss(request:Request,app:str,files:t.List[UploadFile] = File(...),env = Depends(getkintoneenv)):
try:
jscs=[]
for file in files:
@@ -542,21 +542,21 @@ async def jscss(request:Request,app:str,files:t.List[UploadFile] = File(...),env
raise APIException('kintone:updatejscss',request.url._url, f"Error occurred while update js/css {file.filename} is not an Excel file",e)
@r.get("/app")
async def app(request:Request,app:str,env:config.KINTONE_ENV=Depends(getkintoneenv)):
async def app(request:Request,app:str,c:config.KINTONE_ENV=Depends(getkintoneenv)):
try:
headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE}
url = f"{env.BASE_URL}{config.API_V1_STR}/app.json"
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({env.DOMAIN_NAME}->{app}):",e)
raise APIException('kintone:app',request.url._url, f"Error occurred while get app({c.DOMAIN_NAME}->{app}):",e)
@r.get("/allapps")
async def allapps(request:Request,env:config.KINTONE_ENV=Depends(getkintoneenv)):
async def allapps(request:Request,c:config.KINTONE_ENV=Depends(getkintoneenv)):
try:
headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE}
url = f"{env.BASE_URL}{config.API_V1_STR}/apps.json"
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
url = f"{c.BASE_URL}{config.API_V1_STR}/apps.json"
offset = 0
limit = 100
all_apps = []
@@ -572,17 +572,17 @@ async def allapps(request:Request,env:config.KINTONE_ENV=Depends(getkintoneenv))
return {"apps": all_apps}
except Exception as e:
raise APIException('kintone:allapps', request.url._url, f"Error occurred while get allapps({env.DOMAIN_NAME}):", e)
raise APIException('kintone:allapps', request.url._url, f"Error occurred while get allapps({c.DOMAIN_NAME}):", e)
@r.get("/appfields")
async def appfields(request:Request,app:str,env:config.KINTONE_ENV = Depends(getkintoneenv)):
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_NAME}->{app}):",e)
@r.get("/allfields")
async def allfields(request:Request,app:str,env:config.KINTONE_ENV = Depends(getkintoneenv)):
async def allfields(request:Request,app:str,env = Depends(getkintoneenv)):
try:
field_resp = getfieldsfromkintone(app,env)
form_resp = getformfromkintone(app,env)
@@ -591,38 +591,38 @@ async def allfields(request:Request,app:str,env:config.KINTONE_ENV = Depends(get
raise APIException('kintone:allfields',request.url._url, f"Error occurred while get form fileds({env.DOMAIN_NAME}->{app}):",e)
@r.get("/appprocess")
async def appprocess(request:Request,app:str,env:config.KINTONE_ENV = Depends(getkintoneenv)):
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_NAME}->{app}):",e)
@r.get("/alljscss")
async def alljscs(request:Request,app:str,env:config.KINTONE_ENV=Depends(getkintoneenv)):
async def alljscs(request:Request,app:str,c:config.KINTONE_ENV=Depends(getkintoneenv)):
try:
headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE}
url = f"{env.BASE_URL}{config.API_V1_STR}/app/customize.json"
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({env.DOMAIN_NAME}->{app}):",e)
raise APIException('kintone:alljscss',request.url._url, f"Error occurred while get app js/css({c.DOMAIN_NAME}->{app}):",e)
@r.post("/createapp",)
async def createapp(request:Request,name:str,env:config.KINTONE_ENV=Depends(getkintoneenv)):
async def createapp(request:Request,name:str,c:config.KINTONE_ENV=Depends(getkintoneenv)):
try:
headers={config.API_V1_AUTH_KEY:env.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
data = {"name":name}
url = f"{env.BASE_URL}{config.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))
result = r.json()
if result.get("app") != None:
url = f"{env.BASE_URL}{config.API_V1_STR}/preview/app/deploy.json"
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({env.DOMAIN_NAME}->{name}):",e)
raise APIException('kintone:createapp',request.url._url, f"Error occurred while create app({c.DOMAIN_NAME}->{name}):",e)
@r.post("/createappfromexcel",)
@@ -761,7 +761,7 @@ async def createjstokintone(request:Request,app:str,env:config.KINTONE_ENV = Dep
try:
jscs=[]
files=[]
files.append(createappjs(env.BASE_URL, app))
files.append(createappjs(env.DOMAIN_ID, app))
files.append(getTempPath('alc_runtime.js'))
files.append(getTempPath('alc_runtime.css'))
for file in files:

View File

@@ -1,7 +1,4 @@
from http import HTTPStatus
from fastapi import Query, Request,Depends, APIRouter, UploadFile,HTTPException,File
from fastapi.responses import JSONResponse
# from app.core.operation import log_operation
from app.db import Base,engine
from app.db.session import get_db
from app.db.crud import *
@@ -10,79 +7,8 @@ from typing import List, Optional
from app.core.auth import get_current_active_user,get_current_user
from app.core.apiexception import APIException
import httpx
import app.core.config as config
platform_router = r = APIRouter()
@r.get(
"/apps",
response_model=List[AppList],
response_model_exclude_none=True,
)
async def apps_list(
request: Request,
user = Depends(get_current_active_user),
db=Depends(get_db),
):
try:
domain = get_activedomain(db, user.id)
platformapps = get_apps(db,domain.url)
kintoneevn = config.KINTONE_ENV(domain)
headers={config.API_V1_AUTH_KEY:kintoneevn.API_V1_AUTH_VALUE}
url = f"{kintoneevn.BASE_URL}{config.API_V1_STR}/apps.json"
offset = 0
limit = 100
all_apps = []
while True:
r = httpx.get(f"{url}?limit={limit}&offset={offset}", headers=headers)
json_data = r.json()
apps = json_data.get("apps",[])
all_apps.extend(apps)
if len(apps)<limit:
break
offset += limit
kintone_apps_dict = {app['appId']: app for app in all_apps}
filtered_apps = []
for papp in platformapps:
if papp.appid in kintone_apps_dict:
papp.appname = kintone_apps_dict[papp.appid]["name"]
filtered_apps.append(papp)
return filtered_apps
except Exception as e:
raise APIException('platform:apps',request.url._url,f"Error occurred while get apps:",e)
@r.post("/apps", response_model=AppList, response_model_exclude_none=True)
async def apps_update(
request: Request,
app: AppVersion,
user=Depends(get_current_active_user),
db=Depends(get_db),
):
try:
return update_appversion(db, app,user.id)
except Exception as e:
raise APIException('platform:apps',request.url._url,f"Error occurred while get create app :",e)
@r.delete(
"/apps/{domainurl}/{appid}", response_model_exclude_none=True
)
async def apps_delete(
request: Request,
domainurl:str,
appid: str,
user=Depends(get_current_active_user),
db=Depends(get_db),
):
try:
return delete_apps(db, domainurl,appid)
except Exception as e:
raise APIException('platform:apps',request.url._url,f"Error occurred while delete apps({domainurl}:{appid}):",e)
@r.get(
"/appsettings/{id}",
response_model=App,
@@ -197,13 +123,13 @@ async def flow_details(
async def flow_list(
request: Request,
appid: str,
user=Depends(get_current_active_user),
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.url, appid)
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)
@@ -212,13 +138,13 @@ async def flow_list(
@r.post("/flow", response_model=Flow, response_model_exclude_none=True)
async def flow_create(
request: Request,
flow: FlowIn,
user=Depends(get_current_active_user),
flow: FlowBase,
user=Depends(get_current_user),
db=Depends(get_db),
):
try:
domain = get_activedomain(db, user.id)
return create_flow(db, domain.url, flow)
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)
@@ -228,14 +154,11 @@ async def flow_create(
)
async def flow_edit(
request: Request,
flowid: str,
flow: FlowIn,
user=Depends(get_current_active_user),
flow: FlowBase,
db=Depends(get_db),
):
try:
domain = get_activedomain(db, user.id)
return edit_flow(db,domain.url, flow,user.id)
return edit_flow(db, flow)
except Exception as e:
raise APIException('platform:flow',request.url._url,f"Error occurred while edit flow:",e)
@@ -273,11 +196,10 @@ async def domain_details(
async def domain_create(
request: Request,
domain: DomainBase,
user=Depends(get_current_active_user),
db=Depends(get_db),
):
try:
return create_domain(db, domain,user.id)
return create_domain(db, domain)
except Exception as e:
raise APIException('platform:domain',request.url._url,f"Error occurred while create domain:",e)
@@ -288,11 +210,10 @@ async def domain_create(
async def domain_edit(
request: Request,
domain: DomainBase,
user=Depends(get_current_active_user),
db=Depends(get_db),
):
try:
return edit_domain(db, domain,user.id)
return edit_domain(db, domain)
except Exception as e:
raise APIException('platform:domain',request.url._url,f"Error occurred while edit domain:",e)
@@ -318,7 +239,7 @@ async def domain_delete(
async def userdomain_details(
request: Request,
userId: Optional[int] = Query(None, alias="userId"),
user=Depends(get_current_active_user),
user=Depends(get_current_user),
db=Depends(get_db),
):
try:
@@ -366,14 +287,13 @@ async def userdomain_delete(
async def get_useractivedomain(
request: Request,
userId: Optional[int] = Query(None, alias="userId"),
user=Depends(get_current_active_user),
user=Depends(get_current_user),
db=Depends(get_db),
):
try:
# domain = get_activedomain(db, user.id)
domain = get_activedomain(db, userId if userId is not None else user.id)
if domain is None:
return JSONResponse(content=None,status_code=HTTPStatus.OK)
return domain
except Exception as e:
raise APIException('platform:activedomain',request.url._url,f"Error occurred while get user({user.id}) activedomain:",e)
@@ -386,7 +306,7 @@ async def update_activeuserdomain(
request: Request,
domainid:int,
userId: Optional[int] = Query(None, alias="userId"),
user=Depends(get_current_active_user),
user=Depends(get_current_user),
db=Depends(get_db),
):
try:

View File

@@ -1,4 +1,4 @@
from fastapi import APIRouter, Request, Depends, Response, Security, encoders
from fastapi import APIRouter, Request, Depends, Response, encoders
import typing as t
from app.db.session import get_db
@@ -8,11 +8,9 @@ from app.db.crud import (
create_user,
delete_user,
edit_user,
assign_userrole,
get_roles,
)
from app.db.schemas import UserCreate, UserEdit, User, UserOut,Role
from app.core.auth import get_current_user,get_current_active_user, get_current_active_superuser
from app.db.schemas import UserCreate, UserEdit, User, UserOut
from app.core.auth import get_current_active_user, get_current_active_superuser
users_router = r = APIRouter()
@@ -25,14 +23,14 @@ users_router = r = APIRouter()
async def users_list(
response: Response,
db=Depends(get_db),
current_user=Depends(get_current_active_user),
current_user=Depends(get_current_active_superuser),
):
"""
Get all users
"""
users = get_users(db,current_user.is_superuser)
users = get_users(db)
# This is necessary for react-admin to work
#response.headers["Content-Range"] = f"0-9/{len(users)}"
response.headers["Content-Range"] = f"0-9/{len(users)}"
return users
@@ -107,30 +105,3 @@ async def user_delete(
Delete existing user
"""
return delete_user(db, user_id)
@r.post("/userrole",
response_model=User,
response_model_exclude_none=True,)
async def assign_role(
request: Request,
userid:int,
roles:t.List[int],
db=Depends(get_db)
):
return assign_userrole(db,userid,roles)
@r.get(
"/roles",
response_model=t.List[Role],
response_model_exclude_none=True,
)
async def roles_list(
response: Response,
db=Depends(get_db),
current_user=Security(get_current_active_user, scopes=["role_list"]),
):
roles = get_roles(db)
return roles

View File

@@ -1,6 +1,5 @@
from fastapi.security import SecurityScopes
import jwt
from fastapi import Depends, HTTPException, Request, Security, status
from fastapi import Depends, HTTPException, status
from jwt import PyJWTError
from app.db import models, schemas, session
@@ -8,7 +7,7 @@ from app.db.crud import get_user_by_email, create_user,get_user
from app.core import security
async def get_current_user(security_scopes: SecurityScopes,
async def get_current_user(
db=Depends(session.get_db), token: str = Depends(security.oauth2_scheme)
):
credentials_exception = HTTPException(
@@ -17,21 +16,13 @@ async def get_current_user(security_scopes: SecurityScopes,
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(
token, security.SECRET_KEY, algorithms=[security.ALGORITHM]
)
id: int = payload.get("sub")
if id is None:
raise credentials_exception
permissions: str = payload.get("permissions")
if not permissions =="ALL":
for scope in security_scopes.scopes:
if scope not in permissions.split(";"):
raise HTTPException(
status_code=403, detail="The user doesn't have enough privileges"
)
token_data = schemas.TokenData(id = id, permissions=permissions)
except PyJWTError:
raise credentials_exception

View File

@@ -5,7 +5,7 @@ import base64
PROJECT_NAME = "KintoneAppBuilder"
#SQLALCHEMY_DATABASE_URI = "postgres://kabAdmin:P@ssw0rd!@kintonetooldb.postgres.database.azure.com/dev"
SQLALCHEMY_DATABASE_URI = f"postgresql+psycopg2://kabAdmin:P%40ssw0rd!@kintonetooldb.postgres.database.azure.com/dev_v2"
SQLALCHEMY_DATABASE_URI = "postgres://kabAdmin:P@ssw0rd!@kintonetooldb.postgres.database.azure.com/postgres"
#SQLALCHEMY_DATABASE_URI = "postgres://kabAdmin:P@ssw0rd!@kintonetooldb.postgres.database.azure.com/test"
#SQLALCHEMY_DATABASE_URI = "postgres://kabAdmin:P@ssw0rd!@ktune-prod-db.postgres.database.azure.com/postgres"
API_V1_STR = "/k/v1"

View File

@@ -1,4 +1,3 @@
from datetime import datetime
from fastapi import HTTPException, status
from sqlalchemy.orm import Session
from sqlalchemy import and_
@@ -20,12 +19,9 @@ def get_user_by_email(db: Session, email: str) -> schemas.UserBase:
def get_users(
db: Session, super:bool
db: Session, skip: int = 0, limit: int = 100
) -> t.List[schemas.UserOut]:
if super:
return db.query(models.User).all()
else:
return db.query(models.User).filter(models.User.is_superuser == False)
return db.query(models.User).offset(skip).limit(limit).all()
def create_user(db: Session, user: schemas.UserCreate):
@@ -74,80 +70,6 @@ def edit_user(
return db_user
def get_roles(
db: Session
) -> t.List[schemas.Role]:
return db.query(models.Role).all()
def assign_userrole( db: Session, user_id: int, roles: t.List[int]):
db_user = db.query(models.User).get(user_id)
if db_user:
for role in db_user.roles:
db_user.roles.remove(role)
for roleid in roles:
role = db.query(models.Role).get(roleid)
if role:
db_user.roles.append(role)
db.commit()
db.refresh(db_user)
return db_user
def get_apps(
db: Session,
domainurl:str
) -> t.List[schemas.AppList]:
return db.query(models.App).filter(models.App.domainurl == domainurl).all()
def update_appversion(db: Session, appedit: schemas.AppVersion,userid:int):
db_app = db.query(models.App).filter(and_(models.App.domainurl == appedit.domainurl,models.App.appid == appedit.appid)).first()
if not db_app:
raise HTTPException(status.HTTP_404_NOT_FOUND, detail="User not found")
db_app.version = db_app.version + 1
appversion = models.AppVersion(
domainurl = appedit.domainurl,
appid=appedit.appid,
appname=db_app.appname,
version = db_app.version,
versionname = appedit.versionname,
comment = appedit.comment,
updateuserid = userid,
createuserid = userid
)
db.add(appversion)
db.add(db_app)
flows = db.query(models.Flow).filter(and_(models.Flow.domainurl == appedit.domainurl,models.App.appid == appedit.appid))
for flow in flows:
db_flowhistory = models.FlowHistory(
flowid = flow.flowid,
appid = flow.appid,
eventid = flow.eventid,
domainurl = flow.domainurl,
name = flow.name,
content = flow.content,
createuser = userid,
version = db_app.version,
updateuserid = userid,
createuserid = userid
)
db.add(db_flowhistory)
db.commit()
db.refresh(db_app)
return db_app
def delete_apps(db: Session, domainurl: str,appid: str ):
db_app = db.query(models.App).filter(and_(models.App.domainurl == domainurl,models.App.appid ==appid)).first()
if not db_app:
raise HTTPException(status.HTTP_404_NOT_FOUND, detail="App not found")
db.delete(db_app)
db_flows = db.query(models.Flow).filter(and_(models.Flow.domainurl == domainurl,models.Flow.appid ==appid))
for flow in db_flows:
db.delete(flow)
db.commit()
return db_app
def get_appsetting(db: Session, id: int):
app = db.query(models.AppSetting).get(id)
if not app:
@@ -203,28 +125,16 @@ def get_actions(db: Session):
return actions
def create_flow(db: Session, domainurl: str, flow: schemas.FlowIn,userid:int):
def create_flow(db: Session, domainid: int, flow: schemas.FlowBase):
db_flow = models.Flow(
flowid=flow.flowid,
appid=flow.appid,
eventid=flow.eventid,
domainurl=domainurl,
domainid=domainid,
name=flow.name,
content=flow.content,
createuserid = userid,
updateuserid = userid
content=flow.content
)
db.add(db_flow)
db_app = db.query(models.App).filter(and_(models.App.domainurl == domainurl,models.App.appid == flow.appid)).first()
if not db_app:
db_app = models.App(
domainurl = domainurl,
appid=flow.appid,
appname=flow.appname,
version = 0,
createuserid= userid,
updateuserid = userid
)
db.commit()
db.refresh(db_flow)
return db_flow
@@ -239,19 +149,15 @@ def delete_flow(db: Session, flowid: str):
def edit_flow(
db: Session, domainurl: str, flow: schemas.FlowIn,userid:int
db: Session, flow: schemas.FlowBase
) -> schemas.Flow:
db_flow = get_flow(db, flow.flowid)
if not db_flow:
#見つからない時新規作成
return create_flow(db,domainurl,flow,userid)
raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Flow not found")
update_data = flow.dict(exclude_unset=True)
db_flow.appid =flow.appid
db_flow.eventid=flow.eventid
db_flow.domainurl=domainurl
db_flow.name=flow.name
db_flow.content=flow.content
db_flow.updateuserid = userid
for key, value in update_data.items():
setattr(db_flow, key, value)
db.add(db_flow)
db.commit()
@@ -267,30 +173,26 @@ def get_flows(db: Session, flowid: str):
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")
if not flow:
raise HTTPException(status_code=404, detail="Data not found")
return flow
def get_flows_by_app(db: Session,domainurl: str, appid: str):
flows = db.query(models.Flow).filter(and_(models.Flow.domainurl == domainurl,models.Flow.appid == appid)).all()
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,userid:int):
def create_domain(db: Session, domain: schemas.DomainBase):
domain.encrypt_kintonepwd()
db_domain = models.Domain(
tenantid = domain.tenantid,
name=domain.name,
url=domain.url,
kintoneuser=domain.kintoneuser,
kintonepwd=domain.kintonepwd,
createuserid = userid,
updateuserid = userid
kintonepwd=domain.kintonepwd
)
db.add(db_domain)
db.flush()
add_userdomain(db,userid,db_domain.id)
db.commit()
db.refresh(db_domain)
return db_domain
@@ -305,31 +207,24 @@ def delete_domain(db: Session,id: int):
def edit_domain(
db: Session, domain: schemas.DomainBase,userid:int
db: Session, domain: schemas.DomainBase
) -> schemas.Domain:
domain.encrypt_kintonepwd()
db_domain = db.query(models.Domain).get(domain.id)
if not db_domain:
raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Domain not found")
db_domain.tenantid = domain.tenantid
db_domain.name=domain.name
db_domain.url=domain.url
db_domain.kintoneuser=domain.kintoneuser
db_domain.kintonepwd = domain.kintonepwd
db_domain.updateuserid = userid
db_domain.update_time = datetime.now
update_data = domain.dict(exclude_unset=True)
for key, value in update_data.items():
if key != "id" and not (key == "kintonepwd" and (value is None or value == "")):
setattr(db_domain, key, value)
print(str(db_domain))
db.add(db_domain)
db.commit()
db.refresh(db_domain)
return db_domain
def add_userdomain(db: Session, userid:int,domainid:int):
user_domain = models.UserDomain(userid = userid, domainid = domainid )
db.add(user_domain)
return user_domain
def add_userdomains(db: Session, userid:int,domainids:list[str]):
def add_userdomain(db: Session, userid:int,domainids:list[str]):
dbCommits = list(map(lambda domainid: models.UserDomain(userid = userid, domainid = domainid ), domainids))
db.bulk_save_objects(dbCommits)
db.commit()
@@ -356,23 +251,16 @@ def active_userdomain(db: Session, userid: int,domainid: int):
db.commit()
return db_userdomains
def get_activedomain(db: Session, userid: int)-> t.Optional[models.Domain]:
user_domains = (db.query(models.Domain,models.UserDomain.active)
.join(models.UserDomain,models.UserDomain.domainid == models.Domain.id )
.filter(models.UserDomain.userid == userid)
.all())
db_domain=None
if len(user_domains)==1:
db_domain = user_domains[0][0];
else:
db_domain = next((domain for domain,active in user_domains if active),None)
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")
if not domains:
raise HTTPException(status_code=404, detail="Data not found")
# for domain in domains:
# decrypted_pwd = chacha20Decrypt(domain.kintonepwd)
# domain.kintonepwd = decrypted_pwd

View File

@@ -1,8 +1,7 @@
from sqlalchemy import Boolean, Column, Integer, String, DateTime,ForeignKey,Table
from sqlalchemy import Boolean, Column, Integer, String, DateTime,ForeignKey
from sqlalchemy.ext.declarative import as_declarative
from sqlalchemy.orm import relationship
from datetime import datetime
from app.db.session import Base
from app.core.security import chacha20Decrypt
@as_declarative()
@@ -11,21 +10,6 @@ class Base:
create_time = Column(DateTime, default=datetime.now)
update_time = Column(DateTime, default=datetime.now, onupdate=datetime.now)
userrole = Table(
"userrole",
Base.metadata,
Column("userid",Integer,ForeignKey("user.id")),
Column("roleid",Integer,ForeignKey("role.id")),
)
rolepermission = Table(
"rolepermission",
Base.metadata,
Column("roleid",Integer,ForeignKey("role.id")),
Column("permissionid",Integer,ForeignKey("permission.id")),
)
class User(Base):
__tablename__ = "user"
@@ -35,52 +19,6 @@ class User(Base):
hashed_password = Column(String(200), nullable=False)
is_active = Column(Boolean, default=True)
is_superuser = Column(Boolean, default=False)
roles = relationship("Role",secondary=userrole,back_populates="users")
class Role(Base):
__tablename__ = "role"
name = Column(String(100))
description = Column(String(255))
users = relationship("User",secondary=userrole,back_populates="roles")
permissions = relationship("Permission",secondary=rolepermission,back_populates="roles")
class Permission(Base):
__tablename__ = "permission"
menu = Column(String(100))
function = Column(String(255))
privilege = Column(String(100))
roles = relationship("Role",secondary=rolepermission,back_populates="permissions")
class App(Base):
__tablename__ = "app"
domainurl = Column(String(200), nullable=False)
appname = Column(String(200), nullable=False)
appid = Column(String(100), index=True, nullable=False)
version = Column(Integer)
createuserid = Column(Integer,ForeignKey("user.id"))
updateuserid = Column(Integer,ForeignKey("user.id"))
createuser = relationship('User',foreign_keys=[createuserid])
updateuser = relationship('User',foreign_keys=[updateuserid])
class AppVersion(Base):
__tablename__ = "appversion"
domainurl = Column(String(200), nullable=False)
appname = Column(String(200), nullable=False)
appid = Column(String(100), index=True, nullable=False)
version = Column(Integer)
versionname = Column(String(200), nullable=False)
comment = Column(String(200), nullable=False)
createuserid = Column(Integer,ForeignKey("user.id"))
updateuserid = Column(Integer,ForeignKey("user.id"))
createuser = relationship('User',foreign_keys=[createuserid])
updateuser = relationship('User',foreign_keys=[updateuserid])
class AppSetting(Base):
__tablename__ = "appsetting"
@@ -113,28 +51,9 @@ class Flow(Base):
flowid = Column(String(100), index=True, nullable=False)
appid = Column(String(100), index=True, nullable=False)
eventid = Column(String(100), index=True, nullable=False)
domainurl = Column(String(200))
domainid = Column(Integer,ForeignKey("domain.id"))
name = Column(String(200))
content = Column(String)
createuserid = Column(Integer,ForeignKey("user.id"))
updateuserid = Column(Integer,ForeignKey("user.id"))
createuser = relationship('User',foreign_keys=[createuserid])
updateuser = relationship('User',foreign_keys=[updateuserid])
class FlowHistory(Base):
__tablename__ = "flowhistory"
flowid = Column(String(100), index=True, nullable=False)
appid = Column(String(100), index=True, nullable=False)
eventid = Column(String(100), index=True, nullable=False)
domainurl = Column(String(200))
name = Column(String(200))
content = Column(String)
version = Column(Integer)
createuserid = Column(Integer,ForeignKey("user.id"))
updateuserid = Column(Integer,ForeignKey("user.id"))
createuser = relationship('User',foreign_keys=[createuserid])
updateuser = relationship('User',foreign_keys=[updateuserid])
class Tenant(Base):
__tablename__ = "tenant"
@@ -156,10 +75,7 @@ class Domain(Base):
def decrypt_kintonepwd(self):
decrypted_pwd = chacha20Decrypt(self.kintonepwd)
return decrypted_pwd
createuserid = Column(Integer,ForeignKey("user.id"))
updateuserid = Column(Integer,ForeignKey("user.id"))
createuser = relationship('User',foreign_keys=[createuserid])
updateuser = relationship('User',foreign_keys=[updateuserid])
class UserDomain(Base):
__tablename__ = "userdomain"
@@ -192,17 +108,6 @@ class ErrorLog(Base):
location = Column(String(500))
content = Column(String(5000))
class OperationLog(Base):
__tablename__ = "operationlog"
tenantid = Column(String(100))
domainurl = Column(String(200))
userid = Column(Integer,ForeignKey("user.id"))
operation = Column(String(200))
function = Column(String(200))
detail = Column(String(200))
user = relationship('User')
class KintoneFormat(Base):
__tablename__ = "kintoneformat"

View File

@@ -8,26 +8,13 @@ class Base(BaseModel):
create_time: datetime
update_time: datetime
class Permission(BaseModel):
id: int
menu:str
function:str
privilege:str
class Role(BaseModel):
id: int
name:str
description:str
permissions:t.List[Permission] = []
class UserBase(BaseModel):
email: str
is_active: bool = True
is_superuser: bool = False
first_name: str = None
last_name: str = None
roles:t.List[Role] = []
class UserOut(UserBase):
pass
@@ -41,21 +28,21 @@ class UserCreate(UserBase):
is_active:bool
is_superuser:bool
class ConfigDict:
class Config:
orm_mode = True
class UserEdit(UserBase):
password: t.Optional[str] = None
class ConfigDict:
class Config:
orm_mode = True
class User(UserBase):
id: int
class ConfigDict:
class Config:
orm_mode = True
@@ -63,20 +50,6 @@ class Token(BaseModel):
access_token: str
token_type: str
class AppList(Base):
domainurl: str
appname: str
appid:str
updateuser: UserOut
version:int
class AppVersion(BaseModel):
domainurl: str
appname: str
versionname: str
comment:str
appid:str
class TokenData(BaseModel):
id:int = 0
@@ -95,7 +68,7 @@ class AppBase(BaseModel):
class App(AppBase):
id: int
class ConfigDict:
class Config:
orm_mode = True
@@ -106,7 +79,7 @@ class Kintone(BaseModel):
desc: str = None
content: str = None
class ConfigDict:
class Config:
orm_mode = True
class Action(BaseModel):
@@ -119,14 +92,12 @@ class Action(BaseModel):
categoryid: int = None
nosort: int
categoryname : str =None
class ConfigDict:
class Config:
orm_mode = True
class FlowIn(BaseModel):
class FlowBase(BaseModel):
flowid: str
# domainurl:str
appid: str
appname:str
eventid: str
name: str = None
content: str = None
@@ -136,11 +107,11 @@ class Flow(Base):
flowid: str
appid: str
eventid: str
domainurl: str
domainid: int
name: str = None
content: str = None
class ConfigDict:
class Config:
orm_mode = True
class DomainBase(BaseModel):
@@ -162,7 +133,7 @@ class Domain(Base):
url: str
kintoneuser: str
kintonepwd: str
class ConfigDict:
class Config:
orm_mode = True
class Event(Base):
@@ -174,7 +145,7 @@ class Event(Base):
mobile: bool
eventgroup: bool
class ConfigDict:
class Config:
orm_mode = True
class ErrorCreate(BaseModel):

Binary file not shown.

View File

@@ -1,4 +1,4 @@
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" version="24.8.6" pages="4">
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" version="24.8.3" pages="4">
<diagram name="Page-1" id="efa7a0a1-bf9b-a30e-e6df-94a7791c09e9">
<mxGraphModel dx="1434" dy="884" 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>
@@ -134,7 +134,7 @@
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="-EYEuPrK34tZavjatbhk-1" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;dashed=1;" parent="1" vertex="1">
<mxGeometry x="635" y="-920" width="775" height="1200" as="geometry" />
<mxGeometry x="635" y="-920" width="605" height="1120" as="geometry" />
</mxCell>
<mxCell id="vKKEXlAMpGyNXKJgxOUS-2" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;dashed=1;" parent="1" vertex="1">
<mxGeometry x="295" y="-920" width="290" height="505" as="geometry" />
@@ -552,15 +552,15 @@
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-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="GH2g80-cBXHe62XdPV4N-18" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-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;" vertex="1" parent="GH2g80-cBXHe62XdPV4N-18">
<mxGeometry y="120" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-2" value="UK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" parent="tkXtZmliqQ14OWrfpaW_-1" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-2" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-1">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-3" value="app_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" parent="tkXtZmliqQ14OWrfpaW_-1" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-3" value="app_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-1">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
@@ -578,28 +578,28 @@
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="65XQlPrDDXONBYnOkRAB-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="GH2g80-cBXHe62XdPV4N-18" vertex="1">
<mxCell id="65XQlPrDDXONBYnOkRAB-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;" vertex="1" parent="GH2g80-cBXHe62XdPV4N-18">
<mxGeometry y="180" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="65XQlPrDDXONBYnOkRAB-2" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" parent="65XQlPrDDXONBYnOkRAB-1" vertex="1">
<mxCell id="65XQlPrDDXONBYnOkRAB-2" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" vertex="1" parent="65XQlPrDDXONBYnOkRAB-1">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="65XQlPrDDXONBYnOkRAB-3" value="Update_User" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" parent="65XQlPrDDXONBYnOkRAB-1" vertex="1">
<mxCell id="65XQlPrDDXONBYnOkRAB-3" value="Update_User" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" vertex="1" parent="65XQlPrDDXONBYnOkRAB-1">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="65XQlPrDDXONBYnOkRAB-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="GH2g80-cBXHe62XdPV4N-18" vertex="1">
<mxCell id="65XQlPrDDXONBYnOkRAB-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;" vertex="1" parent="GH2g80-cBXHe62XdPV4N-18">
<mxGeometry y="210" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="65XQlPrDDXONBYnOkRAB-5" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" parent="65XQlPrDDXONBYnOkRAB-4" vertex="1">
<mxCell id="65XQlPrDDXONBYnOkRAB-5" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" vertex="1" parent="65XQlPrDDXONBYnOkRAB-4">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="65XQlPrDDXONBYnOkRAB-6" value="Verion" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" parent="65XQlPrDDXONBYnOkRAB-4" vertex="1">
<mxCell id="65XQlPrDDXONBYnOkRAB-6" value="Verion" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" vertex="1" parent="65XQlPrDDXONBYnOkRAB-4">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
@@ -978,358 +978,217 @@
<mxCell id="-EYEuPrK34tZavjatbhk-2" value="テナントDB" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=#6c8ebf;fillColor=#dae8fc;dashed=1;gradientColor=#7ea6e0;" parent="1" vertex="1">
<mxGeometry x="635" y="-950" width="90" height="30" as="geometry" />
</mxCell>
<mxCell id="r-0MZSSSpHWbTn0B3lSh-1" value="Flow_stage" 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">
<mxCell id="r-0MZSSSpHWbTn0B3lSh-1" value="Flow_stage" 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;" vertex="1" parent="1">
<mxGeometry x="380" y="-385" width="180" height="210" as="geometry">
<mxRectangle x="320" y="370" width="60" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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="r-0MZSSSpHWbTn0B3lSh-1" vertex="1">
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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;" vertex="1" parent="r-0MZSSSpHWbTn0B3lSh-1">
<mxGeometry y="30" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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="r-0MZSSSpHWbTn0B3lSh-2" vertex="1">
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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;" vertex="1" parent="r-0MZSSSpHWbTn0B3lSh-2">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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="r-0MZSSSpHWbTn0B3lSh-2" vertex="1">
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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;" vertex="1" parent="r-0MZSSSpHWbTn0B3lSh-2">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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="r-0MZSSSpHWbTn0B3lSh-1" vertex="1">
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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;" vertex="1" parent="r-0MZSSSpHWbTn0B3lSh-1">
<mxGeometry y="60" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="r-0MZSSSpHWbTn0B3lSh-6" 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="r-0MZSSSpHWbTn0B3lSh-5" vertex="1">
<mxCell id="r-0MZSSSpHWbTn0B3lSh-6" 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;" vertex="1" parent="r-0MZSSSpHWbTn0B3lSh-5">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="r-0MZSSSpHWbTn0B3lSh-7" value="domain_url" style="shape=partialRectangle;connectable=0;fillColor=#e51400;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=0;overflow=hidden;whiteSpace=wrap;html=1;fontColor=#ffffff;strokeColor=#B20000;" parent="r-0MZSSSpHWbTn0B3lSh-5" vertex="1">
<mxCell id="r-0MZSSSpHWbTn0B3lSh-7" value="domain_url" style="shape=partialRectangle;connectable=0;fillColor=#e51400;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=0;overflow=hidden;whiteSpace=wrap;html=1;fontColor=#ffffff;strokeColor=#B20000;" vertex="1" parent="r-0MZSSSpHWbTn0B3lSh-5">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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="r-0MZSSSpHWbTn0B3lSh-1" vertex="1">
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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;" vertex="1" parent="r-0MZSSSpHWbTn0B3lSh-1">
<mxGeometry y="90" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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="r-0MZSSSpHWbTn0B3lSh-8" vertex="1">
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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;" vertex="1" parent="r-0MZSSSpHWbTn0B3lSh-8">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="r-0MZSSSpHWbTn0B3lSh-10" 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="r-0MZSSSpHWbTn0B3lSh-8" vertex="1">
<mxCell id="r-0MZSSSpHWbTn0B3lSh-10" 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;" vertex="1" parent="r-0MZSSSpHWbTn0B3lSh-8">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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="r-0MZSSSpHWbTn0B3lSh-1" vertex="1">
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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;" vertex="1" parent="r-0MZSSSpHWbTn0B3lSh-1">
<mxGeometry y="120" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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="r-0MZSSSpHWbTn0B3lSh-11" vertex="1">
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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;" vertex="1" parent="r-0MZSSSpHWbTn0B3lSh-11">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="r-0MZSSSpHWbTn0B3lSh-13" 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="r-0MZSSSpHWbTn0B3lSh-11" vertex="1">
<mxCell id="r-0MZSSSpHWbTn0B3lSh-13" 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;" vertex="1" parent="r-0MZSSSpHWbTn0B3lSh-11">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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="r-0MZSSSpHWbTn0B3lSh-1" vertex="1">
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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;" vertex="1" parent="r-0MZSSSpHWbTn0B3lSh-1">
<mxGeometry y="150" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="r-0MZSSSpHWbTn0B3lSh-15" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" parent="r-0MZSSSpHWbTn0B3lSh-14" vertex="1">
<mxCell id="r-0MZSSSpHWbTn0B3lSh-15" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" vertex="1" parent="r-0MZSSSpHWbTn0B3lSh-14">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="r-0MZSSSpHWbTn0B3lSh-16" 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="r-0MZSSSpHWbTn0B3lSh-14" vertex="1">
<mxCell id="r-0MZSSSpHWbTn0B3lSh-16" value="content(json)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" vertex="1" parent="r-0MZSSSpHWbTn0B3lSh-14">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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="r-0MZSSSpHWbTn0B3lSh-1" vertex="1">
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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;" vertex="1" parent="r-0MZSSSpHWbTn0B3lSh-1">
<mxGeometry y="180" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="r-0MZSSSpHWbTn0B3lSh-18" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" parent="r-0MZSSSpHWbTn0B3lSh-17" vertex="1">
<mxCell id="r-0MZSSSpHWbTn0B3lSh-18" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" vertex="1" parent="r-0MZSSSpHWbTn0B3lSh-17">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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="r-0MZSSSpHWbTn0B3lSh-17" vertex="1">
<mxCell id="r-0MZSSSpHWbTn0B3lSh-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;" vertex="1" parent="r-0MZSSSpHWbTn0B3lSh-17">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="r-0MZSSSpHWbTn0B3lSh-20" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="8Zu1yShcSHxMs68hy39H-2" target="r-0MZSSSpHWbTn0B3lSh-2" edge="1">
<mxCell id="r-0MZSSSpHWbTn0B3lSh-20" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="8Zu1yShcSHxMs68hy39H-2" target="r-0MZSSSpHWbTn0B3lSh-2">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-4" value="OperateLog" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" parent="1" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-4" value="OperateLog" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" vertex="1" parent="1">
<mxGeometry x="380" y="-140" width="180" height="300" as="geometry" />
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-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=1;" parent="tkXtZmliqQ14OWrfpaW_-4" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-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=1;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-4">
<mxGeometry y="30" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-6" 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="tkXtZmliqQ14OWrfpaW_-5" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-6" 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;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-5">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-7" 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="tkXtZmliqQ14OWrfpaW_-5" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-7" 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;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-5">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-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="tkXtZmliqQ14OWrfpaW_-4" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-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;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-4">
<mxGeometry y="60" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-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="tkXtZmliqQ14OWrfpaW_-8" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-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;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-8">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-10" value="event_datetime" 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="tkXtZmliqQ14OWrfpaW_-8" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-10" value="event_datetime" 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;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-8">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-30" 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="tkXtZmliqQ14OWrfpaW_-4" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-30" 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;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-4">
<mxGeometry y="90" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-31" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" parent="tkXtZmliqQ14OWrfpaW_-30" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-31" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-30">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-32" value="tenant_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" parent="tkXtZmliqQ14OWrfpaW_-30" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-32" value="tenant_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-30">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-27" 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="tkXtZmliqQ14OWrfpaW_-4" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-27" 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;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-4">
<mxGeometry y="120" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-28" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" parent="tkXtZmliqQ14OWrfpaW_-27" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-28" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-27">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-29" value="domain_url" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" parent="tkXtZmliqQ14OWrfpaW_-27" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-29" value="domain_url" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-27">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-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="tkXtZmliqQ14OWrfpaW_-4" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-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;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-4">
<mxGeometry y="150" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-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="tkXtZmliqQ14OWrfpaW_-11" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-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;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-11">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-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="tkXtZmliqQ14OWrfpaW_-11" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-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;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-11">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-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="tkXtZmliqQ14OWrfpaW_-4" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-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;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-4">
<mxGeometry y="180" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-15" 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="tkXtZmliqQ14OWrfpaW_-14" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-15" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-14">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-16" value="evnetname" 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="tkXtZmliqQ14OWrfpaW_-14" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-16" value="evnetname" 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;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-14">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-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="tkXtZmliqQ14OWrfpaW_-4" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-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;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-4">
<mxGeometry y="210" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-18" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" parent="tkXtZmliqQ14OWrfpaW_-17" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-18" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-17">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-19" value="operation" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" parent="tkXtZmliqQ14OWrfpaW_-17" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-19" value="operation" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-17">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-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="tkXtZmliqQ14OWrfpaW_-4" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-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;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-4">
<mxGeometry y="240" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-25" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" parent="tkXtZmliqQ14OWrfpaW_-24" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-25" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-24">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-26" value="function" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" parent="tkXtZmliqQ14OWrfpaW_-24" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-26" value="function" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-24">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-35" 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="tkXtZmliqQ14OWrfpaW_-4" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-35" 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;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-4">
<mxGeometry y="270" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-36" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" parent="tkXtZmliqQ14OWrfpaW_-35" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-36" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-35">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="tkXtZmliqQ14OWrfpaW_-37" value="detail" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" parent="tkXtZmliqQ14OWrfpaW_-35" vertex="1">
<mxCell id="tkXtZmliqQ14OWrfpaW_-37" value="detail" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" vertex="1" parent="tkXtZmliqQ14OWrfpaW_-35">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-4" value="App_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;" vertex="1" parent="1">
<mxGeometry x="1220" y="-680" width="180" height="330" as="geometry">
<mxRectangle x="600" y="370" width="60" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-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=1;" vertex="1" parent="BQHE1joUryQacNBmIgG7-4">
<mxGeometry y="30" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-6" 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;" vertex="1" parent="BQHE1joUryQacNBmIgG7-5">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-7" 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;" vertex="1" parent="BQHE1joUryQacNBmIgG7-5">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-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;" vertex="1" parent="BQHE1joUryQacNBmIgG7-4">
<mxGeometry y="60" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-9" 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;" vertex="1" parent="BQHE1joUryQacNBmIgG7-8">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-10" value="domain_url" style="shape=partialRectangle;connectable=0;fillColor=#e51400;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;fontColor=#ffffff;strokeColor=#B20000;" vertex="1" parent="BQHE1joUryQacNBmIgG7-8">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-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;" vertex="1" parent="BQHE1joUryQacNBmIgG7-4">
<mxGeometry y="90" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-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;" vertex="1" parent="BQHE1joUryQacNBmIgG7-11">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-13" 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;" vertex="1" parent="BQHE1joUryQacNBmIgG7-11">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-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;" vertex="1" parent="BQHE1joUryQacNBmIgG7-4">
<mxGeometry y="120" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-15" value="UK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" vertex="1" parent="BQHE1joUryQacNBmIgG7-14">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-16" value="app_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" vertex="1" parent="BQHE1joUryQacNBmIgG7-14">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-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;" vertex="1" parent="BQHE1joUryQacNBmIgG7-4">
<mxGeometry y="150" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-18" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" vertex="1" parent="BQHE1joUryQacNBmIgG7-17">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-19" 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;" vertex="1" parent="BQHE1joUryQacNBmIgG7-17">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-20" 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;" vertex="1" parent="BQHE1joUryQacNBmIgG7-4">
<mxGeometry y="180" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-21" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" vertex="1" parent="BQHE1joUryQacNBmIgG7-20">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-22" value="Update_User" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" vertex="1" parent="BQHE1joUryQacNBmIgG7-20">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-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=0;" vertex="1" parent="BQHE1joUryQacNBmIgG7-4">
<mxGeometry y="210" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-24" value="UK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" vertex="1" parent="BQHE1joUryQacNBmIgG7-23">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="BQHE1joUryQacNBmIgG7-25" value="Verion" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" vertex="1" parent="BQHE1joUryQacNBmIgG7-23">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="-PBKhDU9AzNn-prZe6Pj-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;" vertex="1" parent="BQHE1joUryQacNBmIgG7-4">
<mxGeometry y="240" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="-PBKhDU9AzNn-prZe6Pj-5" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" vertex="1" parent="-PBKhDU9AzNn-prZe6Pj-4">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="-PBKhDU9AzNn-prZe6Pj-6" value="Version_Name" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" vertex="1" parent="-PBKhDU9AzNn-prZe6Pj-4">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="-PBKhDU9AzNn-prZe6Pj-7" 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;" vertex="1" parent="BQHE1joUryQacNBmIgG7-4">
<mxGeometry y="270" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="-PBKhDU9AzNn-prZe6Pj-8" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;" vertex="1" parent="-PBKhDU9AzNn-prZe6Pj-7">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="-PBKhDU9AzNn-prZe6Pj-9" value="Comment" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;" vertex="1" parent="-PBKhDU9AzNn-prZe6Pj-7">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="-PBKhDU9AzNn-prZe6Pj-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;" vertex="1" parent="BQHE1joUryQacNBmIgG7-4">
<mxGeometry y="300" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="-PBKhDU9AzNn-prZe6Pj-2" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=0;overflow=hidden;whiteSpace=wrap;html=1;" vertex="1" parent="-PBKhDU9AzNn-prZe6Pj-1">
<mxGeometry width="30" height="30" as="geometry">
<mxRectangle width="30" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="-PBKhDU9AzNn-prZe6Pj-3" value="" 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;" vertex="1" parent="-PBKhDU9AzNn-prZe6Pj-1">
<mxGeometry x="30" width="150" height="30" as="geometry">
<mxRectangle width="150" height="30" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="-PBKhDU9AzNn-prZe6Pj-10" value="" style="edgeStyle=entityRelationEdgeStyle;fontSize=12;html=1;endArrow=ERoneToMany;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="NCbWPNvujZOKFJAbQVH6-51" target="BQHE1joUryQacNBmIgG7-8">
<mxGeometry width="100" height="100" relative="1" as="geometry">
<mxPoint x="1210" y="-230" as="sourcePoint" />
<mxPoint x="1310" y="-330" as="targetPoint" />
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
<diagram id="yu2qkxLoxjZt0KdZdE3U" name="サイトマップ">
<mxGraphModel dx="1434" dy="820" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<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" />
@@ -1356,7 +1215,7 @@
</Array>
</mxGeometry>
</mxCell>
<mxCell id="Eq-ANaZqQ9FOvZb4mf5f-2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="pWS3KtQQPnqtkGdZ5dy--7" target="Eq-ANaZqQ9FOvZb4mf5f-1" edge="1">
<mxCell id="Eq-ANaZqQ9FOvZb4mf5f-2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="pWS3KtQQPnqtkGdZ5dy--7" target="Eq-ANaZqQ9FOvZb4mf5f-1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="pWS3KtQQPnqtkGdZ5dy--7" value="Home" style="html=1;whiteSpace=wrap;strokeColor=#2D7600;fillColor=#60a917;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;fontColor=#ffffff;sketch=0;shape=mxgraph.sitemap.home;" parent="1" vertex="1">
@@ -1409,17 +1268,9 @@
<mxCell id="pWS3KtQQPnqtkGdZ5dy--22" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="pWS3KtQQPnqtkGdZ5dy--23" target="pWS3KtQQPnqtkGdZ5dy--25" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="uYWa1kwDf4TWZ3BUWFD4-2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="pWS3KtQQPnqtkGdZ5dy--23" target="pWS3KtQQPnqtkGdZ5dy--34" edge="1">
<mxCell id="uYWa1kwDf4TWZ3BUWFD4-2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="pWS3KtQQPnqtkGdZ5dy--23" target="pWS3KtQQPnqtkGdZ5dy--34">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="cVGsqKUb7IUMrPYZG-Pq-1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="pWS3KtQQPnqtkGdZ5dy--23" target="pWS3KtQQPnqtkGdZ5dy--32">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="590" y="685" />
<mxPoint x="590" y="485" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="pWS3KtQQPnqtkGdZ5dy--23" value="アプリ一覧" style="html=1;whiteSpace=wrap;strokeColor=#006EAF;fillColor=#1ba1e2;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;sketch=0;shape=mxgraph.sitemap.news;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="440" y="650" width="120" height="70" as="geometry" />
</mxCell>
@@ -1450,7 +1301,15 @@
<mxGeometry x="620" y="755" width="120" height="70" as="geometry" />
</mxCell>
<mxCell id="pWS3KtQQPnqtkGdZ5dy--32" value="設計書ダウロード" style="html=1;whiteSpace=wrap;strokeColor=#006EAF;fillColor=#1ba1e2;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;sketch=0;shape=mxgraph.sitemap.news;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="630" y="450" width="120" height="70" as="geometry" />
<mxGeometry x="440" y="865" width="120" height="70" as="geometry" />
</mxCell>
<mxCell id="pWS3KtQQPnqtkGdZ5dy--33" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="pWS3KtQQPnqtkGdZ5dy--21" target="pWS3KtQQPnqtkGdZ5dy--32" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="390" y="685" />
<mxPoint x="390" y="900" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="pWS3KtQQPnqtkGdZ5dy--34" value="フロー履歴管理" style="html=1;whiteSpace=wrap;strokeColor=#006EAF;fillColor=#1ba1e2;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;sketch=0;shape=mxgraph.sitemap.news;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="620" y="550" width="120" height="70" as="geometry" />
@@ -1490,7 +1349,7 @@
<mxCell id="rk_IxCTN61cNepe1bzat-3" value="テナントDB&lt;br&gt;作成" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" parent="1" vertex="1">
<mxGeometry x="660" y="40" width="90" height="70" as="geometry" />
</mxCell>
<mxCell id="Eq-ANaZqQ9FOvZb4mf5f-1" value="ログ管理" style="html=1;whiteSpace=wrap;strokeColor=#56517e;fillColor=#d0cee2;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;sketch=0;shape=mxgraph.sitemap.home;" parent="1" vertex="1">
<mxCell id="Eq-ANaZqQ9FOvZb4mf5f-1" value="ログ管理" style="html=1;whiteSpace=wrap;strokeColor=#56517e;fillColor=#d0cee2;labelPosition=center;verticalLabelPosition=middle;verticalAlign=top;align=center;fontSize=12;outlineConnect=0;spacingTop=-6;sketch=0;shape=mxgraph.sitemap.home;" vertex="1" parent="1">
<mxGeometry x="440" y="450" width="120" height="70" as="geometry" />
</mxCell>
</root>

View File

@@ -17,38 +17,28 @@
</div>
</template>
<script lang="ts">
import { ref, onMounted, reactive, watchEffect, PropType } from 'vue'
import { ref, onMounted, reactive, watchEffect } from 'vue'
import { api } from 'boot/axios';
interface IAppDisplay {
id: string;
name: string;
description: string;
createdate: string;
}
export default {
name: 'AppSelectBox',
props: {
name: String,
type: String,
filter: String,
filterInitRowsFunc: {
type: Function as PropType<(app: IAppDisplay) => boolean>,
},
updateSelectApp: {
type: Function
}
},
setup(props) {
const columns = [
{ name: 'id', required: true, label: 'ID', align: 'left', field: 'id', sortable: true, sort: (a: string, b: string) => parseInt(a, 10) - parseInt(b, 10) },
{ name: 'id', required: true, label: 'ID', align: 'left', field: 'id', sortable: true },
{ name: 'name', label: 'アプリ名', field: 'name', sortable: true, align: 'left' },
{ name: 'description', label: '概要', field: 'description', align: 'left', sortable: false },
{ name: 'createdate', label: '作成日時', field: 'createdate', align: 'left' }
]
const isLoaded = ref(false);
const rows = reactive<IAppDisplay[]>([]);
const rows: any[] = reactive([]);
const selected = ref([])
watchEffect(()=>{
@@ -59,16 +49,12 @@ export default {
onMounted(() => {
api.get('api/v1/allapps').then(res => {
res.data.apps.forEach((item: any) => {
const row : IAppDisplay = {
rows.push({
id: item.appId,
name: item.name,
description: item.description,
createdate: dateFormat(item.createdAt)
}
if (props.filterInitRowsFunc && !props.filterInitRowsFunc(row)) {
return;
}
rows.push(row);
});
});
isLoaded.value = true;
});

View File

@@ -1,15 +1,12 @@
<template>
<q-btn-dropdown
class="customized-disabled-btn"
color="primay"
push
flat
no-caps
icon="share"
size="md"
:label="userStore.currentDomain.domainName"
:disable-dropdown="isUnclickable"
:dropdown-icon="isUnclickable ? 'none' : ''"
:disable="isUnclickable"
>
<q-list>
<q-item v-for="domain in domains" :key="domain.domainName"
@@ -29,32 +26,18 @@
<script setup lang="ts" >
import { IDomainInfo } from 'src/types/ActionTypes';
import { useAuthStore,IUserState } from 'stores/useAuthStore';
import { ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import { ref } from 'vue';
const userStore = useAuthStore();
const route = useRoute()
const domains = ref<IDomainInfo[]>([]);
(async ()=>{
domains.value = await userStore.getUserDomains();
})();
const isUnclickable = computed(()=>{
return route.path.startsWith('/FlowChart/') || domains.value === undefined || domains.value.length === 0;
});
const onItemClick=(domain:IDomainInfo)=>{
console.log(domain);
userStore.setCurrentDomain(domain);
}
</script>
<style lang="scss">
.q-btn.disabled.customized-disabled-btn {
opacity: 1 !important;
cursor: default !important;
}
.q-btn.disabled.customized-disabled-btn * {
cursor: default !important;
}
</style>

View File

@@ -4,6 +4,7 @@
tag="a"
:target="target?target:'_blank'"
:href="link"
:disable="disable"
v-if="!isSeparator"
>
<q-item-section
@@ -33,6 +34,7 @@ export interface EssentialLinkProps {
icon?: string;
isSeparator?: boolean;
target?:string;
disable?:boolean;
}
withDefaults(defineProps<EssentialLinkProps>(), {
caption: '',

View File

@@ -12,7 +12,7 @@
<slot></slot>
</q-card-section>
<q-card-actions v-if="!disableBtn" align="right" class="text-primary">
<q-btn flat label="確定" :loading="okBtnLoading" :v-close-popup="okBtnAutoClose" @click="CloseDialogue('OK')" />
<q-btn flat label="確定" v-close-popup @click="CloseDialogue('OK')" />
<q-btn flat label="キャンセル" v-close-popup @click="CloseDialogue('Cancel')" />
</q-card-actions>
</q-card>
@@ -30,11 +30,6 @@ export default {
height:String,
minWidth:String,
minHeight:String,
okBtnLoading:Boolean,
okBtnAutoClose:{
type: Boolean,
default: true
},
disableBtn:{
type: Boolean,
default: false

View File

@@ -7,14 +7,18 @@
<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="getSelectedClass(prop.node)">{{ prop.node.label }}</div>
<div class="no-wrap"
:class="selectedEvent && prop.node.eventId === selectedEvent.eventId ? 'selected-node' : ''">{{prop.node.label }}
</div>
<q-space></q-space>
<!-- <q-icon v-if="prop.node.hasFlow" name="delete" color="negative" size="16px" class="q-mr-sm"></q-icon> -->
</div>
</template>
<template v-slot:header-CHANGE="prop">
<div class="row col items-start no-wrap event-node">
<div class="no-wrap" :class="getSelectedClass(prop.node)">{{ prop.node.label }}</div>
<div class="no-wrap"
:class="selectedEvent && prop.node.eventId === selectedEvent.eventId ? 'selected-node' : ''"
>{{ prop.node.label }}</div>
<q-space></q-space>
<q-icon name="add_circle" color="primary" size="16px" class="q-mr-sm"
@click="addChangeEvent(prop.node)"></q-icon>
@@ -23,7 +27,7 @@
<template v-slot:header-DELETABLE="prop">
<div class="row col items-start event-node" @click="onSelected(prop.node)">
<q-icon v-if="prop.node.eventId" name="play_circle" :color="prop.node.hasFlow ? 'green' : 'grey'" size="16px" class="q-mr-sm" />
<div class="no-wrap" :class="getSelectedClass(prop.node)">{{ prop.node.label }}</div>
<div class="no-wrap" :class="selectedEvent && prop.node.eventId === selectedEvent.eventId ? 'selected-node' : ''" >{{ prop.node.label}}</div>
<q-space></q-space>
<q-icon name="delete_forever" color="negative" size="16px" @click="deleteEvent(prop.node)"></q-icon>
</div>
@@ -38,7 +42,7 @@
import { QTree, useQuasar } from 'quasar';
import { ActionFlow, RootAction } from 'src/types/ActionTypes';
import { useFlowEditorStore } from 'stores/flowEditor';
import { defineComponent, ref, watchEffect } from 'vue';
import { defineComponent, ref,watchEffect } from 'vue';
import { IKintoneEvent, IKintoneEventGroup, IKintoneEventNode, kintoneEvent } from '../../types/KintoneEvents';
import FieldSelect from '../FieldSelect.vue';
import ShowDialog from '../ShowDialog.vue';
@@ -76,11 +80,6 @@ export default defineComponent({
const isFieldChange = (node: IKintoneEventNode) => {
return node.header == 'EVENT' && node.eventId.indexOf(".change.") > -1;
}
const getSelectedClass = (node: IKintoneEventNode) => {
return store.selectedEvent && node.eventId === store.selectedEvent.eventId ? 'selected-node' : '';
};
//フィールド値変更イベント追加
const closeDg = (val: string) => {
if (val == 'OK') {
@@ -133,7 +132,7 @@ export default defineComponent({
const screen = store.eventTree.findEventById(node.parentId);
let flow = store.findFlowByEventId(node.eventId);
let screenName = screen !== null ? screen.label : '';
let screenName = screen !== null ? screen.label : "";
let nodeLabel = node.label;
// if(isFieldChange(node)){
// screenName=nodeLabel;
@@ -160,7 +159,6 @@ export default defineComponent({
tree,
showDialog,
isFieldChange,
getSelectedClass,
onSelected,
selectedEvent,
addChangeEvent,

View File

@@ -34,7 +34,7 @@
</template>
<script setup lang="ts">
import { onMounted } from 'vue';
import { onMounted, computed } from 'vue';
import EssentialLink, { EssentialLinkProps } from 'components/EssentialLink.vue';
import DomainSelector from 'components/DomainSelector.vue';
import { useAuthStore } from 'stores/useAuthStore';
@@ -47,21 +47,16 @@ const essentialLinks: EssentialLinkProps[] = [
caption: '設計書から導入する',
icon: 'home',
link: '/',
target: '_self'
target: '_self',
disable: !authStore.hasDomain,
},
// {
// title: 'フローエディター',
// caption: 'イベントを設定する',
// icon: 'account_tree',
// link: '/#/FlowChart',
// target: '_self'
// },
{
title: 'アプリ管理',
caption: 'アプリを管理する',
icon: 'widgets',
link: '/#/app',
target: '_self'
title: 'フローエディター',
caption: 'イベントを設定する',
icon: 'account_tree',
link: '/#/FlowChart',
target: '_self',
disable: !authStore.hasDomain,
},
// {
// title: '条件エディター',

View File

@@ -1,161 +0,0 @@
<template>
<div class="q-pa-md">
<div class="q-gutter-sm row items-start">
<q-breadcrumbs>
<q-breadcrumbs-el icon="widgets" label="アプリ管理" />
</q-breadcrumbs>
</div>
<q-table title="Treats" :rows="rows" :columns="columns" row-key="id" :filter="filter" :loading="loading" :pagination="pagination">
<template v-slot:top>
<q-btn color="primary" :disable="loading" label="新規" @click="showAddAppDialog" />
<q-space />
<q-input borderless dense filled debounce="300" v-model="filter" placeholder="検索">
<template v-slot:append>
<q-icon name="search" />
</template>
</q-input>
</template>
<template v-slot:body-cell-url="prop">
<q-td :props="prop">
<a :href="prop.row.url" target="_blank" :title="prop.row.name" >
{{ prop.row.url }}
</a>
</q-td>
</template>
<template v-slot:body-cell-actions="p">
<q-td :props="p">
<q-btn-group flat>
<q-btn flat color="primary" padding="xs" size="1em" icon="edit_note" @click="toEditFlowPage(p.row)" />
<q-btn disabled flat color="primary" padding="xs" size="1em" icon="history" @click="showHistory(p.row)" />
<q-btn disabled flat color="negative" padding="xs" size="1em" icon="delete_outline" @click="removeRow(p.row)" />
</q-btn-group>
</q-td>
</template>
</q-table>
<show-dialog v-model:visible="showSelectApp" name="アプリ選択" @close="closeSelectAppDialog" min-width="50vw" min-height="50vh" :ok-btn-auto-close="false" :ok-btn-loading="isAdding">
<template v-slot:toolbar>
<q-input dense debounce="300" v-model="filter" placeholder="検索" clearable>
<template v-slot:before>
<q-icon name="search" />
</template>
</q-input>
</template>
<app-select-box ref="appDialog" name="アプリ" type="single" :filter="filter" :filterInitRowsFunc="filterInitRows" />
</show-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, watch, reactive } from 'vue';
import { api } from 'boot/axios';
import { useAuthStore } from 'stores/useAuthStore';
import { useFlowEditorStore } from 'stores/flowEditor';
import { router } from 'src/router';
import { date } from 'quasar'
import { IManagedApp } from 'src/types/AppTypes';
import ShowDialog from 'src/components/ShowDialog.vue';
import AppSelectBox from 'src/components/AppSelectBox.vue';
interface IAppDisplay{
id:string;
sortId: number;
name:string;
url:string;
user:string;
version:string;
updatetime:string;
}
const authStore = useAuthStore();
const numberStringSorting = (a: string, b: string) => parseInt(a, 10) - parseInt(b, 10);
const columns = [
{ name: 'id', label: 'アプリID', field: 'id', align: 'left', sortable: true, sort: numberStringSorting },
{ name: 'name', label: 'アプリ名', field: 'name', align: 'left', sortable: true },
{ name: 'url', label: 'URL', field: 'url', align: 'left', sortable: true },
{ name: 'user', label: '最後更新者', field: 'user', align: 'left', sortable: true},
{ name: 'updatetime', label: '最後更新日', field: 'updatetime', align: 'left', sortable: true},
{ name: 'version', label: 'バージョン', field: 'version', align: 'left', sortable: true, sort: numberStringSorting },
{ name: 'actions', label: '操作', field: 'actions' }
];
const pagination = ref({ sortBy: 'id', descending: true, rowsPerPage: 20 });
const loading = ref(false);
const filter = ref('');
const rows = ref<IAppDisplay[]>([]);
const rowIds = new Set<string>();
const store = useFlowEditorStore();
const appDialog = ref();
const showSelectApp=ref(false);
const isAdding = ref(false);
const getApps = async () => {
loading.value = true;
rowIds.clear();
const result = await api.get('api/apps');
rows.value = result.data.map((item: IManagedApp) => {
rowIds.add(item.appid);
return appToAppDisplay(item)
}).sort((a: IAppDisplay, b: IAppDisplay) => a.sortId - b.sortId); // set default order
loading.value = false;
}
onMounted(async () => {
authStore.setLeftMenu(false);
await getApps();
});
watch(() => authStore.currentDomain.id, async () => {
await getApps();
});
const filterInitRows = (row: {id: string}) => {
return !rowIds.has(row.id);
}
const showAddAppDialog = () => {
showSelectApp.value = true;
}
const closeSelectAppDialog = async (val: 'OK'|'Cancel') => {
showSelectApp.value = true;
if (val == 'OK' && appDialog.value.selected[0]) {
isAdding.value = true;
toEditFlowPage(appDialog.value.selected[0]);
}
showSelectApp.value = false;
isAdding.value = false;
}
const removeRow = (app:IAppDisplay) => {
return
}
const showHistory = (app:IAppDisplay) => {
return
}
const appToAppDisplay = (app: IManagedApp) => {
return {
id: app.appid,
sortId: parseInt(app.appid, 10),
name: app.appname,
url: `${app.domainurl}/k/${app.appid}`,
user: `${app.updateuser.first_name} ${app.updateuser.last_name}` ,
updatetime:date.formatDate(app.update_time, 'YYYY/MM/DD HH:mm'),
version: app.version
}
}
const toEditFlowPage = (app:IAppDisplay) => {
store.setApp({
appId: app.id,
name: app.name
});
store.selectFlow(undefined);
router.push('/FlowChart/' + app.id);
};
</script>

View File

@@ -3,7 +3,11 @@
<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 absolute-full" style="padding:15px">
<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>
@@ -38,24 +42,8 @@
</div>
<q-btn flat dense round
:icon="drawerLeft?'keyboard_double_arrow_left':'keyboard_double_arrow_right'"
:style="{'left': fixedLeftPosition}"
:style="[drawerLeft?{'left':'300px'}:{'left':'0px'}]"
@click="drawerLeft=!drawerLeft" class="expand" />
<q-breadcrumbs v-if="store.appInfo" class="fixed q-pl-md"
:style="{'left': fixedLeftPosition}">
<q-breadcrumbs-el icon="widgets" label="アプリ管理" to="/app" />
<q-breadcrumbs-el>
<template v-slot>
<a class="full-width" :href="!store.appInfo?'':`${authStore.currentDomain.kintoneUrl}/k/${store.appInfo?.appId}`" target="_blank" title="Kiontoneへ">
{{ store.appInfo?.name }}
<q-icon
class="q-ma-xs"
name="open_in_new"
color="grey-9"
/>
</a>
</template>
</q-breadcrumbs-el>
</q-breadcrumbs>
<div class="q-pa-md q-gutter-sm" :style="{minWidth: minPanelWidth}">
<div class="flowchart" v-if="store.currentFlow" :style="[drawerLeft?{paddingLeft:'300px'}:{}]">
<node-item v-if="rootNode!==undefined" :key="rootNode.id" :isSelected="rootNode === store.activeNode"
@@ -75,40 +63,31 @@
</template>
<action-select ref="appDg" name="model" :filter="filter" type="single" @clearFilter="onClearFilter" ></action-select>
</ShowDialog>
<q-inner-loading
:showing="initLoading"
color="primary"
label="読み込み中..."
/>
</q-page>
</template>
<script setup lang="ts">
import { ref, reactive, computed, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import { IActionNode, ActionNode, IActionFlow, ActionFlow, RootAction, IActionProperty } from 'src/types/ActionTypes';
import { IManagedApp } from 'src/types/AppTypes';
import { storeToRefs } from 'pinia';
import { useFlowEditorStore } from 'stores/flowEditor';
import { useAuthStore } from 'stores/useAuthStore';
import { api } from 'boot/axios';
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 initLoading = ref(true);
const drawerLeft = ref(false);
const $q = useQuasar();
const store = useFlowEditorStore();
const authStore = useAuthStore();
const route = useRoute()
const appDg = ref();
const prevNodeIfo = ref({
@@ -132,9 +111,6 @@ const minPanelWidth=computed(()=>{
return "300px";
}
});
const fixedLeftPosition = computed(()=>{
return drawerLeft.value?"300px":"0px";
});
const addNode = (node: IActionNode, inputPoint: string) => {
if (drawerRight.value) {
@@ -314,35 +290,19 @@ const onSaveAllFlow= async ()=>{
}
const fetchData = async () => {
initLoading.value = true;
if (store.appInfo === undefined && route?.params?.id !== undefined) {
const { appid, appname } = await fetchAppById(route.params.id as string);
store.setApp({
appId: appid,
name: appname
});
};
await store.loadFlow();
initLoading.value = false
drawerLeft.value = true;
}
const fetchAppById = async(id: string) => {
try {
const result = await api.get('api/apps');
return result.data.find((item: IManagedApp) => item.appid === id ) as IManagedApp;
} catch (e) {
console.error(e);
const result = await api.get(`api/v1/app?app=${id}`);
const data = result?.data;
if (data?.message) {
$q.notify({
type: 'negative',
caption: "エラー",
message: data.message
});
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);
}
return { appid: data.appId, appname: data.name };
if (actionFlows && actionFlows.length == 1) {
store.selectFlow(actionFlows[0]);
}
const root = actionFlows[0].getRoot();
if (root) {
store.setActiveNode(root);
}
}
@@ -351,12 +311,17 @@ const onClearFilter=()=>{
}
onMounted(() => {
authStore.setLeftMenu(false);
authStore.toggleLeftMenu();
fetchData();
});
</script>
<style lang="scss">
.app-selector {
padding: 15px;
z-index: 999;
}
.flowchart {
padding-top: 10px;
}

View File

@@ -155,8 +155,7 @@ let editId = ref(0);
const getDomain = async () => {
loading.value = true;
const userId = authStore.userId;
const result = await api.get(`api/domain?userId=${userId}`);
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 }
});

View File

@@ -47,6 +47,13 @@ export default route(function (/* { store, ssrContext } */) {
authStore.returnUrl = to.fullPath;
return '/login';
}
// redirect to domain setting page if no domain exist
const domainPages = [...publicPages, '/domain'];
if (!authStore.hasDomain && !domainPages.includes(to.path)) {
authStore.returnUrl = to.fullPath;
return '/domain';
}
});
return routerInstance;
});

View File

@@ -6,7 +6,7 @@ const routes: RouteRecordRaw[] = [
component: () => import('pages/LoginPage.vue')
},
{
path:'/FlowChart/:id',
path:'/FlowChart',
component:()=>import('layouts/MainLayout.vue'),
children:[
{path:'',component:()=>import('pages/FlowChart.vue')}
@@ -25,9 +25,8 @@ const routes: RouteRecordRaw[] = [
// { 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: 'userdomain', component: () => import('pages/UserDomain.vue')},
{ path: 'user', component: () => import('pages/UserManagement.vue')},
{ path: 'app', component: () => import('pages/AppManagement.vue')},
{ path: 'condition', component: () => import('pages/conditionPage.vue') }
],
},

View File

@@ -64,9 +64,7 @@ export const useFlowEditorStore = defineStore('flowEditor', {
this.selectedFlow = flow;
if(flow!==undefined){
const eventId = flow.getRoot()?.name;
this.selectedEvent = this.eventTree.findEventById(eventId) as IKintoneEvent;
} else {
this.selectedEvent = undefined;
this.selectedEvent=this.eventTree.findEventById(eventId) as IKintoneEvent;
}
},
setActiveNode(node: IActionNode) {
@@ -88,8 +86,8 @@ export const useFlowEditorStore = defineStore('flowEditor', {
//eventTreeにバンドする
this.eventTree.bindFlows(actionFlows);
if (actionFlows === undefined || actionFlows.length === 0) {
this.setFlows([]);
this.selectFlow(undefined);
this.flows = [];
this.selectedFlow = undefined;
this.expandedScreen =[];
return;
}
@@ -97,11 +95,6 @@ export const useFlowEditorStore = defineStore('flowEditor', {
if (actionFlows && actionFlows.length > 0) {
this.selectFlow(actionFlows[0]);
}
const root = actionFlows[0].getRoot();
if (root) {
this.setActiveNode(root);
}
const expandEventIds = actionFlows.map((flow) => flow.getRoot()?.name);
const expandScreens:string[]=[];
expandEventIds.forEach((eventid)=>{
@@ -128,7 +121,6 @@ export const useFlowEditorStore = defineStore('flowEditor', {
const jsonData = {
flowid: isNew ? flow.createNewId() : flow.id,
appid: this.appInfo?.appId,
appname: this.appInfo?.name,
eventid: root?.name,
name: root?.subTitle,
content: JSON.stringify(flow),

View File

@@ -33,11 +33,11 @@ export const useAuthStore = defineStore('auth', {
toggleLeftDrawer(): boolean {
return this.LeftDrawer;
},
hasDomain(): boolean {
return this.currentDomain.id === null;
}
},
actions: {
setLeftMenu(value:boolean){
this.LeftDrawer=value;
},
toggleLeftMenu() {
this.LeftDrawer = !this.LeftDrawer;
},
@@ -63,8 +63,7 @@ export const useAuthStore = defineStore('auth', {
}
},
async getCurrentDomain(): Promise<IDomainInfo> {
const resp = await api.get(`api/activedomain`);
const activedomain = resp?.data;
const activedomain = (await api.get(`api/activedomain`))?.data;
return {
id: activedomain?.id,
domainName: activedomain?.name,

View File

@@ -1,14 +0,0 @@
interface IUser {
first_name: string;
last_name: string;
email: string;
}
export interface IManagedApp {
appid: string;
appname: string;
domainurl: string;
version: string;
updateuser: IUser;
update_time: string;
}