@aiquants/authz-react-router 0.1.0

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.
@@ -0,0 +1,474 @@
1
+ import * as react from 'react';
2
+ import { ReactNode, CSSProperties } from 'react';
3
+ import * as _aiquants_authz_core from '@aiquants/authz-core';
4
+ import { EffectivePermission, DenyInfo, AuthzAction, GuardResult, AuthzGrant, AuthzResource, AuthzRole, AuthzAssignment, AuthzUser, AuthzAdminStore } from '@aiquants/authz-core';
5
+ import * as react_router from 'react-router';
6
+
7
+ type Awaitable<T> = T | Promise<T>;
8
+ type AuthzUserId = string | number;
9
+ type AuthzConfig = {
10
+ /** Stable app identifier (e.g. "quants"). Bound into every permission query. */
11
+ appKey: string;
12
+ /** Resolve the acting user id from the request (cookie/session/openid → TDUsers.id). */
13
+ resolveUserId: (request: Request) => Awaitable<AuthzUserId | null | undefined>;
14
+ /** Load effective permissions for (user, app, resource) — typically via @aiquants/authz-drizzle. */
15
+ getEffectivePermissions: (args: {
16
+ userId: AuthzUserId;
17
+ appKey: string;
18
+ resourceKey: string;
19
+ }) => Awaitable<EffectivePermission | null | undefined>;
20
+ /** Default deny handler. If omitted, denies throw AuthzDeniedError (403). */
21
+ onDeny?: (info: DenyInfo) => void;
22
+ };
23
+ type RequirePermissionOptions = {
24
+ /** When set, denials `throw redirect(failureRedirect)` instead of throwing 403. */
25
+ failureRedirect?: string;
26
+ };
27
+ /** Serializable per-resource permission summary for UI (loader → component). */
28
+ type PermissionView = {
29
+ resourceKey: string;
30
+ read: boolean;
31
+ create: boolean;
32
+ update: boolean;
33
+ delete: boolean;
34
+ /** create ∪ update */
35
+ write: boolean;
36
+ /** read granted but row and/or column restricted (→ △ partial). */
37
+ readPartial: boolean;
38
+ actions: AuthzAction[];
39
+ };
40
+ /** Map an EffectivePermission to a serializable {@link PermissionView}. */
41
+ declare function toPermissionView(resourceKey: string, perm: EffectivePermission | null | undefined): PermissionView;
42
+ /**
43
+ * React Router adapter. Binds `appKey` and the DI deps, exposing:
44
+ * - `requirePermission(request, {resourceKey, action}, options?)` → `{ userId, scope }` on allow
45
+ * (apply row WHERE / column mask with the returned scope); denies throw 403 or redirect.
46
+ * - `getMyPermissions(request, {resourceKeys})` → `Record<resourceKey, PermissionView>` for the UI.
47
+ */
48
+ declare function createAuthz(config: AuthzConfig): {
49
+ requirePermission: (request: Request, query: {
50
+ resourceKey: string;
51
+ action: AuthzAction;
52
+ }, options?: RequirePermissionOptions) => Promise<GuardResult<AuthzUserId>>;
53
+ getMyPermissions: (request: Request, query: {
54
+ resourceKeys: string[];
55
+ }) => Promise<Record<string, PermissionView>>;
56
+ };
57
+
58
+ /** Authz admin UI strings (i18n). Defaults are English; override per-section via `createAuthzAdminRoutes(..., { labels })`. */
59
+ type AuthzAdminLabels = {
60
+ title: string;
61
+ myPermission: string;
62
+ tabs: {
63
+ roles: string;
64
+ resources: string;
65
+ role_permissions: string;
66
+ user_roles: string;
67
+ };
68
+ common: {
69
+ add: string;
70
+ save: string;
71
+ delete: string;
72
+ remove: string;
73
+ assign: string;
74
+ grant: string;
75
+ select: string;
76
+ active: string;
77
+ inactive: string;
78
+ optional: string;
79
+ };
80
+ roles: {
81
+ heading: string;
82
+ note: string;
83
+ roleKey: string;
84
+ name: string;
85
+ description: string;
86
+ activeHeader: string;
87
+ empty: string;
88
+ newHeading: string;
89
+ hintRoleKey: string;
90
+ };
91
+ resources: {
92
+ heading: string;
93
+ note: string;
94
+ appKey: string;
95
+ resourceKey: string;
96
+ name: string;
97
+ description: string;
98
+ empty: string;
99
+ newHeading: string;
100
+ hintAppKey: string;
101
+ hintResourceKey: string;
102
+ hintDailyReport: string;
103
+ };
104
+ grants: {
105
+ heading: string;
106
+ note: string;
107
+ role: string;
108
+ resource: string;
109
+ action: string;
110
+ rowScope: string;
111
+ columnScope: string;
112
+ empty: string;
113
+ newHeading: string;
114
+ rowScopeHint: string;
115
+ columnScopeHint: string;
116
+ rowScopePlaceholder: string;
117
+ columnScopePlaceholder: string;
118
+ nullRows: string;
119
+ nullCols: string;
120
+ selectPlaceholder: string;
121
+ };
122
+ userRoles: {
123
+ heading: string;
124
+ user: string;
125
+ role: string;
126
+ empty: string;
127
+ newHeading: string;
128
+ selectPlaceholder: string;
129
+ };
130
+ error: {
131
+ forbiddenTitle: string;
132
+ forbiddenBody: string;
133
+ genericTitlePrefix: string;
134
+ genericTitle: string;
135
+ genericBody: string;
136
+ };
137
+ warn: {
138
+ selfRoleDisable: string;
139
+ selfRoleDelete: string;
140
+ selfAssignmentRemove: string;
141
+ };
142
+ };
143
+ declare const defaultAuthzAdminLabels: AuthzAdminLabels;
144
+ type PartialAuthzAdminLabels = {
145
+ title?: string;
146
+ myPermission?: string;
147
+ tabs?: Partial<AuthzAdminLabels["tabs"]>;
148
+ common?: Partial<AuthzAdminLabels["common"]>;
149
+ roles?: Partial<AuthzAdminLabels["roles"]>;
150
+ resources?: Partial<AuthzAdminLabels["resources"]>;
151
+ grants?: Partial<AuthzAdminLabels["grants"]>;
152
+ userRoles?: Partial<AuthzAdminLabels["userRoles"]>;
153
+ error?: Partial<AuthzAdminLabels["error"]>;
154
+ warn?: Partial<AuthzAdminLabels["warn"]>;
155
+ };
156
+ /** Shallow per-section merge over the English defaults. */
157
+ declare function resolveLabels(over?: PartialAuthzAdminLabels): AuthzAdminLabels;
158
+
159
+ type WithLabels = {
160
+ labels: AuthzAdminLabels;
161
+ };
162
+ type AuthzLayoutData = WithLabels & {
163
+ myPermissions: Record<string, PermissionView>;
164
+ adminResourceKey: string;
165
+ basePath?: string;
166
+ };
167
+ /** ネストルート用レイアウト(子は Outlet)。`routes.ts` でネスト構成にする場合に使う。 */
168
+ declare function AuthzLayout(): react.JSX.Element;
169
+ /**
170
+ * 認可管理 UI のエラー境界。ErrorBoundary は loader データを読めないため、ラベルは
171
+ * `makeAuthzErrorBoundary(labels)` で注入する(アプリは自分のロケールで生成する)。
172
+ * 既定の `AuthzErrorBoundary` は英語(パッケージ既定)。
173
+ */
174
+ declare function makeAuthzErrorBoundary(over?: PartialAuthzAdminLabels): () => React.ReactElement;
175
+ /** 英語(既定ラベル)のエラー境界。i18n したい場合は {@link makeAuthzErrorBoundary} を使う。 */
176
+ declare const AuthzErrorBoundary: () => React.ReactElement;
177
+ type AuthzRolesData = WithLabels & {
178
+ roles: AuthzRole[];
179
+ selfAdminRoleIds?: number[];
180
+ };
181
+ declare function AuthzRolesView(): react.JSX.Element;
182
+ type AuthzResourcesData = WithLabels & {
183
+ resources: AuthzResource[];
184
+ };
185
+ declare function AuthzResourcesView(): react.JSX.Element;
186
+ type AuthzGrantsData = WithLabels & {
187
+ grants: AuthzGrant[];
188
+ roles: Array<{
189
+ id: number;
190
+ roleKey: string;
191
+ }>;
192
+ resources: Array<{
193
+ id: number;
194
+ appKey: string;
195
+ resourceKey: string;
196
+ }>;
197
+ };
198
+ declare function AuthzGrantsView(): react.JSX.Element;
199
+ type AuthzUserRolesData = WithLabels & {
200
+ assignments: AuthzAssignment[];
201
+ roles: Array<{
202
+ id: number;
203
+ roleKey: string;
204
+ }>;
205
+ users: AuthzUser[];
206
+ actorUserId?: number;
207
+ selfAdminRoleIds?: number[];
208
+ };
209
+ declare function AuthzUserRolesView(): react.JSX.Element;
210
+ /**
211
+ * スプラット(`authz/*`)1 ルートで認可管理 UI 全体を描画するコンポーネント(store 非依存)。
212
+ * loader が返す `segment` に応じて該当タブのビューを描画する。レイアウト殻と各ビューは同一の
213
+ * loader データ(セグメントデータ + myPermissions + labels をトップレベルに統合)を読む。
214
+ */
215
+ declare function AuthzAdminAppView(): react.JSX.Element;
216
+
217
+ type Req = {
218
+ request: Request;
219
+ };
220
+ type PermissionQuery = {
221
+ resourceKey: string;
222
+ action: AuthzAction;
223
+ };
224
+ type CreateAuthzAdminServerOptions = {
225
+ store: AuthzAdminStore;
226
+ /** 管理画面のガード資源キー(既定 `authz_admin`)。 */
227
+ resourceKey?: string;
228
+ /** 未ログインをログインへ誘導する(例: throw redirect(...))。 */
229
+ requireUser: (request: Request) => Promise<unknown>;
230
+ /** 認可ガード(アプリの createAuthz 由来)。allow で { userId } を返す。 */
231
+ requirePermission: (request: Request, query: PermissionQuery) => Promise<{
232
+ userId: string | number;
233
+ }>;
234
+ /** 自己権限表示用(アプリの createAuthz 由来)。 */
235
+ getMyPermissions: (request: Request, args: {
236
+ resourceKeys: string[];
237
+ }) => Promise<Record<string, PermissionView>>;
238
+ /** 文言の部分上書き(既定は日本語)。 */
239
+ labels?: PartialAuthzAdminLabels;
240
+ };
241
+ declare function createAuthzAdminServer(opts: CreateAuthzAdminServerOptions): {
242
+ /** 露出: スプラットマウント(app.ts)がガードを 1 回だけ行うために使う。 */
243
+ labels: AuthzAdminLabels;
244
+ resourceKey: string;
245
+ layoutGuard: (request: Request) => Promise<{
246
+ userId: string | number;
247
+ }>;
248
+ loadMyPermissions: (request: Request) => Promise<Record<string, PermissionView>>;
249
+ /** /authz レイアウト: requireUser(302) → requirePermission(read, 403) → 自己権限取得。 */
250
+ layout: {
251
+ loader({ request }: Req): Promise<AuthzLayoutData>;
252
+ };
253
+ /** /authz index → roles へ。 */
254
+ index: {
255
+ loader(): never;
256
+ };
257
+ roles: {
258
+ data: (userId?: string | number) => Promise<AuthzRolesData>;
259
+ loader({ request }: Req): Promise<AuthzRolesData>;
260
+ action({ request }: Req): Promise<react_router.UNSAFE_DataWithResponseInit<{
261
+ error: string;
262
+ }> | {
263
+ ok: boolean;
264
+ }>;
265
+ };
266
+ resources: {
267
+ data: () => Promise<AuthzResourcesData>;
268
+ loader({ request }: Req): Promise<AuthzResourcesData>;
269
+ action({ request }: Req): Promise<react_router.UNSAFE_DataWithResponseInit<{
270
+ error: string;
271
+ }> | {
272
+ ok: boolean;
273
+ }>;
274
+ };
275
+ grants: {
276
+ data: () => Promise<AuthzGrantsData>;
277
+ loader({ request }: Req): Promise<AuthzGrantsData>;
278
+ action({ request }: Req): Promise<react_router.UNSAFE_DataWithResponseInit<{
279
+ error: string;
280
+ }> | {
281
+ ok: boolean;
282
+ }>;
283
+ };
284
+ userRoles: {
285
+ data: (userId?: string | number) => Promise<AuthzUserRolesData>;
286
+ loader({ request }: Req): Promise<AuthzUserRolesData>;
287
+ action({ request }: Req): Promise<react_router.UNSAFE_DataWithResponseInit<{
288
+ error: string;
289
+ }> | {
290
+ ok: boolean;
291
+ }>;
292
+ };
293
+ };
294
+
295
+ type RouteArgs = {
296
+ request: Request;
297
+ params: Record<string, string | undefined>;
298
+ };
299
+ type CreateAuthzAdminAppOptions = CreateAuthzAdminServerOptions & {
300
+ /** マウントのベースパス(タブリンク/未指定セグメントのリダイレクト先)。既定 `/authz`。 */
301
+ basePath?: string;
302
+ };
303
+ declare function createAuthzAdminApp(opts: CreateAuthzAdminAppOptions): {
304
+ loader: (args: RouteArgs) => Promise<{
305
+ labels: AuthzAdminLabels;
306
+ roles: _aiquants_authz_core.AuthzRole[];
307
+ selfAdminRoleIds?: number[];
308
+ segment: string;
309
+ basePath: string;
310
+ myPermissions: Record<string, PermissionView>;
311
+ adminResourceKey: string;
312
+ } | {
313
+ labels: AuthzAdminLabels;
314
+ resources: _aiquants_authz_core.AuthzResource[];
315
+ segment: string;
316
+ basePath: string;
317
+ myPermissions: Record<string, PermissionView>;
318
+ adminResourceKey: string;
319
+ } | {
320
+ labels: AuthzAdminLabels;
321
+ grants: _aiquants_authz_core.AuthzGrant[];
322
+ roles: Array<{
323
+ id: number;
324
+ roleKey: string;
325
+ }>;
326
+ resources: Array<{
327
+ id: number;
328
+ appKey: string;
329
+ resourceKey: string;
330
+ }>;
331
+ segment: string;
332
+ basePath: string;
333
+ myPermissions: Record<string, PermissionView>;
334
+ adminResourceKey: string;
335
+ } | {
336
+ labels: AuthzAdminLabels;
337
+ assignments: _aiquants_authz_core.AuthzAssignment[];
338
+ roles: Array<{
339
+ id: number;
340
+ roleKey: string;
341
+ }>;
342
+ users: _aiquants_authz_core.AuthzUser[];
343
+ actorUserId?: number;
344
+ selfAdminRoleIds?: number[];
345
+ segment: string;
346
+ basePath: string;
347
+ myPermissions: Record<string, PermissionView>;
348
+ adminResourceKey: string;
349
+ }>;
350
+ action: (args: RouteArgs) => Promise<react_router.UNSAFE_DataWithResponseInit<{
351
+ error: string;
352
+ }> | {
353
+ ok: boolean;
354
+ }>;
355
+ server: {
356
+ labels: AuthzAdminLabels;
357
+ resourceKey: string;
358
+ layoutGuard: (request: Request) => Promise<{
359
+ userId: string | number;
360
+ }>;
361
+ loadMyPermissions: (request: Request) => Promise<Record<string, PermissionView>>;
362
+ layout: {
363
+ loader({ request }: {
364
+ request: Request;
365
+ }): Promise<AuthzLayoutData>;
366
+ };
367
+ index: {
368
+ loader(): never;
369
+ };
370
+ roles: {
371
+ data: (userId?: string | number) => Promise<AuthzRolesData>;
372
+ loader({ request }: {
373
+ request: Request;
374
+ }): Promise<AuthzRolesData>;
375
+ action({ request }: {
376
+ request: Request;
377
+ }): Promise<react_router.UNSAFE_DataWithResponseInit<{
378
+ error: string;
379
+ }> | {
380
+ ok: boolean;
381
+ }>;
382
+ };
383
+ resources: {
384
+ data: () => Promise<AuthzResourcesData>;
385
+ loader({ request }: {
386
+ request: Request;
387
+ }): Promise<AuthzResourcesData>;
388
+ action({ request }: {
389
+ request: Request;
390
+ }): Promise<react_router.UNSAFE_DataWithResponseInit<{
391
+ error: string;
392
+ }> | {
393
+ ok: boolean;
394
+ }>;
395
+ };
396
+ grants: {
397
+ data: () => Promise<AuthzGrantsData>;
398
+ loader({ request }: {
399
+ request: Request;
400
+ }): Promise<AuthzGrantsData>;
401
+ action({ request }: {
402
+ request: Request;
403
+ }): Promise<react_router.UNSAFE_DataWithResponseInit<{
404
+ error: string;
405
+ }> | {
406
+ ok: boolean;
407
+ }>;
408
+ };
409
+ userRoles: {
410
+ data: (userId?: string | number) => Promise<AuthzUserRolesData>;
411
+ loader({ request }: {
412
+ request: Request;
413
+ }): Promise<AuthzUserRolesData>;
414
+ action({ request }: {
415
+ request: Request;
416
+ }): Promise<react_router.UNSAFE_DataWithResponseInit<{
417
+ error: string;
418
+ }> | {
419
+ ok: boolean;
420
+ }>;
421
+ };
422
+ };
423
+ };
424
+
425
+ declare const ui: Record<string, CSSProperties>;
426
+ /**
427
+ * ラベルを上、コントロールを下に縦積みするフィールド(重なり防止・一貫レイアウト)。
428
+ * コントロール側は `aria-label` を持つ前提なので `<div>` で構成する。
429
+ */
430
+ declare function Field({ label, hint, children }: {
431
+ label: string;
432
+ hint?: string;
433
+ children: ReactNode;
434
+ }): react.JSX.Element;
435
+ /** エラー表示(role="alert")。 */
436
+ declare function ErrorAlert({ message }: {
437
+ message?: string;
438
+ }): react.JSX.Element | null;
439
+
440
+ type MyPermissionIndicatorProps = {
441
+ permission: PermissionView | null | undefined;
442
+ labels?: {
443
+ read?: string;
444
+ write?: string;
445
+ delete?: string;
446
+ };
447
+ /** Show a "(部分)" hint when read is partial. Default true. */
448
+ showScopeSummary?: boolean;
449
+ className?: string;
450
+ };
451
+ /**
452
+ * Compact self-permission indicator: read / write(create∪update) / delete as ○△×.
453
+ * `write` is ○ only when both create & update are held, △ when one, × when none.
454
+ */
455
+ declare function MyPermissionIndicator({ permission, labels, showScopeSummary, className }: MyPermissionIndicatorProps): react.JSX.Element;
456
+
457
+ type PermState = "full" | "partial" | "none";
458
+ type UsePermission = {
459
+ canRead: boolean;
460
+ canWrite: boolean;
461
+ canDelete: boolean;
462
+ /** read: none(×) / partial(△, row|col restricted) / full(○). */
463
+ readState: PermState;
464
+ /** write = create ∪ update: full(○ both) / partial(△ one) / none(×). */
465
+ writeState: PermState;
466
+ deleteState: PermState;
467
+ };
468
+ /**
469
+ * Derive ○△× display states from a {@link PermissionView}. Pure (safe to call in render);
470
+ * named `usePermission` for ergonomic call-sites.
471
+ */
472
+ declare function usePermission(view: PermissionView | null | undefined): UsePermission;
473
+
474
+ export { AuthzAdminAppView, type AuthzAdminLabels, type AuthzConfig, AuthzErrorBoundary, type AuthzGrantsData, AuthzGrantsView, AuthzLayout, type AuthzLayoutData, type AuthzResourcesData, AuthzResourcesView, type AuthzRolesData, AuthzRolesView, type AuthzUserId, type AuthzUserRolesData, AuthzUserRolesView, type CreateAuthzAdminAppOptions, type CreateAuthzAdminServerOptions, ErrorAlert, Field, MyPermissionIndicator, type MyPermissionIndicatorProps, type PartialAuthzAdminLabels, type PermState, type PermissionView, type RequirePermissionOptions, type UsePermission, createAuthz, createAuthzAdminApp, createAuthzAdminServer, defaultAuthzAdminLabels, makeAuthzErrorBoundary, resolveLabels, toPermissionView, ui, usePermission };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";var D=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var Y=Object.getOwnPropertyNames;var Z=Object.prototype.hasOwnProperty;var X=(o,r)=>{for(var n in r)D(o,n,{get:r[n],enumerable:!0})},j=(o,r,n,l)=>{if(r&&typeof r=="object"||typeof r=="function")for(let s of Y(r))!Z.call(o,s)&&s!==n&&D(o,s,{get:()=>r[s],enumerable:!(l=Q(r,s))||l.enumerable});return o};var ee=o=>j(D({},"__esModule",{value:!0}),o);var le={};X(le,{AuthzAdminAppView:()=>ie,AuthzErrorBoundary:()=>oe,AuthzGrantsView:()=>M,AuthzLayout:()=>se,AuthzResourcesView:()=>W,AuthzRolesView:()=>F,AuthzUserRolesView:()=>B,ErrorAlert:()=>v,Field:()=>h,MyPermissionIndicator:()=>U,createAuthz:()=>ae,createAuthzAdminApp:()=>re,createAuthzAdminServer:()=>_,defaultAuthzAdminLabels:()=>$,makeAuthzErrorBoundary:()=>G,resolveLabels:()=>x,toPermissionView:()=>J,ui:()=>t,usePermission:()=>E});module.exports=ee(le);var I=require("react-router");var L=require("@aiquants/authz-core"),f=require("react-router");var $={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 x(o){let r=$;return o?{title:o.title??r.title,myPermission:o.myPermission??r.myPermission,tabs:{...r.tabs,...o.tabs},common:{...r.common,...o.common},roles:{...r.roles,...o.roles},resources:{...r.resources,...o.resources},grants:{...r.grants,...o.grants},userRoles:{...r.userRoles,...o.userRoles},error:{...r.error,...o.error},warn:{...r.warn,...o.warn}}:r}var te=o=>o instanceof Response;function K(o){if(te(o))throw o;if(o instanceof L.AuthzDeniedError)throw new Response(o.message,{status:403});return(0,f.data)({error:o instanceof Error?o.message:"\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"},{status:400})}function _(o){let r=o.store,n=o.resourceKey??"authz_admin",l=x(o.labels),s=o.requirePermission;async function u(d){await o.requireUser(d);try{return await s(d,{resourceKey:n,action:"read"})}catch(a){throw a instanceof L.AuthzDeniedError?new Response(`Forbidden: ${n}`,{status:403}):a}}let i=d=>o.getMyPermissions(d,{resourceKeys:[n]}),g=async d=>{let[a,A]=await Promise.all([r.listRoles(),r.getSelfAdminContext(Number(d))]);return{roles:a,selfAdminRoleIds:A.selfAdminRoleIds,labels:l}},b=async()=>({resources:await r.listResources(),labels:l}),m=async()=>{let[d,a,A]=await Promise.all([r.listGrants(),r.listRoles(),r.listResources()]);return{grants:d,roles:a,resources:A,labels:l}},R=async d=>{let[a,A,p,y]=await Promise.all([r.listUserRoles(),r.listRoles(),r.listUsers(),r.getSelfAdminContext(Number(d))]);return{assignments:a,roles:A,users:p,actorUserId:y.actorUserId,selfAdminRoleIds:y.selfAdminRoleIds,labels:l}};return{labels:l,resourceKey:n,layoutGuard:u,loadMyPermissions:i,layout:{async loader({request:d}){return await u(d),{myPermissions:await i(d),labels:l,adminResourceKey:n}}},index:{loader(){throw(0,f.redirect)("/authz/roles")}},roles:{data:g,async loader({request:d}){let{userId:a}=await s(d,{resourceKey:n,action:"read"});return g(a)},async action({request:d}){let a=await d.formData(),A=String(a.get("_action"));try{switch(A){case"create":{let{userId:p}=await s(d,{resourceKey:n,action:"create"}),y=String(a.get("roleKey")??"").trim(),w=String(a.get("name")??"").trim();return y&&w?(await r.createRole({roleKey:y,name:w,description:String(a.get("description")??"").trim()||null},String(p)),{ok:!0}):(0,f.data)({error:"role_key \u3068 name \u306F\u5FC5\u9808\u3067\u3059"},{status:400})}case"save":{let{userId:p}=await s(d,{resourceKey:n,action:"update"}),y=String(a.get("name")??"").trim();return y?(await r.updateRole(Number(a.get("id")),{name:y,description:String(a.get("description")??"").trim()||null},String(p)),{ok:!0}):(0,f.data)({error:"name \u306F\u5FC5\u9808\u3067\u3059"},{status:400})}case"toggle":{let{userId:p}=await s(d,{resourceKey:n,action:"update"});return await r.setRoleActive(Number(a.get("id")),a.get("isActive")==="true",String(p)),{ok:!0}}case"delete":return await s(d,{resourceKey:n,action:"delete"}),await r.deleteRole(Number(a.get("id"))),{ok:!0};default:return(0,f.data)({error:"unknown action"},{status:400})}}catch(p){return K(p)}}},resources:{data:b,async loader({request:d}){return await s(d,{resourceKey:n,action:"read"}),b()},async action({request:d}){let a=await d.formData(),A=String(a.get("_action"));try{switch(A){case"create":{let{userId:p}=await s(d,{resourceKey:n,action:"create"}),y=String(a.get("appKey")??"").trim(),w=String(a.get("resourceKey")??"").trim(),C=String(a.get("name")??"").trim();return y&&w&&C?(await r.createResource({appKey:y,resourceKey:w,name:C,description:String(a.get("description")??"").trim()||null},String(p)),{ok:!0}):(0,f.data)({error:"app_key / resource_key / name \u306F\u5FC5\u9808\u3067\u3059"},{status:400})}case"save":{let{userId:p}=await s(d,{resourceKey:n,action:"update"}),y=String(a.get("name")??"").trim();return y?(await r.updateResource(Number(a.get("id")),{name:y,description:String(a.get("description")??"").trim()||null},String(p)),{ok:!0}):(0,f.data)({error:"name \u306F\u5FC5\u9808\u3067\u3059"},{status:400})}case"delete":return await s(d,{resourceKey:n,action:"delete"}),await r.deleteResource(Number(a.get("id"))),{ok:!0};default:return(0,f.data)({error:"unknown action"},{status:400})}}catch(p){return K(p)}}},grants:{data:m,async loader({request:d}){return await s(d,{resourceKey:n,action:"read"}),m()},async action({request:d}){let a=await d.formData(),A=String(a.get("_action"));try{switch(A){case"create":{let{userId:p}=await s(d,{resourceKey:n,action:"create"}),y=Number(a.get("roleId")),w=Number(a.get("resourceId"));return y&&w?(await r.createGrant({roleId:y,resourceId:w,action:String(a.get("action")??""),rowScope:String(a.get("rowScope")??""),columnScope:String(a.get("columnScope")??"")},String(p)),{ok:!0}):(0,f.data)({error:"\u30ED\u30FC\u30EB\u3068\u30EA\u30BD\u30FC\u30B9\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044"},{status:400})}case"save":{let{userId:p}=await s(d,{resourceKey:n,action:"update"});return await r.updateGrant(Number(a.get("id")),{rowScope:String(a.get("rowScope")??""),columnScope:String(a.get("columnScope")??"")},String(p)),{ok:!0}}case"delete":return await s(d,{resourceKey:n,action:"delete"}),await r.deleteGrant(Number(a.get("id"))),{ok:!0};default:return(0,f.data)({error:"unknown action"},{status:400})}}catch(p){return K(p)}}},userRoles:{data:R,async loader({request:d}){let{userId:a}=await s(d,{resourceKey:n,action:"read"});return R(a)},async action({request:d}){let a=await d.formData(),A=String(a.get("_action"));try{switch(A){case"assign":{let{userId:p}=await s(d,{resourceKey:n,action:"create"}),y=Number(a.get("userId")),w=Number(a.get("roleId"));return y&&w?(await r.assignUserRole(y,w,String(p)),{ok:!0}):(0,f.data)({error:"\u30E6\u30FC\u30B6\u30FC\u3068\u30ED\u30FC\u30EB\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044"},{status:400})}case"remove":return await s(d,{resourceKey:n,action:"delete"}),await r.removeUserRole(Number(a.get("userId")),Number(a.get("roleId"))),{ok:!0};default:return(0,f.data)({error:"unknown action"},{status:400})}}catch(p){return K(p)}}}}}function T(o){return String(o["*"]??"").split("/")[0]}function re(o){let r=_(o),n=o.basePath??"/authz",l=["roles","resources","role_permissions","user_roles"],s={roles:r.roles.data,resources:r.resources.data,role_permissions:r.grants.data,user_roles:r.userRoles.data},u={roles:r.roles.action,resources:r.resources.action,role_permissions:r.grants.action,user_roles:r.userRoles.action};async function i(b){let m=T(b.params);if(!l.includes(m))throw(0,I.redirect)(`${n}/roles`);let{userId:R}=await r.layoutGuard(b.request),[d,a]=await Promise.all([r.loadMyPermissions(b.request),s[m](R)]);return{segment:m,basePath:n,myPermissions:d,adminResourceKey:r.resourceKey,...a}}async function g(b){let m=T(b.params),R=u[m];return R?R(b):(0,I.data)({error:"unknown action"},{status:400})}return{loader:i,action:g,server:r}}var z=require("react/jsx-runtime"),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 h({label:o,hint:r,children:n}){return(0,z.jsxs)("div",{style:{display:"flex",flexDirection:"column",gap:"0.3rem"},children:[(0,z.jsxs)("span",{style:{fontSize:"0.8rem",color:"#475569",fontWeight:600},children:[o,r?(0,z.jsxs)("span",{style:{fontWeight:400,color:"#94a3b8"},children:[" \u2014 ",r]}):null]}),n]})}function v({message:o}){return o?(0,z.jsx)("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}var V=require("@aiquants/authz-core"),c=require("react-router");function E(o){let r=o?.read?o.readPartial?"partial":"full":"none",n=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:r,writeState:n,deleteState:l}}var S=require("react/jsx-runtime"),N={full:"\u25CB",partial:"\u25B3",none:"\xD7"};function U({permission:o,labels:r,showScopeSummary:n=!0,className:l="authz-permission-indicator"}){let s=E(o),u={read:r?.read??"\u8AAD",write:r?.write??"\u66F8",delete:r?.delete??"\u524A\u9664"};return(0,S.jsxs)("span",{className:l,"data-resource":o?.resourceKey??"",children:[(0,S.jsxs)("span",{"data-perm":"read",title:`${u.read}: ${s.readState}`,children:[u.read,N[s.readState]]}),(0,S.jsxs)("span",{"data-perm":"write",title:`${u.write}: ${s.writeState}`,children:[u.write,N[s.writeState]]}),(0,S.jsxs)("span",{"data-perm":"delete",title:`${u.delete}: ${s.deleteState}`,children:[u.delete,N[s.deleteState]]}),n&&s.readState==="partial"?(0,S.jsx)("span",{"data-perm":"scope",children:"\uFF08\u90E8\u5206\uFF09"}):null]})}var e=require("react/jsx-runtime"),k=o=>o?.error;function H({children:o}){let{myPermissions:r,labels:n,adminResourceKey:l,basePath:s}=(0,c.useLoaderData)(),u=s??"/authz",i=[["roles",n.tabs.roles],["resources",n.tabs.resources],["role_permissions",n.tabs.role_permissions],["user_roles",n.tabs.user_roles]];return(0,e.jsxs)("div",{className:"authz-admin",style:t.page,children:[(0,e.jsxs)("header",{style:{display:"flex",alignItems:"baseline",justifyContent:"space-between",gap:"1rem",flexWrap:"wrap"},children:[(0,e.jsx)("h1",{style:{fontSize:"1.3rem",margin:0,fontWeight:700},children:n.title}),(0,e.jsxs)("span",{style:{fontSize:"0.82rem",color:"#475569",display:"inline-flex",alignItems:"center",gap:"0.4rem"},children:[n.myPermission,": ",(0,e.jsx)(U,{permission:r[l]})]})]}),(0,e.jsx)("nav",{style:{display:"flex",gap:"0.25rem",borderBottom:"1px solid #e2e8f0",margin:"0.9rem 0 1.25rem"},children:i.map(([g,b])=>(0,e.jsx)(c.NavLink,{to:`${u}/${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 se(){return(0,e.jsx)(H,{children:(0,e.jsx)(c.Outlet,{})})}function G(o){let r=x(o).error;return function(){let l=(0,c.useRouteError)(),s=(0,c.isRouteErrorResponse)(l)?l:null,u=s?.status===403,i=u?r.forbiddenTitle:s?`${r.genericTitlePrefix} (${s.status})`:r.genericTitle,g=u?r.forbiddenBody:s?typeof s.data=="string"&&s.data?s.data:s.statusText:r.genericBody;return(0,e.jsx)("div",{style:t.page,children:(0,e.jsxs)("div",{role:"alert",style:{maxWidth:480,margin:"3rem auto",padding:"1.5rem",border:"1px solid #fecaca",borderRadius:12,background:"#fef2f2"},children:[(0,e.jsx)("h1",{style:{fontSize:"1.1rem",fontWeight:700,color:"#b91c1c",margin:"0 0 0.5rem"},children:i}),(0,e.jsx)("p",{style:{color:"#7f1d1d",fontSize:"0.9rem",margin:0,lineHeight:1.7},children:g})]})})}}var oe=G(),q=(o,r)=>n=>{o&&!window.confirm(r)&&n.preventDefault()};function F(){let{roles:o,selfAdminRoleIds:r,labels:n}=(0,c.useLoaderData)(),l=n.roles,s=n.common,u=new Set(r??[]);return(0,e.jsxs)("section",{children:[(0,e.jsx)("h2",{style:t.h2,children:l.heading}),(0,e.jsx)(v,{message:k((0,c.useActionData)())}),(0,e.jsx)("p",{style:t.note,children:l.note}),(0,e.jsxs)("table",{style:t.table,children:[(0,e.jsx)("thead",{children:(0,e.jsxs)("tr",{children:[(0,e.jsx)("th",{style:t.th,children:l.roleKey}),(0,e.jsx)("th",{style:t.th,children:l.name}),(0,e.jsx)("th",{style:t.th,children:l.description}),(0,e.jsx)("th",{style:t.th,children:l.activeHeader}),(0,e.jsx)("th",{style:t.th})]})}),(0,e.jsxs)("tbody",{children:[o.map(i=>(0,e.jsxs)("tr",{children:[(0,e.jsx)("td",{style:t.td,children:(0,e.jsx)("span",{style:t.code,children:i.roleKey})}),(0,e.jsx)("td",{style:t.td,children:(0,e.jsx)("input",{name:"name",defaultValue:i.name,form:`save-role-${i.id}`,"aria-label":`name-${i.id}`,required:!0,style:t.input})}),(0,e.jsx)("td",{style:t.td,children:(0,e.jsx)("input",{name:"description",defaultValue:i.description??"",form:`save-role-${i.id}`,"aria-label":`description-${i.id}`,style:t.input})}),(0,e.jsx)("td",{style:t.td,children:(0,e.jsxs)(c.Form,{method:"post",style:{display:"inline"},children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"toggle"}),(0,e.jsx)("input",{type:"hidden",name:"id",value:i.id}),(0,e.jsx)("input",{type:"hidden",name:"isActive",value:String(!i.isActive)}),(0,e.jsx)("button",{type:"submit",style:t.button,onClick:i.isActive?q(u.has(i.id),n.warn.selfRoleDisable):void 0,children:i.isActive?s.active:s.inactive})]})}),(0,e.jsxs)("td",{style:{...t.td,whiteSpace:"nowrap"},children:[(0,e.jsxs)(c.Form,{method:"post",id:`save-role-${i.id}`,style:{display:"inline"},children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"save"}),(0,e.jsx)("input",{type:"hidden",name:"id",value:i.id}),(0,e.jsx)("button",{type:"submit",style:t.save,children:s.save})]}),(0,e.jsxs)(c.Form,{method:"post",style:{display:"inline",marginLeft:"0.4rem"},children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"delete"}),(0,e.jsx)("input",{type:"hidden",name:"id",value:i.id}),(0,e.jsx)("button",{type:"submit",style:t.danger,onClick:q(u.has(i.id),n.warn.selfRoleDelete),children:s.delete})]})]})]},i.id)),o.length===0?(0,e.jsx)("tr",{children:(0,e.jsx)("td",{style:t.empty,colSpan:5,children:l.empty})}):null]})]}),(0,e.jsx)("h3",{style:t.h3,children:l.newHeading}),(0,e.jsxs)(c.Form,{method:"post",style:t.card,children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"create"}),(0,e.jsx)(h,{label:l.roleKey,hint:l.hintRoleKey,children:(0,e.jsx)("input",{name:"roleKey","aria-label":"role_key",required:!0,style:t.input})}),(0,e.jsx)(h,{label:l.name,children:(0,e.jsx)("input",{name:"name","aria-label":"name",required:!0,style:t.input})}),(0,e.jsx)(h,{label:l.description,hint:s.optional,children:(0,e.jsx)("input",{name:"description","aria-label":"description",style:t.input})}),(0,e.jsx)("button",{type:"submit",style:t.primary,children:s.add})]})]})}function W(){let{resources:o,labels:r}=(0,c.useLoaderData)(),n=r.resources,l=r.common;return(0,e.jsxs)("section",{children:[(0,e.jsx)("h2",{style:t.h2,children:n.heading}),(0,e.jsx)(v,{message:k((0,c.useActionData)())}),(0,e.jsx)("p",{style:t.note,children:n.note}),(0,e.jsxs)("table",{style:t.table,children:[(0,e.jsx)("thead",{children:(0,e.jsxs)("tr",{children:[(0,e.jsx)("th",{style:t.th,children:n.appKey}),(0,e.jsx)("th",{style:t.th,children:n.resourceKey}),(0,e.jsx)("th",{style:t.th,children:n.name}),(0,e.jsx)("th",{style:t.th,children:n.description}),(0,e.jsx)("th",{style:t.th})]})}),(0,e.jsxs)("tbody",{children:[o.map(s=>(0,e.jsxs)("tr",{children:[(0,e.jsx)("td",{style:t.td,children:(0,e.jsx)("span",{style:t.code,children:s.appKey})}),(0,e.jsx)("td",{style:t.td,children:(0,e.jsx)("span",{style:t.code,children:s.resourceKey})}),(0,e.jsx)("td",{style:t.td,children:(0,e.jsx)("input",{name:"name",defaultValue:s.name,form:`save-res-${s.id}`,"aria-label":`name-${s.id}`,required:!0,style:t.input})}),(0,e.jsx)("td",{style:t.td,children:(0,e.jsx)("input",{name:"description",defaultValue:s.description??"",form:`save-res-${s.id}`,"aria-label":`description-${s.id}`,style:t.input})}),(0,e.jsxs)("td",{style:{...t.td,whiteSpace:"nowrap"},children:[(0,e.jsxs)(c.Form,{method:"post",id:`save-res-${s.id}`,style:{display:"inline"},children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"save"}),(0,e.jsx)("input",{type:"hidden",name:"id",value:s.id}),(0,e.jsx)("button",{type:"submit",style:t.save,children:l.save})]}),(0,e.jsxs)(c.Form,{method:"post",style:{display:"inline",marginLeft:"0.4rem"},children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"delete"}),(0,e.jsx)("input",{type:"hidden",name:"id",value:s.id}),(0,e.jsx)("button",{type:"submit",style:t.danger,children:l.delete})]})]})]},s.id)),o.length===0?(0,e.jsx)("tr",{children:(0,e.jsx)("td",{style:t.empty,colSpan:5,children:n.empty})}):null]})]}),(0,e.jsx)("h3",{style:t.h3,children:n.newHeading}),(0,e.jsxs)(c.Form,{method:"post",style:t.card,children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"create"}),(0,e.jsx)(h,{label:n.appKey,hint:n.hintAppKey,children:(0,e.jsx)("input",{name:"appKey","aria-label":"app_key",required:!0,style:t.input})}),(0,e.jsx)(h,{label:n.resourceKey,hint:n.hintResourceKey,children:(0,e.jsx)("input",{name:"resourceKey","aria-label":"resource_key",required:!0,style:t.input})}),(0,e.jsx)(h,{label:n.name,children:(0,e.jsx)("input",{name:"name","aria-label":"name",required:!0,style:t.input})}),(0,e.jsx)(h,{label:n.description,hint:l.optional,children:(0,e.jsx)("input",{name:"description","aria-label":"description",style:t.input})}),(0,e.jsx)("button",{type:"submit",style:t.primary,children:l.add})]})]})}function M(){let{grants:o,roles:r,resources:n,labels:l}=(0,c.useLoaderData)(),s=l.grants,u=l.common;return(0,e.jsxs)("section",{children:[(0,e.jsx)("h2",{style:t.h2,children:s.heading}),(0,e.jsx)("p",{style:t.note,children:s.note}),(0,e.jsx)(v,{message:k((0,c.useActionData)())}),(0,e.jsxs)("table",{style:t.table,children:[(0,e.jsx)("thead",{children:(0,e.jsxs)("tr",{children:[(0,e.jsx)("th",{style:t.th,children:s.role}),(0,e.jsx)("th",{style:t.th,children:s.resource}),(0,e.jsx)("th",{style:t.th,children:s.action}),(0,e.jsx)("th",{style:t.th,children:s.rowScope}),(0,e.jsx)("th",{style:t.th,children:s.columnScope}),(0,e.jsx)("th",{style:t.th})]})}),(0,e.jsxs)("tbody",{children:[o.map(i=>(0,e.jsxs)("tr",{children:[(0,e.jsx)("td",{style:t.td,children:(0,e.jsx)("span",{style:t.code,children:i.roleKey})}),(0,e.jsx)("td",{style:t.td,children:(0,e.jsxs)("span",{style:t.code,children:[i.appKey,":",i.resourceKey]})}),(0,e.jsx)("td",{style:t.td,children:i.action}),(0,e.jsx)("td",{style:t.td,children:(0,e.jsx)("textarea",{name:"rowScope",defaultValue:i.rowScope??"",form:`save-grant-${i.id}`,"aria-label":`row_scope-${i.id}`,rows:2,placeholder:s.rowScopePlaceholder,style:t.textarea})}),(0,e.jsx)("td",{style:t.td,children:(0,e.jsx)("textarea",{name:"columnScope",defaultValue:i.columnScope??"",form:`save-grant-${i.id}`,"aria-label":`column_scope-${i.id}`,rows:2,placeholder:s.columnScopePlaceholder,style:t.textarea})}),(0,e.jsxs)("td",{style:{...t.td,whiteSpace:"nowrap"},children:[(0,e.jsxs)(c.Form,{method:"post",id:`save-grant-${i.id}`,style:{display:"inline"},children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"save"}),(0,e.jsx)("input",{type:"hidden",name:"id",value:i.id}),(0,e.jsx)("button",{type:"submit",style:t.save,children:u.save})]}),(0,e.jsxs)(c.Form,{method:"post",style:{display:"inline",marginLeft:"0.4rem"},children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"delete"}),(0,e.jsx)("input",{type:"hidden",name:"id",value:i.id}),(0,e.jsx)("button",{type:"submit",style:t.danger,children:u.delete})]})]})]},i.id)),o.length===0?(0,e.jsx)("tr",{children:(0,e.jsx)("td",{style:t.empty,colSpan:6,children:s.empty})}):null]})]}),(0,e.jsx)("h3",{style:t.h3,children:s.newHeading}),(0,e.jsxs)(c.Form,{method:"post",style:t.card,children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"create"}),(0,e.jsx)(h,{label:s.role,children:(0,e.jsxs)("select",{name:"roleId","aria-label":"role",required:!0,style:t.select,children:[(0,e.jsx)("option",{value:"",children:s.selectPlaceholder}),r.map(i=>(0,e.jsx)("option",{value:i.id,children:i.roleKey},i.id))]})}),(0,e.jsx)(h,{label:s.resource,children:(0,e.jsxs)("select",{name:"resourceId","aria-label":"resource",required:!0,style:t.select,children:[(0,e.jsx)("option",{value:"",children:s.selectPlaceholder}),n.map(i=>(0,e.jsxs)("option",{value:i.id,children:[i.appKey,":",i.resourceKey]},i.id))]})}),(0,e.jsx)(h,{label:s.action,children:(0,e.jsx)("select",{name:"action","aria-label":"action",required:!0,style:t.select,children:V.AUTHZ_ACTIONS.map(i=>(0,e.jsx)("option",{value:i,children:i},i))})}),(0,e.jsx)(h,{label:s.rowScope,hint:s.rowScopeHint,children:(0,e.jsx)("textarea",{name:"rowScope","aria-label":"row_scope",rows:2,style:t.textarea,placeholder:'{"filters":[{"field":"\u90E8\u9580CD","op":"in","values":["A"]}]}'})}),(0,e.jsx)(h,{label:s.columnScope,hint:s.columnScopeHint,children:(0,e.jsx)("textarea",{name:"columnScope","aria-label":"column_scope",rows:2,style:t.textarea,placeholder:'{"mode":"deny","columns":["\u91D1\u984D"]}'})}),(0,e.jsx)("button",{type:"submit",style:t.primary,children:u.grant})]})]})}function B(){let{assignments:o,roles:r,users:n,actorUserId:l,selfAdminRoleIds:s,labels:u}=(0,c.useLoaderData)(),i=u.userRoles,g=u.common,b=new Set(s??[]);return(0,e.jsxs)("section",{children:[(0,e.jsx)("h2",{style:t.h2,children:i.heading}),(0,e.jsx)(v,{message:k((0,c.useActionData)())}),(0,e.jsxs)("table",{style:t.table,children:[(0,e.jsx)("thead",{children:(0,e.jsxs)("tr",{children:[(0,e.jsx)("th",{style:t.th,children:i.user}),(0,e.jsx)("th",{style:t.th,children:i.role}),(0,e.jsx)("th",{style:t.th})]})}),(0,e.jsxs)("tbody",{children:[o.map(m=>(0,e.jsxs)("tr",{children:[(0,e.jsxs)("td",{style:t.td,children:[m.email,(0,e.jsxs)("span",{style:t.muted,children:["\uFF08",m.displayName,"\uFF09"]})]}),(0,e.jsx)("td",{style:t.td,children:m.roleKey}),(0,e.jsx)("td",{style:t.td,children:(0,e.jsxs)(c.Form,{method:"post",style:{display:"inline"},children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"remove"}),(0,e.jsx)("input",{type:"hidden",name:"userId",value:m.userId}),(0,e.jsx)("input",{type:"hidden",name:"roleId",value:m.roleId}),(0,e.jsx)("button",{type:"submit",style:t.danger,onClick:q(m.userId===l&&b.has(m.roleId),u.warn.selfAssignmentRemove),children:g.remove})]})})]},`${m.userId}-${m.roleId}`)),o.length===0?(0,e.jsx)("tr",{children:(0,e.jsx)("td",{style:t.empty,colSpan:3,children:i.empty})}):null]})]}),(0,e.jsx)("h3",{style:t.h3,children:i.newHeading}),(0,e.jsxs)(c.Form,{method:"post",style:t.card,children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"assign"}),(0,e.jsx)(h,{label:i.user,children:(0,e.jsxs)("select",{name:"userId","aria-label":"user",required:!0,style:t.select,children:[(0,e.jsx)("option",{value:"",children:i.selectPlaceholder}),n.map(m=>(0,e.jsx)("option",{value:m.id,children:m.email},m.id))]})}),(0,e.jsx)(h,{label:i.role,children:(0,e.jsxs)("select",{name:"roleId","aria-label":"role",required:!0,style:t.select,children:[(0,e.jsx)("option",{value:"",children:i.selectPlaceholder}),r.map(m=>(0,e.jsx)("option",{value:m.id,children:m.roleKey},m.id))]})}),(0,e.jsx)("button",{type:"submit",style:t.primary,children:g.assign})]})]})}var ne={roles:F,resources:W,role_permissions:M,user_roles:B};function ie(){let{segment:o}=(0,c.useLoaderData)(),r=ne[o]??F;return(0,e.jsx)(H,{children:(0,e.jsx)(r,{})})}var P=require("@aiquants/authz-core"),O=require("react-router");function J(o,r){let n=(0,P.can)(r,"read"),l=(0,P.can)(r,"create"),s=(0,P.can)(r,"update"),u=(0,P.can)(r,"delete"),i=r?.scopeByAction.read,g=n&&!!i&&(i.rowScope!==null||i.columnScope!==null);return{resourceKey:o,read:n,create:l,update:s,delete:u,write:l||s,readPartial:g,actions:r?Array.from(r.actions):[]}}function ae(o){async function r(l,s,u){let i=u?.failureRedirect?()=>{throw(0,O.redirect)(u.failureRedirect)}:o.onDeny;return(0,P.createRequirePermission)({resolveUserId:o.resolveUserId,getEffectivePermissions:o.getEffectivePermissions,onDeny:i})(l,{appKey:o.appKey,resourceKey:s.resourceKey,action:s.action})}async function n(l,s){let u=await o.resolveUserId(l),i={};for(let g of s.resourceKeys){let b=u==null?null:await o.getEffectivePermissions({userId:u,appKey:o.appKey,resourceKey:g});i[g]=J(g,b)}return i}return{requirePermission:r,getMyPermissions:n}}0&&(module.exports={AuthzAdminAppView,AuthzErrorBoundary,AuthzGrantsView,AuthzLayout,AuthzResourcesView,AuthzRolesView,AuthzUserRolesView,ErrorAlert,Field,MyPermissionIndicator,createAuthz,createAuthzAdminApp,createAuthzAdminServer,defaultAuthzAdminLabels,makeAuthzErrorBoundary,resolveLabels,toPermissionView,ui,usePermission});
2
+ //# sourceMappingURL=index.js.map