@aiquants/authz-react-router 0.3.0 → 0.4.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.
- package/README.md +7 -6
- package/dist/index.d.mts +83 -2
- package/dist/index.d.ts +83 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -92,11 +92,11 @@ WHERE r.role_key='viewer';
|
|
|
92
92
|
import { MyPermissionIndicator, MyPermissionStatus } from "@aiquants/authz-react-router"
|
|
93
93
|
|
|
94
94
|
// 1. Single indicator badge group
|
|
95
|
-
<MyPermissionIndicator permission={myPermissions.report} resourceName="
|
|
95
|
+
<MyPermissionIndicator permission={myPermissions.report} resourceName="Monthly Report" />
|
|
96
96
|
|
|
97
97
|
// 2. Full "Your Permissions" status bar component for any page header/toolbar
|
|
98
|
-
<MyPermissionStatus permission={myPermissions.report} resourceName="
|
|
99
|
-
// → "
|
|
98
|
+
<MyPermissionStatus permission={myPermissions.report} resourceName="Monthly Report" />
|
|
99
|
+
// → "Your Permissions: [Read ○][Write △][Delete ×]" with tooltip "Target Resource: Monthly Report (report)"
|
|
100
100
|
```
|
|
101
101
|
|
|
102
102
|
## Scope cheat-sheet (§3.2)
|
|
@@ -121,8 +121,9 @@ Multiple roles **union** (wider wins): rows OR'd (any `NULL` ⇒ all rows); colu
|
|
|
121
121
|
- `getMyPermissions(request, {resourceKeys})` → `Record<resourceKey, PermissionView>` for the UI.
|
|
122
122
|
- `toPermissionView(resourceKey, perm)` → serializable view (loader → client).
|
|
123
123
|
- `usePermission(view)` → ○△× display states (`readState`/`writeState`/`deleteState`); pure, safe in render.
|
|
124
|
-
- `<MyPermissionIndicator permission={view} resourceName="
|
|
125
|
-
- `<MyPermissionStatus permission={view} resourceName="
|
|
124
|
+
- `<MyPermissionIndicator permission={view} resourceName="Documents" expectedResourceKey="documents" />` → read / write(create∪update) / delete as ○△×. `read` is △ when row/column-restricted; `write` is ○ only when both create & update are held, △ when one. Hover shows resource name & key tooltip. Automatically flags mismatches if `permission.resourceKey !== expectedResourceKey`.
|
|
125
|
+
- `<MyPermissionStatus permission={view} resourceName="Documents" expectedResourceKey="documents" prefixLabel="Your Permissions" />` → Reusable status component combining prefix label and permission indicator badges for any application page.
|
|
126
|
+
- `<MyPermissionGroupStatus items={[{ resourceName: "Primary Resource", permission: primaryView }, { resourceName: "Sub Resource", permission: subView, level: 1 }]} variant="pills" | "popover" size="xs" labels={{ fullWrite: "Writable", readOnly: "Read-only" }} />` → Multi-resource permission widget for pages with multiple distinct resource scopes. Supports inline status tags (`variant="pills"`), single-button popover cards (`variant="popover"`), hierarchical tree indentation via `level` / `children`, and fully customizable status label mappings (`labels`).
|
|
126
127
|
|
|
127
128
|
## Demo App
|
|
128
129
|
|
|
@@ -133,7 +134,7 @@ This package contains an interactive React Router 7 SPA demo in the `demo/` subd
|
|
|
133
134
|
- **Role-Based Access Control**: Demonstrates role switching (Admin, Manager, Operator, Reader) and how it affects UI elements.
|
|
134
135
|
- **Route Guards**: Uses `authz.requirePermission` to protect routes and handle unauthorized access.
|
|
135
136
|
- **Scope Verification**: Demonstrates `rowScope` (row filters) and `columnScope` (masked values) dynamically applied based on the active role's permissions.
|
|
136
|
-
- **In-Browser Database Reset**: Includes a
|
|
137
|
+
- **In-Browser Database Reset**: Includes a **"Reset Demo Data"** button in the header of key views (Dashboard, Protected Documents, and Sales pages) to wipe customized roles, assignments, permissions, and CRUD data from `localStorage`, instantly restoring default test states.
|
|
137
138
|
|
|
138
139
|
### Running the Demo
|
|
139
140
|
|
package/dist/index.d.mts
CHANGED
|
@@ -449,6 +449,77 @@ declare function ErrorAlert({ message }: {
|
|
|
449
449
|
message?: string;
|
|
450
450
|
}): react.JSX.Element | null;
|
|
451
451
|
|
|
452
|
+
type MyPermissionGroupItem = {
|
|
453
|
+
/** Expected or actual resource key */
|
|
454
|
+
resourceKey?: string;
|
|
455
|
+
/** Human-readable resource display name (e.g. "NI", "KT", "オリジナル") */
|
|
456
|
+
resourceName: string;
|
|
457
|
+
/** Permission view data for this resource */
|
|
458
|
+
permission: PermissionView | null | undefined;
|
|
459
|
+
/** Expected resource key to detect mismatches with permission.resourceKey during development */
|
|
460
|
+
expectedResourceKey?: string;
|
|
461
|
+
/** Nesting level for hierarchical rendering (0: root, 1: child, etc.) */
|
|
462
|
+
level?: number;
|
|
463
|
+
/** Optional child items for hierarchical rendering */
|
|
464
|
+
children?: MyPermissionGroupItem[];
|
|
465
|
+
};
|
|
466
|
+
/**
|
|
467
|
+
* Flattens hierarchical items tree into a single array with computed nesting levels.
|
|
468
|
+
* 木構造またはフラット配列のアイテムに level 属性を付与してフラット化する処理。
|
|
469
|
+
*/
|
|
470
|
+
declare function flattenGroupItems(items: MyPermissionGroupItem[], currentLevel?: number): MyPermissionGroupItem[];
|
|
471
|
+
type MyPermissionGroupStatusProps = {
|
|
472
|
+
/** List of resources and their permissions */
|
|
473
|
+
items: MyPermissionGroupItem[];
|
|
474
|
+
/** Prefix label shown before group items or inside popover header. Default: "あなたの権限" */
|
|
475
|
+
prefixLabel?: string;
|
|
476
|
+
/**
|
|
477
|
+
* Display style variant:
|
|
478
|
+
* - "pills": Inline parent label + compact status tags per item
|
|
479
|
+
* - "popover": Compact single button trigger opening detailed popup card
|
|
480
|
+
* Default: "pills"
|
|
481
|
+
*/
|
|
482
|
+
variant?: "pills" | "popover";
|
|
483
|
+
/**
|
|
484
|
+
* Component size variant:
|
|
485
|
+
* - "2xs": Ultra micro size for extremely dense UI
|
|
486
|
+
* - "xs": Extra small size for compact headers
|
|
487
|
+
* - "sm": Small size
|
|
488
|
+
* - "md": Standard default size
|
|
489
|
+
* - "lg": Larger size
|
|
490
|
+
* Default: "md"
|
|
491
|
+
*/
|
|
492
|
+
size?: "2xs" | "xs" | "sm" | "md" | "lg";
|
|
493
|
+
labels?: {
|
|
494
|
+
read?: string;
|
|
495
|
+
write?: string;
|
|
496
|
+
delete?: string;
|
|
497
|
+
noPermission?: string;
|
|
498
|
+
fullWrite?: string;
|
|
499
|
+
partialWrite?: string;
|
|
500
|
+
readOnly?: string;
|
|
501
|
+
partialRead?: string;
|
|
502
|
+
};
|
|
503
|
+
className?: string;
|
|
504
|
+
style?: CSSProperties;
|
|
505
|
+
};
|
|
506
|
+
/**
|
|
507
|
+
* Get human-readable summary text and style for a resource permission.
|
|
508
|
+
* 権限状態から簡潔なサマリテキストとスタイルを判定 (カスタムラベル対応)。
|
|
509
|
+
*/
|
|
510
|
+
declare function getPermissionSummary(permission: PermissionView | null | undefined, customLabels?: MyPermissionGroupStatusProps["labels"]): {
|
|
511
|
+
text: string;
|
|
512
|
+
color: string;
|
|
513
|
+
bgColor: string;
|
|
514
|
+
borderColor: string;
|
|
515
|
+
};
|
|
516
|
+
/**
|
|
517
|
+
* Multi-resource "Your Permissions" status component.
|
|
518
|
+
* Supports inline compact pills (Proposal 1) and dropdown popover card (Proposal 2).
|
|
519
|
+
* 複数リソースの権限状態を共通レイアウト(pills/popover)で綺麗に整列・表示するコンポーネント。
|
|
520
|
+
*/
|
|
521
|
+
declare function MyPermissionGroupStatus({ items, prefixLabel, variant, size, labels, className, style }: MyPermissionGroupStatusProps): react.JSX.Element;
|
|
522
|
+
|
|
452
523
|
type MyPermissionIndicatorProps = {
|
|
453
524
|
permission: PermissionView | null | undefined;
|
|
454
525
|
/** Human-readable resource display name (e.g. "文書データ"). Falls back to permission.resourceKey. */
|
|
@@ -502,12 +573,22 @@ type ResourceDefinition = {
|
|
|
502
573
|
/** Optional description for administration UI */
|
|
503
574
|
description?: string;
|
|
504
575
|
};
|
|
576
|
+
type ResourceDefinitionInput = {
|
|
577
|
+
/** Optional explicit resource key; defaults to the object property name */
|
|
578
|
+
key?: string;
|
|
579
|
+
/** Human-readable display name (e.g. "文書管理") */
|
|
580
|
+
name: string;
|
|
581
|
+
/** Optional description for administration UI */
|
|
582
|
+
description?: string;
|
|
583
|
+
};
|
|
505
584
|
type ResourceRegistry<T extends Record<string, ResourceDefinition>> = T;
|
|
506
585
|
/**
|
|
507
586
|
* Define type-safe resource registry for an application.
|
|
508
587
|
* アプリ全体のリソース定義(キー・表示名・説明)を一元管理するヘルパー。
|
|
509
588
|
*/
|
|
510
|
-
declare function defineResources<T extends Record<string,
|
|
589
|
+
declare function defineResources<T extends Record<string, ResourceDefinitionInput>>(resources: T): {
|
|
590
|
+
[K in keyof T & string]: ResourceDefinition;
|
|
591
|
+
};
|
|
511
592
|
|
|
512
593
|
type PermState = "full" | "partial" | "none";
|
|
513
594
|
type UsePermission = {
|
|
@@ -526,4 +607,4 @@ type UsePermission = {
|
|
|
526
607
|
*/
|
|
527
608
|
declare function usePermission(view: PermissionView | null | undefined): UsePermission;
|
|
528
609
|
|
|
529
|
-
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, MyPermissionStatus, type MyPermissionStatusProps, type PartialAuthzAdminLabels, type PermState, type PermissionView, type RequirePermissionOptions, type ResourceDefinition, type ResourceRegistry, type UsePermission, createAuthz, createAuthzAdminApp, createAuthzAdminServer, defaultAuthzAdminLabels, defineResources, formatResourceTooltip, makeAuthzErrorBoundary, resolveLabels, toPermissionView, ui, usePermission };
|
|
610
|
+
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, type MyPermissionGroupItem, MyPermissionGroupStatus, type MyPermissionGroupStatusProps, MyPermissionIndicator, type MyPermissionIndicatorProps, MyPermissionStatus, type MyPermissionStatusProps, type PartialAuthzAdminLabels, type PermState, type PermissionView, type RequirePermissionOptions, type ResourceDefinition, type ResourceDefinitionInput, type ResourceRegistry, type UsePermission, createAuthz, createAuthzAdminApp, createAuthzAdminServer, defaultAuthzAdminLabels, defineResources, flattenGroupItems, formatResourceTooltip, getPermissionSummary, makeAuthzErrorBoundary, resolveLabels, toPermissionView, ui, usePermission };
|
package/dist/index.d.ts
CHANGED
|
@@ -449,6 +449,77 @@ declare function ErrorAlert({ message }: {
|
|
|
449
449
|
message?: string;
|
|
450
450
|
}): react.JSX.Element | null;
|
|
451
451
|
|
|
452
|
+
type MyPermissionGroupItem = {
|
|
453
|
+
/** Expected or actual resource key */
|
|
454
|
+
resourceKey?: string;
|
|
455
|
+
/** Human-readable resource display name (e.g. "NI", "KT", "オリジナル") */
|
|
456
|
+
resourceName: string;
|
|
457
|
+
/** Permission view data for this resource */
|
|
458
|
+
permission: PermissionView | null | undefined;
|
|
459
|
+
/** Expected resource key to detect mismatches with permission.resourceKey during development */
|
|
460
|
+
expectedResourceKey?: string;
|
|
461
|
+
/** Nesting level for hierarchical rendering (0: root, 1: child, etc.) */
|
|
462
|
+
level?: number;
|
|
463
|
+
/** Optional child items for hierarchical rendering */
|
|
464
|
+
children?: MyPermissionGroupItem[];
|
|
465
|
+
};
|
|
466
|
+
/**
|
|
467
|
+
* Flattens hierarchical items tree into a single array with computed nesting levels.
|
|
468
|
+
* 木構造またはフラット配列のアイテムに level 属性を付与してフラット化する処理。
|
|
469
|
+
*/
|
|
470
|
+
declare function flattenGroupItems(items: MyPermissionGroupItem[], currentLevel?: number): MyPermissionGroupItem[];
|
|
471
|
+
type MyPermissionGroupStatusProps = {
|
|
472
|
+
/** List of resources and their permissions */
|
|
473
|
+
items: MyPermissionGroupItem[];
|
|
474
|
+
/** Prefix label shown before group items or inside popover header. Default: "あなたの権限" */
|
|
475
|
+
prefixLabel?: string;
|
|
476
|
+
/**
|
|
477
|
+
* Display style variant:
|
|
478
|
+
* - "pills": Inline parent label + compact status tags per item
|
|
479
|
+
* - "popover": Compact single button trigger opening detailed popup card
|
|
480
|
+
* Default: "pills"
|
|
481
|
+
*/
|
|
482
|
+
variant?: "pills" | "popover";
|
|
483
|
+
/**
|
|
484
|
+
* Component size variant:
|
|
485
|
+
* - "2xs": Ultra micro size for extremely dense UI
|
|
486
|
+
* - "xs": Extra small size for compact headers
|
|
487
|
+
* - "sm": Small size
|
|
488
|
+
* - "md": Standard default size
|
|
489
|
+
* - "lg": Larger size
|
|
490
|
+
* Default: "md"
|
|
491
|
+
*/
|
|
492
|
+
size?: "2xs" | "xs" | "sm" | "md" | "lg";
|
|
493
|
+
labels?: {
|
|
494
|
+
read?: string;
|
|
495
|
+
write?: string;
|
|
496
|
+
delete?: string;
|
|
497
|
+
noPermission?: string;
|
|
498
|
+
fullWrite?: string;
|
|
499
|
+
partialWrite?: string;
|
|
500
|
+
readOnly?: string;
|
|
501
|
+
partialRead?: string;
|
|
502
|
+
};
|
|
503
|
+
className?: string;
|
|
504
|
+
style?: CSSProperties;
|
|
505
|
+
};
|
|
506
|
+
/**
|
|
507
|
+
* Get human-readable summary text and style for a resource permission.
|
|
508
|
+
* 権限状態から簡潔なサマリテキストとスタイルを判定 (カスタムラベル対応)。
|
|
509
|
+
*/
|
|
510
|
+
declare function getPermissionSummary(permission: PermissionView | null | undefined, customLabels?: MyPermissionGroupStatusProps["labels"]): {
|
|
511
|
+
text: string;
|
|
512
|
+
color: string;
|
|
513
|
+
bgColor: string;
|
|
514
|
+
borderColor: string;
|
|
515
|
+
};
|
|
516
|
+
/**
|
|
517
|
+
* Multi-resource "Your Permissions" status component.
|
|
518
|
+
* Supports inline compact pills (Proposal 1) and dropdown popover card (Proposal 2).
|
|
519
|
+
* 複数リソースの権限状態を共通レイアウト(pills/popover)で綺麗に整列・表示するコンポーネント。
|
|
520
|
+
*/
|
|
521
|
+
declare function MyPermissionGroupStatus({ items, prefixLabel, variant, size, labels, className, style }: MyPermissionGroupStatusProps): react.JSX.Element;
|
|
522
|
+
|
|
452
523
|
type MyPermissionIndicatorProps = {
|
|
453
524
|
permission: PermissionView | null | undefined;
|
|
454
525
|
/** Human-readable resource display name (e.g. "文書データ"). Falls back to permission.resourceKey. */
|
|
@@ -502,12 +573,22 @@ type ResourceDefinition = {
|
|
|
502
573
|
/** Optional description for administration UI */
|
|
503
574
|
description?: string;
|
|
504
575
|
};
|
|
576
|
+
type ResourceDefinitionInput = {
|
|
577
|
+
/** Optional explicit resource key; defaults to the object property name */
|
|
578
|
+
key?: string;
|
|
579
|
+
/** Human-readable display name (e.g. "文書管理") */
|
|
580
|
+
name: string;
|
|
581
|
+
/** Optional description for administration UI */
|
|
582
|
+
description?: string;
|
|
583
|
+
};
|
|
505
584
|
type ResourceRegistry<T extends Record<string, ResourceDefinition>> = T;
|
|
506
585
|
/**
|
|
507
586
|
* Define type-safe resource registry for an application.
|
|
508
587
|
* アプリ全体のリソース定義(キー・表示名・説明)を一元管理するヘルパー。
|
|
509
588
|
*/
|
|
510
|
-
declare function defineResources<T extends Record<string,
|
|
589
|
+
declare function defineResources<T extends Record<string, ResourceDefinitionInput>>(resources: T): {
|
|
590
|
+
[K in keyof T & string]: ResourceDefinition;
|
|
591
|
+
};
|
|
511
592
|
|
|
512
593
|
type PermState = "full" | "partial" | "none";
|
|
513
594
|
type UsePermission = {
|
|
@@ -526,4 +607,4 @@ type UsePermission = {
|
|
|
526
607
|
*/
|
|
527
608
|
declare function usePermission(view: PermissionView | null | undefined): UsePermission;
|
|
528
609
|
|
|
529
|
-
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, MyPermissionStatus, type MyPermissionStatusProps, type PartialAuthzAdminLabels, type PermState, type PermissionView, type RequirePermissionOptions, type ResourceDefinition, type ResourceRegistry, type UsePermission, createAuthz, createAuthzAdminApp, createAuthzAdminServer, defaultAuthzAdminLabels, defineResources, formatResourceTooltip, makeAuthzErrorBoundary, resolveLabels, toPermissionView, ui, usePermission };
|
|
610
|
+
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, type MyPermissionGroupItem, MyPermissionGroupStatus, type MyPermissionGroupStatusProps, MyPermissionIndicator, type MyPermissionIndicatorProps, MyPermissionStatus, type MyPermissionStatusProps, type PartialAuthzAdminLabels, type PermState, type PermissionView, type RequirePermissionOptions, type ResourceDefinition, type ResourceDefinitionInput, type ResourceRegistry, type UsePermission, createAuthz, createAuthzAdminApp, createAuthzAdminServer, defaultAuthzAdminLabels, defineResources, flattenGroupItems, formatResourceTooltip, getPermissionSummary, makeAuthzErrorBoundary, resolveLabels, toPermissionView, ui, usePermission };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";var E=Object.defineProperty;var X=Object.getOwnPropertyDescriptor;var ee=Object.getOwnPropertyNames;var te=Object.prototype.hasOwnProperty;var re=(t,r)=>{for(var s in r)E(t,s,{get:r[s],enumerable:!0})},ne=(t,r,s,l)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of ee(r))!te.call(t,o)&&o!==s&&E(t,o,{get:()=>r[o],enumerable:!(l=X(r,o))||l.enumerable});return t};var oe=t=>ne(E({},"__esModule",{value:!0}),t);var he={};re(he,{AuthzAdminAppView:()=>pe,AuthzErrorBoundary:()=>ue,AuthzGrantsView:()=>Q,AuthzLayout:()=>de,AuthzResourcesView:()=>J,AuthzRolesView:()=>M,AuthzUserRolesView:()=>Y,ErrorAlert:()=>I,Field:()=>R,MyPermissionIndicator:()=>H,MyPermissionStatus:()=>F,createAuthz:()=>ge,createAuthzAdminApp:()=>ie,createAuthzAdminServer:()=>T,defaultAuthzAdminLabels:()=>V,defineResources:()=>ye,formatResourceTooltip:()=>U,makeAuthzErrorBoundary:()=>O,resolveLabels:()=>L,toPermissionView:()=>j,ui:()=>n,usePermission:()=>$});module.exports=oe(he);var _=require("react-router");var P=require("@aiquants/authz-core"),S=require("react-router");var V={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 L(t){let r=V;return t?{title:t.title??r.title,myPermission:t.myPermission??r.myPermission,tabs:{...r.tabs,...t.tabs},common:{...r.common,...t.common},roles:{...r.roles,...t.roles},resources:{...r.resources,...t.resources},grants:{...r.grants,...t.grants},userRoles:{...r.userRoles,...t.userRoles},error:{...r.error,...t.error},warn:{...r.warn,...t.warn}}:r}var se=t=>t instanceof Response;function D(t){if(se(t))throw t;if(t instanceof P.AuthzDeniedError)throw new Response(t.message,{status:403});return(0,S.data)({error:t instanceof Error?t.message:"\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"},{status:400})}function T(t){let r=t.store,s=t.resourceKey??"authz_admin",l=L(t.labels),o=async(u,a)=>{let{userId:f}=await t.requirePermission(u,a);if(f==null)throw new P.AuthzDeniedError({appKey:"",resourceKey:a.resourceKey,action:a.action,reason:"unresolved-user",userId:null});return{userId:f}};async function c(u){await t.requireUser(u);try{return await o(u,{resourceKey:s,action:"read"})}catch(a){throw a instanceof P.AuthzDeniedError?new Response(`Forbidden: ${s}`,{status:403}):a}}let d=u=>t.getMyPermissions(u,{resourceKeys:[s]}),y=async u=>{let[a,f]=await Promise.all([r.listRoles(),r.getSelfAdminContext(Number(u))]);return{roles:a,selfAdminRoleIds:f.selfAdminRoleIds,labels:l}},h=async()=>({resources:await r.listResources(),labels:l}),g=async()=>{let[u,a,f]=await Promise.all([r.listGrants(),r.listRoles(),r.listResources()]);return{grants:u,roles:a,resources:f,labels:l}},A=async u=>{let[a,f,p,i]=await Promise.all([r.listUserRoles(),r.listRoles(),r.listUsers(),r.getSelfAdminContext(Number(u))]);return{assignments:a,roles:f,users:p,actorUserId:i.actorUserId,selfAdminRoleIds:i.selfAdminRoleIds,labels:l}};return{labels:l,resourceKey:s,layoutGuard:c,loadMyPermissions:d,layout:{async loader({request:u}){return await c(u),{myPermissions:await d(u),labels:l,adminResourceKey:s}}},index:{loader(){throw(0,S.redirect)("/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(),f=String(a.get("_action"));try{switch(f){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 r.createRole({roleKey:i,name:b,description:String(a.get("description")??"").trim()||null},String(p)),{ok:!0}):(0,S.data)({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 r.updateRole(Number(a.get("id")),{roleKey:i,name:b,description:String(a.get("description")??"").trim()||null},String(p)),{ok:!0}):(0,S.data)({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 r.setRoleActive(Number(a.get("id")),a.get("isActive")==="true",String(p)),{ok:!0}}case"delete":return await o(u,{resourceKey:s,action:"delete"}),await r.deleteRole(Number(a.get("id"))),{ok:!0};default:return(0,S.data)({error:"unknown action"},{status:400})}}catch(p){return D(p)}}},resources:{data:h,async loader({request:u}){return await o(u,{resourceKey:s,action:"read"}),h()},async action({request:u}){let a=await u.formData(),f=String(a.get("_action"));try{switch(f){case"create":{let{userId:p}=await o(u,{resourceKey:s,action:"create"}),i=String(a.get("appKey")??"").trim(),b=String(a.get("resourceKey")??"").trim(),v=String(a.get("name")??"").trim();return i&&b&&v?(await r.createResource({appKey:i,resourceKey:b,name:v,description:String(a.get("description")??"").trim()||null},String(p)),{ok:!0}):(0,S.data)({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 r.updateResource(Number(a.get("id")),{name:i,description:String(a.get("description")??"").trim()||null},String(p)),{ok:!0}):(0,S.data)({error:"name \u306F\u5FC5\u9808\u3067\u3059"},{status:400})}case"delete":return await o(u,{resourceKey:s,action:"delete"}),await r.deleteResource(Number(a.get("id"))),{ok:!0};default:return(0,S.data)({error:"unknown action"},{status:400})}}catch(p){return D(p)}}},grants:{data:g,async loader({request:u}){return await o(u,{resourceKey:s,action:"read"}),g()},async action({request:u}){let a=await u.formData(),f=String(a.get("_action"));try{switch(f){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(0,S.data)({error:"\u30ED\u30FC\u30EB\u3068\u30EA\u30BD\u30FC\u30B9\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044"},{status:400});let v=String(a.get("action")??"");if(!P.AUTHZ_ACTIONS.includes(v))return(0,S.data)({error:"\u7121\u52B9\u306A action \u3067\u3059"},{status:400});let N=v;return await r.createGrant({roleId:i,resourceId:b,action:N,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(!P.AUTHZ_ACTIONS.includes(i))return(0,S.data)({error:"\u7121\u52B9\u306A action \u3067\u3059"},{status:400});let b=i;return await r.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 r.deleteGrant(Number(a.get("id"))),{ok:!0};default:return(0,S.data)({error:"unknown action"},{status:400})}}catch(p){return D(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(),f=String(a.get("_action"));try{switch(f){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 r.assignUserRole(i,b,String(p)),{ok:!0}):(0,S.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 o(u,{resourceKey:s,action:"delete"}),await r.removeUserRole(Number(a.get("userId")),Number(a.get("roleId"))),{ok:!0};default:return(0,S.data)({error:"unknown action"},{status:400})}}catch(p){return D(p)}}}}}function G(t){return String(t["*"]??"").split("/")[0]}function ie(t){let r=T(t),s=t.basePath??"/authz",l=["roles","resources","role_permissions","user_roles"],o={roles:r.roles.data,resources:r.resources.data,role_permissions:r.grants.data,user_roles:r.userRoles.data},c={roles:r.roles.action,resources:r.resources.action,role_permissions:r.grants.action,user_roles:r.userRoles.action};async function d(h){let g=G(h.params);if(!l.includes(g))throw(0,_.redirect)(`${s}/roles`);let{userId:A}=await r.layoutGuard(h.request),[u,a]=await Promise.all([r.loadMyPermissions(h.request),o[g](A)]);return{segment:g,basePath:s,myPermissions:u,adminResourceKey:r.resourceKey,...a}}async function y(h){let g=G(h.params),A=c[g];return A?A(h):(0,_.data)({error:"unknown action"},{status:400})}return{loader:d,action:y,server:r}}var k=require("react/jsx-runtime"),n={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 R({label:t,hint:r,children:s}){return(0,k.jsxs)("div",{style:{display:"flex",flexDirection:"column",gap:"0.3rem"},children:[(0,k.jsxs)("span",{style:{fontSize:"0.8rem",color:"#475569",fontWeight:600},children:[t,r?(0,k.jsxs)("span",{style:{fontWeight:400,color:"#94a3b8"},children:[" \u2014 ",r]}):null]}),s]})}function I({message:t}){return t?(0,k.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:t}):null}var W=require("@aiquants/authz-core"),z=require("@aiquants/select-box"),x=require("react"),m=require("react-router");function $(t){let r=t?.read?t.readPartial?"partial":"full":"none",s=t?.create&&t?.update?"full":t?.create||t?.update?"partial":"none",l=t?.delete?"full":"none";return{canRead:!!t?.read,canWrite:!!t?.write,canDelete:!!t?.delete,readState:r,writeState:s,deleteState:l}}var w=require("react/jsx-runtime"),ae={full:{bg:"#ecfdf5",text:"#047857",border:"#a7f3d0"},partial:{bg:"#fffbeb",text:"#b45309",border:"#fde68a"},none:{bg:"#f8fafc",text:"#94a3b8",border:"#cbd5e1"}};function U(t,r){let s=t?.trim(),l=r?.trim();if(l&&s&&l!==s)return`\u5BFE\u8C61\u30EA\u30BD\u30FC\u30B9: ${l} (${s})`;if(l||s)return`\u5BFE\u8C61\u30EA\u30BD\u30FC\u30B9: ${l||s}`}function le({state:t}){return t==="full"?(0,w.jsx)("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:(0,w.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5 13l4 4L19 7"})}):t==="partial"?(0,w.jsx)("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:(0,w.jsx)("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"})}):(0,w.jsx)("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:(0,w.jsx)("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 H({permission:t,resourceName:r,expectedResourceKey:s,showResourceTooltip:l=!0,labels:o,showScopeSummary:c=!0,className:d="authz-permission-indicator"}){let y=$(t),h={read:o?.read??"\u95B2\u89A7",write:o?.write??"\u7DE8\u96C6",delete:o?.delete??"\u524A\u9664"},g=t?.resourceKey,A=r||g,u=l?U(g,r):void 0,a=!!(s&&g&&g!==s);a&&typeof console<"u"&&typeof console.error=="function"&&console.error(`[Authz Warning] Resource key mismatch in MyPermissionIndicator! Expected: "${s}", but received permission for: "${g}".`);let f=(p,i,b)=>{let v=ae[i],N=u?`${b}: ${i}
|
|
2
|
-
${u}`:`${b}: ${i}`;return(0,w.jsxs)("span",{"data-perm":p,"data-state":i,title:N,style:{display:"inline-flex",alignItems:"center",gap:"0.25rem",padding:"0.2rem 0.5rem",borderRadius:"100px",fontSize:"0.75rem",fontWeight:600,backgroundColor:v.bg,color:v.text,border:`1px solid ${v.border}`,lineHeight:1,userSelect:"none"},children:[(0,w.jsx)(le,{state:i}),(0,w.jsx)("span",{children:b})]})};return(0,w.jsxs)("span",{className:d,title:u,"data-resource":g??"","data-resource-name":A??"","data-mismatch":a?"true":void 0,style:{display:"inline-flex",gap:"0.35rem",alignItems:"center",verticalAlign:"middle"},children:[f("read",y.readState,h.read),f("write",y.writeState,h.write),f("delete",y.deleteState,h.delete),c&&y.readState==="partial"?(0,w.jsx)("span",{"data-perm":"scope",title:u,style:{fontSize:"0.7rem",color:"#b45309",backgroundColor:"#fef3c7",padding:"0.15rem 0.35rem",borderRadius:"4px",fontWeight:600},children:"\u90E8\u5206\u5236\u9650"}):null,a?(0,w.jsxs)("span",{"data-testid":"resource-mismatch-warning",title:`expected: "${s}", actual: "${g}"`,style:{fontSize:"0.7rem",color:"#991b1b",backgroundColor:"#fee2e2",border:"1px solid #fca5a5",padding:"0.15rem 0.35rem",borderRadius:"4px",fontWeight:700},children:["\u26A0\uFE0F \u30EA\u30BD\u30FC\u30B9\u4E0D\u4E00\u81F4 (",g," \u2260 ",s,")"]}):null]})}function F({permission:t,resourceName:r,expectedResourceKey:s,prefixLabel:l="\u3042\u306A\u305F\u306E\u6A29\u9650",showPrefixLabel:o=!0,showResourceTooltip:c=!0,labels:d,showScopeSummary:y=!0,className:h="authz-permission-status",style:g}){let A=t?.resourceKey,u=r||A,a=c?U(A,r):void 0;return(0,w.jsxs)("span",{className:h,title:a,"data-testid":"my-permission-status","data-resource":A??"","data-resource-name":u??"",style:{fontSize:"0.82rem",color:"#475569",display:"inline-flex",alignItems:"center",gap:"0.4rem",...g},children:[o&&(0,w.jsxs)("span",{"data-testid":"prefix-label",children:[l,":"]}),(0,w.jsx)(H,{permission:t,resourceName:r,expectedResourceKey:s,showResourceTooltip:c,labels:d,showScopeSummary:y})]})}var e=require("react/jsx-runtime"),C=t=>t?.error;function B({children:t}){let{myPermissions:r,labels:s,adminResourceKey:l,basePath:o}=(0,m.useLoaderData)(),c=o??"/authz",d=[["roles",s.tabs.roles],["resources",s.tabs.resources],["role_permissions",s.tabs.role_permissions],["user_roles",s.tabs.user_roles]];return(0,e.jsxs)("div",{className:"authz-admin",style:n.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:s.title}),(0,e.jsx)(F,{prefixLabel:s.myPermission,permission:r[l],resourceName:l})]}),(0,e.jsx)("nav",{style:{display:"flex",gap:"0.25rem",borderBottom:"1px solid #e2e8f0",margin:"0.9rem 0 1.25rem"},children:d.map(([y,h])=>(0,e.jsx)(m.NavLink,{to:`${c}/${y}`,style:({isActive:g})=>({padding:"0.5rem 0.9rem",textDecoration:"none",color:g?"#2563eb":"#475569",borderBottom:g?"2px solid #2563eb":"2px solid transparent",marginBottom:-1,fontWeight:g?700:500,fontSize:"0.92rem"}),children:h},y))}),t]})}function de(){return(0,e.jsx)(B,{children:(0,e.jsx)(m.Outlet,{})})}function O(t){let r=L(t).error;return function(){let l=(0,m.useRouteError)(),o=(0,m.isRouteErrorResponse)(l)?l:null,c=o?.status===403,d=c?r.forbiddenTitle:o?`${r.genericTitlePrefix} (${o.status})`:r.genericTitle,y=c?r.forbiddenBody:o?typeof o.data=="string"&&o.data?o.data:o.statusText:r.genericBody;return(0,e.jsx)("div",{style:n.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:d}),(0,e.jsx)("p",{style:{color:"#7f1d1d",fontSize:"0.9rem",margin:0,lineHeight:1.7},children:y})]})})}}var ue=O(),q=(t,r)=>s=>{t&&!window.confirm(r)&&s.preventDefault()};function M(){let{roles:t,selfAdminRoleIds:r,labels:s}=(0,m.useLoaderData)(),l=s.roles,o=s.common,c=new Set(r??[]);return(0,e.jsxs)("section",{children:[(0,e.jsx)("h2",{style:n.h2,children:l.heading}),(0,e.jsx)(I,{message:C((0,m.useActionData)())}),(0,e.jsx)("p",{style:n.note,children:l.note}),(0,e.jsx)("div",{style:n.tableContainer,children:(0,e.jsxs)("table",{style:n.table,children:[(0,e.jsx)("thead",{children:(0,e.jsxs)("tr",{children:[(0,e.jsx)("th",{style:{...n.th,width:"20%"},children:l.roleKey}),(0,e.jsx)("th",{style:{...n.th,width:"25%"},children:l.name}),(0,e.jsx)("th",{style:{...n.th,width:"35%"},children:l.description}),(0,e.jsx)("th",{style:{...n.th,width:"10%"},children:l.activeHeader}),(0,e.jsx)("th",{style:{...n.th,width:"10%"}})]})}),(0,e.jsxs)("tbody",{children:[t.map(d=>(0,e.jsxs)("tr",{children:[(0,e.jsx)("td",{style:n.td,children:d.roleKey==="@authenticated"||d.roleKey==="@anonymous"?(0,e.jsx)("span",{style:n.code,children:d.roleKey}):(0,e.jsx)("input",{name:"roleKey",defaultValue:d.roleKey,form:`save-role-${d.id}`,"aria-label":`roleKey-${d.id}`,required:!0,style:n.input})}),(0,e.jsx)("td",{style:n.td,children:(0,e.jsx)("input",{name:"name",defaultValue:d.name,form:`save-role-${d.id}`,"aria-label":`name-${d.id}`,required:!0,style:n.input})}),(0,e.jsx)("td",{style:n.td,children:(0,e.jsx)("input",{name:"description",defaultValue:d.description??"",form:`save-role-${d.id}`,"aria-label":`description-${d.id}`,style:n.input})}),(0,e.jsx)("td",{style:n.td,children:(0,e.jsxs)(m.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:d.id}),(0,e.jsx)("input",{type:"hidden",name:"isActive",value:String(!d.isActive)}),(0,e.jsx)("button",{type:"submit",style:n.button,onClick:d.isActive?q(c.has(d.id),s.warn.selfRoleDisable):void 0,children:d.isActive?o.active:o.inactive})]})}),(0,e.jsxs)("td",{style:{...n.td,whiteSpace:"nowrap"},children:[(0,e.jsxs)(m.Form,{method:"post",id:`save-role-${d.id}`,style:{display:"inline"},children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"save"}),(0,e.jsx)("input",{type:"hidden",name:"id",value:d.id}),(0,e.jsx)("button",{type:"submit",style:n.save,children:o.save})]}),(0,e.jsxs)(m.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:d.id}),(0,e.jsx)("button",{type:"submit",style:n.danger,onClick:q(c.has(d.id),s.warn.selfRoleDelete),children:o.delete})]})]})]},d.id)),t.length===0?(0,e.jsx)("tr",{children:(0,e.jsx)("td",{style:n.empty,colSpan:5,children:l.empty})}):null]})]})}),(0,e.jsx)("h3",{style:n.h3,children:l.newHeading}),(0,e.jsxs)(m.Form,{method:"post",style:n.card,children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"create"}),(0,e.jsx)(R,{label:l.roleKey,hint:l.hintRoleKey,children:(0,e.jsx)("input",{name:"roleKey","aria-label":"role_key",required:!0,style:n.input})}),(0,e.jsx)(R,{label:l.name,children:(0,e.jsx)("input",{name:"name","aria-label":"name",required:!0,style:n.input})}),(0,e.jsx)(R,{label:l.description,hint:o.optional,children:(0,e.jsx)("input",{name:"description","aria-label":"description",style:n.input})}),(0,e.jsx)("button",{type:"submit",style:n.primary,children:o.add})]})]})}function J(){let{resources:t,labels:r}=(0,m.useLoaderData)(),s=r.resources,l=r.common;return(0,e.jsxs)("section",{children:[(0,e.jsx)("h2",{style:n.h2,children:s.heading}),(0,e.jsx)(I,{message:C((0,m.useActionData)())}),(0,e.jsx)("p",{style:n.note,children:s.note}),(0,e.jsx)("div",{style:n.tableContainer,children:(0,e.jsxs)("table",{style:n.table,children:[(0,e.jsx)("thead",{children:(0,e.jsxs)("tr",{children:[(0,e.jsx)("th",{style:{...n.th,width:"15%"},children:s.appKey}),(0,e.jsx)("th",{style:{...n.th,width:"20%"},children:s.resourceKey}),(0,e.jsx)("th",{style:{...n.th,width:"25%"},children:s.name}),(0,e.jsx)("th",{style:{...n.th,width:"30%"},children:s.description}),(0,e.jsx)("th",{style:{...n.th,width:"10%"}})]})}),(0,e.jsxs)("tbody",{children:[t.map(o=>(0,e.jsxs)("tr",{children:[(0,e.jsx)("td",{style:n.td,children:(0,e.jsx)("span",{style:n.code,children:o.appKey})}),(0,e.jsx)("td",{style:n.td,children:(0,e.jsx)("span",{style:n.code,children:o.resourceKey})}),(0,e.jsx)("td",{style:n.td,children:(0,e.jsx)("input",{name:"name",defaultValue:o.name,form:`save-res-${o.id}`,"aria-label":`name-${o.id}`,required:!0,style:n.input})}),(0,e.jsx)("td",{style:n.td,children:(0,e.jsx)("input",{name:"description",defaultValue:o.description??"",form:`save-res-${o.id}`,"aria-label":`description-${o.id}`,style:n.input})}),(0,e.jsxs)("td",{style:{...n.td,whiteSpace:"nowrap"},children:[(0,e.jsxs)(m.Form,{method:"post",id:`save-res-${o.id}`,style:{display:"inline"},children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"save"}),(0,e.jsx)("input",{type:"hidden",name:"id",value:o.id}),(0,e.jsx)("button",{type:"submit",style:n.save,children:l.save})]}),(0,e.jsxs)(m.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:o.id}),(0,e.jsx)("button",{type:"submit",style:n.danger,children:l.delete})]})]})]},o.id)),t.length===0?(0,e.jsx)("tr",{children:(0,e.jsx)("td",{style:n.empty,colSpan:5,children:s.empty})}):null]})]})}),(0,e.jsx)("h3",{style:n.h3,children:s.newHeading}),(0,e.jsxs)(m.Form,{method:"post",style:n.card,children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"create"}),(0,e.jsx)(R,{label:s.appKey,hint:s.hintAppKey,children:(0,e.jsx)("input",{name:"appKey","aria-label":"app_key",required:!0,style:n.input})}),(0,e.jsx)(R,{label:s.resourceKey,hint:s.hintResourceKey,children:(0,e.jsx)("input",{name:"resourceKey","aria-label":"resource_key",required:!0,style:n.input})}),(0,e.jsx)(R,{label:s.name,children:(0,e.jsx)("input",{name:"name","aria-label":"name",required:!0,style:n.input})}),(0,e.jsx)(R,{label:s.description,hint:l.optional,children:(0,e.jsx)("input",{name:"description","aria-label":"description",style:n.input})}),(0,e.jsx)("button",{type:"submit",style:n.primary,children:l.add})]})]})}function ce({g:t,labels:r}){let s=r.common,[l,o]=(0,x.useState)({label:t.action,value:t.action});return(0,e.jsxs)("tr",{children:[(0,e.jsx)("td",{style:n.td,children:(0,e.jsx)("span",{style:n.code,children:t.roleKey})}),(0,e.jsx)("td",{style:n.td,children:(0,e.jsxs)("span",{style:n.code,children:[t.appKey,":",t.resourceKey]})}),(0,e.jsx)("td",{style:n.td,children:t.roleKey==="@anonymous"?(0,e.jsx)("span",{style:n.code,children:t.action}):(0,e.jsxs)(e.Fragment,{children:[(0,e.jsx)("input",{type:"hidden",name:"action",value:l.value,form:`save-grant-${t.id}`}),(0,e.jsx)(z.SelectBox,{options:W.AUTHZ_ACTIONS.map(c=>({label:c,value:c})),value:l,onChange:c=>{c&&o(c)}})]})}),(0,e.jsx)("td",{style:n.td,children:(0,e.jsx)("textarea",{name:"rowScope",defaultValue:t.rowScope??"",form:`save-grant-${t.id}`,"aria-label":`row_scope-${t.id}`,rows:2,placeholder:r.grants.rowScopePlaceholder,style:n.textarea})}),(0,e.jsx)("td",{style:n.td,children:(0,e.jsx)("textarea",{name:"columnScope",defaultValue:t.columnScope??"",form:`save-grant-${t.id}`,"aria-label":`column_scope-${t.id}`,rows:2,placeholder:r.grants.columnScopePlaceholder,style:n.textarea})}),(0,e.jsxs)("td",{style:{...n.td,whiteSpace:"nowrap"},children:[(0,e.jsxs)(m.Form,{method:"post",id:`save-grant-${t.id}`,style:{display:"inline"},children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"save"}),(0,e.jsx)("input",{type:"hidden",name:"id",value:t.id}),(0,e.jsx)("button",{type:"submit",style:n.save,children:s.save})]}),(0,e.jsxs)(m.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:t.id}),(0,e.jsx)("button",{type:"submit",style:n.danger,children:s.delete})]})]})]})}function Q(){let{grants:t,roles:r,resources:s,labels:l}=(0,m.useLoaderData)(),o=l.grants,c=l.common,d=r.map(i=>({label:i.roleKey,value:i.id})),y=s.map(i=>({label:`${i.appKey}:${i.resourceKey}`,value:i.id})),h=W.AUTHZ_ACTIONS.map(i=>({label:i,value:i})),[g,A]=(0,x.useState)(void 0),[u,a]=(0,x.useState)(void 0),[f,p]=(0,x.useState)({label:"read",value:"read"});return(0,e.jsxs)("section",{children:[(0,e.jsx)("h2",{style:n.h2,children:o.heading}),(0,e.jsx)("p",{style:n.note,children:o.note}),(0,e.jsx)(I,{message:C((0,m.useActionData)())}),(0,e.jsx)("div",{style:n.tableContainer,children:(0,e.jsxs)("table",{style:n.table,children:[(0,e.jsx)("thead",{children:(0,e.jsxs)("tr",{children:[(0,e.jsx)("th",{style:{...n.th,width:"15%"},children:o.role}),(0,e.jsx)("th",{style:{...n.th,width:"20%"},children:o.resource}),(0,e.jsx)("th",{style:{...n.th,width:"15%"},children:o.action}),(0,e.jsx)("th",{style:{...n.th,width:"20%"},children:o.rowScope}),(0,e.jsx)("th",{style:{...n.th,width:"20%"},children:o.columnScope}),(0,e.jsx)("th",{style:{...n.th,width:"10%"}})]})}),(0,e.jsxs)("tbody",{children:[t.map(i=>(0,e.jsx)(ce,{g:i,labels:l},i.id)),t.length===0?(0,e.jsx)("tr",{children:(0,e.jsx)("td",{style:n.empty,colSpan:6,children:o.empty})}):null]})]})}),(0,e.jsx)("h3",{style:n.h3,children:o.newHeading}),(0,e.jsxs)(m.Form,{method:"post",style:n.card,children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"create"}),(0,e.jsx)("input",{type:"hidden",name:"roleId",value:g?.value??""}),(0,e.jsx)("input",{type:"hidden",name:"resourceId",value:u?.value??""}),(0,e.jsx)("input",{type:"hidden",name:"action",value:f?.value??""}),(0,e.jsx)(R,{label:o.role,children:(0,e.jsx)(z.SelectBox,{options:d,value:g,onChange:i=>A(i||void 0),placeholder:o.selectPlaceholder})}),(0,e.jsx)(R,{label:o.resource,children:(0,e.jsx)(z.SelectBox,{options:y,value:u,onChange:i=>a(i||void 0),placeholder:o.selectPlaceholder})}),(0,e.jsx)(R,{label:o.action,children:(0,e.jsx)(z.SelectBox,{options:h,value:f,onChange:i=>p(i||void 0)})}),(0,e.jsx)(R,{label:o.rowScope,hint:o.rowScopeHint,children:(0,e.jsx)("textarea",{name:"rowScope","aria-label":"row_scope",rows:2,style:n.textarea,placeholder:'{"filters":[{"field":"\u90E8\u9580CD","op":"in","values":["A"]}]}'})}),(0,e.jsx)(R,{label:o.columnScope,hint:o.columnScopeHint,children:(0,e.jsx)("textarea",{name:"columnScope","aria-label":"column_scope",rows:2,style:n.textarea,placeholder:'{"mode":"deny","columns":["\u91D1\u984D"]}'})}),(0,e.jsx)("button",{type:"submit",style:n.primary,children:c.grant})]})]})}function Y(){let{assignments:t,roles:r,users:s,actorUserId:l,selfAdminRoleIds:o,labels:c}=(0,m.useLoaderData)(),d=c.userRoles,y=c.common,h=new Set(o??[]),g=s.map(i=>({label:`${i.email}\uFF08${i.displayName}\uFF09`,value:i.id})),A=r.filter(i=>i.roleKey!=="@authenticated"&&i.roleKey!=="@anonymous").map(i=>({label:i.roleKey,value:i.id})),[u,a]=(0,x.useState)(void 0),[f,p]=(0,x.useState)(void 0);return(0,e.jsxs)("section",{children:[(0,e.jsx)("h2",{style:n.h2,children:d.heading}),(0,e.jsx)(I,{message:C((0,m.useActionData)())}),(0,e.jsx)("p",{style:n.note,children:d.note}),(0,e.jsx)("div",{style:n.tableContainer,children:(0,e.jsxs)("table",{style:n.table,children:[(0,e.jsx)("thead",{children:(0,e.jsxs)("tr",{children:[(0,e.jsx)("th",{style:{...n.th,width:"45%"},children:d.user}),(0,e.jsx)("th",{style:{...n.th,width:"45%"},children:d.role}),(0,e.jsx)("th",{style:{...n.th,width:"10%"}})]})}),(0,e.jsxs)("tbody",{children:[t.map(i=>(0,e.jsxs)("tr",{children:[(0,e.jsxs)("td",{style:n.td,children:[i.email,(0,e.jsxs)("span",{style:n.muted,children:["\uFF08",i.displayName,"\uFF09"]})]}),(0,e.jsx)("td",{style:n.td,children:i.roleKey}),(0,e.jsx)("td",{style:n.td,children:(0,e.jsxs)(m.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:i.userId}),(0,e.jsx)("input",{type:"hidden",name:"roleId",value:i.roleId}),(0,e.jsx)("button",{type:"submit",style:n.danger,onClick:q(i.userId===l&&h.has(i.roleId),c.warn.selfAssignmentRemove),children:y.remove})]})})]},`${i.userId}-${i.roleId}`)),t.length===0?(0,e.jsx)("tr",{children:(0,e.jsx)("td",{style:n.empty,colSpan:3,children:d.empty})}):null]})]})}),(0,e.jsx)("h3",{style:n.h3,children:d.newHeading}),(0,e.jsxs)(m.Form,{method:"post",style:n.card,children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"assign"}),(0,e.jsx)("input",{type:"hidden",name:"userId",value:u?.value??""}),(0,e.jsx)("input",{type:"hidden",name:"roleId",value:f?.value??""}),(0,e.jsx)(R,{label:d.user,children:(0,e.jsx)(z.SelectBox,{options:g,value:u,onChange:i=>a(i||void 0),placeholder:d.selectPlaceholder})}),(0,e.jsx)(R,{label:d.role,children:(0,e.jsx)(z.SelectBox,{options:A,value:f,onChange:i=>p(i||void 0),placeholder:d.selectPlaceholder})}),(0,e.jsx)("button",{type:"submit",style:n.primary,children:y.assign})]})]})}var me={roles:M,resources:J,role_permissions:Q,user_roles:Y};function pe(){let{segment:t}=(0,m.useLoaderData)(),r=me[t]??M;return(0,e.jsx)(B,{children:(0,e.jsx)(r,{})})}function ye(t){return t}var K=require("@aiquants/authz-core"),Z=require("react-router");function j(t,r){let s=(0,K.can)(r,"read"),l=(0,K.can)(r,"create"),o=(0,K.can)(r,"update"),c=(0,K.can)(r,"delete"),d=r?.scopeByAction.read,y=s&&!!d&&(d.rowScope!==null||d.columnScope!==null);return{resourceKey:t,read:s,create:l,update:o,delete:c,write:l||o,readPartial:y,actions:r?Array.from(r.actions):[]}}function ge(t){async function r(o,c,d){let y=d?.failureRedirect?()=>{throw(0,Z.redirect)(d.failureRedirect)}:t.onDeny;return(0,K.createRequirePermission)({resolveUserId:t.resolveUserId,getEffectivePermissions:t.getEffectivePermissions,onDeny:y})(o,{appKey:t.appKey,resourceKey:c.resourceKey,action:c.action})}async function s(o,c){let d=await t.resolveUserId(o),y={};for(let h of c.resourceKeys){let g=await t.getEffectivePermissions({userId:d??null,appKey:t.appKey,resourceKey:h});y[h]=j(h,g)}return y}async function l(o,c,d){let y=await r(o,c,d),h=await s(o,{resourceKeys:[c.resourceKey]});return{...y,permission:h[c.resourceKey]}}return{requirePermission:r,getMyPermissions:s,requireAndGetPermission:l}}0&&(module.exports={AuthzAdminAppView,AuthzErrorBoundary,AuthzGrantsView,AuthzLayout,AuthzResourcesView,AuthzRolesView,AuthzUserRolesView,ErrorAlert,Field,MyPermissionIndicator,MyPermissionStatus,createAuthz,createAuthzAdminApp,createAuthzAdminServer,defaultAuthzAdminLabels,defineResources,formatResourceTooltip,makeAuthzErrorBoundary,resolveLabels,toPermissionView,ui,usePermission});
|
|
1
|
+
"use strict";var F=Object.defineProperty;var oe=Object.getOwnPropertyDescriptor;var se=Object.getOwnPropertyNames;var ie=Object.prototype.hasOwnProperty;var ae=(t,r)=>{for(var n in r)F(t,n,{get:r[n],enumerable:!0})},le=(t,r,n,i)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of se(r))!ie.call(t,o)&&o!==n&&F(t,o,{get:()=>r[o],enumerable:!(i=oe(r,o))||i.enumerable});return t};var de=t=>le(F({},"__esModule",{value:!0}),t);var xe={};ae(xe,{AuthzAdminAppView:()=>Se,AuthzErrorBoundary:()=>he,AuthzGrantsView:()=>ee,AuthzLayout:()=>fe,AuthzResourcesView:()=>X,AuthzRolesView:()=>B,AuthzUserRolesView:()=>te,ErrorAlert:()=>C,Field:()=>x,MyPermissionGroupStatus:()=>q,MyPermissionIndicator:()=>_,MyPermissionStatus:()=>ye,createAuthz:()=>Re,createAuthzAdminApp:()=>ce,createAuthzAdminServer:()=>T,defaultAuthzAdminLabels:()=>H,defineResources:()=>Ae,flattenGroupItems:()=>U,formatResourceTooltip:()=>W,getPermissionSummary:()=>Q,makeAuthzErrorBoundary:()=>Z,resolveLabels:()=>D,toPermissionView:()=>ne,ui:()=>s,usePermission:()=>M});module.exports=de(xe);var G=require("react-router");var z=require("@aiquants/authz-core"),R=require("react-router");var H={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 D(t){let r=H;return t?{title:t.title??r.title,myPermission:t.myPermission??r.myPermission,tabs:{...r.tabs,...t.tabs},common:{...r.common,...t.common},roles:{...r.roles,...t.roles},resources:{...r.resources,...t.resources},grants:{...r.grants,...t.grants},userRoles:{...r.userRoles,...t.userRoles},error:{...r.error,...t.error},warn:{...r.warn,...t.warn}}:r}var ue=t=>t instanceof Response;function N(t){if(ue(t))throw t;if(t instanceof z.AuthzDeniedError)throw new Response(t.message,{status:403});return(0,R.data)({error:t instanceof Error?t.message:"\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F"},{status:400})}function T(t){let r=t.store,n=t.resourceKey??"authz_admin",i=D(t.labels),o=async(u,a)=>{let{userId:y}=await t.requirePermission(u,a);if(y==null)throw new z.AuthzDeniedError({appKey:"",resourceKey:a.resourceKey,action:a.action,reason:"unresolved-user",userId:null});return{userId:y}};async function c(u){await t.requireUser(u);try{return await o(u,{resourceKey:n,action:"read"})}catch(a){throw a instanceof z.AuthzDeniedError?new Response(`Forbidden: ${n}`,{status:403}):a}}let l=u=>t.getMyPermissions(u,{resourceKeys:[n]}),p=async u=>{let[a,y]=await Promise.all([r.listRoles(),r.getSelfAdminContext(Number(u))]);return{roles:a,selfAdminRoleIds:y.selfAdminRoleIds,labels:i}},g=async()=>({resources:await r.listResources(),labels:i}),f=async()=>{let[u,a,y]=await Promise.all([r.listGrants(),r.listRoles(),r.listResources()]);return{grants:u,roles:a,resources:y,labels:i}},b=async u=>{let[a,y,m,d]=await Promise.all([r.listUserRoles(),r.listRoles(),r.listUsers(),r.getSelfAdminContext(Number(u))]);return{assignments:a,roles:y,users:m,actorUserId:d.actorUserId,selfAdminRoleIds:d.selfAdminRoleIds,labels:i}};return{labels:i,resourceKey:n,layoutGuard:c,loadMyPermissions:l,layout:{async loader({request:u}){return await c(u),{myPermissions:await l(u),labels:i,adminResourceKey:n}}},index:{loader(){throw(0,R.redirect)("/authz/roles")}},roles:{data:p,async loader({request:u}){let{userId:a}=await o(u,{resourceKey:n,action:"read"});return p(a)},async action({request:u}){let a=await u.formData(),y=String(a.get("_action"));try{switch(y){case"create":{let{userId:m}=await o(u,{resourceKey:n,action:"create"}),d=String(a.get("roleKey")??"").trim(),w=String(a.get("name")??"").trim();return d&&w?(await r.createRole({roleKey:d,name:w,description:String(a.get("description")??"").trim()||null},String(m)),{ok:!0}):(0,R.data)({error:"role_key \u3068 name \u306F\u5FC5\u9808\u3067\u3059"},{status:400})}case"save":{let{userId:m}=await o(u,{resourceKey:n,action:"update"}),d=String(a.get("roleKey")??"").trim(),w=String(a.get("name")??"").trim();return d&&w?(await r.updateRole(Number(a.get("id")),{roleKey:d,name:w,description:String(a.get("description")??"").trim()||null},String(m)),{ok:!0}):(0,R.data)({error:"roleKey \u3068 name \u306F\u5FC5\u9808\u3067\u3059"},{status:400})}case"toggle":{let{userId:m}=await o(u,{resourceKey:n,action:"update"});return await r.setRoleActive(Number(a.get("id")),a.get("isActive")==="true",String(m)),{ok:!0}}case"delete":return await o(u,{resourceKey:n,action:"delete"}),await r.deleteRole(Number(a.get("id"))),{ok:!0};default:return(0,R.data)({error:"unknown action"},{status:400})}}catch(m){return N(m)}}},resources:{data:g,async loader({request:u}){return await o(u,{resourceKey:n,action:"read"}),g()},async action({request:u}){let a=await u.formData(),y=String(a.get("_action"));try{switch(y){case"create":{let{userId:m}=await o(u,{resourceKey:n,action:"create"}),d=String(a.get("appKey")??"").trim(),w=String(a.get("resourceKey")??"").trim(),v=String(a.get("name")??"").trim();return d&&w&&v?(await r.createResource({appKey:d,resourceKey:w,name:v,description:String(a.get("description")??"").trim()||null},String(m)),{ok:!0}):(0,R.data)({error:"app_key / resource_key / name \u306F\u5FC5\u9808\u3067\u3059"},{status:400})}case"save":{let{userId:m}=await o(u,{resourceKey:n,action:"update"}),d=String(a.get("name")??"").trim();return d?(await r.updateResource(Number(a.get("id")),{name:d,description:String(a.get("description")??"").trim()||null},String(m)),{ok:!0}):(0,R.data)({error:"name \u306F\u5FC5\u9808\u3067\u3059"},{status:400})}case"delete":return await o(u,{resourceKey:n,action:"delete"}),await r.deleteResource(Number(a.get("id"))),{ok:!0};default:return(0,R.data)({error:"unknown action"},{status:400})}}catch(m){return N(m)}}},grants:{data:f,async loader({request:u}){return await o(u,{resourceKey:n,action:"read"}),f()},async action({request:u}){let a=await u.formData(),y=String(a.get("_action"));try{switch(y){case"create":{let{userId:m}=await o(u,{resourceKey:n,action:"create"}),d=Number(a.get("roleId")),w=Number(a.get("resourceId"));if(!(d&&w))return(0,R.data)({error:"\u30ED\u30FC\u30EB\u3068\u30EA\u30BD\u30FC\u30B9\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044"},{status:400});let v=String(a.get("action")??"");if(!z.AUTHZ_ACTIONS.includes(v))return(0,R.data)({error:"\u7121\u52B9\u306A action \u3067\u3059"},{status:400});let E=v;return await r.createGrant({roleId:d,resourceId:w,action:E,rowScope:String(a.get("rowScope")??""),columnScope:String(a.get("columnScope")??"")},String(m)),{ok:!0}}case"save":{let{userId:m}=await o(u,{resourceKey:n,action:"update"}),d=String(a.get("action")??"");if(!z.AUTHZ_ACTIONS.includes(d))return(0,R.data)({error:"\u7121\u52B9\u306A action \u3067\u3059"},{status:400});let w=d;return await r.updateGrant(Number(a.get("id")),{action:w,rowScope:String(a.get("rowScope")??""),columnScope:String(a.get("columnScope")??"")},String(m)),{ok:!0}}case"delete":return await o(u,{resourceKey:n,action:"delete"}),await r.deleteGrant(Number(a.get("id"))),{ok:!0};default:return(0,R.data)({error:"unknown action"},{status:400})}}catch(m){return N(m)}}},userRoles:{data:b,async loader({request:u}){let{userId:a}=await o(u,{resourceKey:n,action:"read"});return b(a)},async action({request:u}){let a=await u.formData(),y=String(a.get("_action"));try{switch(y){case"assign":{let{userId:m}=await o(u,{resourceKey:n,action:"create"}),d=Number(a.get("userId")),w=Number(a.get("roleId"));return d&&w?(await r.assignUserRole(d,w,String(m)),{ok:!0}):(0,R.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 o(u,{resourceKey:n,action:"delete"}),await r.removeUserRole(Number(a.get("userId")),Number(a.get("roleId"))),{ok:!0};default:return(0,R.data)({error:"unknown action"},{status:400})}}catch(m){return N(m)}}}}}function j(t){return String(t["*"]??"").split("/")[0]}function ce(t){let r=T(t),n=t.basePath??"/authz",i=["roles","resources","role_permissions","user_roles"],o={roles:r.roles.data,resources:r.resources.data,role_permissions:r.grants.data,user_roles:r.userRoles.data},c={roles:r.roles.action,resources:r.resources.action,role_permissions:r.grants.action,user_roles:r.userRoles.action};async function l(g){let f=j(g.params);if(!i.includes(f))throw(0,G.redirect)(`${n}/roles`);let{userId:b}=await r.layoutGuard(g.request),[u,a]=await Promise.all([r.loadMyPermissions(g.request),o[f](b)]);return{segment:f,basePath:n,myPermissions:u,adminResourceKey:r.resourceKey,...a}}async function p(g){let f=j(g.params),b=c[f];return b?b(g):(0,G.data)({error:"unknown action"},{status:400})}return{loader:l,action:p,server:r}}var I=require("react/jsx-runtime"),s={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 x({label:t,hint:r,children:n}){return(0,I.jsxs)("div",{style:{display:"flex",flexDirection:"column",gap:"0.3rem"},children:[(0,I.jsxs)("span",{style:{fontSize:"0.8rem",color:"#475569",fontWeight:600},children:[t,r?(0,I.jsxs)("span",{style:{fontWeight:400,color:"#94a3b8"},children:[" \u2014 ",r]}):null]}),n]})}function C({message:t}){return t?(0,I.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:t}):null}var V=require("@aiquants/authz-core"),K=require("@aiquants/select-box"),P=require("react"),h=require("react-router");var L=require("react");function M(t){let r=t?.read?t.readPartial?"partial":"full":"none",n=t?.create&&t?.update?"full":t?.create||t?.update?"partial":"none",i=t?.delete?"full":"none";return{canRead:!!t?.read,canWrite:!!t?.write,canDelete:!!t?.delete,readState:r,writeState:n,deleteState:i}}var A=require("react/jsx-runtime"),pe={full:{bg:"#ecfdf5",text:"#047857",border:"#a7f3d0"},partial:{bg:"#fffbeb",text:"#b45309",border:"#fde68a"},none:{bg:"#f8fafc",text:"#94a3b8",border:"#cbd5e1"}};function W(t,r){let n=t?.trim(),i=r?.trim();if(i&&n&&i!==n)return`\u5BFE\u8C61\u30EA\u30BD\u30FC\u30B9: ${i} (${n})`;if(i||n)return`\u5BFE\u8C61\u30EA\u30BD\u30FC\u30B9: ${i||n}`}function me({state:t}){return t==="full"?(0,A.jsx)("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:(0,A.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5 13l4 4L19 7"})}):t==="partial"?(0,A.jsx)("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:(0,A.jsx)("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"})}):(0,A.jsx)("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:(0,A.jsx)("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 _({permission:t,resourceName:r,expectedResourceKey:n,showResourceTooltip:i=!0,labels:o,showScopeSummary:c=!0,className:l="authz-permission-indicator"}){let p=M(t),g={read:o?.read??"\u95B2\u89A7",write:o?.write??"\u7DE8\u96C6",delete:o?.delete??"\u524A\u9664"},f=t?.resourceKey,b=r||f,u=i?W(f,r):void 0,a=!!(n&&f&&f!==n);a&&typeof console<"u"&&typeof console.error=="function"&&console.error(`[Authz Warning] Resource key mismatch in MyPermissionIndicator! Expected: "${n}", but received permission for: "${f}".`);let y=(m,d,w)=>{let v=pe[d],E=u?`${w}: ${d}
|
|
2
|
+
${u}`:`${w}: ${d}`;return(0,A.jsxs)("span",{"data-perm":m,"data-state":d,title:E,style:{display:"inline-flex",alignItems:"center",gap:"0.25rem",padding:"0.2rem 0.5rem",borderRadius:"100px",fontSize:"0.75rem",fontWeight:600,backgroundColor:v.bg,color:v.text,border:`1px solid ${v.border}`,lineHeight:1,userSelect:"none"},children:[(0,A.jsx)(me,{state:d}),(0,A.jsx)("span",{children:w})]})};return(0,A.jsxs)("span",{className:l,title:u,"data-resource":f??"","data-resource-name":b??"","data-mismatch":a?"true":void 0,style:{display:"inline-flex",gap:"0.35rem",alignItems:"center",verticalAlign:"middle"},children:[y("read",p.readState,g.read),y("write",p.writeState,g.write),y("delete",p.deleteState,g.delete),c&&p.readState==="partial"?(0,A.jsx)("span",{"data-perm":"scope",title:u,style:{fontSize:"0.7rem",color:"#b45309",backgroundColor:"#fef3c7",padding:"0.15rem 0.35rem",borderRadius:"4px",fontWeight:600},children:"\u90E8\u5206\u5236\u9650"}):null,a?(0,A.jsxs)("span",{"data-testid":"resource-mismatch-warning",title:`expected: "${n}", actual: "${f}"`,style:{fontSize:"0.7rem",color:"#991b1b",backgroundColor:"#fee2e2",border:"1px solid #fca5a5",padding:"0.15rem 0.35rem",borderRadius:"4px",fontWeight:700},children:["\u26A0\uFE0F \u30EA\u30BD\u30FC\u30B9\u4E0D\u4E00\u81F4 (",f," \u2260 ",n,")"]}):null]})}function ye({permission:t,resourceName:r,expectedResourceKey:n,prefixLabel:i="\u3042\u306A\u305F\u306E\u6A29\u9650",showPrefixLabel:o=!0,showResourceTooltip:c=!0,labels:l,showScopeSummary:p=!0,className:g="authz-permission-status",style:f}){let b=t?.resourceKey,u=r||b,a=c?W(b,r):void 0;return(0,A.jsxs)("span",{className:g,title:a,"data-testid":"my-permission-status","data-resource":b??"","data-resource-name":u??"",style:{fontSize:"0.82rem",color:"#475569",display:"inline-flex",alignItems:"center",gap:"0.4rem",...f},children:[o&&(0,A.jsxs)("span",{"data-testid":"prefix-label",children:[i,":"]}),(0,A.jsx)(_,{permission:t,resourceName:r,expectedResourceKey:n,showResourceTooltip:c,labels:l,showScopeSummary:p})]})}var S=require("react/jsx-runtime");function U(t,r=0){let n=[];for(let i of t){let o=i.level??r;n.push({...i,level:o}),i.children&&i.children.length>0&&n.push(...U(i.children,o+1))}return n}var J={"2xs":{fontSize:"0.6rem",pillPadding:"0.05rem 0.25rem",pillGap:"0.15rem",wrapperGap:"0.15rem",triggerPadding:"0.1rem 0.35rem",triggerFontSize:"0.62rem",badgeFontSize:"0.58rem"},xs:{fontSize:"0.65rem",pillPadding:"0.08rem 0.35rem",pillGap:"0.18rem",wrapperGap:"0.2rem",triggerPadding:"0.12rem 0.4rem",triggerFontSize:"0.68rem",badgeFontSize:"0.62rem"},sm:{fontSize:"0.72rem",pillPadding:"0.1rem 0.4rem",pillGap:"0.2rem",wrapperGap:"0.25rem",triggerPadding:"0.15rem 0.45rem",triggerFontSize:"0.72rem",badgeFontSize:"0.65rem"},md:{fontSize:"0.78rem",pillPadding:"0.15rem 0.5rem",pillGap:"0.3rem",wrapperGap:"0.35rem",triggerPadding:"0.2rem 0.6rem",triggerFontSize:"0.78rem",badgeFontSize:"0.7rem"},lg:{fontSize:"0.85rem",pillPadding:"0.25rem 0.65rem",pillGap:"0.4rem",wrapperGap:"0.45rem",triggerPadding:"0.25rem 0.75rem",triggerFontSize:"0.85rem",badgeFontSize:"0.75rem"}};function Q(t,r){let n=r?.noPermission??"\u6A29\u9650\u306A\u3057",i=r?.fullWrite??"\u7DE8\u96C6\u53EF",o=r?.partialRead??"\u4E00\u90E8\u95B2\u89A7",c=r?.readOnly??"\u95B2\u89A7\u306E\u307F";return t&&(t.read||t.write||t.delete)?t.write?{text:i,color:"#047857",bgColor:"#ecfdf5",borderColor:"#a7f3d0"}:t.read?t.readPartial?{text:o,color:"#b45309",bgColor:"#fffbeb",borderColor:"#fde68a"}:{text:c,color:"#1d4ed8",bgColor:"#eff6ff",borderColor:"#bfdbfe"}:{text:n,color:"#64748b",bgColor:"#f1f5f9",borderColor:"#cbd5e1"}:{text:n,color:"#64748b",bgColor:"#f1f5f9",borderColor:"#cbd5e1"}}function ge({item:t,size:r="md",labels:n}){let i=Q(t.permission,n),o=t.permission?.resourceKey||t.resourceKey||t.expectedResourceKey,c=t.resourceName||o,l=!!(t.expectedResourceKey&&t.permission?.resourceKey&&t.permission.resourceKey!==t.expectedResourceKey),p=J[r],g=`\u5BFE\u8C61: ${c}${o?` (${o})`:""}${t.permission?` | ${n?.read??"\u95B2\u89A7"}:${t.permission.read?"\u25CB":"\xD7"} ${n?.write??"\u7DE8\u96C6"}:${t.permission.write?"\u25CB":"\xD7"} ${n?.delete??"\u524A\u9664"}:${t.permission.delete?"\u25CB":"\xD7"}`:""}`;return(0,S.jsxs)("span",{title:g,"data-testid":`permission-pill-${t.resourceName}`,"data-mismatch":l?"true":"false",style:{display:"inline-flex",alignItems:"center",gap:p.pillGap,fontSize:p.fontSize,padding:p.pillPadding,borderRadius:"9999px",backgroundColor:l?"#fee2e2":i.bgColor,color:l?"#991b1b":i.color,border:`1px solid ${l?"#fca5a5":i.borderColor}`,fontWeight:600,lineHeight:"1.2"},children:[(0,S.jsxs)("span",{children:[c,":"]}),(0,S.jsx)("span",{children:i.text}),l&&(0,S.jsx)("span",{title:`expected "${t.expectedResourceKey}", actual "${t.permission?.resourceKey}"`,children:"\u26A0\uFE0F"})]})}function q({items:t,prefixLabel:r="\u3042\u306A\u305F\u306E\u6A29\u9650",variant:n="pills",size:i="md",labels:o,className:c="authz-permission-group-status",style:l}){let[p,g]=(0,L.useState)(!1),f=(0,L.useRef)(null),b=J[i];if((0,L.useEffect)(()=>{if(n!=="popover"||!p)return;function u(y){f.current&&!f.current.contains(y.target)&&g(!1)}function a(y){y.key==="Escape"&&g(!1)}return document.addEventListener("mousedown",u),document.addEventListener("keydown",a),()=>{document.removeEventListener("mousedown",u),document.removeEventListener("keydown",a)}},[n,p]),n==="popover"){let u=t.filter(m=>m.permission?.write).length,a=t.length,y=u===a?o?.fullWrite??"\u7DE8\u96C6\u53EF":u>0?o?.partialWrite??"\u4E00\u90E8\u7DE8\u96C6\u53EF":o?.readOnly??"\u95B2\u89A7\u306E\u307F";return(0,S.jsxs)("span",{ref:f,className:c,"data-testid":"my-permission-group-popover",style:{position:"relative",display:"inline-block",...l},children:[(0,S.jsxs)("button",{type:"button",onClick:()=>g(!p),"data-testid":"permission-popover-trigger",style:{display:"inline-flex",alignItems:"center",gap:b.wrapperGap,fontSize:b.triggerFontSize,padding:b.triggerPadding,borderRadius:"6px",backgroundColor:"#f8fafc",color:"#334155",border:"1px solid #cbd5e1",fontWeight:600,cursor:"pointer"},children:[(0,S.jsxs)("span",{children:["\u{1F512} ",r]}),(0,S.jsxs)("span",{style:{fontSize:b.badgeFontSize,color:"#64748b"},children:["(",y,")"]}),(0,S.jsx)("span",{style:{fontSize:"0.65rem",marginLeft:"0.1rem"},children:p?"\u25B2":"\u25BE"})]}),p&&(0,S.jsxs)("div",{"data-testid":"permission-popover-card",style:{position:"absolute",top:"calc(100% + 6px)",right:0,zIndex:50,minWidth:"280px",whiteSpace:"nowrap",padding:"0.75rem 0.85rem",backgroundColor:"#ffffff",borderRadius:"8px",boxShadow:"0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)",border:"1px solid #e2e8f0",fontSize:"0.82rem"},children:[(0,S.jsxs)("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:"0.5rem",paddingBottom:"0.4rem",borderBottom:"1px solid #f1f5f9",fontWeight:700,color:"#1e293b",whiteSpace:"nowrap"},children:[(0,S.jsxs)("span",{children:["\u{1F512} ",r]}),(0,S.jsx)("button",{type:"button",onClick:()=>g(!1),style:{border:"none",background:"none",cursor:"pointer",color:"#94a3b8",fontSize:"0.85rem",padding:"0 0.2rem"},children:"\u2715"})]}),(0,S.jsx)("div",{style:{display:"flex",flexDirection:"column",gap:"0.4rem"},children:U(t).map(m=>{let d=m.level??0,w=d>0;return(0,S.jsxs)("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",gap:"1.25rem",whiteSpace:"nowrap",paddingLeft:w?`${d*.85}rem`:"0"},children:[(0,S.jsxs)("div",{style:{display:"inline-flex",alignItems:"center",whiteSpace:"nowrap"},children:[w&&(0,S.jsx)("span",{"aria-hidden":"true",style:{display:"inline-block",width:"10px",height:"10px",borderLeft:"1.5px solid #cbd5e1",borderBottom:"1.5px solid #cbd5e1",borderBottomLeftRadius:"3px",marginRight:"6px",marginTop:"-4px",flexShrink:0}}),(0,S.jsxs)("span",{style:{fontWeight:w?500:600,color:w?"#64748b":"#1e293b",fontSize:w?"0.78rem":"0.82rem",whiteSpace:"nowrap"},children:[m.resourceName,":"]})]}),(0,S.jsx)(_,{permission:m.permission,resourceName:m.resourceName,expectedResourceKey:m.expectedResourceKey,labels:o})]},m.resourceName)})})]})]})}return(0,S.jsxs)("span",{className:c,"data-testid":"my-permission-group-pills",style:{display:"inline-flex",alignItems:"center",flexWrap:"wrap",gap:b.pillGap,fontSize:b.fontSize,color:"#475569",...l},children:[r&&(0,S.jsxs)("span",{style:{fontWeight:600,color:"#334155"},children:[r,":"]}),(0,S.jsx)("span",{style:{display:"inline-flex",alignItems:"center",flexWrap:"wrap",gap:b.pillGap},children:t.map(u=>(0,S.jsx)(ge,{item:u,size:i,labels:o},u.resourceName))})]})}var e=require("react/jsx-runtime"),$=t=>t?.error;function Y({children:t}){let{myPermissions:r,labels:n,adminResourceKey:i,basePath:o}=(0,h.useLoaderData)(),c=o??"/authz",[l,p]=(0,P.useState)("pills"),g=[["roles",n.tabs.roles],["resources",n.tabs.resources],["role_permissions",n.tabs.role_permissions],["user_roles",n.tabs.user_roles]],f=Object.entries(r||{}).map(([u,a])=>({resourceKey:u,resourceName:a?.resourceKey||u,permission:a,expectedResourceKey:u})),b=f.length>0?f:[{resourceKey:i,resourceName:i,permission:r?.[i],expectedResourceKey:i}];return(0,e.jsxs)("div",{className:"authz-admin",style:s.page,children:[(0,e.jsxs)("header",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",gap:"0.75rem",flexWrap:"wrap",margin:"0 0 0.4rem"},children:[(0,e.jsx)("h1",{style:{fontSize:"1.15rem",margin:0,fontWeight:700,color:"#1e293b"},children:n.title}),(0,e.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:"0.4rem"},children:[(0,e.jsx)(q,{prefixLabel:n.myPermission,items:b,variant:l,size:"xs"}),(0,e.jsxs)("div",{style:{display:"inline-flex",borderRadius:"4px",border:"1px solid #cbd5e1",padding:"1px",backgroundColor:"#f8fafc",fontSize:"0.7rem"},children:[(0,e.jsx)("button",{type:"button",onClick:()=>p("pills"),"data-testid":"switch-variant-pills",style:{padding:"1px 5px",borderRadius:"3px",border:"none",cursor:"pointer",fontSize:"0.7rem",lineHeight:"1.2",fontWeight:l==="pills"?600:400,backgroundColor:l==="pills"?"#ffffff":"transparent",color:l==="pills"?"#1e293b":"#64748b",boxShadow:l==="pills"?"0 1px 2px rgba(0,0,0,0.05)":"none"},children:"Pills"}),(0,e.jsx)("button",{type:"button",onClick:()=>p("popover"),"data-testid":"switch-variant-popover",style:{padding:"1px 5px",borderRadius:"3px",border:"none",cursor:"pointer",fontSize:"0.7rem",lineHeight:"1.2",fontWeight:l==="popover"?600:400,backgroundColor:l==="popover"?"#ffffff":"transparent",color:l==="popover"?"#1e293b":"#64748b",boxShadow:l==="popover"?"0 1px 2px rgba(0,0,0,0.05)":"none"},children:"Popover"})]})]})]}),(0,e.jsx)("nav",{style:{display:"flex",gap:"0.25rem",borderBottom:"1px solid #e2e8f0",margin:"0.6rem 0 1rem"},children:g.map(([u,a])=>(0,e.jsx)(h.NavLink,{to:`${c}/${u}`,style:({isActive:y})=>({padding:"0.5rem 0.9rem",textDecoration:"none",color:y?"#2563eb":"#475569",borderBottom:y?"2px solid #2563eb":"2px solid transparent",marginBottom:-1,fontWeight:y?700:500,fontSize:"0.92rem"}),children:a},u))}),t]})}function fe(){return(0,e.jsx)(Y,{children:(0,e.jsx)(h.Outlet,{})})}function Z(t){let r=D(t).error;return function(){let i=(0,h.useRouteError)(),o=(0,h.isRouteErrorResponse)(i)?i:null,c=o?.status===403,l=c?r.forbiddenTitle:o?`${r.genericTitlePrefix} (${o.status})`:r.genericTitle,p=c?r.forbiddenBody:o?typeof o.data=="string"&&o.data?o.data:o.statusText:r.genericBody;return(0,e.jsx)("div",{style:s.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:l}),(0,e.jsx)("p",{style:{color:"#7f1d1d",fontSize:"0.9rem",margin:0,lineHeight:1.7},children:p})]})})}}var he=Z(),O=(t,r)=>n=>{t&&!window.confirm(r)&&n.preventDefault()};function B(){let{roles:t,selfAdminRoleIds:r,labels:n}=(0,h.useLoaderData)(),i=n.roles,o=n.common,c=new Set(r??[]);return(0,e.jsxs)("section",{children:[(0,e.jsx)("h2",{style:s.h2,children:i.heading}),(0,e.jsx)(C,{message:$((0,h.useActionData)())}),(0,e.jsx)("p",{style:s.note,children:i.note}),(0,e.jsx)("div",{style:s.tableContainer,children:(0,e.jsxs)("table",{style:s.table,children:[(0,e.jsx)("thead",{children:(0,e.jsxs)("tr",{children:[(0,e.jsx)("th",{style:{...s.th,width:"20%"},children:i.roleKey}),(0,e.jsx)("th",{style:{...s.th,width:"25%"},children:i.name}),(0,e.jsx)("th",{style:{...s.th,width:"35%"},children:i.description}),(0,e.jsx)("th",{style:{...s.th,width:"10%"},children:i.activeHeader}),(0,e.jsx)("th",{style:{...s.th,width:"10%"}})]})}),(0,e.jsxs)("tbody",{children:[t.map(l=>(0,e.jsxs)("tr",{children:[(0,e.jsx)("td",{style:s.td,children:l.roleKey==="@authenticated"||l.roleKey==="@anonymous"?(0,e.jsx)("span",{style:s.code,children:l.roleKey}):(0,e.jsx)("input",{name:"roleKey",defaultValue:l.roleKey,form:`save-role-${l.id}`,"aria-label":`roleKey-${l.id}`,required:!0,style:s.input})}),(0,e.jsx)("td",{style:s.td,children:(0,e.jsx)("input",{name:"name",defaultValue:l.name,form:`save-role-${l.id}`,"aria-label":`name-${l.id}`,required:!0,style:s.input})}),(0,e.jsx)("td",{style:s.td,children:(0,e.jsx)("input",{name:"description",defaultValue:l.description??"",form:`save-role-${l.id}`,"aria-label":`description-${l.id}`,style:s.input})}),(0,e.jsx)("td",{style:s.td,children:(0,e.jsxs)(h.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:l.id}),(0,e.jsx)("input",{type:"hidden",name:"isActive",value:String(!l.isActive)}),(0,e.jsx)("button",{type:"submit",style:s.button,onClick:l.isActive?O(c.has(l.id),n.warn.selfRoleDisable):void 0,children:l.isActive?o.active:o.inactive})]})}),(0,e.jsxs)("td",{style:{...s.td,whiteSpace:"nowrap"},children:[(0,e.jsxs)(h.Form,{method:"post",id:`save-role-${l.id}`,style:{display:"inline"},children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"save"}),(0,e.jsx)("input",{type:"hidden",name:"id",value:l.id}),(0,e.jsx)("button",{type:"submit",style:s.save,children:o.save})]}),(0,e.jsxs)(h.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:l.id}),(0,e.jsx)("button",{type:"submit",style:s.danger,onClick:O(c.has(l.id),n.warn.selfRoleDelete),children:o.delete})]})]})]},l.id)),t.length===0?(0,e.jsx)("tr",{children:(0,e.jsx)("td",{style:s.empty,colSpan:5,children:i.empty})}):null]})]})}),(0,e.jsx)("h3",{style:s.h3,children:i.newHeading}),(0,e.jsxs)(h.Form,{method:"post",style:s.card,children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"create"}),(0,e.jsx)(x,{label:i.roleKey,hint:i.hintRoleKey,children:(0,e.jsx)("input",{name:"roleKey","aria-label":"role_key",required:!0,style:s.input})}),(0,e.jsx)(x,{label:i.name,children:(0,e.jsx)("input",{name:"name","aria-label":"name",required:!0,style:s.input})}),(0,e.jsx)(x,{label:i.description,hint:o.optional,children:(0,e.jsx)("input",{name:"description","aria-label":"description",style:s.input})}),(0,e.jsx)("button",{type:"submit",style:s.primary,children:o.add})]})]})}function X(){let{resources:t,labels:r}=(0,h.useLoaderData)(),n=r.resources,i=r.common;return(0,e.jsxs)("section",{children:[(0,e.jsx)("h2",{style:s.h2,children:n.heading}),(0,e.jsx)(C,{message:$((0,h.useActionData)())}),(0,e.jsx)("p",{style:s.note,children:n.note}),(0,e.jsx)("div",{style:s.tableContainer,children:(0,e.jsxs)("table",{style:s.table,children:[(0,e.jsx)("thead",{children:(0,e.jsxs)("tr",{children:[(0,e.jsx)("th",{style:{...s.th,width:"15%"},children:n.appKey}),(0,e.jsx)("th",{style:{...s.th,width:"20%"},children:n.resourceKey}),(0,e.jsx)("th",{style:{...s.th,width:"25%"},children:n.name}),(0,e.jsx)("th",{style:{...s.th,width:"30%"},children:n.description}),(0,e.jsx)("th",{style:{...s.th,width:"10%"}})]})}),(0,e.jsxs)("tbody",{children:[t.map(o=>(0,e.jsxs)("tr",{children:[(0,e.jsx)("td",{style:s.td,children:(0,e.jsx)("span",{style:s.code,children:o.appKey})}),(0,e.jsx)("td",{style:s.td,children:(0,e.jsx)("span",{style:s.code,children:o.resourceKey})}),(0,e.jsx)("td",{style:s.td,children:(0,e.jsx)("input",{name:"name",defaultValue:o.name,form:`save-res-${o.id}`,"aria-label":`name-${o.id}`,required:!0,style:s.input})}),(0,e.jsx)("td",{style:s.td,children:(0,e.jsx)("input",{name:"description",defaultValue:o.description??"",form:`save-res-${o.id}`,"aria-label":`description-${o.id}`,style:s.input})}),(0,e.jsxs)("td",{style:{...s.td,whiteSpace:"nowrap"},children:[(0,e.jsxs)(h.Form,{method:"post",id:`save-res-${o.id}`,style:{display:"inline"},children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"save"}),(0,e.jsx)("input",{type:"hidden",name:"id",value:o.id}),(0,e.jsx)("button",{type:"submit",style:s.save,children:i.save})]}),(0,e.jsxs)(h.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:o.id}),(0,e.jsx)("button",{type:"submit",style:s.danger,children:i.delete})]})]})]},o.id)),t.length===0?(0,e.jsx)("tr",{children:(0,e.jsx)("td",{style:s.empty,colSpan:5,children:n.empty})}):null]})]})}),(0,e.jsx)("h3",{style:s.h3,children:n.newHeading}),(0,e.jsxs)(h.Form,{method:"post",style:s.card,children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"create"}),(0,e.jsx)(x,{label:n.appKey,hint:n.hintAppKey,children:(0,e.jsx)("input",{name:"appKey","aria-label":"app_key",required:!0,style:s.input})}),(0,e.jsx)(x,{label:n.resourceKey,hint:n.hintResourceKey,children:(0,e.jsx)("input",{name:"resourceKey","aria-label":"resource_key",required:!0,style:s.input})}),(0,e.jsx)(x,{label:n.name,children:(0,e.jsx)("input",{name:"name","aria-label":"name",required:!0,style:s.input})}),(0,e.jsx)(x,{label:n.description,hint:i.optional,children:(0,e.jsx)("input",{name:"description","aria-label":"description",style:s.input})}),(0,e.jsx)("button",{type:"submit",style:s.primary,children:i.add})]})]})}function be({g:t,labels:r}){let n=r.common,[i,o]=(0,P.useState)({label:t.action,value:t.action});return(0,e.jsxs)("tr",{children:[(0,e.jsx)("td",{style:s.td,children:(0,e.jsx)("span",{style:s.code,children:t.roleKey})}),(0,e.jsx)("td",{style:s.td,children:(0,e.jsxs)("span",{style:s.code,children:[t.appKey,":",t.resourceKey]})}),(0,e.jsx)("td",{style:s.td,children:t.roleKey==="@anonymous"?(0,e.jsx)("span",{style:s.code,children:t.action}):(0,e.jsxs)(e.Fragment,{children:[(0,e.jsx)("input",{type:"hidden",name:"action",value:i.value,form:`save-grant-${t.id}`}),(0,e.jsx)(K.SelectBox,{options:V.AUTHZ_ACTIONS.map(c=>({label:c,value:c})),value:i,onChange:c=>{c&&o(c)}})]})}),(0,e.jsx)("td",{style:s.td,children:(0,e.jsx)("textarea",{name:"rowScope",defaultValue:t.rowScope??"",form:`save-grant-${t.id}`,"aria-label":`row_scope-${t.id}`,rows:2,placeholder:r.grants.rowScopePlaceholder,style:s.textarea})}),(0,e.jsx)("td",{style:s.td,children:(0,e.jsx)("textarea",{name:"columnScope",defaultValue:t.columnScope??"",form:`save-grant-${t.id}`,"aria-label":`column_scope-${t.id}`,rows:2,placeholder:r.grants.columnScopePlaceholder,style:s.textarea})}),(0,e.jsxs)("td",{style:{...s.td,whiteSpace:"nowrap"},children:[(0,e.jsxs)(h.Form,{method:"post",id:`save-grant-${t.id}`,style:{display:"inline"},children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"save"}),(0,e.jsx)("input",{type:"hidden",name:"id",value:t.id}),(0,e.jsx)("button",{type:"submit",style:s.save,children:n.save})]}),(0,e.jsxs)(h.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:t.id}),(0,e.jsx)("button",{type:"submit",style:s.danger,children:n.delete})]})]})]})}function ee(){let{grants:t,roles:r,resources:n,labels:i}=(0,h.useLoaderData)(),o=i.grants,c=i.common,l=r.map(d=>({label:d.roleKey,value:d.id})),p=n.map(d=>({label:`${d.appKey}:${d.resourceKey}`,value:d.id})),g=V.AUTHZ_ACTIONS.map(d=>({label:d,value:d})),[f,b]=(0,P.useState)(void 0),[u,a]=(0,P.useState)(void 0),[y,m]=(0,P.useState)({label:"read",value:"read"});return(0,e.jsxs)("section",{children:[(0,e.jsx)("h2",{style:s.h2,children:o.heading}),(0,e.jsx)("p",{style:s.note,children:o.note}),(0,e.jsx)(C,{message:$((0,h.useActionData)())}),(0,e.jsx)("div",{style:s.tableContainer,children:(0,e.jsxs)("table",{style:s.table,children:[(0,e.jsx)("thead",{children:(0,e.jsxs)("tr",{children:[(0,e.jsx)("th",{style:{...s.th,width:"15%"},children:o.role}),(0,e.jsx)("th",{style:{...s.th,width:"20%"},children:o.resource}),(0,e.jsx)("th",{style:{...s.th,width:"15%"},children:o.action}),(0,e.jsx)("th",{style:{...s.th,width:"20%"},children:o.rowScope}),(0,e.jsx)("th",{style:{...s.th,width:"20%"},children:o.columnScope}),(0,e.jsx)("th",{style:{...s.th,width:"10%"}})]})}),(0,e.jsxs)("tbody",{children:[t.map(d=>(0,e.jsx)(be,{g:d,labels:i},d.id)),t.length===0?(0,e.jsx)("tr",{children:(0,e.jsx)("td",{style:s.empty,colSpan:6,children:o.empty})}):null]})]})}),(0,e.jsx)("h3",{style:s.h3,children:o.newHeading}),(0,e.jsxs)(h.Form,{method:"post",style:s.card,children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"create"}),(0,e.jsx)("input",{type:"hidden",name:"roleId",value:f?.value??""}),(0,e.jsx)("input",{type:"hidden",name:"resourceId",value:u?.value??""}),(0,e.jsx)("input",{type:"hidden",name:"action",value:y?.value??""}),(0,e.jsx)(x,{label:o.role,children:(0,e.jsx)(K.SelectBox,{options:l,value:f,onChange:d=>b(d||void 0),placeholder:o.selectPlaceholder})}),(0,e.jsx)(x,{label:o.resource,children:(0,e.jsx)(K.SelectBox,{options:p,value:u,onChange:d=>a(d||void 0),placeholder:o.selectPlaceholder})}),(0,e.jsx)(x,{label:o.action,children:(0,e.jsx)(K.SelectBox,{options:g,value:y,onChange:d=>m(d||void 0)})}),(0,e.jsx)(x,{label:o.rowScope,hint:o.rowScopeHint,children:(0,e.jsx)("textarea",{name:"rowScope","aria-label":"row_scope",rows:2,style:s.textarea,placeholder:'{"filters":[{"field":"\u90E8\u9580CD","op":"in","values":["A"]}]}'})}),(0,e.jsx)(x,{label:o.columnScope,hint:o.columnScopeHint,children:(0,e.jsx)("textarea",{name:"columnScope","aria-label":"column_scope",rows:2,style:s.textarea,placeholder:'{"mode":"deny","columns":["\u91D1\u984D"]}'})}),(0,e.jsx)("button",{type:"submit",style:s.primary,children:c.grant})]})]})}function te(){let{assignments:t,roles:r,users:n,actorUserId:i,selfAdminRoleIds:o,labels:c}=(0,h.useLoaderData)(),l=c.userRoles,p=c.common,g=new Set(o??[]),f=n.map(d=>({label:`${d.email}\uFF08${d.displayName}\uFF09`,value:d.id})),b=r.filter(d=>d.roleKey!=="@authenticated"&&d.roleKey!=="@anonymous").map(d=>({label:d.roleKey,value:d.id})),[u,a]=(0,P.useState)(void 0),[y,m]=(0,P.useState)(void 0);return(0,e.jsxs)("section",{children:[(0,e.jsx)("h2",{style:s.h2,children:l.heading}),(0,e.jsx)(C,{message:$((0,h.useActionData)())}),(0,e.jsx)("p",{style:s.note,children:l.note}),(0,e.jsx)("div",{style:s.tableContainer,children:(0,e.jsxs)("table",{style:s.table,children:[(0,e.jsx)("thead",{children:(0,e.jsxs)("tr",{children:[(0,e.jsx)("th",{style:{...s.th,width:"45%"},children:l.user}),(0,e.jsx)("th",{style:{...s.th,width:"45%"},children:l.role}),(0,e.jsx)("th",{style:{...s.th,width:"10%"}})]})}),(0,e.jsxs)("tbody",{children:[t.map(d=>(0,e.jsxs)("tr",{children:[(0,e.jsxs)("td",{style:s.td,children:[d.email,(0,e.jsxs)("span",{style:s.muted,children:["\uFF08",d.displayName,"\uFF09"]})]}),(0,e.jsx)("td",{style:s.td,children:d.roleKey}),(0,e.jsx)("td",{style:s.td,children:(0,e.jsxs)(h.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:d.userId}),(0,e.jsx)("input",{type:"hidden",name:"roleId",value:d.roleId}),(0,e.jsx)("button",{type:"submit",style:s.danger,onClick:O(d.userId===i&&g.has(d.roleId),c.warn.selfAssignmentRemove),children:p.remove})]})})]},`${d.userId}-${d.roleId}`)),t.length===0?(0,e.jsx)("tr",{children:(0,e.jsx)("td",{style:s.empty,colSpan:3,children:l.empty})}):null]})]})}),(0,e.jsx)("h3",{style:s.h3,children:l.newHeading}),(0,e.jsxs)(h.Form,{method:"post",style:s.card,children:[(0,e.jsx)("input",{type:"hidden",name:"_action",value:"assign"}),(0,e.jsx)("input",{type:"hidden",name:"userId",value:u?.value??""}),(0,e.jsx)("input",{type:"hidden",name:"roleId",value:y?.value??""}),(0,e.jsx)(x,{label:l.user,children:(0,e.jsx)(K.SelectBox,{options:f,value:u,onChange:d=>a(d||void 0),placeholder:l.selectPlaceholder})}),(0,e.jsx)(x,{label:l.role,children:(0,e.jsx)(K.SelectBox,{options:b,value:y,onChange:d=>m(d||void 0),placeholder:l.selectPlaceholder})}),(0,e.jsx)("button",{type:"submit",style:s.primary,children:p.assign})]})]})}var we={roles:B,resources:X,role_permissions:ee,user_roles:te};function Se(){let{segment:t}=(0,h.useLoaderData)(),r=we[t]??B;return(0,e.jsx)(Y,{children:(0,e.jsx)(r,{})})}function Ae(t){let r={};for(let n of Object.keys(t)){let i=t[n];r[n]={key:i.key??n,name:i.name,description:i.description}}return r}var k=require("@aiquants/authz-core"),re=require("react-router");function ne(t,r){let n=(0,k.can)(r,"read"),i=(0,k.can)(r,"create"),o=(0,k.can)(r,"update"),c=(0,k.can)(r,"delete"),l=r?.scopeByAction.read,p=n&&!!l&&(l.rowScope!==null||l.columnScope!==null);return{resourceKey:t,read:n,create:i,update:o,delete:c,write:i||o,readPartial:p,actions:r?Array.from(r.actions):[]}}function Re(t){async function r(o,c,l){let p=l?.failureRedirect?()=>{throw(0,re.redirect)(l.failureRedirect)}:t.onDeny;return(0,k.createRequirePermission)({resolveUserId:t.resolveUserId,getEffectivePermissions:t.getEffectivePermissions,onDeny:p})(o,{appKey:t.appKey,resourceKey:c.resourceKey,action:c.action})}async function n(o,c){let l=await t.resolveUserId(o),p={};for(let g of c.resourceKeys){let f=await t.getEffectivePermissions({userId:l??null,appKey:t.appKey,resourceKey:g});p[g]=ne(g,f)}return p}async function i(o,c,l){let p=await r(o,c,l),g=await n(o,{resourceKeys:[c.resourceKey]});return{...p,permission:g[c.resourceKey]}}return{requirePermission:r,getMyPermissions:n,requireAndGetPermission:i}}0&&(module.exports={AuthzAdminAppView,AuthzErrorBoundary,AuthzGrantsView,AuthzLayout,AuthzResourcesView,AuthzRolesView,AuthzUserRolesView,ErrorAlert,Field,MyPermissionGroupStatus,MyPermissionIndicator,MyPermissionStatus,createAuthz,createAuthzAdminApp,createAuthzAdminServer,defaultAuthzAdminLabels,defineResources,flattenGroupItems,formatResourceTooltip,getPermissionSummary,makeAuthzErrorBoundary,resolveLabels,toPermissionView,ui,usePermission});
|
|
3
3
|
//# sourceMappingURL=index.js.map
|