@aiquants/authz-react-router 0.2.4 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +1 -4
- package/dist/index.d.ts +1 -4
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -3
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{data as O,redirect as J}from"react-router";import{AUTHZ_ACTIONS as W,AuthzDeniedError as _}from"@aiquants/authz-core";import{data as A,redirect as M}from"react-router";var G={title:"Authorization (RBAC)",myPermission:"Your permissions",tabs:{roles:"Roles",resources:"Resources",role_permissions:"Permissions",user_roles:"User assignments"},common:{add:"Add",save:"Save",delete:"Delete",remove:"Remove",assign:"Assign",grant:"Grant",select:"Select\u2026",active:"\u25CB Enabled",inactive:"\xD7 Disabled",optional:"optional"},roles:{heading:"Roles (TMRole)",note:"Edit name / description inline and click Save (role_key is an immutable identifier).",roleKey:"role_key",name:"name",description:"description",activeHeader:"Active",empty:"No roles",newHeading:"New role",hintRoleKey:"e.g. admin"},resources:{heading:"Resources (TMResource)",note:"Edit name / description inline and click Save (app_key / resource_key are immutable identifiers).",appKey:"app_key",resourceKey:"resource_key",name:"name",description:"description",empty:"No resources",newHeading:"New resource",hintAppKey:"e.g. quants",hintResourceKey:"e.g. daily_report",hintDailyReport:"optional"},grants:{heading:"Permissions (TDRolePermission)",note:"Empty row_scope / column_scope = all rows / all columns (NULL). JSON must satisfy the \xA73.2 contract.",role:"role",resource:"resource",action:"action",rowScope:"row_scope",columnScope:"column_scope",empty:"No permissions",newHeading:"Grant a permission",rowScopeHint:"JSON / empty = all rows",columnScopeHint:"JSON / empty = all columns",rowScopePlaceholder:"empty = all rows (NULL)",columnScopePlaceholder:"empty = all columns (NULL)",nullRows:"NULL (all rows)",nullCols:"NULL (all columns)",selectPlaceholder:"Select\u2026"},userRoles:{heading:"User assignments (TDUserRole)",user:"user",role:"role",empty:"No assignments",newHeading:"Assign a role",selectPlaceholder:"Select\u2026"},error:{forbiddenTitle:"Access denied",forbiddenBody:"You don't have permission to view this screen. Ask an administrator to grant access.",genericTitlePrefix:"Error",genericTitle:"An error occurred",genericBody:"An unexpected error occurred. Please try again later."},warn:{selfRoleDisable:"This role backs your own authorization-admin access. Disabling it may lock you out of this screen. Continue?",selfRoleDelete:"This role backs your own authorization-admin access. Deleting it may lock you out of this screen. Continue?",selfAssignmentRemove:"This assignment backs your own authorization-admin access. Removing it may lock you out of this screen. Continue?"}};function K(o){let s=G;return o?{title:o.title??s.title,myPermission:o.myPermission??s.myPermission,tabs:{...s.tabs,...o.tabs},common:{...s.common,...o.common},roles:{...s.roles,...o.roles},resources:{...s.resources,...o.resources},grants:{...s.grants,...o.grants},userRoles:{...s.userRoles,...o.userRoles},error:{...s.error,...o.error},warn:{...s.warn,...o.warn}}:s}var B=o=>o instanceof Response;function x(o){if(B(o))throw o;if(o instanceof _)throw new Response(o.message,{status:403});return A({error:o instanceof Error?o.message:"\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"},{status:400})}function q(o){let s=o.store,i=o.resourceKey??"authz_admin",l=K(o.labels),r=async(u,a)=>{let{userId:h}=await o.requirePermission(u,a);if(h==null)throw new _({appKey:"",resourceKey:a.resourceKey,action:a.action,reason:"unresolved-user",userId:null});return{userId:h}};async function c(u){await o.requireUser(u);try{return await r(u,{resourceKey:i,action:"read"})}catch(a){throw a instanceof _?new Response(`Forbidden: ${i}`,{status:403}):a}}let n=u=>o.getMyPermissions(u,{resourceKeys:[i]}),g=async u=>{let[a,h]=await Promise.all([s.listRoles(),s.getSelfAdminContext(Number(u))]);return{roles:a,selfAdminRoleIds:h.selfAdminRoleIds,labels:l}},b=async()=>({resources:await s.listResources(),labels:l}),m=async()=>{let[u,a,h]=await Promise.all([s.listGrants(),s.listRoles(),s.listResources()]);return{grants:u,roles:a,resources:h,labels:l}},S=async u=>{let[a,h,p,y]=await Promise.all([s.listUserRoles(),s.listRoles(),s.listUsers(),s.getSelfAdminContext(Number(u))]);return{assignments:a,roles:h,users:p,actorUserId:y.actorUserId,selfAdminRoleIds:y.selfAdminRoleIds,labels:l}};return{labels:l,resourceKey:i,layoutGuard:c,loadMyPermissions:n,layout:{async loader({request:u}){return await c(u),{myPermissions:await n(u),labels:l,adminResourceKey:i}}},index:{loader(){throw M("/authz/roles")}},roles:{data:g,async loader({request:u}){let{userId:a}=await r(u,{resourceKey:i,action:"read"});return g(a)},async action({request:u}){let a=await u.formData(),h=String(a.get("_action"));try{switch(h){case"create":{let{userId:p}=await r(u,{resourceKey:i,action:"create"}),y=String(a.get("roleKey")??"").trim(),R=String(a.get("name")??"").trim();return y&&R?(await s.createRole({roleKey:y,name:R,description:String(a.get("description")??"").trim()||null},String(p)),{ok:!0}):A({error:"role_key \u3068 name \u306F\u5FC5\u9808\u3067\u3059"},{status:400})}case"save":{let{userId:p}=await r(u,{resourceKey:i,action:"update"}),y=String(a.get("name")??"").trim();return y?(await s.updateRole(Number(a.get("id")),{name:y,description:String(a.get("description")??"").trim()||null},String(p)),{ok:!0}):A({error:"name \u306F\u5FC5\u9808\u3067\u3059"},{status:400})}case"toggle":{let{userId:p}=await r(u,{resourceKey:i,action:"update"});return await s.setRoleActive(Number(a.get("id")),a.get("isActive")==="true",String(p)),{ok:!0}}case"delete":return await r(u,{resourceKey:i,action:"delete"}),await s.deleteRole(Number(a.get("id"))),{ok:!0};default:return A({error:"unknown action"},{status:400})}}catch(p){return x(p)}}},resources:{data:b,async loader({request:u}){return await r(u,{resourceKey:i,action:"read"}),b()},async action({request:u}){let a=await u.formData(),h=String(a.get("_action"));try{switch(h){case"create":{let{userId:p}=await r(u,{resourceKey:i,action:"create"}),y=String(a.get("appKey")??"").trim(),R=String(a.get("resourceKey")??"").trim(),z=String(a.get("name")??"").trim();return y&&R&&z?(await s.createResource({appKey:y,resourceKey:R,name:z,description:String(a.get("description")??"").trim()||null},String(p)),{ok:!0}):A({error:"app_key / resource_key / name \u306F\u5FC5\u9808\u3067\u3059"},{status:400})}case"save":{let{userId:p}=await r(u,{resourceKey:i,action:"update"}),y=String(a.get("name")??"").trim();return y?(await s.updateResource(Number(a.get("id")),{name:y,description:String(a.get("description")??"").trim()||null},String(p)),{ok:!0}):A({error:"name \u306F\u5FC5\u9808\u3067\u3059"},{status:400})}case"delete":return await r(u,{resourceKey:i,action:"delete"}),await s.deleteResource(Number(a.get("id"))),{ok:!0};default:return A({error:"unknown action"},{status:400})}}catch(p){return x(p)}}},grants:{data:m,async loader({request:u}){return await r(u,{resourceKey:i,action:"read"}),m()},async action({request:u}){let a=await u.formData(),h=String(a.get("_action"));try{switch(h){case"create":{let{userId:p}=await r(u,{resourceKey:i,action:"create"}),y=Number(a.get("roleId")),R=Number(a.get("resourceId"));if(!(y&&R))return A({error:"\u30ED\u30FC\u30EB\u3068\u30EA\u30BD\u30FC\u30B9\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044"},{status:400});let z=String(a.get("action")??"");if(!W.includes(z))return A({error:"\u7121\u52B9\u306A action \u3067\u3059"},{status:400});let H=z;return await s.createGrant({roleId:y,resourceId:R,action:H,rowScope:String(a.get("rowScope")??""),columnScope:String(a.get("columnScope")??"")},String(p)),{ok:!0}}case"save":{let{userId:p}=await r(u,{resourceKey:i,action:"update"});return await s.updateGrant(Number(a.get("id")),{rowScope:String(a.get("rowScope")??""),columnScope:String(a.get("columnScope")??"")},String(p)),{ok:!0}}case"delete":return await r(u,{resourceKey:i,action:"delete"}),await s.deleteGrant(Number(a.get("id"))),{ok:!0};default:return A({error:"unknown action"},{status:400})}}catch(p){return x(p)}}},userRoles:{data:S,async loader({request:u}){let{userId:a}=await r(u,{resourceKey:i,action:"read"});return S(a)},async action({request:u}){let a=await u.formData(),h=String(a.get("_action"));try{switch(h){case"assign":{let{userId:p}=await r(u,{resourceKey:i,action:"create"}),y=Number(a.get("userId")),R=Number(a.get("roleId"));return y&&R?(await s.assignUserRole(y,R,String(p)),{ok:!0}):A({error:"\u30E6\u30FC\u30B6\u30FC\u3068\u30ED\u30FC\u30EB\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044"},{status:400})}case"remove":return await r(u,{resourceKey:i,action:"delete"}),await s.removeUserRole(Number(a.get("userId")),Number(a.get("roleId"))),{ok:!0};default:return A({error:"unknown action"},{status:400})}}catch(p){return x(p)}}}}}function F(o){return String(o["*"]??"").split("/")[0]}function be(o){let s=q(o),i=o.basePath??"/authz",l=["roles","resources","role_permissions","user_roles"],r={roles:s.roles.data,resources:s.resources.data,role_permissions:s.grants.data,user_roles:s.userRoles.data},c={roles:s.roles.action,resources:s.resources.action,role_permissions:s.grants.action,user_roles:s.userRoles.action};async function n(b){let m=F(b.params);if(!l.includes(m))throw J(`${i}/roles`);let{userId:S}=await s.layoutGuard(b.request),[u,a]=await Promise.all([s.loadMyPermissions(b.request),r[m](S)]);return{segment:m,basePath:i,myPermissions:u,adminResourceKey:s.resourceKey,...a}}async function g(b){let m=F(b.params),S=c[m];return S?S(b):O({error:"unknown action"},{status:400})}return{loader:n,action:g,server:s}}import{jsx as Q,jsxs as N}from"react/jsx-runtime";var t={page:{padding:"1.25rem",maxWidth:1120,margin:"0 auto",color:"#0f172a"},table:{borderCollapse:"collapse",width:"100%",fontSize:"0.9rem"},th:{textAlign:"left",borderBottom:"2px solid #e2e8f0",padding:"0.45rem 0.65rem",fontSize:"0.78rem",color:"#475569",fontWeight:600,textTransform:"uppercase",letterSpacing:"0.03em"},td:{borderBottom:"1px solid #f1f5f9",padding:"0.5rem 0.65rem",verticalAlign:"middle"},input:{padding:"0.4rem 0.55rem",border:"1px solid #cbd5e1",borderRadius:6,fontSize:"0.9rem",background:"#fff",width:"100%",boxSizing:"border-box"},select:{padding:"0.4rem 0.55rem",border:"1px solid #cbd5e1",borderRadius:6,fontSize:"0.9rem",background:"#fff",width:"100%",boxSizing:"border-box"},textarea:{padding:"0.4rem 0.55rem",border:"1px solid #cbd5e1",borderRadius:6,fontSize:"0.82rem",fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace",minHeight:"3.25rem",resize:"vertical",width:"100%",boxSizing:"border-box"},button:{padding:"0.3rem 0.7rem",border:"1px solid #cbd5e1",borderRadius:6,background:"#fff",cursor:"pointer",fontSize:"0.82rem",color:"#334155"},save:{padding:"0.3rem 0.7rem",border:"1px solid #2563eb",borderRadius:6,background:"#eff6ff",cursor:"pointer",fontSize:"0.82rem",color:"#2563eb",fontWeight:600},danger:{padding:"0.3rem 0.7rem",border:"1px solid #fecaca",borderRadius:6,background:"#fff",cursor:"pointer",fontSize:"0.82rem",color:"#dc2626"},primary:{padding:"0.5rem 1.25rem",border:"1px solid #2563eb",borderRadius:6,background:"#2563eb",color:"#fff",cursor:"pointer",fontSize:"0.9rem",fontWeight:600,alignSelf:"flex-start"},card:{display:"flex",flexDirection:"column",gap:"0.85rem",maxWidth:600,marginTop:"0.75rem",padding:"1rem 1.1rem",border:"1px solid #e2e8f0",borderRadius:10,background:"#f8fafc"},code:{fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace",fontSize:"0.78rem",color:"#334155",wordBreak:"break-all"},muted:{color:"#94a3b8"},h2:{fontSize:"1.05rem",margin:"0 0 0.35rem",fontWeight:700},h3:{fontSize:"0.92rem",margin:"1.25rem 0 0",color:"#334155",fontWeight:600},note:{color:"#64748b",fontSize:"0.82rem",margin:"0 0 0.75rem"},empty:{color:"#94a3b8",padding:"0.75rem 0.65rem"}};function f({label:o,hint:s,children:i}){return N("div",{style:{display:"flex",flexDirection:"column",gap:"0.3rem"},children:[N("span",{style:{fontSize:"0.8rem",color:"#475569",fontWeight:600},children:[o,s?N("span",{style:{fontWeight:400,color:"#94a3b8"},children:[" \u2014 ",s]}):null]}),i]})}function v({message:o}){return o?Q("p",{role:"alert",style:{color:"#dc2626",background:"#fef2f2",border:"1px solid #fecaca",borderRadius:8,padding:"0.55rem 0.8rem",fontSize:"0.85rem",margin:"0.25rem 0"},children:o}):null}import{AUTHZ_ACTIONS as Z}from"@aiquants/authz-core";import{Form as w,isRouteErrorResponse as X,NavLink as j,Outlet as ee,useActionData as k,useLoaderData as P,useRouteError as te}from"react-router";function C(o){let s=o?.read?o.readPartial?"partial":"full":"none",i=o?.create&&o?.update?"full":o?.create||o?.update?"partial":"none",l=o?.delete?"full":"none";return{canRead:!!o?.read,canWrite:!!o?.write,canDelete:!!o?.delete,readState:s,writeState:i,deleteState:l}}import{jsx as Y,jsxs as I}from"react/jsx-runtime";var E={full:"\u25CB",partial:"\u25B3",none:"\xD7"};function T({permission:o,labels:s,showScopeSummary:i=!0,className:l="authz-permission-indicator"}){let r=C(o),c={read:s?.read??"\u8AAD",write:s?.write??"\u66F8",delete:s?.delete??"\u524A\u9664"};return I("span",{className:l,"data-resource":o?.resourceKey??"",children:[I("span",{"data-perm":"read",title:`${c.read}: ${r.readState}`,children:[c.read,E[r.readState]]}),I("span",{"data-perm":"write",title:`${c.write}: ${r.writeState}`,children:[c.write,E[r.writeState]]}),I("span",{"data-perm":"delete",title:`${c.delete}: ${r.deleteState}`,children:[c.delete,E[r.deleteState]]}),i&&r.readState==="partial"?Y("span",{"data-perm":"scope",children:"\uFF08\u90E8\u5206\uFF09"}):null]})}import{jsx as e,jsxs as d}from"react/jsx-runtime";var D=o=>o?.error;function $({children:o}){let{myPermissions:s,labels:i,adminResourceKey:l,basePath:r}=P(),c=r??"/authz",n=[["roles",i.tabs.roles],["resources",i.tabs.resources],["role_permissions",i.tabs.role_permissions],["user_roles",i.tabs.user_roles]];return d("div",{className:"authz-admin",style:t.page,children:[d("header",{style:{display:"flex",alignItems:"baseline",justifyContent:"space-between",gap:"1rem",flexWrap:"wrap"},children:[e("h1",{style:{fontSize:"1.3rem",margin:0,fontWeight:700},children:i.title}),d("span",{style:{fontSize:"0.82rem",color:"#475569",display:"inline-flex",alignItems:"center",gap:"0.4rem"},children:[i.myPermission,": ",e(T,{permission:s[l]})]})]}),e("nav",{style:{display:"flex",gap:"0.25rem",borderBottom:"1px solid #e2e8f0",margin:"0.9rem 0 1.25rem"},children:n.map(([g,b])=>e(j,{to:`${c}/${g}`,style:({isActive:m})=>({padding:"0.5rem 0.9rem",textDecoration:"none",color:m?"#2563eb":"#475569",borderBottom:m?"2px solid #2563eb":"2px solid transparent",marginBottom:-1,fontWeight:m?700:500,fontSize:"0.92rem"}),children:b},g))}),o]})}function De(){return e($,{children:e(ee,{})})}function re(o){let s=K(o).error;return function(){let l=te(),r=X(l)?l:null,c=r?.status===403,n=c?s.forbiddenTitle:r?`${s.genericTitlePrefix} (${r.status})`:s.genericTitle,g=c?s.forbiddenBody:r?typeof r.data=="string"&&r.data?r.data:r.statusText:s.genericBody;return e("div",{style:t.page,children:d("div",{role:"alert",style:{maxWidth:480,margin:"3rem auto",padding:"1.5rem",border:"1px solid #fecaca",borderRadius:12,background:"#fef2f2"},children:[e("h1",{style:{fontSize:"1.1rem",fontWeight:700,color:"#b91c1c",margin:"0 0 0.5rem"},children:n}),e("p",{style:{color:"#7f1d1d",fontSize:"0.9rem",margin:0,lineHeight:1.7},children:g})]})})}}var Le=re(),U=(o,s)=>i=>{o&&!window.confirm(s)&&i.preventDefault()};function V(){let{roles:o,selfAdminRoleIds:s,labels:i}=P(),l=i.roles,r=i.common,c=new Set(s??[]);return d("section",{children:[e("h2",{style:t.h2,children:l.heading}),e(v,{message:D(k())}),e("p",{style:t.note,children:l.note}),d("table",{style:t.table,children:[e("thead",{children:d("tr",{children:[e("th",{style:t.th,children:l.roleKey}),e("th",{style:t.th,children:l.name}),e("th",{style:t.th,children:l.description}),e("th",{style:t.th,children:l.activeHeader}),e("th",{style:t.th})]})}),d("tbody",{children:[o.map(n=>d("tr",{children:[e("td",{style:t.td,children:e("span",{style:t.code,children:n.roleKey})}),e("td",{style:t.td,children:e("input",{name:"name",defaultValue:n.name,form:`save-role-${n.id}`,"aria-label":`name-${n.id}`,required:!0,style:t.input})}),e("td",{style:t.td,children:e("input",{name:"description",defaultValue:n.description??"",form:`save-role-${n.id}`,"aria-label":`description-${n.id}`,style:t.input})}),e("td",{style:t.td,children:d(w,{method:"post",style:{display:"inline"},children:[e("input",{type:"hidden",name:"_action",value:"toggle"}),e("input",{type:"hidden",name:"id",value:n.id}),e("input",{type:"hidden",name:"isActive",value:String(!n.isActive)}),e("button",{type:"submit",style:t.button,onClick:n.isActive?U(c.has(n.id),i.warn.selfRoleDisable):void 0,children:n.isActive?r.active:r.inactive})]})}),d("td",{style:{...t.td,whiteSpace:"nowrap"},children:[d(w,{method:"post",id:`save-role-${n.id}`,style:{display:"inline"},children:[e("input",{type:"hidden",name:"_action",value:"save"}),e("input",{type:"hidden",name:"id",value:n.id}),e("button",{type:"submit",style:t.save,children:r.save})]}),d(w,{method:"post",style:{display:"inline",marginLeft:"0.4rem"},children:[e("input",{type:"hidden",name:"_action",value:"delete"}),e("input",{type:"hidden",name:"id",value:n.id}),e("button",{type:"submit",style:t.danger,onClick:U(c.has(n.id),i.warn.selfRoleDelete),children:r.delete})]})]})]},n.id)),o.length===0?e("tr",{children:e("td",{style:t.empty,colSpan:5,children:l.empty})}):null]})]}),e("h3",{style:t.h3,children:l.newHeading}),d(w,{method:"post",style:t.card,children:[e("input",{type:"hidden",name:"_action",value:"create"}),e(f,{label:l.roleKey,hint:l.hintRoleKey,children:e("input",{name:"roleKey","aria-label":"role_key",required:!0,style:t.input})}),e(f,{label:l.name,children:e("input",{name:"name","aria-label":"name",required:!0,style:t.input})}),e(f,{label:l.description,hint:r.optional,children:e("input",{name:"description","aria-label":"description",style:t.input})}),e("button",{type:"submit",style:t.primary,children:r.add})]})]})}function se(){let{resources:o,labels:s}=P(),i=s.resources,l=s.common;return d("section",{children:[e("h2",{style:t.h2,children:i.heading}),e(v,{message:D(k())}),e("p",{style:t.note,children:i.note}),d("table",{style:t.table,children:[e("thead",{children:d("tr",{children:[e("th",{style:t.th,children:i.appKey}),e("th",{style:t.th,children:i.resourceKey}),e("th",{style:t.th,children:i.name}),e("th",{style:t.th,children:i.description}),e("th",{style:t.th})]})}),d("tbody",{children:[o.map(r=>d("tr",{children:[e("td",{style:t.td,children:e("span",{style:t.code,children:r.appKey})}),e("td",{style:t.td,children:e("span",{style:t.code,children:r.resourceKey})}),e("td",{style:t.td,children:e("input",{name:"name",defaultValue:r.name,form:`save-res-${r.id}`,"aria-label":`name-${r.id}`,required:!0,style:t.input})}),e("td",{style:t.td,children:e("input",{name:"description",defaultValue:r.description??"",form:`save-res-${r.id}`,"aria-label":`description-${r.id}`,style:t.input})}),d("td",{style:{...t.td,whiteSpace:"nowrap"},children:[d(w,{method:"post",id:`save-res-${r.id}`,style:{display:"inline"},children:[e("input",{type:"hidden",name:"_action",value:"save"}),e("input",{type:"hidden",name:"id",value:r.id}),e("button",{type:"submit",style:t.save,children:l.save})]}),d(w,{method:"post",style:{display:"inline",marginLeft:"0.4rem"},children:[e("input",{type:"hidden",name:"_action",value:"delete"}),e("input",{type:"hidden",name:"id",value:r.id}),e("button",{type:"submit",style:t.danger,children:l.delete})]})]})]},r.id)),o.length===0?e("tr",{children:e("td",{style:t.empty,colSpan:5,children:i.empty})}):null]})]}),e("h3",{style:t.h3,children:i.newHeading}),d(w,{method:"post",style:t.card,children:[e("input",{type:"hidden",name:"_action",value:"create"}),e(f,{label:i.appKey,hint:i.hintAppKey,children:e("input",{name:"appKey","aria-label":"app_key",required:!0,style:t.input})}),e(f,{label:i.resourceKey,hint:i.hintResourceKey,children:e("input",{name:"resourceKey","aria-label":"resource_key",required:!0,style:t.input})}),e(f,{label:i.name,children:e("input",{name:"name","aria-label":"name",required:!0,style:t.input})}),e(f,{label:i.description,hint:l.optional,children:e("input",{name:"description","aria-label":"description",style:t.input})}),e("button",{type:"submit",style:t.primary,children:l.add})]})]})}function oe(){let{grants:o,roles:s,resources:i,labels:l}=P(),r=l.grants,c=l.common;return d("section",{children:[e("h2",{style:t.h2,children:r.heading}),e("p",{style:t.note,children:r.note}),e(v,{message:D(k())}),d("table",{style:t.table,children:[e("thead",{children:d("tr",{children:[e("th",{style:t.th,children:r.role}),e("th",{style:t.th,children:r.resource}),e("th",{style:t.th,children:r.action}),e("th",{style:t.th,children:r.rowScope}),e("th",{style:t.th,children:r.columnScope}),e("th",{style:t.th})]})}),d("tbody",{children:[o.map(n=>d("tr",{children:[e("td",{style:t.td,children:e("span",{style:t.code,children:n.roleKey})}),e("td",{style:t.td,children:d("span",{style:t.code,children:[n.appKey,":",n.resourceKey]})}),e("td",{style:t.td,children:n.action}),e("td",{style:t.td,children:e("textarea",{name:"rowScope",defaultValue:n.rowScope??"",form:`save-grant-${n.id}`,"aria-label":`row_scope-${n.id}`,rows:2,placeholder:r.rowScopePlaceholder,style:t.textarea})}),e("td",{style:t.td,children:e("textarea",{name:"columnScope",defaultValue:n.columnScope??"",form:`save-grant-${n.id}`,"aria-label":`column_scope-${n.id}`,rows:2,placeholder:r.columnScopePlaceholder,style:t.textarea})}),d("td",{style:{...t.td,whiteSpace:"nowrap"},children:[d(w,{method:"post",id:`save-grant-${n.id}`,style:{display:"inline"},children:[e("input",{type:"hidden",name:"_action",value:"save"}),e("input",{type:"hidden",name:"id",value:n.id}),e("button",{type:"submit",style:t.save,children:c.save})]}),d(w,{method:"post",style:{display:"inline",marginLeft:"0.4rem"},children:[e("input",{type:"hidden",name:"_action",value:"delete"}),e("input",{type:"hidden",name:"id",value:n.id}),e("button",{type:"submit",style:t.danger,children:c.delete})]})]})]},n.id)),o.length===0?e("tr",{children:e("td",{style:t.empty,colSpan:6,children:r.empty})}):null]})]}),e("h3",{style:t.h3,children:r.newHeading}),d(w,{method:"post",style:t.card,children:[e("input",{type:"hidden",name:"_action",value:"create"}),e(f,{label:r.role,children:d("select",{name:"roleId","aria-label":"role",required:!0,style:t.select,children:[e("option",{value:"",children:r.selectPlaceholder}),s.map(n=>e("option",{value:n.id,children:n.roleKey},n.id))]})}),e(f,{label:r.resource,children:d("select",{name:"resourceId","aria-label":"resource",required:!0,style:t.select,children:[e("option",{value:"",children:r.selectPlaceholder}),i.map(n=>d("option",{value:n.id,children:[n.appKey,":",n.resourceKey]},n.id))]})}),e(f,{label:r.action,children:e("select",{name:"action","aria-label":"action",required:!0,style:t.select,children:Z.map(n=>e("option",{value:n,children:n},n))})}),e(f,{label:r.rowScope,hint:r.rowScopeHint,children:e("textarea",{name:"rowScope","aria-label":"row_scope",rows:2,style:t.textarea,placeholder:'{"filters":[{"field":"\u90E8\u9580CD","op":"in","values":["A"]}]}'})}),e(f,{label:r.columnScope,hint:r.columnScopeHint,children:e("textarea",{name:"columnScope","aria-label":"column_scope",rows:2,style:t.textarea,placeholder:'{"mode":"deny","columns":["\u91D1\u984D"]}'})}),e("button",{type:"submit",style:t.primary,children:c.grant})]})]})}function ne(){let{assignments:o,roles:s,users:i,actorUserId:l,selfAdminRoleIds:r,labels:c}=P(),n=c.userRoles,g=c.common,b=new Set(r??[]);return d("section",{children:[e("h2",{style:t.h2,children:n.heading}),e(v,{message:D(k())}),d("table",{style:t.table,children:[e("thead",{children:d("tr",{children:[e("th",{style:t.th,children:n.user}),e("th",{style:t.th,children:n.role}),e("th",{style:t.th})]})}),d("tbody",{children:[o.map(m=>d("tr",{children:[d("td",{style:t.td,children:[m.email,d("span",{style:t.muted,children:["\uFF08",m.displayName,"\uFF09"]})]}),e("td",{style:t.td,children:m.roleKey}),e("td",{style:t.td,children:d(w,{method:"post",style:{display:"inline"},children:[e("input",{type:"hidden",name:"_action",value:"remove"}),e("input",{type:"hidden",name:"userId",value:m.userId}),e("input",{type:"hidden",name:"roleId",value:m.roleId}),e("button",{type:"submit",style:t.danger,onClick:U(m.userId===l&&b.has(m.roleId),c.warn.selfAssignmentRemove),children:g.remove})]})})]},`${m.userId}-${m.roleId}`)),o.length===0?e("tr",{children:e("td",{style:t.empty,colSpan:3,children:n.empty})}):null]})]}),e("h3",{style:t.h3,children:n.newHeading}),d(w,{method:"post",style:t.card,children:[e("input",{type:"hidden",name:"_action",value:"assign"}),e(f,{label:n.user,children:d("select",{name:"userId","aria-label":"user",required:!0,style:t.select,children:[e("option",{value:"",children:n.selectPlaceholder}),i.map(m=>e("option",{value:m.id,children:m.email},m.id))]})}),e(f,{label:n.role,children:d("select",{name:"roleId","aria-label":"role",required:!0,style:t.select,children:[e("option",{value:"",children:n.selectPlaceholder}),s.filter(m=>m.roleKey!=="@authenticated"&&m.roleKey!=="@anonymous").map(m=>e("option",{value:m.id,children:m.roleKey},m.id))]})}),e("button",{type:"submit",style:t.primary,children:g.assign})]})]})}var ie={roles:V,resources:se,role_permissions:oe,user_roles:ne};function _e(){let{segment:o}=P(),s=ie[o]??V;return e($,{children:e(s,{})})}import{can as L,createRequirePermission as ae}from"@aiquants/authz-core";import{redirect as le}from"react-router";function de(o,s){let i=L(s,"read"),l=L(s,"create"),r=L(s,"update"),c=L(s,"delete"),n=s?.scopeByAction.read,g=i&&!!n&&(n.rowScope!==null||n.columnScope!==null);return{resourceKey:o,read:i,create:l,update:r,delete:c,write:l||r,readPartial:g,actions:s?Array.from(s.actions):[]}}function Fe(o){async function s(l,r,c){let n=c?.failureRedirect?()=>{throw le(c.failureRedirect)}:o.onDeny;return ae({resolveUserId:o.resolveUserId,getEffectivePermissions:o.getEffectivePermissions,onDeny:n})(l,{appKey:o.appKey,resourceKey:r.resourceKey,action:r.action})}async function i(l,r){let c=await o.resolveUserId(l),n={};for(let g of r.resourceKeys){let b=await o.getEffectivePermissions({userId:c??null,appKey:o.appKey,resourceKey:g});n[g]=de(g,b)}return n}return{requirePermission:s,getMyPermissions:i}}export{_e as AuthzAdminAppView,Le as AuthzErrorBoundary,oe as AuthzGrantsView,De as AuthzLayout,se as AuthzResourcesView,V as AuthzRolesView,ne as AuthzUserRolesView,v as ErrorAlert,f as Field,T as MyPermissionIndicator,Fe as createAuthz,be as createAuthzAdminApp,q as createAuthzAdminServer,G as defaultAuthzAdminLabels,re as makeAuthzErrorBoundary,K as resolveLabels,de as toPermissionView,t as ui,C as usePermission};
|
|
1
|
+
import{data as Y,redirect as Z}from"react-router";import{AUTHZ_ACTIONS as F,AuthzDeniedError as E}from"@aiquants/authz-core";import{data as S,redirect as J}from"react-router";var O={title:"Authorization (RBAC)",myPermission:"Your permissions",tabs:{roles:"Roles",resources:"Resources",role_permissions:"Permissions",user_roles:"User assignments"},common:{add:"Add",save:"Save",delete:"Delete",remove:"Remove",assign:"Assign",grant:"Grant",select:"Select\u2026",active:"\u25CB Enabled",inactive:"\xD7 Disabled",optional:"optional"},roles:{heading:"Roles (TMRole)",note:"Edit name / description inline and click Save (role_key is an immutable identifier).",roleKey:"role_key",name:"name",description:"description",activeHeader:"Active",empty:"No roles",newHeading:"New role",hintRoleKey:"e.g. admin"},resources:{heading:"Resources (TMResource)",note:"Edit name / description inline and click Save (app_key / resource_key are immutable identifiers).",appKey:"app_key",resourceKey:"resource_key",name:"name",description:"description",empty:"No resources",newHeading:"New resource",hintAppKey:"e.g. quants",hintResourceKey:"e.g. daily_report",hintDailyReport:"optional"},grants:{heading:"Permissions (TDRolePermission)",note:"Empty row_scope / column_scope = all rows / all columns (NULL). JSON must satisfy the \xA73.2 contract.",role:"role",resource:"resource",action:"action",rowScope:"row_scope",columnScope:"column_scope",empty:"No permissions",newHeading:"Grant a permission",rowScopeHint:"JSON / empty = all rows",columnScopeHint:"JSON / empty = all columns",rowScopePlaceholder:"empty = all rows (NULL)",columnScopePlaceholder:"empty = all columns (NULL)",nullRows:"NULL (all rows)",nullCols:"NULL (all columns)",selectPlaceholder:"Select\u2026"},userRoles:{heading:"User assignments (TDUserRole)",note:"Assign active roles to specific users.",user:"user",role:"role",empty:"No assignments",newHeading:"Assign a role",selectPlaceholder:"Select\u2026"},error:{forbiddenTitle:"Access denied",forbiddenBody:"You don't have permission to view this screen. Ask an administrator to grant access.",genericTitlePrefix:"Error",genericTitle:"An error occurred",genericBody:"An unexpected error occurred. Please try again later."},warn:{selfRoleDisable:"This role backs your own authorization-admin access. Disabling it may lock you out of this screen. Continue?",selfRoleDelete:"This role backs your own authorization-admin access. Deleting it may lock you out of this screen. Continue?",selfAssignmentRemove:"This assignment backs your own authorization-admin access. Removing it may lock you out of this screen. Continue?"}};function I(t){let n=O;return t?{title:t.title??n.title,myPermission:t.myPermission??n.myPermission,tabs:{...n.tabs,...t.tabs},common:{...n.common,...t.common},roles:{...n.roles,...t.roles},resources:{...n.resources,...t.resources},grants:{...n.grants,...t.grants},userRoles:{...n.userRoles,...t.userRoles},error:{...n.error,...t.error},warn:{...n.warn,...t.warn}}:n}var Q=t=>t instanceof Response;function L(t){if(Q(t))throw t;if(t instanceof E)throw new Response(t.message,{status:403});return S({error:t instanceof Error?t.message:"\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"},{status:400})}function T(t){let n=t.store,s=t.resourceKey??"authz_admin",d=I(t.labels),o=async(u,a)=>{let{userId:h}=await t.requirePermission(u,a);if(h==null)throw new E({appKey:"",resourceKey:a.resourceKey,action:a.action,reason:"unresolved-user",userId:null});return{userId:h}};async function m(u){await t.requireUser(u);try{return await o(u,{resourceKey:s,action:"read"})}catch(a){throw a instanceof E?new Response(`Forbidden: ${s}`,{status:403}):a}}let l=u=>t.getMyPermissions(u,{resourceKeys:[s]}),y=async u=>{let[a,h]=await Promise.all([n.listRoles(),n.getSelfAdminContext(Number(u))]);return{roles:a,selfAdminRoleIds:h.selfAdminRoleIds,labels:d}},g=async()=>({resources:await n.listResources(),labels:d}),f=async()=>{let[u,a,h]=await Promise.all([n.listGrants(),n.listRoles(),n.listResources()]);return{grants:u,roles:a,resources:h,labels:d}},A=async u=>{let[a,h,p,i]=await Promise.all([n.listUserRoles(),n.listRoles(),n.listUsers(),n.getSelfAdminContext(Number(u))]);return{assignments:a,roles:h,users:p,actorUserId:i.actorUserId,selfAdminRoleIds:i.selfAdminRoleIds,labels:d}};return{labels:d,resourceKey:s,layoutGuard:m,loadMyPermissions:l,layout:{async loader({request:u}){return await m(u),{myPermissions:await l(u),labels:d,adminResourceKey:s}}},index:{loader(){throw J("/authz/roles")}},roles:{data:y,async loader({request:u}){let{userId:a}=await o(u,{resourceKey:s,action:"read"});return y(a)},async action({request:u}){let a=await u.formData(),h=String(a.get("_action"));try{switch(h){case"create":{let{userId:p}=await o(u,{resourceKey:s,action:"create"}),i=String(a.get("roleKey")??"").trim(),b=String(a.get("name")??"").trim();return i&&b?(await n.createRole({roleKey:i,name:b,description:String(a.get("description")??"").trim()||null},String(p)),{ok:!0}):S({error:"role_key \u3068 name \u306F\u5FC5\u9808\u3067\u3059"},{status:400})}case"save":{let{userId:p}=await o(u,{resourceKey:s,action:"update"}),i=String(a.get("roleKey")??"").trim(),b=String(a.get("name")??"").trim();return i&&b?(await n.updateRole(Number(a.get("id")),{roleKey:i,name:b,description:String(a.get("description")??"").trim()||null},String(p)),{ok:!0}):S({error:"roleKey \u3068 name \u306F\u5FC5\u9808\u3067\u3059"},{status:400})}case"toggle":{let{userId:p}=await o(u,{resourceKey:s,action:"update"});return await n.setRoleActive(Number(a.get("id")),a.get("isActive")==="true",String(p)),{ok:!0}}case"delete":return await o(u,{resourceKey:s,action:"delete"}),await n.deleteRole(Number(a.get("id"))),{ok:!0};default:return S({error:"unknown action"},{status:400})}}catch(p){return L(p)}}},resources:{data:g,async loader({request:u}){return await o(u,{resourceKey:s,action:"read"}),g()},async action({request:u}){let a=await u.formData(),h=String(a.get("_action"));try{switch(h){case"create":{let{userId:p}=await o(u,{resourceKey:s,action:"create"}),i=String(a.get("appKey")??"").trim(),b=String(a.get("resourceKey")??"").trim(),K=String(a.get("name")??"").trim();return i&&b&&K?(await n.createResource({appKey:i,resourceKey:b,name:K,description:String(a.get("description")??"").trim()||null},String(p)),{ok:!0}):S({error:"app_key / resource_key / name \u306F\u5FC5\u9808\u3067\u3059"},{status:400})}case"save":{let{userId:p}=await o(u,{resourceKey:s,action:"update"}),i=String(a.get("name")??"").trim();return i?(await n.updateResource(Number(a.get("id")),{name:i,description:String(a.get("description")??"").trim()||null},String(p)),{ok:!0}):S({error:"name \u306F\u5FC5\u9808\u3067\u3059"},{status:400})}case"delete":return await o(u,{resourceKey:s,action:"delete"}),await n.deleteResource(Number(a.get("id"))),{ok:!0};default:return S({error:"unknown action"},{status:400})}}catch(p){return L(p)}}},grants:{data:f,async loader({request:u}){return await o(u,{resourceKey:s,action:"read"}),f()},async action({request:u}){let a=await u.formData(),h=String(a.get("_action"));try{switch(h){case"create":{let{userId:p}=await o(u,{resourceKey:s,action:"create"}),i=Number(a.get("roleId")),b=Number(a.get("resourceId"));if(!(i&&b))return S({error:"\u30ED\u30FC\u30EB\u3068\u30EA\u30BD\u30FC\u30B9\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044"},{status:400});let K=String(a.get("action")??"");if(!F.includes(K))return S({error:"\u7121\u52B9\u306A action \u3067\u3059"},{status:400});let M=K;return await n.createGrant({roleId:i,resourceId:b,action:M,rowScope:String(a.get("rowScope")??""),columnScope:String(a.get("columnScope")??"")},String(p)),{ok:!0}}case"save":{let{userId:p}=await o(u,{resourceKey:s,action:"update"}),i=String(a.get("action")??"");if(!F.includes(i))return S({error:"\u7121\u52B9\u306A action \u3067\u3059"},{status:400});let b=i;return await n.updateGrant(Number(a.get("id")),{action:b,rowScope:String(a.get("rowScope")??""),columnScope:String(a.get("columnScope")??"")},String(p)),{ok:!0}}case"delete":return await o(u,{resourceKey:s,action:"delete"}),await n.deleteGrant(Number(a.get("id"))),{ok:!0};default:return S({error:"unknown action"},{status:400})}}catch(p){return L(p)}}},userRoles:{data:A,async loader({request:u}){let{userId:a}=await o(u,{resourceKey:s,action:"read"});return A(a)},async action({request:u}){let a=await u.formData(),h=String(a.get("_action"));try{switch(h){case"assign":{let{userId:p}=await o(u,{resourceKey:s,action:"create"}),i=Number(a.get("userId")),b=Number(a.get("roleId"));return i&&b?(await n.assignUserRole(i,b,String(p)),{ok:!0}):S({error:"\u30E6\u30FC\u30B6\u30FC\u3068\u30ED\u30FC\u30EB\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044"},{status:400})}case"remove":return await o(u,{resourceKey:s,action:"delete"}),await n.removeUserRole(Number(a.get("userId")),Number(a.get("roleId"))),{ok:!0};default:return S({error:"unknown action"},{status:400})}}catch(p){return L(p)}}}}}function $(t){return String(t["*"]??"").split("/")[0]}function Re(t){let n=T(t),s=t.basePath??"/authz",d=["roles","resources","role_permissions","user_roles"],o={roles:n.roles.data,resources:n.resources.data,role_permissions:n.grants.data,user_roles:n.userRoles.data},m={roles:n.roles.action,resources:n.resources.action,role_permissions:n.grants.action,user_roles:n.userRoles.action};async function l(g){let f=$(g.params);if(!d.includes(f))throw Z(`${s}/roles`);let{userId:A}=await n.layoutGuard(g.request),[u,a]=await Promise.all([n.loadMyPermissions(g.request),o[f](A)]);return{segment:f,basePath:s,myPermissions:u,adminResourceKey:n.resourceKey,...a}}async function y(g){let f=$(g.params),A=m[f];return A?A(g):Y({error:"unknown action"},{status:400})}return{loader:l,action:y,server:n}}import{jsx as j,jsxs as N}from"react/jsx-runtime";var r={page:{padding:"1.25rem",maxWidth:1280,margin:"0 auto",color:"#0f172a"},tableContainer:{width:"100%",overflowX:"auto",marginBottom:"1rem",WebkitOverflowScrolling:"touch"},table:{borderCollapse:"collapse",width:"100%",fontSize:"0.9rem",tableLayout:"fixed"},th:{textAlign:"left",borderBottom:"2px solid #e2e8f0",padding:"0.45rem 0.65rem",fontSize:"0.78rem",color:"#475569",fontWeight:600,textTransform:"uppercase",letterSpacing:"0.03em"},td:{borderBottom:"1px solid #f1f5f9",padding:"0.5rem 0.65rem",verticalAlign:"middle",wordBreak:"break-all"},input:{padding:"0.4rem 0.55rem",border:"1px solid #cbd5e1",borderRadius:6,fontSize:"0.9rem",background:"#fff",width:"100%",boxSizing:"border-box"},select:{padding:"0.4rem 0.55rem",border:"1px solid #cbd5e1",borderRadius:6,fontSize:"0.9rem",background:"#fff",width:"100%",boxSizing:"border-box"},textarea:{padding:"0.4rem 0.55rem",border:"1px solid #cbd5e1",borderRadius:6,fontSize:"0.82rem",fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace",minHeight:"3.25rem",resize:"vertical",width:"100%",boxSizing:"border-box"},button:{padding:"0.3rem 0.7rem",border:"1px solid #cbd5e1",borderRadius:6,background:"#fff",cursor:"pointer",fontSize:"0.82rem",color:"#334155"},save:{padding:"0.3rem 0.7rem",border:"1px solid #2563eb",borderRadius:6,background:"#eff6ff",cursor:"pointer",fontSize:"0.82rem",color:"#2563eb",fontWeight:600},danger:{padding:"0.3rem 0.7rem",border:"1px solid #fecaca",borderRadius:6,background:"#fff",cursor:"pointer",fontSize:"0.82rem",color:"#dc2626"},primary:{padding:"0.5rem 1.25rem",border:"1px solid #2563eb",borderRadius:6,background:"#2563eb",color:"#fff",cursor:"pointer",fontSize:"0.9rem",fontWeight:600,alignSelf:"flex-start"},card:{display:"flex",flexDirection:"column",gap:"0.85rem",maxWidth:600,marginTop:"0.75rem",padding:"1rem 1.1rem",border:"1px solid #e2e8f0",borderRadius:10,background:"#f8fafc"},code:{fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace",fontSize:"0.78rem",color:"#334155",wordBreak:"break-all"},muted:{color:"#94a3b8"},h2:{fontSize:"1.05rem",margin:"0 0 0.35rem",fontWeight:700},h3:{fontSize:"0.92rem",margin:"1.25rem 0 0",color:"#334155",fontWeight:600},note:{color:"#64748b",fontSize:"0.82rem",margin:"0 0 0.75rem"},empty:{color:"#94a3b8",padding:"0.75rem 0.65rem"}};function w({label:t,hint:n,children:s}){return N("div",{style:{display:"flex",flexDirection:"column",gap:"0.3rem"},children:[N("span",{style:{fontSize:"0.8rem",color:"#475569",fontWeight:600},children:[t,n?N("span",{style:{fontWeight:400,color:"#94a3b8"},children:[" \u2014 ",n]}):null]}),s]})}function k({message:t}){return t?j("p",{role:"alert",style:{color:"#dc2626",background:"#fef2f2",border:"1px solid #fecaca",borderRadius:8,padding:"0.55rem 0.8rem",fontSize:"0.85rem",margin:"0.25rem 0"},children:t}):null}import{AUTHZ_ACTIONS as H}from"@aiquants/authz-core";import{SelectBox as z}from"@aiquants/select-box";import{useState as P}from"react";import{Form as R,isRouteErrorResponse as te,NavLink as re,Outlet as ne,useActionData as D,useLoaderData as x,useRouteError as oe}from"react-router";function q(t){let n=t?.read?t.readPartial?"partial":"full":"none",s=t?.create&&t?.update?"full":t?.create||t?.update?"partial":"none",d=t?.delete?"full":"none";return{canRead:!!t?.read,canWrite:!!t?.write,canDelete:!!t?.delete,readState:n,writeState:s,deleteState:d}}import{jsx as v,jsxs as W}from"react/jsx-runtime";var X={full:{bg:"#ecfdf5",text:"#047857",border:"#a7f3d0"},partial:{bg:"#fffbeb",text:"#b45309",border:"#fde68a"},none:{bg:"#f8fafc",text:"#94a3b8",border:"#cbd5e1"}};function ee({state:t}){return t==="full"?v("svg",{style:{width:"0.85rem",height:"0.85rem",flexShrink:0},fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:3,"aria-hidden":"true",children:v("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5 13l4 4L19 7"})}):t==="partial"?v("svg",{style:{width:"0.85rem",height:"0.85rem",flexShrink:0},fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2.5,"aria-hidden":"true",children:v("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"})}):v("svg",{style:{width:"0.85rem",height:"0.85rem",flexShrink:0},fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2.5,"aria-hidden":"true",children:v("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636"})})}function V({permission:t,labels:n,showScopeSummary:s=!0,className:d="authz-permission-indicator"}){let o=q(t),m={read:n?.read??"\u95B2\u89A7",write:n?.write??"\u7DE8\u96C6",delete:n?.delete??"\u524A\u9664"},l=(y,g,f)=>{let A=X[g];return W("span",{"data-perm":y,"data-state":g,title:`${f}: ${g}`,style:{display:"inline-flex",alignItems:"center",gap:"0.25rem",padding:"0.2rem 0.5rem",borderRadius:"100px",fontSize:"0.75rem",fontWeight:600,backgroundColor:A.bg,color:A.text,border:`1px solid ${A.border}`,lineHeight:1,userSelect:"none"},children:[v(ee,{state:g}),v("span",{children:f})]})};return W("span",{className:d,"data-resource":t?.resourceKey??"",style:{display:"inline-flex",gap:"0.35rem",alignItems:"center",verticalAlign:"middle"},children:[l("read",o.readState,m.read),l("write",o.writeState,m.write),l("delete",o.deleteState,m.delete),s&&o.readState==="partial"?v("span",{"data-perm":"scope",style:{fontSize:"0.7rem",color:"#b45309",backgroundColor:"#fef3c7",padding:"0.15rem 0.35rem",borderRadius:"4px",fontWeight:600},children:"\u90E8\u5206\u5236\u9650"}):null]})}import{Fragment as ce,jsx as e,jsxs as c}from"react/jsx-runtime";var _=t=>t?.error;function G({children:t}){let{myPermissions:n,labels:s,adminResourceKey:d,basePath:o}=x(),m=o??"/authz",l=[["roles",s.tabs.roles],["resources",s.tabs.resources],["role_permissions",s.tabs.role_permissions],["user_roles",s.tabs.user_roles]];return c("div",{className:"authz-admin",style:r.page,children:[c("header",{style:{display:"flex",alignItems:"baseline",justifyContent:"space-between",gap:"1rem",flexWrap:"wrap"},children:[e("h1",{style:{fontSize:"1.3rem",margin:0,fontWeight:700},children:s.title}),c("span",{style:{fontSize:"0.82rem",color:"#475569",display:"inline-flex",alignItems:"center",gap:"0.4rem"},children:[s.myPermission,": ",e(V,{permission:n[d]})]})]}),e("nav",{style:{display:"flex",gap:"0.25rem",borderBottom:"1px solid #e2e8f0",margin:"0.9rem 0 1.25rem"},children:l.map(([y,g])=>e(re,{to:`${m}/${y}`,style:({isActive:f})=>({padding:"0.5rem 0.9rem",textDecoration:"none",color:f?"#2563eb":"#475569",borderBottom:f?"2px solid #2563eb":"2px solid transparent",marginBottom:-1,fontWeight:f?700:500,fontSize:"0.92rem"}),children:g},y))}),t]})}function Fe(){return e(G,{children:e(ne,{})})}function se(t){let n=I(t).error;return function(){let d=oe(),o=te(d)?d:null,m=o?.status===403,l=m?n.forbiddenTitle:o?`${n.genericTitlePrefix} (${o.status})`:n.genericTitle,y=m?n.forbiddenBody:o?typeof o.data=="string"&&o.data?o.data:o.statusText:n.genericBody;return e("div",{style:r.page,children:c("div",{role:"alert",style:{maxWidth:480,margin:"3rem auto",padding:"1.5rem",border:"1px solid #fecaca",borderRadius:12,background:"#fef2f2"},children:[e("h1",{style:{fontSize:"1.1rem",fontWeight:700,color:"#b91c1c",margin:"0 0 0.5rem"},children:l}),e("p",{style:{color:"#7f1d1d",fontSize:"0.9rem",margin:0,lineHeight:1.7},children:y})]})})}}var Te=se(),U=(t,n)=>s=>{t&&!window.confirm(n)&&s.preventDefault()};function B(){let{roles:t,selfAdminRoleIds:n,labels:s}=x(),d=s.roles,o=s.common,m=new Set(n??[]);return c("section",{children:[e("h2",{style:r.h2,children:d.heading}),e(k,{message:_(D())}),e("p",{style:r.note,children:d.note}),e("div",{style:r.tableContainer,children:c("table",{style:r.table,children:[e("thead",{children:c("tr",{children:[e("th",{style:{...r.th,width:"20%"},children:d.roleKey}),e("th",{style:{...r.th,width:"25%"},children:d.name}),e("th",{style:{...r.th,width:"35%"},children:d.description}),e("th",{style:{...r.th,width:"10%"},children:d.activeHeader}),e("th",{style:{...r.th,width:"10%"}})]})}),c("tbody",{children:[t.map(l=>c("tr",{children:[e("td",{style:r.td,children:l.roleKey==="@authenticated"||l.roleKey==="@anonymous"?e("span",{style:r.code,children:l.roleKey}):e("input",{name:"roleKey",defaultValue:l.roleKey,form:`save-role-${l.id}`,"aria-label":`roleKey-${l.id}`,required:!0,style:r.input})}),e("td",{style:r.td,children:e("input",{name:"name",defaultValue:l.name,form:`save-role-${l.id}`,"aria-label":`name-${l.id}`,required:!0,style:r.input})}),e("td",{style:r.td,children:e("input",{name:"description",defaultValue:l.description??"",form:`save-role-${l.id}`,"aria-label":`description-${l.id}`,style:r.input})}),e("td",{style:r.td,children:c(R,{method:"post",style:{display:"inline"},children:[e("input",{type:"hidden",name:"_action",value:"toggle"}),e("input",{type:"hidden",name:"id",value:l.id}),e("input",{type:"hidden",name:"isActive",value:String(!l.isActive)}),e("button",{type:"submit",style:r.button,onClick:l.isActive?U(m.has(l.id),s.warn.selfRoleDisable):void 0,children:l.isActive?o.active:o.inactive})]})}),c("td",{style:{...r.td,whiteSpace:"nowrap"},children:[c(R,{method:"post",id:`save-role-${l.id}`,style:{display:"inline"},children:[e("input",{type:"hidden",name:"_action",value:"save"}),e("input",{type:"hidden",name:"id",value:l.id}),e("button",{type:"submit",style:r.save,children:o.save})]}),c(R,{method:"post",style:{display:"inline",marginLeft:"0.4rem"},children:[e("input",{type:"hidden",name:"_action",value:"delete"}),e("input",{type:"hidden",name:"id",value:l.id}),e("button",{type:"submit",style:r.danger,onClick:U(m.has(l.id),s.warn.selfRoleDelete),children:o.delete})]})]})]},l.id)),t.length===0?e("tr",{children:e("td",{style:r.empty,colSpan:5,children:d.empty})}):null]})]})}),e("h3",{style:r.h3,children:d.newHeading}),c(R,{method:"post",style:r.card,children:[e("input",{type:"hidden",name:"_action",value:"create"}),e(w,{label:d.roleKey,hint:d.hintRoleKey,children:e("input",{name:"roleKey","aria-label":"role_key",required:!0,style:r.input})}),e(w,{label:d.name,children:e("input",{name:"name","aria-label":"name",required:!0,style:r.input})}),e(w,{label:d.description,hint:o.optional,children:e("input",{name:"description","aria-label":"description",style:r.input})}),e("button",{type:"submit",style:r.primary,children:o.add})]})]})}function ie(){let{resources:t,labels:n}=x(),s=n.resources,d=n.common;return c("section",{children:[e("h2",{style:r.h2,children:s.heading}),e(k,{message:_(D())}),e("p",{style:r.note,children:s.note}),e("div",{style:r.tableContainer,children:c("table",{style:r.table,children:[e("thead",{children:c("tr",{children:[e("th",{style:{...r.th,width:"15%"},children:s.appKey}),e("th",{style:{...r.th,width:"20%"},children:s.resourceKey}),e("th",{style:{...r.th,width:"25%"},children:s.name}),e("th",{style:{...r.th,width:"30%"},children:s.description}),e("th",{style:{...r.th,width:"10%"}})]})}),c("tbody",{children:[t.map(o=>c("tr",{children:[e("td",{style:r.td,children:e("span",{style:r.code,children:o.appKey})}),e("td",{style:r.td,children:e("span",{style:r.code,children:o.resourceKey})}),e("td",{style:r.td,children:e("input",{name:"name",defaultValue:o.name,form:`save-res-${o.id}`,"aria-label":`name-${o.id}`,required:!0,style:r.input})}),e("td",{style:r.td,children:e("input",{name:"description",defaultValue:o.description??"",form:`save-res-${o.id}`,"aria-label":`description-${o.id}`,style:r.input})}),c("td",{style:{...r.td,whiteSpace:"nowrap"},children:[c(R,{method:"post",id:`save-res-${o.id}`,style:{display:"inline"},children:[e("input",{type:"hidden",name:"_action",value:"save"}),e("input",{type:"hidden",name:"id",value:o.id}),e("button",{type:"submit",style:r.save,children:d.save})]}),c(R,{method:"post",style:{display:"inline",marginLeft:"0.4rem"},children:[e("input",{type:"hidden",name:"_action",value:"delete"}),e("input",{type:"hidden",name:"id",value:o.id}),e("button",{type:"submit",style:r.danger,children:d.delete})]})]})]},o.id)),t.length===0?e("tr",{children:e("td",{style:r.empty,colSpan:5,children:s.empty})}):null]})]})}),e("h3",{style:r.h3,children:s.newHeading}),c(R,{method:"post",style:r.card,children:[e("input",{type:"hidden",name:"_action",value:"create"}),e(w,{label:s.appKey,hint:s.hintAppKey,children:e("input",{name:"appKey","aria-label":"app_key",required:!0,style:r.input})}),e(w,{label:s.resourceKey,hint:s.hintResourceKey,children:e("input",{name:"resourceKey","aria-label":"resource_key",required:!0,style:r.input})}),e(w,{label:s.name,children:e("input",{name:"name","aria-label":"name",required:!0,style:r.input})}),e(w,{label:s.description,hint:d.optional,children:e("input",{name:"description","aria-label":"description",style:r.input})}),e("button",{type:"submit",style:r.primary,children:d.add})]})]})}function ae({g:t,labels:n}){let s=n.common,[d,o]=P({label:t.action,value:t.action});return c("tr",{children:[e("td",{style:r.td,children:e("span",{style:r.code,children:t.roleKey})}),e("td",{style:r.td,children:c("span",{style:r.code,children:[t.appKey,":",t.resourceKey]})}),e("td",{style:r.td,children:t.roleKey==="@anonymous"?e("span",{style:r.code,children:t.action}):c(ce,{children:[e("input",{type:"hidden",name:"action",value:d.value,form:`save-grant-${t.id}`}),e(z,{options:H.map(m=>({label:m,value:m})),value:d,onChange:m=>{m&&o(m)}})]})}),e("td",{style:r.td,children:e("textarea",{name:"rowScope",defaultValue:t.rowScope??"",form:`save-grant-${t.id}`,"aria-label":`row_scope-${t.id}`,rows:2,placeholder:n.grants.rowScopePlaceholder,style:r.textarea})}),e("td",{style:r.td,children:e("textarea",{name:"columnScope",defaultValue:t.columnScope??"",form:`save-grant-${t.id}`,"aria-label":`column_scope-${t.id}`,rows:2,placeholder:n.grants.columnScopePlaceholder,style:r.textarea})}),c("td",{style:{...r.td,whiteSpace:"nowrap"},children:[c(R,{method:"post",id:`save-grant-${t.id}`,style:{display:"inline"},children:[e("input",{type:"hidden",name:"_action",value:"save"}),e("input",{type:"hidden",name:"id",value:t.id}),e("button",{type:"submit",style:r.save,children:s.save})]}),c(R,{method:"post",style:{display:"inline",marginLeft:"0.4rem"},children:[e("input",{type:"hidden",name:"_action",value:"delete"}),e("input",{type:"hidden",name:"id",value:t.id}),e("button",{type:"submit",style:r.danger,children:s.delete})]})]})]})}function le(){let{grants:t,roles:n,resources:s,labels:d}=x(),o=d.grants,m=d.common,l=n.map(i=>({label:i.roleKey,value:i.id})),y=s.map(i=>({label:`${i.appKey}:${i.resourceKey}`,value:i.id})),g=H.map(i=>({label:i,value:i})),[f,A]=P(void 0),[u,a]=P(void 0),[h,p]=P({label:"read",value:"read"});return c("section",{children:[e("h2",{style:r.h2,children:o.heading}),e("p",{style:r.note,children:o.note}),e(k,{message:_(D())}),e("div",{style:r.tableContainer,children:c("table",{style:r.table,children:[e("thead",{children:c("tr",{children:[e("th",{style:{...r.th,width:"15%"},children:o.role}),e("th",{style:{...r.th,width:"20%"},children:o.resource}),e("th",{style:{...r.th,width:"15%"},children:o.action}),e("th",{style:{...r.th,width:"20%"},children:o.rowScope}),e("th",{style:{...r.th,width:"20%"},children:o.columnScope}),e("th",{style:{...r.th,width:"10%"}})]})}),c("tbody",{children:[t.map(i=>e(ae,{g:i,labels:d},i.id)),t.length===0?e("tr",{children:e("td",{style:r.empty,colSpan:6,children:o.empty})}):null]})]})}),e("h3",{style:r.h3,children:o.newHeading}),c(R,{method:"post",style:r.card,children:[e("input",{type:"hidden",name:"_action",value:"create"}),e("input",{type:"hidden",name:"roleId",value:f?.value??""}),e("input",{type:"hidden",name:"resourceId",value:u?.value??""}),e("input",{type:"hidden",name:"action",value:h?.value??""}),e(w,{label:o.role,children:e(z,{options:l,value:f,onChange:i=>A(i||void 0),placeholder:o.selectPlaceholder})}),e(w,{label:o.resource,children:e(z,{options:y,value:u,onChange:i=>a(i||void 0),placeholder:o.selectPlaceholder})}),e(w,{label:o.action,children:e(z,{options:g,value:h,onChange:i=>p(i||void 0)})}),e(w,{label:o.rowScope,hint:o.rowScopeHint,children:e("textarea",{name:"rowScope","aria-label":"row_scope",rows:2,style:r.textarea,placeholder:'{"filters":[{"field":"\u90E8\u9580CD","op":"in","values":["A"]}]}'})}),e(w,{label:o.columnScope,hint:o.columnScopeHint,children:e("textarea",{name:"columnScope","aria-label":"column_scope",rows:2,style:r.textarea,placeholder:'{"mode":"deny","columns":["\u91D1\u984D"]}'})}),e("button",{type:"submit",style:r.primary,children:m.grant})]})]})}function de(){let{assignments:t,roles:n,users:s,actorUserId:d,selfAdminRoleIds:o,labels:m}=x(),l=m.userRoles,y=m.common,g=new Set(o??[]),f=s.map(i=>({label:`${i.email}\uFF08${i.displayName}\uFF09`,value:i.id})),A=n.filter(i=>i.roleKey!=="@authenticated"&&i.roleKey!=="@anonymous").map(i=>({label:i.roleKey,value:i.id})),[u,a]=P(void 0),[h,p]=P(void 0);return c("section",{children:[e("h2",{style:r.h2,children:l.heading}),e(k,{message:_(D())}),e("p",{style:r.note,children:l.note}),e("div",{style:r.tableContainer,children:c("table",{style:r.table,children:[e("thead",{children:c("tr",{children:[e("th",{style:{...r.th,width:"45%"},children:l.user}),e("th",{style:{...r.th,width:"45%"},children:l.role}),e("th",{style:{...r.th,width:"10%"}})]})}),c("tbody",{children:[t.map(i=>c("tr",{children:[c("td",{style:r.td,children:[i.email,c("span",{style:r.muted,children:["\uFF08",i.displayName,"\uFF09"]})]}),e("td",{style:r.td,children:i.roleKey}),e("td",{style:r.td,children:c(R,{method:"post",style:{display:"inline"},children:[e("input",{type:"hidden",name:"_action",value:"remove"}),e("input",{type:"hidden",name:"userId",value:i.userId}),e("input",{type:"hidden",name:"roleId",value:i.roleId}),e("button",{type:"submit",style:r.danger,onClick:U(i.userId===d&&g.has(i.roleId),m.warn.selfAssignmentRemove),children:y.remove})]})})]},`${i.userId}-${i.roleId}`)),t.length===0?e("tr",{children:e("td",{style:r.empty,colSpan:3,children:l.empty})}):null]})]})}),e("h3",{style:r.h3,children:l.newHeading}),c(R,{method:"post",style:r.card,children:[e("input",{type:"hidden",name:"_action",value:"assign"}),e("input",{type:"hidden",name:"userId",value:u?.value??""}),e("input",{type:"hidden",name:"roleId",value:h?.value??""}),e(w,{label:l.user,children:e(z,{options:f,value:u,onChange:i=>a(i||void 0),placeholder:l.selectPlaceholder})}),e(w,{label:l.role,children:e(z,{options:A,value:h,onChange:i=>p(i||void 0),placeholder:l.selectPlaceholder})}),e("button",{type:"submit",style:r.primary,children:y.assign})]})]})}var ue={roles:B,resources:ie,role_permissions:le,user_roles:de};function $e(){let{segment:t}=x(),n=ue[t]??B;return e(G,{children:e(n,{})})}import{can as C,createRequirePermission as me}from"@aiquants/authz-core";import{redirect as pe}from"react-router";function ye(t,n){let s=C(n,"read"),d=C(n,"create"),o=C(n,"update"),m=C(n,"delete"),l=n?.scopeByAction.read,y=s&&!!l&&(l.rowScope!==null||l.columnScope!==null);return{resourceKey:t,read:s,create:d,update:o,delete:m,write:d||o,readPartial:y,actions:n?Array.from(n.actions):[]}}function Ge(t){async function n(d,o,m){let l=m?.failureRedirect?()=>{throw pe(m.failureRedirect)}:t.onDeny;return me({resolveUserId:t.resolveUserId,getEffectivePermissions:t.getEffectivePermissions,onDeny:l})(d,{appKey:t.appKey,resourceKey:o.resourceKey,action:o.action})}async function s(d,o){let m=await t.resolveUserId(d),l={};for(let y of o.resourceKeys){let g=await t.getEffectivePermissions({userId:m??null,appKey:t.appKey,resourceKey:y});l[y]=ye(y,g)}return l}return{requirePermission:n,getMyPermissions:s}}export{$e as AuthzAdminAppView,Te as AuthzErrorBoundary,le as AuthzGrantsView,Fe as AuthzLayout,ie as AuthzResourcesView,B as AuthzRolesView,de as AuthzUserRolesView,k as ErrorAlert,w as Field,V as MyPermissionIndicator,Ge as createAuthz,Re as createAuthzAdminApp,T as createAuthzAdminServer,O as defaultAuthzAdminLabels,se as makeAuthzErrorBoundary,I as resolveLabels,ye as toPermissionView,r as ui,q as usePermission};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|