@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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/admin/app.ts","../src/admin/server.ts","../src/admin/labels.ts","../src/admin/ui.tsx","../src/admin/views.tsx","../src/usePermission.ts","../src/MyPermissionIndicator.tsx","../src/resources.ts","../src/server.ts"],"sourcesContent":["export * from \"./admin/app\"\nexport * from \"./admin/labels\"\nexport * from \"./admin/server\"\nexport * from \"./admin/ui\"\nexport * from \"./admin/views\"\nexport * from \"./MyPermissionIndicator\"\nexport * from \"./resources\"\nexport * from \"./server\"\nexport * from \"./usePermission\"\n","/**\n * 認可管理 UI を **スプラット 1 ルート(`authz/*`)** にマウントするためのサーバ結線。\n * `routes.ts` の 1 エントリ + 極小のマウントファイル 1 個だけで全タブを提供できる\n * (タブごとのルートディレクトリ/ファイルが不要)。\n *\n * 返り値の `loader`/`action` は store 依存(サーバ)。Component は store 非依存の\n * `AuthzAdminAppView`(views.tsx)を、ErrorBoundary は `makeAuthzErrorBoundary` を使う。\n */\nimport { data, redirect } from \"react-router\"\nimport { type CreateAuthzAdminServerOptions, createAuthzAdminServer } from \"./server\"\n\ntype RouteArgs = { request: Request; params: Record<string, string | undefined> }\n\nexport type CreateAuthzAdminAppOptions = CreateAuthzAdminServerOptions & {\n /** マウントのベースパス(タブリンク/未指定セグメントのリダイレクト先)。既定 `/authz`。 */\n basePath?: string\n}\n\n/** スプラット param(\"*\")から先頭セグメントを取り出す(`roles/...` → `roles`)。 */\nfunction segmentOf(params: Record<string, string | undefined>): string {\n return String(params[\"*\"] ?? \"\").split(\"/\")[0]\n}\n\nexport function createAuthzAdminApp(opts: CreateAuthzAdminAppOptions) {\n const server = createAuthzAdminServer(opts)\n const basePath = opts.basePath ?? \"/authz\"\n const SEGMENTS = [\"roles\", \"resources\", \"role_permissions\", \"user_roles\"] as const\n // データ取得(ガード無し)。ガードはスプラット loader で 1 回だけ行い、userId を渡す。\n const segmentData = { roles: server.roles.data, resources: server.resources.data, role_permissions: server.grants.data, user_roles: server.userRoles.data }\n const actions = { roles: server.roles.action, resources: server.resources.action, role_permissions: server.grants.action, user_roles: server.userRoles.action }\n\n async function loader(args: RouteArgs) {\n const segment = segmentOf(args.params)\n if (!(SEGMENTS as readonly string[]).includes(segment)) throw redirect(`${basePath}/roles`)\n // ガードは 1 回だけ(requireUser + requirePermission(read))。userId を取り回して再ガードしない。\n const { userId } = await server.layoutGuard(args.request)\n const [myPermissions, segData] = await Promise.all([server.loadMyPermissions(args.request), segmentData[segment as (typeof SEGMENTS)[number]](userId)])\n // segData は labels を含む(各 data 関数が付与)。myPermissions/adminResourceKey はレイアウト殻用。\n return { segment, basePath, myPermissions, adminResourceKey: server.resourceKey, ...segData }\n }\n\n async function action(args: RouteArgs) {\n const segment = segmentOf(args.params)\n const act = actions[segment as (typeof SEGMENTS)[number]]\n if (!act) return data({ error: \"unknown action\" }, { status: 400 })\n return act(args)\n }\n\n // server: 個別タブの loader/action を露出(統合テスト等から直接呼ぶ用)。\n return { loader, action, server }\n}\n","/**\n * 認可管理 UI のサーバ結線(loader/action 工場)。store ポート + アプリのガード/セッションを束ね、\n * 各ルートの loader/action を生成する。返り値の loader データには解決済みラベルを含める。\n * store(drizzle)を渡すのはこの工場の呼び出し側(アプリのサーバモジュール)に限る。\n */\nimport { AUTHZ_ACTIONS, type AuthzAction, type AuthzAdminStore, AuthzDeniedError } from \"@aiquants/authz-core\"\nimport { data, redirect } from \"react-router\"\nimport type { PermissionView } from \"../server\"\nimport { type AuthzAdminLabels, type PartialAuthzAdminLabels, resolveLabels } from \"./labels\"\nimport type { AuthzGrantsData, AuthzLayoutData, AuthzResourcesData, AuthzRolesData, AuthzUserRolesData } from \"./views\"\n\ntype Req = { request: Request }\ntype PermissionQuery = { resourceKey: string; action: AuthzAction }\n\nexport type CreateAuthzAdminServerOptions = {\n store: AuthzAdminStore\n /** 管理画面のガード資源キー(既定 `authz_admin`)。 */\n resourceKey?: string\n /** 未ログインをログインへ誘導する(例: throw redirect(...))。 */\n requireUser: (request: Request) => Promise<unknown>\n /**\n * 認可ガード(アプリの createAuthz 由来)。allow で { userId } を返す。\n * 0.2.0 で GuardResult.userId が nullable 化したため、戻り型も null を受ける。\n * userId==null(未解決/万一の public 付与)は createAuthzAdminServer 内で deny する\n * (管理経路は監査・自己権限計算に実 id が必須のため非 null を保証)。\n */\n requirePermission: (request: Request, query: PermissionQuery) => Promise<{ userId: string | number | null }>\n /** 自己権限表示用(アプリの createAuthz 由来)。 */\n getMyPermissions: (request: Request, args: { resourceKeys: string[] }) => Promise<Record<string, PermissionView>>\n /** 文言の部分上書き(既定は日本語)。 */\n labels?: PartialAuthzAdminLabels\n}\n\nconst isResponse = (e: unknown): e is Response => e instanceof Response\n\n/** action 内の例外を 403(認可拒否のみ)/ 400(検証等)へ変換する。 */\nfunction toActionError(e: unknown) {\n if (isResponse(e)) throw e\n if (e instanceof AuthzDeniedError) throw new Response(e.message, { status: 403 })\n return data({ error: e instanceof Error ? e.message : \"エラーが発生しました\" }, { status: 400 })\n}\n\nexport function createAuthzAdminServer(opts: CreateAuthzAdminServerOptions) {\n const store = opts.store\n const RES = opts.resourceKey ?? \"authz_admin\"\n const labels: AuthzAdminLabels = resolveLabels(opts.labels)\n // 未解決ユーザー(userId==null)を境界で 1 回だけ deny。これ以降の userId は非 null 保証。\n // 管理リソースは public を付与しない前提だが、防御的に拒否する(監査/自己権限計算に実 id が必須)。\n const requirePermission = async (request: Request, query: PermissionQuery): Promise<{ userId: string | number }> => {\n const { userId } = await opts.requirePermission(request, query)\n if (userId == null) {\n throw new AuthzDeniedError({ appKey: \"\", resourceKey: query.resourceKey, action: query.action, reason: \"unresolved-user\", userId: null })\n }\n return { userId }\n }\n\n /** レイアウトガード: requireUser(302) → requirePermission(read, 403)。userId を返す(1 回だけ実行)。 */\n async function layoutGuard(request: Request): Promise<{ userId: string | number }> {\n await opts.requireUser(request)\n try {\n return await requirePermission(request, { resourceKey: RES, action: \"read\" })\n } catch (e) {\n if (e instanceof AuthzDeniedError) throw new Response(`Forbidden: ${RES}`, { status: 403 })\n throw e\n }\n }\n /** 自己権限(インジケータ表示用)。 */\n const loadMyPermissions = (request: Request) => opts.getMyPermissions(request, { resourceKeys: [RES] })\n\n // ---- データ取得(ガード無し)。ガード済みの userId を受け取る(resources/grants は未使用)。 ----\n const rolesData = async (userId?: string | number): Promise<AuthzRolesData> => {\n const [roles, self] = await Promise.all([store.listRoles(), store.getSelfAdminContext(Number(userId))])\n return { roles, selfAdminRoleIds: self.selfAdminRoleIds, labels }\n }\n const resourcesData = async (): Promise<AuthzResourcesData> => ({ resources: await store.listResources(), labels })\n const grantsData = async (): Promise<AuthzGrantsData> => {\n const [grants, roles, resources] = await Promise.all([store.listGrants(), store.listRoles(), store.listResources()])\n return { grants, roles, resources, labels }\n }\n const userRolesData = async (userId?: string | number): Promise<AuthzUserRolesData> => {\n const [assignments, roles, users, self] = await Promise.all([store.listUserRoles(), store.listRoles(), store.listUsers(), store.getSelfAdminContext(Number(userId))])\n return { assignments, roles, users, actorUserId: self.actorUserId, selfAdminRoleIds: self.selfAdminRoleIds, labels }\n }\n\n return {\n /** 露出: スプラットマウント(app.ts)がガードを 1 回だけ行うために使う。 */\n labels,\n resourceKey: RES,\n layoutGuard,\n loadMyPermissions,\n\n /** /authz レイアウト: requireUser(302) → requirePermission(read, 403) → 自己権限取得。 */\n layout: {\n async loader({ request }: Req): Promise<AuthzLayoutData> {\n await layoutGuard(request)\n return { myPermissions: await loadMyPermissions(request), labels, adminResourceKey: RES }\n },\n },\n\n /** /authz index → roles へ。 */\n index: {\n loader() {\n throw redirect(\"/authz/roles\")\n },\n },\n\n roles: {\n data: rolesData,\n async loader({ request }: Req): Promise<AuthzRolesData> {\n const { userId } = await requirePermission(request, { resourceKey: RES, action: \"read\" })\n return rolesData(userId)\n },\n async action({ request }: Req) {\n const form = await request.formData()\n const intent = String(form.get(\"_action\"))\n try {\n switch (intent) {\n case \"create\": {\n const { userId } = await requirePermission(request, { resourceKey: RES, action: \"create\" })\n const roleKey = String(form.get(\"roleKey\") ?? \"\").trim()\n const name = String(form.get(\"name\") ?? \"\").trim()\n if (!(roleKey && name)) return data({ error: \"role_key と name は必須です\" }, { status: 400 })\n await store.createRole({ roleKey, name, description: String(form.get(\"description\") ?? \"\").trim() || null }, String(userId))\n return { ok: true }\n }\n case \"save\": {\n const { userId } = await requirePermission(request, { resourceKey: RES, action: \"update\" })\n const roleKey = String(form.get(\"roleKey\") ?? \"\").trim()\n const name = String(form.get(\"name\") ?? \"\").trim()\n if (!(roleKey && name)) return data({ error: \"roleKey と name は必須です\" }, { status: 400 })\n await store.updateRole(Number(form.get(\"id\")), { roleKey, name, description: String(form.get(\"description\") ?? \"\").trim() || null }, String(userId))\n return { ok: true }\n }\n case \"toggle\": {\n const { userId } = await requirePermission(request, { resourceKey: RES, action: \"update\" })\n await store.setRoleActive(Number(form.get(\"id\")), form.get(\"isActive\") === \"true\", String(userId))\n return { ok: true }\n }\n case \"delete\": {\n await requirePermission(request, { resourceKey: RES, action: \"delete\" })\n await store.deleteRole(Number(form.get(\"id\")))\n return { ok: true }\n }\n default:\n return data({ error: \"unknown action\" }, { status: 400 })\n }\n } catch (e) {\n return toActionError(e)\n }\n },\n },\n\n resources: {\n data: resourcesData,\n async loader({ request }: Req): Promise<AuthzResourcesData> {\n await requirePermission(request, { resourceKey: RES, action: \"read\" })\n return resourcesData()\n },\n async action({ request }: Req) {\n const form = await request.formData()\n const intent = String(form.get(\"_action\"))\n try {\n switch (intent) {\n case \"create\": {\n const { userId } = await requirePermission(request, { resourceKey: RES, action: \"create\" })\n const appKey = String(form.get(\"appKey\") ?? \"\").trim()\n const resourceKey = String(form.get(\"resourceKey\") ?? \"\").trim()\n const name = String(form.get(\"name\") ?? \"\").trim()\n if (!(appKey && resourceKey && name)) return data({ error: \"app_key / resource_key / name は必須です\" }, { status: 400 })\n await store.createResource({ appKey, resourceKey, name, description: String(form.get(\"description\") ?? \"\").trim() || null }, String(userId))\n return { ok: true }\n }\n case \"save\": {\n const { userId } = await requirePermission(request, { resourceKey: RES, action: \"update\" })\n const name = String(form.get(\"name\") ?? \"\").trim()\n if (!name) return data({ error: \"name は必須です\" }, { status: 400 })\n await store.updateResource(Number(form.get(\"id\")), { name, description: String(form.get(\"description\") ?? \"\").trim() || null }, String(userId))\n return { ok: true }\n }\n case \"delete\": {\n await requirePermission(request, { resourceKey: RES, action: \"delete\" })\n await store.deleteResource(Number(form.get(\"id\")))\n return { ok: true }\n }\n default:\n return data({ error: \"unknown action\" }, { status: 400 })\n }\n } catch (e) {\n return toActionError(e)\n }\n },\n },\n\n grants: {\n data: grantsData,\n async loader({ request }: Req): Promise<AuthzGrantsData> {\n await requirePermission(request, { resourceKey: RES, action: \"read\" })\n return grantsData()\n },\n async action({ request }: Req) {\n const form = await request.formData()\n const intent = String(form.get(\"_action\"))\n try {\n switch (intent) {\n case \"create\": {\n const { userId } = await requirePermission(request, { resourceKey: RES, action: \"create\" })\n const roleId = Number(form.get(\"roleId\"))\n const resourceId = Number(form.get(\"resourceId\"))\n if (!(roleId && resourceId)) return data({ error: \"ロールとリソースを選択してください\" }, { status: 400 })\n const rawAction = String(form.get(\"action\") ?? \"\")\n if (!(AUTHZ_ACTIONS as readonly string[]).includes(rawAction)) return data({ error: \"無効な action です\" }, { status: 400 })\n const action = rawAction as AuthzAction\n await store.createGrant({ roleId, resourceId, action, rowScope: String(form.get(\"rowScope\") ?? \"\"), columnScope: String(form.get(\"columnScope\") ?? \"\") }, String(userId))\n return { ok: true }\n }\n case \"save\": {\n const { userId } = await requirePermission(request, { resourceKey: RES, action: \"update\" })\n const rawAction = String(form.get(\"action\") ?? \"\")\n if (!(AUTHZ_ACTIONS as readonly string[]).includes(rawAction)) return data({ error: \"無効な action です\" }, { status: 400 })\n const action = rawAction as AuthzAction\n await store.updateGrant(Number(form.get(\"id\")), { action, rowScope: String(form.get(\"rowScope\") ?? \"\"), columnScope: String(form.get(\"columnScope\") ?? \"\") }, String(userId))\n return { ok: true }\n }\n case \"delete\": {\n await requirePermission(request, { resourceKey: RES, action: \"delete\" })\n await store.deleteGrant(Number(form.get(\"id\")))\n return { ok: true }\n }\n default:\n return data({ error: \"unknown action\" }, { status: 400 })\n }\n } catch (e) {\n return toActionError(e)\n }\n },\n },\n\n userRoles: {\n data: userRolesData,\n async loader({ request }: Req): Promise<AuthzUserRolesData> {\n const { userId } = await requirePermission(request, { resourceKey: RES, action: \"read\" })\n return userRolesData(userId)\n },\n async action({ request }: Req) {\n const form = await request.formData()\n const intent = String(form.get(\"_action\"))\n try {\n switch (intent) {\n case \"assign\": {\n const { userId: actor } = await requirePermission(request, { resourceKey: RES, action: \"create\" })\n const userId = Number(form.get(\"userId\"))\n const roleId = Number(form.get(\"roleId\"))\n if (!(userId && roleId)) return data({ error: \"ユーザーとロールを選択してください\" }, { status: 400 })\n await store.assignUserRole(userId, roleId, String(actor))\n return { ok: true }\n }\n case \"remove\": {\n await requirePermission(request, { resourceKey: RES, action: \"delete\" })\n await store.removeUserRole(Number(form.get(\"userId\")), Number(form.get(\"roleId\")))\n return { ok: true }\n }\n default:\n return data({ error: \"unknown action\" }, { status: 400 })\n }\n } catch (e) {\n return toActionError(e)\n }\n },\n },\n }\n}\n","/** Authz admin UI strings (i18n). Defaults are English; override per-section via `createAuthzAdminRoutes(..., { labels })`. */\nexport type AuthzAdminLabels = {\n title: string\n myPermission: string\n tabs: { roles: string; resources: string; role_permissions: string; user_roles: string }\n common: { add: string; save: string; delete: string; remove: string; assign: string; grant: string; select: string; active: string; inactive: string; optional: string }\n roles: { heading: string; note: string; roleKey: string; name: string; description: string; activeHeader: string; empty: string; newHeading: string; hintRoleKey: string }\n resources: { heading: string; note: string; appKey: string; resourceKey: string; name: string; description: string; empty: string; newHeading: string; hintAppKey: string; hintResourceKey: string; hintDailyReport: string }\n grants: {\n heading: string\n note: string\n role: string\n resource: string\n action: string\n rowScope: string\n columnScope: string\n empty: string\n newHeading: string\n rowScopeHint: string\n columnScopeHint: string\n rowScopePlaceholder: string\n columnScopePlaceholder: string\n nullRows: string\n nullCols: string\n selectPlaceholder: string\n }\n userRoles: { heading: string; note: string; user: string; role: string; empty: string; newHeading: string; selectPlaceholder: string }\n error: { forbiddenTitle: string; forbiddenBody: string; genericTitlePrefix: string; genericTitle: string; genericBody: string }\n warn: { selfRoleDisable: string; selfRoleDelete: string; selfAssignmentRemove: string }\n}\n\nexport const defaultAuthzAdminLabels: AuthzAdminLabels = {\n title: \"Authorization (RBAC)\",\n myPermission: \"Your permissions\",\n tabs: { roles: \"Roles\", resources: \"Resources\", role_permissions: \"Permissions\", user_roles: \"User assignments\" },\n common: { add: \"Add\", save: \"Save\", delete: \"Delete\", remove: \"Remove\", assign: \"Assign\", grant: \"Grant\", select: \"Select…\", active: \"○ Enabled\", inactive: \"× Disabled\", optional: \"optional\" },\n roles: {\n heading: \"Roles (TMRole)\",\n note: \"Edit name / description inline and click Save (role_key is an immutable identifier).\",\n roleKey: \"role_key\",\n name: \"name\",\n description: \"description\",\n activeHeader: \"Active\",\n empty: \"No roles\",\n newHeading: \"New role\",\n hintRoleKey: \"e.g. admin\",\n },\n resources: {\n heading: \"Resources (TMResource)\",\n note: \"Edit name / description inline and click Save (app_key / resource_key are immutable identifiers).\",\n appKey: \"app_key\",\n resourceKey: \"resource_key\",\n name: \"name\",\n description: \"description\",\n empty: \"No resources\",\n newHeading: \"New resource\",\n hintAppKey: \"e.g. quants\",\n hintResourceKey: \"e.g. daily_report\",\n hintDailyReport: \"optional\",\n },\n grants: {\n heading: \"Permissions (TDRolePermission)\",\n note: \"Empty row_scope / column_scope = all rows / all columns (NULL). JSON must satisfy the §3.2 contract.\",\n role: \"role\",\n resource: \"resource\",\n action: \"action\",\n rowScope: \"row_scope\",\n columnScope: \"column_scope\",\n empty: \"No permissions\",\n newHeading: \"Grant a permission\",\n rowScopeHint: \"JSON / empty = all rows\",\n columnScopeHint: \"JSON / empty = all columns\",\n rowScopePlaceholder: \"empty = all rows (NULL)\",\n columnScopePlaceholder: \"empty = all columns (NULL)\",\n nullRows: \"NULL (all rows)\",\n nullCols: \"NULL (all columns)\",\n selectPlaceholder: \"Select…\",\n },\n 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…\" },\n error: {\n forbiddenTitle: \"Access denied\",\n forbiddenBody: \"You don't have permission to view this screen. Ask an administrator to grant access.\",\n genericTitlePrefix: \"Error\",\n genericTitle: \"An error occurred\",\n genericBody: \"An unexpected error occurred. Please try again later.\",\n },\n warn: {\n selfRoleDisable: \"This role backs your own authorization-admin access. Disabling it may lock you out of this screen. Continue?\",\n selfRoleDelete: \"This role backs your own authorization-admin access. Deleting it may lock you out of this screen. Continue?\",\n selfAssignmentRemove: \"This assignment backs your own authorization-admin access. Removing it may lock you out of this screen. Continue?\",\n },\n}\n\nexport type PartialAuthzAdminLabels = {\n title?: string\n myPermission?: string\n tabs?: Partial<AuthzAdminLabels[\"tabs\"]>\n common?: Partial<AuthzAdminLabels[\"common\"]>\n roles?: Partial<AuthzAdminLabels[\"roles\"]>\n resources?: Partial<AuthzAdminLabels[\"resources\"]>\n grants?: Partial<AuthzAdminLabels[\"grants\"]>\n userRoles?: Partial<AuthzAdminLabels[\"userRoles\"]>\n error?: Partial<AuthzAdminLabels[\"error\"]>\n warn?: Partial<AuthzAdminLabels[\"warn\"]>\n}\n\n/** Shallow per-section merge over the English defaults. */\nexport function resolveLabels(over?: PartialAuthzAdminLabels): AuthzAdminLabels {\n const d = defaultAuthzAdminLabels\n if (!over) return d\n return {\n title: over.title ?? d.title,\n myPermission: over.myPermission ?? d.myPermission,\n tabs: { ...d.tabs, ...over.tabs },\n common: { ...d.common, ...over.common },\n roles: { ...d.roles, ...over.roles },\n resources: { ...d.resources, ...over.resources },\n grants: { ...d.grants, ...over.grants },\n userRoles: { ...d.userRoles, ...over.userRoles },\n error: { ...d.error, ...over.error },\n warn: { ...d.warn, ...over.warn },\n }\n}\n","/** 認可管理UI 共有のプレゼンテーション部品・スタイル。 */\nimport type { CSSProperties, ReactNode } from \"react\"\n\nexport const ui: Record<string, CSSProperties> = {\n page: { padding: \"1.25rem\", maxWidth: 1280, margin: \"0 auto\", color: \"#0f172a\" },\n tableContainer: { width: \"100%\", overflowX: \"auto\", marginBottom: \"1rem\", WebkitOverflowScrolling: \"touch\" },\n table: { borderCollapse: \"collapse\", width: \"100%\", fontSize: \"0.9rem\", tableLayout: \"fixed\" },\n th: { textAlign: \"left\", borderBottom: \"2px solid #e2e8f0\", padding: \"0.45rem 0.65rem\", fontSize: \"0.78rem\", color: \"#475569\", fontWeight: 600, textTransform: \"uppercase\", letterSpacing: \"0.03em\" },\n td: { borderBottom: \"1px solid #f1f5f9\", padding: \"0.5rem 0.65rem\", verticalAlign: \"middle\", wordBreak: \"break-all\" },\n input: { padding: \"0.4rem 0.55rem\", border: \"1px solid #cbd5e1\", borderRadius: 6, fontSize: \"0.9rem\", background: \"#fff\", width: \"100%\", boxSizing: \"border-box\" },\n select: { padding: \"0.4rem 0.55rem\", border: \"1px solid #cbd5e1\", borderRadius: 6, fontSize: \"0.9rem\", background: \"#fff\", width: \"100%\", boxSizing: \"border-box\" },\n 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\" },\n button: { padding: \"0.3rem 0.7rem\", border: \"1px solid #cbd5e1\", borderRadius: 6, background: \"#fff\", cursor: \"pointer\", fontSize: \"0.82rem\", color: \"#334155\" },\n save: { padding: \"0.3rem 0.7rem\", border: \"1px solid #2563eb\", borderRadius: 6, background: \"#eff6ff\", cursor: \"pointer\", fontSize: \"0.82rem\", color: \"#2563eb\", fontWeight: 600 },\n danger: { padding: \"0.3rem 0.7rem\", border: \"1px solid #fecaca\", borderRadius: 6, background: \"#fff\", cursor: \"pointer\", fontSize: \"0.82rem\", color: \"#dc2626\" },\n 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\" },\n 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\" },\n code: { fontFamily: \"ui-monospace, SFMono-Regular, Menlo, monospace\", fontSize: \"0.78rem\", color: \"#334155\", wordBreak: \"break-all\" },\n muted: { color: \"#94a3b8\" },\n h2: { fontSize: \"1.05rem\", margin: \"0 0 0.35rem\", fontWeight: 700 },\n h3: { fontSize: \"0.92rem\", margin: \"1.25rem 0 0\", color: \"#334155\", fontWeight: 600 },\n note: { color: \"#64748b\", fontSize: \"0.82rem\", margin: \"0 0 0.75rem\" },\n empty: { color: \"#94a3b8\", padding: \"0.75rem 0.65rem\" },\n}\n\n/**\n * ラベルを上、コントロールを下に縦積みするフィールド(重なり防止・一貫レイアウト)。\n * コントロール側は `aria-label` を持つ前提なので `<div>` で構成する。\n */\nexport function Field({ label, hint, children }: { label: string; hint?: string; children: ReactNode }) {\n return (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"0.3rem\" }}>\n <span style={{ fontSize: \"0.8rem\", color: \"#475569\", fontWeight: 600 }}>\n {label}\n {hint ? <span style={{ fontWeight: 400, color: \"#94a3b8\" }}> — {hint}</span> : null}\n </span>\n {children}\n </div>\n )\n}\n\n/** エラー表示(role=\"alert\")。 */\nexport function ErrorAlert({ message }: { message?: string }) {\n if (!message) return null\n return (\n <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\" }}>\n {message}\n </p>\n )\n}\n","/**\n * 認可管理 UI のプレゼンテーション部品(client-safe)。\n * loader データ(行 + ラベル + 自己管理者ヒント)を `useLoaderData` で受け取り描画する。\n * DB/ストアには一切依存しない(サーバ結線は admin/server.ts)。\n */\nimport { AUTHZ_ACTIONS, type AuthzAssignment, type AuthzGrant, type AuthzResource, type AuthzRole, type AuthzUser } from \"@aiquants/authz-core\"\nimport { SelectBox } from \"@aiquants/select-box\"\nimport { useState } from \"react\"\nimport { Form, isRouteErrorResponse, NavLink, Outlet, useActionData, useLoaderData, useRouteError } from \"react-router\"\nimport { MyPermissionIndicator, MyPermissionStatus } from \"../MyPermissionIndicator\"\nimport type { PermissionView } from \"../server\"\nimport { type AuthzAdminLabels, type PartialAuthzAdminLabels, resolveLabels } from \"./labels\"\nimport { ErrorAlert, Field, ui } from \"./ui\"\n\ntype WithLabels = { labels: AuthzAdminLabels }\ntype ActionError = { error?: string } | undefined\nconst actionError = (d: ActionError) => d?.error\n\n// ============================ Layout ============================\n\nexport type AuthzLayoutData = WithLabels & { myPermissions: Record<string, PermissionView>; adminResourceKey: string; basePath?: string }\n\n/** ヘッダ(タイトル + あなたの権限) + タブ。中身は children(splat) か Outlet(ネスト)。 */\nfunction AuthzLayoutShell({ children }: { children: React.ReactNode }) {\n const { myPermissions, labels, adminResourceKey, basePath } = useLoaderData() as AuthzLayoutData\n const base = basePath ?? \"/authz\"\n const tabs: ReadonlyArray<readonly [string, string]> = [\n [\"roles\", labels.tabs.roles],\n [\"resources\", labels.tabs.resources],\n [\"role_permissions\", labels.tabs.role_permissions],\n [\"user_roles\", labels.tabs.user_roles],\n ]\n return (\n <div className=\"authz-admin\" style={ui.page}>\n <header style={{ display: \"flex\", alignItems: \"baseline\", justifyContent: \"space-between\", gap: \"1rem\", flexWrap: \"wrap\" }}>\n <h1 style={{ fontSize: \"1.3rem\", margin: 0, fontWeight: 700 }}>{labels.title}</h1>\n <MyPermissionStatus\n prefixLabel={labels.myPermission}\n permission={myPermissions[adminResourceKey]}\n resourceName={adminResourceKey}\n />\n </header>\n <nav style={{ display: \"flex\", gap: \"0.25rem\", borderBottom: \"1px solid #e2e8f0\", margin: \"0.9rem 0 1.25rem\" }}>\n {tabs.map(([key, label]) => (\n <NavLink\n key={key}\n to={`${base}/${key}`}\n style={({ isActive }) => ({\n padding: \"0.5rem 0.9rem\",\n textDecoration: \"none\",\n color: isActive ? \"#2563eb\" : \"#475569\",\n borderBottom: isActive ? \"2px solid #2563eb\" : \"2px solid transparent\",\n marginBottom: -1,\n fontWeight: isActive ? 700 : 500,\n fontSize: \"0.92rem\",\n })}>\n {label}\n </NavLink>\n ))}\n </nav>\n {children}\n </div>\n )\n}\n\n/** ネストルート用レイアウト(子は Outlet)。`routes.ts` でネスト構成にする場合に使う。 */\nexport function AuthzLayout() {\n return (\n <AuthzLayoutShell>\n <Outlet />\n </AuthzLayoutShell>\n )\n}\n\n/**\n * 認可管理 UI のエラー境界。ErrorBoundary は loader データを読めないため、ラベルは\n * `makeAuthzErrorBoundary(labels)` で注入する(アプリは自分のロケールで生成する)。\n * 既定の `AuthzErrorBoundary` は英語(パッケージ既定)。\n */\nexport function makeAuthzErrorBoundary(over?: PartialAuthzAdminLabels): () => React.ReactElement {\n const L = resolveLabels(over).error\n return function AuthzErrorBoundary() {\n const error = useRouteError()\n const routeError = isRouteErrorResponse(error) ? error : null\n const is403 = routeError?.status === 403\n const title = is403 ? L.forbiddenTitle : routeError ? `${L.genericTitlePrefix} (${routeError.status})` : L.genericTitle\n const message = is403 ? L.forbiddenBody : routeError ? (typeof routeError.data === \"string\" && routeError.data ? routeError.data : routeError.statusText) : L.genericBody\n return (\n <div style={ui.page}>\n <div role=\"alert\" style={{ maxWidth: 480, margin: \"3rem auto\", padding: \"1.5rem\", border: \"1px solid #fecaca\", borderRadius: 12, background: \"#fef2f2\" }}>\n <h1 style={{ fontSize: \"1.1rem\", fontWeight: 700, color: \"#b91c1c\", margin: \"0 0 0.5rem\" }}>{title}</h1>\n <p style={{ color: \"#7f1d1d\", fontSize: \"0.9rem\", margin: 0, lineHeight: 1.7 }}>{message}</p>\n </div>\n </div>\n )\n }\n}\n\n/** 英語(既定ラベル)のエラー境界。i18n したい場合は {@link makeAuthzErrorBoundary} を使う。 */\nexport const AuthzErrorBoundary = makeAuthzErrorBoundary()\n\n/** 自分の管理権限を支える対象への破壊操作前に警告(キャンセルで送信中止)。 */\nconst confirmGuard = (active: boolean, message: string) => (e: React.MouseEvent) => {\n if (active && !window.confirm(message)) e.preventDefault()\n}\n\n// ============================ Roles ============================\n\nexport type AuthzRolesData = WithLabels & { roles: AuthzRole[]; selfAdminRoleIds?: number[] }\n\nexport function AuthzRolesView() {\n const { roles, selfAdminRoleIds, labels } = useLoaderData() as AuthzRolesData\n const L = labels.roles\n const C = labels.common\n const selfAdmin = new Set(selfAdminRoleIds ?? [])\n return (\n <section>\n <h2 style={ui.h2}>{L.heading}</h2>\n <ErrorAlert message={actionError(useActionData() as ActionError)} />\n <p style={ui.note}>{L.note}</p>\n <div style={ui.tableContainer}>\n <table style={ui.table}>\n <thead>\n <tr>\n <th style={{ ...ui.th, width: \"20%\" }}>{L.roleKey}</th>\n <th style={{ ...ui.th, width: \"25%\" }}>{L.name}</th>\n <th style={{ ...ui.th, width: \"35%\" }}>{L.description}</th>\n <th style={{ ...ui.th, width: \"10%\" }}>{L.activeHeader}</th>\n <th style={{ ...ui.th, width: \"10%\" }} />\n </tr>\n </thead>\n <tbody>\n {roles.map((r) => (\n <tr key={r.id}>\n <td style={ui.td}>\n {r.roleKey === \"@authenticated\" || r.roleKey === \"@anonymous\" ? <span style={ui.code}>{r.roleKey}</span> : <input name=\"roleKey\" defaultValue={r.roleKey} form={`save-role-${r.id}`} aria-label={`roleKey-${r.id}`} required style={ui.input} />}\n </td>\n <td style={ui.td}>\n <input name=\"name\" defaultValue={r.name} form={`save-role-${r.id}`} aria-label={`name-${r.id}`} required style={ui.input} />\n </td>\n <td style={ui.td}>\n <input name=\"description\" defaultValue={r.description ?? \"\"} form={`save-role-${r.id}`} aria-label={`description-${r.id}`} style={ui.input} />\n </td>\n <td style={ui.td}>\n <Form method=\"post\" style={{ display: \"inline\" }}>\n <input type=\"hidden\" name=\"_action\" value=\"toggle\" />\n <input type=\"hidden\" name=\"id\" value={r.id} />\n <input type=\"hidden\" name=\"isActive\" value={String(!r.isActive)} />\n <button type=\"submit\" style={ui.button} onClick={r.isActive ? confirmGuard(selfAdmin.has(r.id), labels.warn.selfRoleDisable) : undefined}>\n {r.isActive ? C.active : C.inactive}\n </button>\n </Form>\n </td>\n <td style={{ ...ui.td, whiteSpace: \"nowrap\" }}>\n <Form method=\"post\" id={`save-role-${r.id}`} style={{ display: \"inline\" }}>\n <input type=\"hidden\" name=\"_action\" value=\"save\" />\n <input type=\"hidden\" name=\"id\" value={r.id} />\n <button type=\"submit\" style={ui.save}>\n {C.save}\n </button>\n </Form>\n <Form method=\"post\" style={{ display: \"inline\", marginLeft: \"0.4rem\" }}>\n <input type=\"hidden\" name=\"_action\" value=\"delete\" />\n <input type=\"hidden\" name=\"id\" value={r.id} />\n <button type=\"submit\" style={ui.danger} onClick={confirmGuard(selfAdmin.has(r.id), labels.warn.selfRoleDelete)}>\n {C.delete}\n </button>\n </Form>\n </td>\n </tr>\n ))}\n {roles.length === 0 ? (\n <tr>\n <td style={ui.empty} colSpan={5}>\n {L.empty}\n </td>\n </tr>\n ) : null}\n </tbody>\n </table>\n </div>\n\n <h3 style={ui.h3}>{L.newHeading}</h3>\n <Form method=\"post\" style={ui.card}>\n <input type=\"hidden\" name=\"_action\" value=\"create\" />\n <Field label={L.roleKey} hint={L.hintRoleKey}>\n <input name=\"roleKey\" aria-label=\"role_key\" required style={ui.input} />\n </Field>\n <Field label={L.name}>\n <input name=\"name\" aria-label=\"name\" required style={ui.input} />\n </Field>\n <Field label={L.description} hint={C.optional}>\n <input name=\"description\" aria-label=\"description\" style={ui.input} />\n </Field>\n <button type=\"submit\" style={ui.primary}>\n {C.add}\n </button>\n </Form>\n </section>\n )\n}\n\n// ============================ Resources ============================\n\nexport type AuthzResourcesData = WithLabels & { resources: AuthzResource[] }\n\nexport function AuthzResourcesView() {\n const { resources, labels } = useLoaderData() as AuthzResourcesData\n const L = labels.resources\n const C = labels.common\n return (\n <section>\n <h2 style={ui.h2}>{L.heading}</h2>\n <ErrorAlert message={actionError(useActionData() as ActionError)} />\n <p style={ui.note}>{L.note}</p>\n <div style={ui.tableContainer}>\n <table style={ui.table}>\n <thead>\n <tr>\n <th style={{ ...ui.th, width: \"15%\" }}>{L.appKey}</th>\n <th style={{ ...ui.th, width: \"20%\" }}>{L.resourceKey}</th>\n <th style={{ ...ui.th, width: \"25%\" }}>{L.name}</th>\n <th style={{ ...ui.th, width: \"30%\" }}>{L.description}</th>\n <th style={{ ...ui.th, width: \"10%\" }} />\n </tr>\n </thead>\n <tbody>\n {resources.map((r) => (\n <tr key={r.id}>\n <td style={ui.td}>\n <span style={ui.code}>{r.appKey}</span>\n </td>\n <td style={ui.td}>\n <span style={ui.code}>{r.resourceKey}</span>\n </td>\n <td style={ui.td}>\n <input name=\"name\" defaultValue={r.name} form={`save-res-${r.id}`} aria-label={`name-${r.id}`} required style={ui.input} />\n </td>\n <td style={ui.td}>\n <input name=\"description\" defaultValue={r.description ?? \"\"} form={`save-res-${r.id}`} aria-label={`description-${r.id}`} style={ui.input} />\n </td>\n <td style={{ ...ui.td, whiteSpace: \"nowrap\" }}>\n <Form method=\"post\" id={`save-res-${r.id}`} style={{ display: \"inline\" }}>\n <input type=\"hidden\" name=\"_action\" value=\"save\" />\n <input type=\"hidden\" name=\"id\" value={r.id} />\n <button type=\"submit\" style={ui.save}>\n {C.save}\n </button>\n </Form>\n <Form method=\"post\" style={{ display: \"inline\", marginLeft: \"0.4rem\" }}>\n <input type=\"hidden\" name=\"_action\" value=\"delete\" />\n <input type=\"hidden\" name=\"id\" value={r.id} />\n <button type=\"submit\" style={ui.danger}>\n {C.delete}\n </button>\n </Form>\n </td>\n </tr>\n ))}\n {resources.length === 0 ? (\n <tr>\n <td style={ui.empty} colSpan={5}>\n {L.empty}\n </td>\n </tr>\n ) : null}\n </tbody>\n </table>\n </div>\n\n <h3 style={ui.h3}>{L.newHeading}</h3>\n <Form method=\"post\" style={ui.card}>\n <input type=\"hidden\" name=\"_action\" value=\"create\" />\n <Field label={L.appKey} hint={L.hintAppKey}>\n <input name=\"appKey\" aria-label=\"app_key\" required style={ui.input} />\n </Field>\n <Field label={L.resourceKey} hint={L.hintResourceKey}>\n <input name=\"resourceKey\" aria-label=\"resource_key\" required style={ui.input} />\n </Field>\n <Field label={L.name}>\n <input name=\"name\" aria-label=\"name\" required style={ui.input} />\n </Field>\n <Field label={L.description} hint={C.optional}>\n <input name=\"description\" aria-label=\"description\" style={ui.input} />\n </Field>\n <button type=\"submit\" style={ui.primary}>\n {C.add}\n </button>\n </Form>\n </section>\n )\n}\n\n// ============================ Grants (role_permissions) ============================\n\nexport type AuthzGrantsData = WithLabels & { grants: AuthzGrant[]; roles: Array<{ id: number; roleKey: string }>; resources: Array<{ id: number; appKey: string; resourceKey: string }> }\n\nfunction GrantRow({ g, labels }: { g: AuthzGrant; labels: AuthzAdminLabels }) {\n const C = labels.common\n const [action, setAction] = useState<{ label: string; value: string }>({ label: g.action, value: g.action })\n\n return (\n <tr>\n <td style={ui.td}>\n <span style={ui.code}>{g.roleKey}</span>\n </td>\n <td style={ui.td}>\n <span style={ui.code}>\n {g.appKey}:{g.resourceKey}\n </span>\n </td>\n <td style={ui.td}>\n {g.roleKey === \"@anonymous\" ? (\n <span style={ui.code}>{g.action}</span>\n ) : (\n <>\n <input type=\"hidden\" name=\"action\" value={action.value} form={`save-grant-${g.id}`} />\n <SelectBox\n options={AUTHZ_ACTIONS.map((a) => ({ label: a, value: a }))}\n value={action}\n onChange={(val) => {\n if (val) setAction(val as { label: string; value: string })\n }}\n />\n </>\n )}\n </td>\n <td style={ui.td}>\n <textarea name=\"rowScope\" defaultValue={g.rowScope ?? \"\"} form={`save-grant-${g.id}`} aria-label={`row_scope-${g.id}`} rows={2} placeholder={labels.grants.rowScopePlaceholder} style={ui.textarea} />\n </td>\n <td style={ui.td}>\n <textarea name=\"columnScope\" defaultValue={g.columnScope ?? \"\"} form={`save-grant-${g.id}`} aria-label={`column_scope-${g.id}`} rows={2} placeholder={labels.grants.columnScopePlaceholder} style={ui.textarea} />\n </td>\n <td style={{ ...ui.td, whiteSpace: \"nowrap\" }}>\n <Form method=\"post\" id={`save-grant-${g.id}`} style={{ display: \"inline\" }}>\n <input type=\"hidden\" name=\"_action\" value=\"save\" />\n <input type=\"hidden\" name=\"id\" value={g.id} />\n <button type=\"submit\" style={ui.save}>\n {C.save}\n </button>\n </Form>\n <Form method=\"post\" style={{ display: \"inline\", marginLeft: \"0.4rem\" }}>\n <input type=\"hidden\" name=\"_action\" value=\"delete\" />\n <input type=\"hidden\" name=\"id\" value={g.id} />\n <button type=\"submit\" style={ui.danger}>\n {C.delete}\n </button>\n </Form>\n </td>\n </tr>\n )\n}\n\nexport function AuthzGrantsView() {\n const { grants, roles, resources, labels } = useLoaderData() as AuthzGrantsData\n const L = labels.grants\n const C = labels.common\n\n const roleOptions = roles.map((r) => ({ label: r.roleKey, value: r.id }))\n const resourceOptions = resources.map((r) => ({ label: `${r.appKey}:${r.resourceKey}`, value: r.id }))\n const actionOptions = AUTHZ_ACTIONS.map((a) => ({ label: a, value: a }))\n\n const [selectedRole, setSelectedRole] = useState<{ label: string; value: number } | undefined>(undefined)\n const [selectedResource, setSelectedResource] = useState<{ label: string; value: number } | undefined>(undefined)\n const [selectedAction, setSelectedAction] = useState<{ label: string; value: string } | undefined>({ label: \"read\", value: \"read\" })\n\n return (\n <section>\n <h2 style={ui.h2}>{L.heading}</h2>\n <p style={ui.note}>{L.note}</p>\n <ErrorAlert message={actionError(useActionData() as ActionError)} />\n <div style={ui.tableContainer}>\n <table style={ui.table}>\n <thead>\n <tr>\n <th style={{ ...ui.th, width: \"15%\" }}>{L.role}</th>\n <th style={{ ...ui.th, width: \"20%\" }}>{L.resource}</th>\n <th style={{ ...ui.th, width: \"15%\" }}>{L.action}</th>\n <th style={{ ...ui.th, width: \"20%\" }}>{L.rowScope}</th>\n <th style={{ ...ui.th, width: \"20%\" }}>{L.columnScope}</th>\n <th style={{ ...ui.th, width: \"10%\" }} />\n </tr>\n </thead>\n <tbody>\n {grants.map((g) => (\n <GrantRow key={g.id} g={g} labels={labels} />\n ))}\n {grants.length === 0 ? (\n <tr>\n <td style={ui.empty} colSpan={6}>\n {L.empty}\n </td>\n </tr>\n ) : null}\n </tbody>\n </table>\n </div>\n\n <h3 style={ui.h3}>{L.newHeading}</h3>\n <Form method=\"post\" style={ui.card}>\n <input type=\"hidden\" name=\"_action\" value=\"create\" />\n <input type=\"hidden\" name=\"roleId\" value={selectedRole?.value ?? \"\"} />\n <input type=\"hidden\" name=\"resourceId\" value={selectedResource?.value ?? \"\"} />\n <input type=\"hidden\" name=\"action\" value={selectedAction?.value ?? \"\"} />\n\n <Field label={L.role}>\n <SelectBox options={roleOptions} value={selectedRole} onChange={(val) => setSelectedRole((val || undefined) as { label: string; value: number } | undefined)} placeholder={L.selectPlaceholder} />\n </Field>\n <Field label={L.resource}>\n <SelectBox options={resourceOptions} value={selectedResource} onChange={(val) => setSelectedResource((val || undefined) as { label: string; value: number } | undefined)} placeholder={L.selectPlaceholder} />\n </Field>\n <Field label={L.action}>\n <SelectBox options={actionOptions} value={selectedAction} onChange={(val) => setSelectedAction((val || undefined) as { label: string; value: string } | undefined)} />\n </Field>\n <Field label={L.rowScope} hint={L.rowScopeHint}>\n <textarea name=\"rowScope\" aria-label=\"row_scope\" rows={2} style={ui.textarea} placeholder='{\"filters\":[{\"field\":\"部門CD\",\"op\":\"in\",\"values\":[\"A\"]}]}' />\n </Field>\n <Field label={L.columnScope} hint={L.columnScopeHint}>\n <textarea name=\"columnScope\" aria-label=\"column_scope\" rows={2} style={ui.textarea} placeholder='{\"mode\":\"deny\",\"columns\":[\"金額\"]}' />\n </Field>\n <button type=\"submit\" style={ui.primary}>\n {C.grant}\n </button>\n </Form>\n </section>\n )\n}\n\n// ============================ User roles ============================\n\nexport type AuthzUserRolesData = WithLabels & { assignments: AuthzAssignment[]; roles: Array<{ id: number; roleKey: string }>; users: AuthzUser[]; actorUserId?: number; selfAdminRoleIds?: number[] }\n\nexport function AuthzUserRolesView() {\n const { assignments, roles, users, actorUserId, selfAdminRoleIds, labels } = useLoaderData() as AuthzUserRolesData\n const L = labels.userRoles\n const C = labels.common\n const selfAdmin = new Set(selfAdminRoleIds ?? [])\n\n const userOptions = users.map((u) => ({ label: `${u.email}(${u.displayName})`, value: u.id }))\n const roleOptions = roles.filter((r) => r.roleKey !== \"@authenticated\" && r.roleKey !== \"@anonymous\").map((r) => ({ label: r.roleKey, value: r.id }))\n\n const [selectedUser, setSelectedUser] = useState<{ label: string; value: number } | undefined>(undefined)\n const [selectedRole, setSelectedRole] = useState<{ label: string; value: number } | undefined>(undefined)\n\n return (\n <section>\n <h2 style={ui.h2}>{L.heading}</h2>\n <ErrorAlert message={actionError(useActionData() as ActionError)} />\n <p style={ui.note}>{L.note}</p>\n <div style={ui.tableContainer}>\n <table style={ui.table}>\n <thead>\n <tr>\n <th style={{ ...ui.th, width: \"45%\" }}>{L.user}</th>\n <th style={{ ...ui.th, width: \"45%\" }}>{L.role}</th>\n <th style={{ ...ui.th, width: \"10%\" }} />\n </tr>\n </thead>\n <tbody>\n {assignments.map((a) => (\n <tr key={`${a.userId}-${a.roleId}`}>\n <td style={ui.td}>\n {a.email}\n <span style={ui.muted}>({a.displayName})</span>\n </td>\n <td style={ui.td}>{a.roleKey}</td>\n <td style={ui.td}>\n <Form method=\"post\" style={{ display: \"inline\" }}>\n <input type=\"hidden\" name=\"_action\" value=\"remove\" />\n <input type=\"hidden\" name=\"userId\" value={a.userId} />\n <input type=\"hidden\" name=\"roleId\" value={a.roleId} />\n <button type=\"submit\" style={ui.danger} onClick={confirmGuard(a.userId === actorUserId && selfAdmin.has(a.roleId), labels.warn.selfAssignmentRemove)}>\n {C.remove}\n </button>\n </Form>\n </td>\n </tr>\n ))}\n {assignments.length === 0 ? (\n <tr>\n <td style={ui.empty} colSpan={3}>\n {L.empty}\n </td>\n </tr>\n ) : null}\n </tbody>\n </table>\n </div>\n\n <h3 style={ui.h3}>{L.newHeading}</h3>\n <Form method=\"post\" style={ui.card}>\n <input type=\"hidden\" name=\"_action\" value=\"assign\" />\n <input type=\"hidden\" name=\"userId\" value={selectedUser?.value ?? \"\"} />\n <input type=\"hidden\" name=\"roleId\" value={selectedRole?.value ?? \"\"} />\n <Field label={L.user}>\n <SelectBox options={userOptions} value={selectedUser} onChange={(val) => setSelectedUser((val || undefined) as { label: string; value: number } | undefined)} placeholder={L.selectPlaceholder} />\n </Field>\n <Field label={L.role}>\n <SelectBox options={roleOptions} value={selectedRole} onChange={(val) => setSelectedRole((val || undefined) as { label: string; value: number } | undefined)} placeholder={L.selectPlaceholder} />\n </Field>\n <button type=\"submit\" style={ui.primary}>\n {C.assign}\n </button>\n </Form>\n </section>\n )\n}\n\n// ============================ Single-file (splat) app view ============================\n\nconst SEGMENT_VIEWS: Record<string, () => React.ReactElement> = {\n roles: AuthzRolesView,\n resources: AuthzResourcesView,\n role_permissions: AuthzGrantsView,\n user_roles: AuthzUserRolesView,\n}\n\n/**\n * スプラット(`authz/*`)1 ルートで認可管理 UI 全体を描画するコンポーネント(store 非依存)。\n * loader が返す `segment` に応じて該当タブのビューを描画する。レイアウト殻と各ビューは同一の\n * loader データ(セグメントデータ + myPermissions + labels をトップレベルに統合)を読む。\n */\nexport function AuthzAdminAppView() {\n const { segment } = useLoaderData() as { segment: string }\n const View = SEGMENT_VIEWS[segment] ?? AuthzRolesView\n return (\n <AuthzLayoutShell>\n <View />\n </AuthzLayoutShell>\n )\n}\n","import type { PermissionView } from \"./server\"\n\nexport type PermState = \"full\" | \"partial\" | \"none\"\n\nexport type UsePermission = {\n canRead: boolean\n canWrite: boolean\n canDelete: boolean\n /** read: none(×) / partial(△, row|col restricted) / full(○). */\n readState: PermState\n /** write = create ∪ update: full(○ both) / partial(△ one) / none(×). */\n writeState: PermState\n deleteState: PermState\n}\n\n/**\n * Derive ○△× display states from a {@link PermissionView}. Pure (safe to call in render);\n * named `usePermission` for ergonomic call-sites.\n */\nexport function usePermission(view: PermissionView | null | undefined): UsePermission {\n const readState: PermState = !view?.read ? \"none\" : view.readPartial ? \"partial\" : \"full\"\n const writeState: PermState = view?.create && view?.update ? \"full\" : view?.create || view?.update ? \"partial\" : \"none\"\n const deleteState: PermState = view?.delete ? \"full\" : \"none\"\n return {\n canRead: !!view?.read,\n canWrite: !!view?.write,\n canDelete: !!view?.delete,\n readState,\n writeState,\n deleteState,\n }\n}\n","import type { PermissionView } from \"./server\"\nimport { type PermState, usePermission } from \"./usePermission\"\n\nexport type MyPermissionIndicatorProps = {\n permission: PermissionView | null | undefined\n /** Human-readable resource display name (e.g. \"文書データ\"). Falls back to permission.resourceKey. */\n resourceName?: string\n /** Expected resource key to detect mismatches with permission.resourceKey during development. */\n expectedResourceKey?: string\n /** Whether to include resource name/key tooltip. Default true. */\n showResourceTooltip?: boolean\n labels?: { read?: string; write?: string; delete?: string }\n /** Show a \"(部分)\" hint when read is partial. Default true. */\n showScopeSummary?: boolean\n className?: string\n}\n\nexport type MyPermissionStatusProps = MyPermissionIndicatorProps & {\n /** Label prefix shown before the indicator badges. Default: \"あなたの権限\" */\n prefixLabel?: string\n /** Whether to display the prefix label. Default: true */\n showPrefixLabel?: boolean\n /** Additional inline styles for wrapper element. */\n style?: React.CSSProperties\n}\n\nconst STATE_STYLE: Record<PermState, { bg: string; text: string; border: string }> = {\n full: { bg: \"#ecfdf5\", text: \"#047857\", border: \"#a7f3d0\" },\n partial: { bg: \"#fffbeb\", text: \"#b45309\", border: \"#fde68a\" },\n none: { bg: \"#f8fafc\", text: \"#94a3b8\", border: \"#cbd5e1\" },\n}\n\n/**\n * Format human-readable resource tooltip text.\n * リソース表示名およびキーからツールチップ用テキストを生成。\n */\nexport function formatResourceTooltip(resourceKey?: string, resourceName?: string): string | undefined {\n const key = resourceKey?.trim()\n const name = resourceName?.trim()\n if (name && key && name !== key) {\n return `対象リソース: ${name} (${key})`\n }\n if (name || key) {\n return `対象リソース: ${name || key}`\n }\n return undefined\n}\n\n/**\n * Render icon according to permission state.\n * 権限状態に応じた SVG アイコンをレンダリング。\n */\nfunction PermIcon({ state }: { state: PermState }) {\n if (state === \"full\") {\n return (\n <svg style={{ width: \"0.85rem\", height: \"0.85rem\", flexShrink: 0 }} fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n )\n }\n if (state === \"partial\") {\n return (\n <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\">\n <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\" />\n </svg>\n )\n }\n return (\n <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\">\n <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\" />\n </svg>\n )\n}\n\n/**\n * Display permission indicator badges for read, write, and delete capabilities.\n * 閲覧・編集・削除の権限状態バッジ群を描画。\n */\nexport function MyPermissionIndicator({\n permission,\n resourceName,\n expectedResourceKey,\n showResourceTooltip = true,\n labels,\n showScopeSummary = true,\n className = \"authz-permission-indicator\",\n}: MyPermissionIndicatorProps) {\n const p = usePermission(permission)\n const l = { read: labels?.read ?? \"閲覧\", write: labels?.write ?? \"編集\", delete: labels?.delete ?? \"削除\" }\n const resKey = permission?.resourceKey\n const resName = resourceName || resKey\n const tooltipText = showResourceTooltip ? formatResourceTooltip(resKey, resourceName) : undefined\n\n const hasMismatch = Boolean(expectedResourceKey && resKey && resKey !== expectedResourceKey)\n\n if (hasMismatch && typeof console !== \"undefined\" && typeof console.error === \"function\") {\n console.error(`[Authz Warning] Resource key mismatch in MyPermissionIndicator! Expected: \"${expectedResourceKey}\", but received permission for: \"${resKey}\".`)\n }\n\n const renderBadge = (key: \"read\" | \"write\" | \"delete\", state: PermState, label: string) => {\n const style = STATE_STYLE[state]\n const badgeTitle = tooltipText ? `${label}: ${state}\\n${tooltipText}` : `${label}: ${state}`\n return (\n <span\n data-perm={key}\n data-state={state}\n title={badgeTitle}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"0.25rem\",\n padding: \"0.2rem 0.5rem\",\n borderRadius: \"100px\",\n fontSize: \"0.75rem\",\n fontWeight: 600,\n backgroundColor: style.bg,\n color: style.text,\n border: `1px solid ${style.border}`,\n lineHeight: 1,\n userSelect: \"none\",\n }}>\n <PermIcon state={state} />\n <span>{label}</span>\n </span>\n )\n }\n\n return (\n <span\n className={className}\n title={tooltipText}\n data-resource={resKey ?? \"\"}\n data-resource-name={resName ?? \"\"}\n data-mismatch={hasMismatch ? \"true\" : undefined}\n style={{\n display: \"inline-flex\",\n gap: \"0.35rem\",\n alignItems: \"center\",\n verticalAlign: \"middle\",\n }}>\n {renderBadge(\"read\", p.readState, l.read)}\n {renderBadge(\"write\", p.writeState, l.write)}\n {renderBadge(\"delete\", p.deleteState, l.delete)}\n {showScopeSummary && p.readState === \"partial\" ? (\n <span\n data-perm=\"scope\"\n title={tooltipText}\n style={{\n fontSize: \"0.7rem\",\n color: \"#b45309\",\n backgroundColor: \"#fef3c7\",\n padding: \"0.15rem 0.35rem\",\n borderRadius: \"4px\",\n fontWeight: 600,\n }}>\n 部分制限\n </span>\n ) : null}\n {hasMismatch ? (\n <span\n data-testid=\"resource-mismatch-warning\"\n title={`expected: \"${expectedResourceKey}\", actual: \"${resKey}\"`}\n style={{\n fontSize: \"0.7rem\",\n color: \"#991b1b\",\n backgroundColor: \"#fee2e2\",\n border: \"1px solid #fca5a5\",\n padding: \"0.15rem 0.35rem\",\n borderRadius: \"4px\",\n fontWeight: 700,\n }}>\n ⚠️ リソース不一致 ({resKey} ≠ {expectedResourceKey})\n </span>\n ) : null}\n </span>\n )\n}\n\n/**\n * Reusable \"Your Permissions\" status bar component suitable for any application page.\n * 「あなたの権限」ラベルと権限状態インジケータを束ねた再利用可能なコンポーネント。\n */\nexport function MyPermissionStatus({\n permission,\n resourceName,\n expectedResourceKey,\n prefixLabel = \"あなたの権限\",\n showPrefixLabel = true,\n showResourceTooltip = true,\n labels,\n showScopeSummary = true,\n className = \"authz-permission-status\",\n style,\n}: MyPermissionStatusProps) {\n const resKey = permission?.resourceKey\n const resName = resourceName || resKey\n const tooltipText = showResourceTooltip ? formatResourceTooltip(resKey, resourceName) : undefined\n\n return (\n <span\n className={className}\n title={tooltipText}\n data-testid=\"my-permission-status\"\n data-resource={resKey ?? \"\"}\n data-resource-name={resName ?? \"\"}\n style={{\n fontSize: \"0.82rem\",\n color: \"#475569\",\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"0.4rem\",\n ...style,\n }}>\n {showPrefixLabel && <span data-testid=\"prefix-label\">{prefixLabel}:</span>}\n <MyPermissionIndicator\n permission={permission}\n resourceName={resourceName}\n expectedResourceKey={expectedResourceKey}\n showResourceTooltip={showResourceTooltip}\n labels={labels}\n showScopeSummary={showScopeSummary}\n />\n </span>\n )\n}\n","/**\n * Resource definition and registry utilities for preventing page-resource mismatches.\n * ページとリソースの表示・権限食い違いを防止するためのリソースレジストリ定義。\n */\n\nexport type ResourceDefinition = {\n /** Unique resource key used in authorization rules (e.g. \"documents\") */\n key: string\n /** Human-readable display name (e.g. \"文書管理\") */\n name: string\n /** Optional description for administration UI */\n description?: string\n}\n\nexport type ResourceRegistry<T extends Record<string, ResourceDefinition>> = T\n\n/**\n * Define type-safe resource registry for an application.\n * アプリ全体のリソース定義(キー・表示名・説明)を一元管理するヘルパー。\n */\nexport function defineResources<T extends Record<string, ResourceDefinition>>(resources: T): T {\n return resources\n}\n","import { type AuthzAction, can, createRequirePermission, type DenyInfo, type EffectivePermission, type GuardResult } from \"@aiquants/authz-core\"\nimport { redirect } from \"react-router\"\n\ntype Awaitable<T> = T | Promise<T>\nexport type AuthzUserId = string | number\n\nexport type AuthzConfig = {\n /** Stable app identifier (e.g. \"quants\"). Bound into every permission query. */\n appKey: string\n /** Resolve the acting user id from the request (cookie/session/openid → TDUsers.id). */\n resolveUserId: (request: Request) => Awaitable<AuthzUserId | null | undefined>\n /** Load effective permissions for (user, app, resource) — typically via @aiquants/authz-drizzle. */\n getEffectivePermissions: (args: { userId: AuthzUserId | null; appKey: string; resourceKey: string }) => Awaitable<EffectivePermission | null | undefined>\n /** Default deny handler. If omitted, denies throw AuthzDeniedError (403). */\n onDeny?: (info: DenyInfo) => void\n}\n\nexport type RequirePermissionOptions = {\n /** When set, denials `throw redirect(failureRedirect)` instead of throwing 403. */\n failureRedirect?: string\n}\n\n/** Serializable per-resource permission summary for UI (loader → component). */\nexport type PermissionView = {\n resourceKey: string\n read: boolean\n create: boolean\n update: boolean\n delete: boolean\n /** create ∪ update */\n write: boolean\n /** read granted but row and/or column restricted (→ △ partial). */\n readPartial: boolean\n actions: AuthzAction[]\n}\n\n/** Map an EffectivePermission to a serializable {@link PermissionView}. */\nexport function toPermissionView(resourceKey: string, perm: EffectivePermission | null | undefined): PermissionView {\n const read = can(perm, \"read\")\n const create = can(perm, \"create\")\n const update = can(perm, \"update\")\n const del = can(perm, \"delete\")\n const readScope = perm?.scopeByAction.read\n const readPartial = read && !!readScope && (readScope.rowScope !== null || readScope.columnScope !== null)\n return {\n resourceKey,\n read,\n create,\n update,\n delete: del,\n write: create || update,\n readPartial,\n actions: perm ? Array.from(perm.actions) : [],\n }\n}\n\n/**\n * React Router adapter. Binds `appKey` and the DI deps, exposing:\n * - `requirePermission(request, {resourceKey, action}, options?)` → `{ userId, scope }` on allow\n * (apply row WHERE / column mask with the returned scope); denies throw 403 or redirect.\n * - `getMyPermissions(request, {resourceKeys})` → `Record<resourceKey, PermissionView>` for the UI.\n */\nexport function createAuthz(config: AuthzConfig) {\n async function requirePermission(request: Request, query: { resourceKey: string; action: AuthzAction }, options?: RequirePermissionOptions): Promise<GuardResult<AuthzUserId>> {\n const onDeny: ((info: DenyInfo) => void) | undefined = options?.failureRedirect\n ? () => {\n throw redirect(options.failureRedirect as string)\n }\n : config.onDeny\n const guard = createRequirePermission<Request, AuthzUserId>({\n resolveUserId: config.resolveUserId,\n getEffectivePermissions: config.getEffectivePermissions,\n onDeny,\n })\n return guard(request, { appKey: config.appKey, resourceKey: query.resourceKey, action: query.action })\n }\n\n async function getMyPermissions(request: Request, query: { resourceKeys: string[] }): Promise<Record<string, PermissionView>> {\n const userId = await config.resolveUserId(request)\n const out: Record<string, PermissionView> = {}\n for (const resourceKey of query.resourceKeys) {\n const perm = await config.getEffectivePermissions({ userId: userId ?? null, appKey: config.appKey, resourceKey })\n out[resourceKey] = toPermissionView(resourceKey, perm)\n }\n return out\n }\n\n /**\n * Atomically require permission and return both guard result and UI PermissionView.\n * Guarantees that guarded resource and returned UI permission object remain identical.\n * ガード処理と UI 表示用権限データの取得を同一リソースキーでアトミックに実行。\n */\n async function requireAndGetPermission(\n request: Request,\n query: { resourceKey: string; action: AuthzAction },\n options?: RequirePermissionOptions,\n ): Promise<GuardResult<AuthzUserId> & { permission: PermissionView }> {\n const guard = await requirePermission(request, query, options)\n const perms = await getMyPermissions(request, { resourceKeys: [query.resourceKey] })\n return {\n ...guard,\n permission: perms[query.resourceKey],\n }\n }\n\n return { requirePermission, getMyPermissions, requireAndGetPermission }\n}\n"],"mappings":"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","names":["index_exports","__export","AuthzAdminAppView","AuthzErrorBoundary","AuthzGrantsView","AuthzLayout","AuthzResourcesView","AuthzRolesView","AuthzUserRolesView","ErrorAlert","Field","MyPermissionIndicator","MyPermissionStatus","createAuthz","createAuthzAdminApp","createAuthzAdminServer","defaultAuthzAdminLabels","defineResources","formatResourceTooltip","makeAuthzErrorBoundary","resolveLabels","toPermissionView","ui","usePermission","__toCommonJS","import_react_router","import_authz_core","import_react_router","defaultAuthzAdminLabels","resolveLabels","over","d","isResponse","e","toActionError","createAuthzAdminServer","opts","store","RES","labels","resolveLabels","requirePermission","request","query","userId","layoutGuard","loadMyPermissions","rolesData","roles","self","resourcesData","grantsData","grants","resources","userRolesData","assignments","users","form","intent","roleKey","name","appKey","resourceKey","roleId","resourceId","rawAction","action","actor","segmentOf","params","createAuthzAdminApp","opts","server","createAuthzAdminServer","basePath","SEGMENTS","segmentData","actions","loader","args","segment","userId","myPermissions","segData","action","act","import_jsx_runtime","ui","Field","label","hint","children","ErrorAlert","message","import_authz_core","import_select_box","import_react","import_react_router","usePermission","view","readState","writeState","deleteState","import_jsx_runtime","STATE_STYLE","formatResourceTooltip","resourceKey","resourceName","key","name","PermIcon","state","MyPermissionIndicator","permission","expectedResourceKey","showResourceTooltip","labels","showScopeSummary","className","p","usePermission","l","resKey","resName","tooltipText","hasMismatch","renderBadge","label","style","badgeTitle","MyPermissionStatus","prefixLabel","showPrefixLabel","import_jsx_runtime","actionError","d","AuthzLayoutShell","children","myPermissions","labels","adminResourceKey","basePath","base","tabs","ui","MyPermissionStatus","key","label","isActive","AuthzLayout","makeAuthzErrorBoundary","over","L","resolveLabels","error","routeError","is403","title","message","AuthzErrorBoundary","confirmGuard","active","e","AuthzRolesView","roles","selfAdminRoleIds","C","selfAdmin","ErrorAlert","r","Field","AuthzResourcesView","resources","GrantRow","g","action","setAction","a","val","AuthzGrantsView","grants","roleOptions","resourceOptions","actionOptions","selectedRole","setSelectedRole","selectedResource","setSelectedResource","selectedAction","setSelectedAction","AuthzUserRolesView","assignments","users","actorUserId","userOptions","u","selectedUser","setSelectedUser","SEGMENT_VIEWS","AuthzAdminAppView","segment","View","defineResources","resources","import_authz_core","import_react_router","toPermissionView","resourceKey","perm","read","create","update","del","readScope","readPartial","createAuthz","config","requirePermission","request","query","options","onDeny","getMyPermissions","userId","out","requireAndGetPermission","guard","perms"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/admin/app.ts","../src/admin/server.ts","../src/admin/labels.ts","../src/admin/ui.tsx","../src/admin/views.tsx","../src/MyPermissionGroupStatus.tsx","../src/usePermission.ts","../src/MyPermissionIndicator.tsx","../src/resources.ts","../src/server.ts"],"sourcesContent":["export * from \"./admin/app\"\nexport * from \"./admin/labels\"\nexport * from \"./admin/server\"\nexport * from \"./admin/ui\"\nexport * from \"./admin/views\"\nexport * from \"./MyPermissionGroupStatus\"\nexport * from \"./MyPermissionIndicator\"\nexport * from \"./resources\"\nexport * from \"./server\"\nexport * from \"./usePermission\"\n","/**\n * 認可管理 UI を **スプラット 1 ルート(`authz/*`)** にマウントするためのサーバ結線。\n * `routes.ts` の 1 エントリ + 極小のマウントファイル 1 個だけで全タブを提供できる\n * (タブごとのルートディレクトリ/ファイルが不要)。\n *\n * 返り値の `loader`/`action` は store 依存(サーバ)。Component は store 非依存の\n * `AuthzAdminAppView`(views.tsx)を、ErrorBoundary は `makeAuthzErrorBoundary` を使う。\n */\nimport { data, redirect } from \"react-router\"\nimport { type CreateAuthzAdminServerOptions, createAuthzAdminServer } from \"./server\"\n\ntype RouteArgs = { request: Request; params: Record<string, string | undefined> }\n\nexport type CreateAuthzAdminAppOptions = CreateAuthzAdminServerOptions & {\n /** マウントのベースパス(タブリンク/未指定セグメントのリダイレクト先)。既定 `/authz`。 */\n basePath?: string\n}\n\n/** スプラット param(\"*\")から先頭セグメントを取り出す(`roles/...` → `roles`)。 */\nfunction segmentOf(params: Record<string, string | undefined>): string {\n return String(params[\"*\"] ?? \"\").split(\"/\")[0]\n}\n\nexport function createAuthzAdminApp(opts: CreateAuthzAdminAppOptions) {\n const server = createAuthzAdminServer(opts)\n const basePath = opts.basePath ?? \"/authz\"\n const SEGMENTS = [\"roles\", \"resources\", \"role_permissions\", \"user_roles\"] as const\n // データ取得(ガード無し)。ガードはスプラット loader で 1 回だけ行い、userId を渡す。\n const segmentData = { roles: server.roles.data, resources: server.resources.data, role_permissions: server.grants.data, user_roles: server.userRoles.data }\n const actions = { roles: server.roles.action, resources: server.resources.action, role_permissions: server.grants.action, user_roles: server.userRoles.action }\n\n async function loader(args: RouteArgs) {\n const segment = segmentOf(args.params)\n if (!(SEGMENTS as readonly string[]).includes(segment)) throw redirect(`${basePath}/roles`)\n // ガードは 1 回だけ(requireUser + requirePermission(read))。userId を取り回して再ガードしない。\n const { userId } = await server.layoutGuard(args.request)\n const [myPermissions, segData] = await Promise.all([server.loadMyPermissions(args.request), segmentData[segment as (typeof SEGMENTS)[number]](userId)])\n // segData は labels を含む(各 data 関数が付与)。myPermissions/adminResourceKey はレイアウト殻用。\n return { segment, basePath, myPermissions, adminResourceKey: server.resourceKey, ...segData }\n }\n\n async function action(args: RouteArgs) {\n const segment = segmentOf(args.params)\n const act = actions[segment as (typeof SEGMENTS)[number]]\n if (!act) return data({ error: \"unknown action\" }, { status: 400 })\n return act(args)\n }\n\n // server: 個別タブの loader/action を露出(統合テスト等から直接呼ぶ用)。\n return { loader, action, server }\n}\n","/**\n * 認可管理 UI のサーバ結線(loader/action 工場)。store ポート + アプリのガード/セッションを束ね、\n * 各ルートの loader/action を生成する。返り値の loader データには解決済みラベルを含める。\n * store(drizzle)を渡すのはこの工場の呼び出し側(アプリのサーバモジュール)に限る。\n */\nimport { AUTHZ_ACTIONS, type AuthzAction, type AuthzAdminStore, AuthzDeniedError } from \"@aiquants/authz-core\"\nimport { data, redirect } from \"react-router\"\nimport type { PermissionView } from \"../server\"\nimport { type AuthzAdminLabels, type PartialAuthzAdminLabels, resolveLabels } from \"./labels\"\nimport type { AuthzGrantsData, AuthzLayoutData, AuthzResourcesData, AuthzRolesData, AuthzUserRolesData } from \"./views\"\n\ntype Req = { request: Request }\ntype PermissionQuery = { resourceKey: string; action: AuthzAction }\n\nexport type CreateAuthzAdminServerOptions = {\n store: AuthzAdminStore\n /** 管理画面のガード資源キー(既定 `authz_admin`)。 */\n resourceKey?: string\n /** 未ログインをログインへ誘導する(例: throw redirect(...))。 */\n requireUser: (request: Request) => Promise<unknown>\n /**\n * 認可ガード(アプリの createAuthz 由来)。allow で { userId } を返す。\n * 0.2.0 で GuardResult.userId が nullable 化したため、戻り型も null を受ける。\n * userId==null(未解決/万一の public 付与)は createAuthzAdminServer 内で deny する\n * (管理経路は監査・自己権限計算に実 id が必須のため非 null を保証)。\n */\n requirePermission: (request: Request, query: PermissionQuery) => Promise<{ userId: string | number | null }>\n /** 自己権限表示用(アプリの createAuthz 由来)。 */\n getMyPermissions: (request: Request, args: { resourceKeys: string[] }) => Promise<Record<string, PermissionView>>\n /** 文言の部分上書き(既定は日本語)。 */\n labels?: PartialAuthzAdminLabels\n}\n\nconst isResponse = (e: unknown): e is Response => e instanceof Response\n\n/** action 内の例外を 403(認可拒否のみ)/ 400(検証等)へ変換する。 */\nfunction toActionError(e: unknown) {\n if (isResponse(e)) throw e\n if (e instanceof AuthzDeniedError) throw new Response(e.message, { status: 403 })\n return data({ error: e instanceof Error ? e.message : \"エラーが発生しました\" }, { status: 400 })\n}\n\nexport function createAuthzAdminServer(opts: CreateAuthzAdminServerOptions) {\n const store = opts.store\n const RES = opts.resourceKey ?? \"authz_admin\"\n const labels: AuthzAdminLabels = resolveLabels(opts.labels)\n // 未解決ユーザー(userId==null)を境界で 1 回だけ deny。これ以降の userId は非 null 保証。\n // 管理リソースは public を付与しない前提だが、防御的に拒否する(監査/自己権限計算に実 id が必須)。\n const requirePermission = async (request: Request, query: PermissionQuery): Promise<{ userId: string | number }> => {\n const { userId } = await opts.requirePermission(request, query)\n if (userId == null) {\n throw new AuthzDeniedError({ appKey: \"\", resourceKey: query.resourceKey, action: query.action, reason: \"unresolved-user\", userId: null })\n }\n return { userId }\n }\n\n /** レイアウトガード: requireUser(302) → requirePermission(read, 403)。userId を返す(1 回だけ実行)。 */\n async function layoutGuard(request: Request): Promise<{ userId: string | number }> {\n await opts.requireUser(request)\n try {\n return await requirePermission(request, { resourceKey: RES, action: \"read\" })\n } catch (e) {\n if (e instanceof AuthzDeniedError) throw new Response(`Forbidden: ${RES}`, { status: 403 })\n throw e\n }\n }\n /** 自己権限(インジケータ表示用)。 */\n const loadMyPermissions = (request: Request) => opts.getMyPermissions(request, { resourceKeys: [RES] })\n\n // ---- データ取得(ガード無し)。ガード済みの userId を受け取る(resources/grants は未使用)。 ----\n const rolesData = async (userId?: string | number): Promise<AuthzRolesData> => {\n const [roles, self] = await Promise.all([store.listRoles(), store.getSelfAdminContext(Number(userId))])\n return { roles, selfAdminRoleIds: self.selfAdminRoleIds, labels }\n }\n const resourcesData = async (): Promise<AuthzResourcesData> => ({ resources: await store.listResources(), labels })\n const grantsData = async (): Promise<AuthzGrantsData> => {\n const [grants, roles, resources] = await Promise.all([store.listGrants(), store.listRoles(), store.listResources()])\n return { grants, roles, resources, labels }\n }\n const userRolesData = async (userId?: string | number): Promise<AuthzUserRolesData> => {\n const [assignments, roles, users, self] = await Promise.all([store.listUserRoles(), store.listRoles(), store.listUsers(), store.getSelfAdminContext(Number(userId))])\n return { assignments, roles, users, actorUserId: self.actorUserId, selfAdminRoleIds: self.selfAdminRoleIds, labels }\n }\n\n return {\n /** 露出: スプラットマウント(app.ts)がガードを 1 回だけ行うために使う。 */\n labels,\n resourceKey: RES,\n layoutGuard,\n loadMyPermissions,\n\n /** /authz レイアウト: requireUser(302) → requirePermission(read, 403) → 自己権限取得。 */\n layout: {\n async loader({ request }: Req): Promise<AuthzLayoutData> {\n await layoutGuard(request)\n return { myPermissions: await loadMyPermissions(request), labels, adminResourceKey: RES }\n },\n },\n\n /** /authz index → roles へ。 */\n index: {\n loader() {\n throw redirect(\"/authz/roles\")\n },\n },\n\n roles: {\n data: rolesData,\n async loader({ request }: Req): Promise<AuthzRolesData> {\n const { userId } = await requirePermission(request, { resourceKey: RES, action: \"read\" })\n return rolesData(userId)\n },\n async action({ request }: Req) {\n const form = await request.formData()\n const intent = String(form.get(\"_action\"))\n try {\n switch (intent) {\n case \"create\": {\n const { userId } = await requirePermission(request, { resourceKey: RES, action: \"create\" })\n const roleKey = String(form.get(\"roleKey\") ?? \"\").trim()\n const name = String(form.get(\"name\") ?? \"\").trim()\n if (!(roleKey && name)) return data({ error: \"role_key と name は必須です\" }, { status: 400 })\n await store.createRole({ roleKey, name, description: String(form.get(\"description\") ?? \"\").trim() || null }, String(userId))\n return { ok: true }\n }\n case \"save\": {\n const { userId } = await requirePermission(request, { resourceKey: RES, action: \"update\" })\n const roleKey = String(form.get(\"roleKey\") ?? \"\").trim()\n const name = String(form.get(\"name\") ?? \"\").trim()\n if (!(roleKey && name)) return data({ error: \"roleKey と name は必須です\" }, { status: 400 })\n await store.updateRole(Number(form.get(\"id\")), { roleKey, name, description: String(form.get(\"description\") ?? \"\").trim() || null }, String(userId))\n return { ok: true }\n }\n case \"toggle\": {\n const { userId } = await requirePermission(request, { resourceKey: RES, action: \"update\" })\n await store.setRoleActive(Number(form.get(\"id\")), form.get(\"isActive\") === \"true\", String(userId))\n return { ok: true }\n }\n case \"delete\": {\n await requirePermission(request, { resourceKey: RES, action: \"delete\" })\n await store.deleteRole(Number(form.get(\"id\")))\n return { ok: true }\n }\n default:\n return data({ error: \"unknown action\" }, { status: 400 })\n }\n } catch (e) {\n return toActionError(e)\n }\n },\n },\n\n resources: {\n data: resourcesData,\n async loader({ request }: Req): Promise<AuthzResourcesData> {\n await requirePermission(request, { resourceKey: RES, action: \"read\" })\n return resourcesData()\n },\n async action({ request }: Req) {\n const form = await request.formData()\n const intent = String(form.get(\"_action\"))\n try {\n switch (intent) {\n case \"create\": {\n const { userId } = await requirePermission(request, { resourceKey: RES, action: \"create\" })\n const appKey = String(form.get(\"appKey\") ?? \"\").trim()\n const resourceKey = String(form.get(\"resourceKey\") ?? \"\").trim()\n const name = String(form.get(\"name\") ?? \"\").trim()\n if (!(appKey && resourceKey && name)) return data({ error: \"app_key / resource_key / name は必須です\" }, { status: 400 })\n await store.createResource({ appKey, resourceKey, name, description: String(form.get(\"description\") ?? \"\").trim() || null }, String(userId))\n return { ok: true }\n }\n case \"save\": {\n const { userId } = await requirePermission(request, { resourceKey: RES, action: \"update\" })\n const name = String(form.get(\"name\") ?? \"\").trim()\n if (!name) return data({ error: \"name は必須です\" }, { status: 400 })\n await store.updateResource(Number(form.get(\"id\")), { name, description: String(form.get(\"description\") ?? \"\").trim() || null }, String(userId))\n return { ok: true }\n }\n case \"delete\": {\n await requirePermission(request, { resourceKey: RES, action: \"delete\" })\n await store.deleteResource(Number(form.get(\"id\")))\n return { ok: true }\n }\n default:\n return data({ error: \"unknown action\" }, { status: 400 })\n }\n } catch (e) {\n return toActionError(e)\n }\n },\n },\n\n grants: {\n data: grantsData,\n async loader({ request }: Req): Promise<AuthzGrantsData> {\n await requirePermission(request, { resourceKey: RES, action: \"read\" })\n return grantsData()\n },\n async action({ request }: Req) {\n const form = await request.formData()\n const intent = String(form.get(\"_action\"))\n try {\n switch (intent) {\n case \"create\": {\n const { userId } = await requirePermission(request, { resourceKey: RES, action: \"create\" })\n const roleId = Number(form.get(\"roleId\"))\n const resourceId = Number(form.get(\"resourceId\"))\n if (!(roleId && resourceId)) return data({ error: \"ロールとリソースを選択してください\" }, { status: 400 })\n const rawAction = String(form.get(\"action\") ?? \"\")\n if (!(AUTHZ_ACTIONS as readonly string[]).includes(rawAction)) return data({ error: \"無効な action です\" }, { status: 400 })\n const action = rawAction as AuthzAction\n await store.createGrant({ roleId, resourceId, action, rowScope: String(form.get(\"rowScope\") ?? \"\"), columnScope: String(form.get(\"columnScope\") ?? \"\") }, String(userId))\n return { ok: true }\n }\n case \"save\": {\n const { userId } = await requirePermission(request, { resourceKey: RES, action: \"update\" })\n const rawAction = String(form.get(\"action\") ?? \"\")\n if (!(AUTHZ_ACTIONS as readonly string[]).includes(rawAction)) return data({ error: \"無効な action です\" }, { status: 400 })\n const action = rawAction as AuthzAction\n await store.updateGrant(Number(form.get(\"id\")), { action, rowScope: String(form.get(\"rowScope\") ?? \"\"), columnScope: String(form.get(\"columnScope\") ?? \"\") }, String(userId))\n return { ok: true }\n }\n case \"delete\": {\n await requirePermission(request, { resourceKey: RES, action: \"delete\" })\n await store.deleteGrant(Number(form.get(\"id\")))\n return { ok: true }\n }\n default:\n return data({ error: \"unknown action\" }, { status: 400 })\n }\n } catch (e) {\n return toActionError(e)\n }\n },\n },\n\n userRoles: {\n data: userRolesData,\n async loader({ request }: Req): Promise<AuthzUserRolesData> {\n const { userId } = await requirePermission(request, { resourceKey: RES, action: \"read\" })\n return userRolesData(userId)\n },\n async action({ request }: Req) {\n const form = await request.formData()\n const intent = String(form.get(\"_action\"))\n try {\n switch (intent) {\n case \"assign\": {\n const { userId: actor } = await requirePermission(request, { resourceKey: RES, action: \"create\" })\n const userId = Number(form.get(\"userId\"))\n const roleId = Number(form.get(\"roleId\"))\n if (!(userId && roleId)) return data({ error: \"ユーザーとロールを選択してください\" }, { status: 400 })\n await store.assignUserRole(userId, roleId, String(actor))\n return { ok: true }\n }\n case \"remove\": {\n await requirePermission(request, { resourceKey: RES, action: \"delete\" })\n await store.removeUserRole(Number(form.get(\"userId\")), Number(form.get(\"roleId\")))\n return { ok: true }\n }\n default:\n return data({ error: \"unknown action\" }, { status: 400 })\n }\n } catch (e) {\n return toActionError(e)\n }\n },\n },\n }\n}\n","/** Authz admin UI strings (i18n). Defaults are English; override per-section via `createAuthzAdminRoutes(..., { labels })`. */\nexport type AuthzAdminLabels = {\n title: string\n myPermission: string\n tabs: { roles: string; resources: string; role_permissions: string; user_roles: string }\n common: { add: string; save: string; delete: string; remove: string; assign: string; grant: string; select: string; active: string; inactive: string; optional: string }\n roles: { heading: string; note: string; roleKey: string; name: string; description: string; activeHeader: string; empty: string; newHeading: string; hintRoleKey: string }\n resources: { heading: string; note: string; appKey: string; resourceKey: string; name: string; description: string; empty: string; newHeading: string; hintAppKey: string; hintResourceKey: string; hintDailyReport: string }\n grants: {\n heading: string\n note: string\n role: string\n resource: string\n action: string\n rowScope: string\n columnScope: string\n empty: string\n newHeading: string\n rowScopeHint: string\n columnScopeHint: string\n rowScopePlaceholder: string\n columnScopePlaceholder: string\n nullRows: string\n nullCols: string\n selectPlaceholder: string\n }\n userRoles: { heading: string; note: string; user: string; role: string; empty: string; newHeading: string; selectPlaceholder: string }\n error: { forbiddenTitle: string; forbiddenBody: string; genericTitlePrefix: string; genericTitle: string; genericBody: string }\n warn: { selfRoleDisable: string; selfRoleDelete: string; selfAssignmentRemove: string }\n}\n\nexport const defaultAuthzAdminLabels: AuthzAdminLabels = {\n title: \"Authorization (RBAC)\",\n myPermission: \"Your permissions\",\n tabs: { roles: \"Roles\", resources: \"Resources\", role_permissions: \"Permissions\", user_roles: \"User assignments\" },\n common: { add: \"Add\", save: \"Save\", delete: \"Delete\", remove: \"Remove\", assign: \"Assign\", grant: \"Grant\", select: \"Select…\", active: \"○ Enabled\", inactive: \"× Disabled\", optional: \"optional\" },\n roles: {\n heading: \"Roles (TMRole)\",\n note: \"Edit name / description inline and click Save (role_key is an immutable identifier).\",\n roleKey: \"role_key\",\n name: \"name\",\n description: \"description\",\n activeHeader: \"Active\",\n empty: \"No roles\",\n newHeading: \"New role\",\n hintRoleKey: \"e.g. admin\",\n },\n resources: {\n heading: \"Resources (TMResource)\",\n note: \"Edit name / description inline and click Save (app_key / resource_key are immutable identifiers).\",\n appKey: \"app_key\",\n resourceKey: \"resource_key\",\n name: \"name\",\n description: \"description\",\n empty: \"No resources\",\n newHeading: \"New resource\",\n hintAppKey: \"e.g. quants\",\n hintResourceKey: \"e.g. daily_report\",\n hintDailyReport: \"optional\",\n },\n grants: {\n heading: \"Permissions (TDRolePermission)\",\n note: \"Empty row_scope / column_scope = all rows / all columns (NULL). JSON must satisfy the §3.2 contract.\",\n role: \"role\",\n resource: \"resource\",\n action: \"action\",\n rowScope: \"row_scope\",\n columnScope: \"column_scope\",\n empty: \"No permissions\",\n newHeading: \"Grant a permission\",\n rowScopeHint: \"JSON / empty = all rows\",\n columnScopeHint: \"JSON / empty = all columns\",\n rowScopePlaceholder: \"empty = all rows (NULL)\",\n columnScopePlaceholder: \"empty = all columns (NULL)\",\n nullRows: \"NULL (all rows)\",\n nullCols: \"NULL (all columns)\",\n selectPlaceholder: \"Select…\",\n },\n 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…\" },\n error: {\n forbiddenTitle: \"Access denied\",\n forbiddenBody: \"You don't have permission to view this screen. Ask an administrator to grant access.\",\n genericTitlePrefix: \"Error\",\n genericTitle: \"An error occurred\",\n genericBody: \"An unexpected error occurred. Please try again later.\",\n },\n warn: {\n selfRoleDisable: \"This role backs your own authorization-admin access. Disabling it may lock you out of this screen. Continue?\",\n selfRoleDelete: \"This role backs your own authorization-admin access. Deleting it may lock you out of this screen. Continue?\",\n selfAssignmentRemove: \"This assignment backs your own authorization-admin access. Removing it may lock you out of this screen. Continue?\",\n },\n}\n\nexport type PartialAuthzAdminLabels = {\n title?: string\n myPermission?: string\n tabs?: Partial<AuthzAdminLabels[\"tabs\"]>\n common?: Partial<AuthzAdminLabels[\"common\"]>\n roles?: Partial<AuthzAdminLabels[\"roles\"]>\n resources?: Partial<AuthzAdminLabels[\"resources\"]>\n grants?: Partial<AuthzAdminLabels[\"grants\"]>\n userRoles?: Partial<AuthzAdminLabels[\"userRoles\"]>\n error?: Partial<AuthzAdminLabels[\"error\"]>\n warn?: Partial<AuthzAdminLabels[\"warn\"]>\n}\n\n/** Shallow per-section merge over the English defaults. */\nexport function resolveLabels(over?: PartialAuthzAdminLabels): AuthzAdminLabels {\n const d = defaultAuthzAdminLabels\n if (!over) return d\n return {\n title: over.title ?? d.title,\n myPermission: over.myPermission ?? d.myPermission,\n tabs: { ...d.tabs, ...over.tabs },\n common: { ...d.common, ...over.common },\n roles: { ...d.roles, ...over.roles },\n resources: { ...d.resources, ...over.resources },\n grants: { ...d.grants, ...over.grants },\n userRoles: { ...d.userRoles, ...over.userRoles },\n error: { ...d.error, ...over.error },\n warn: { ...d.warn, ...over.warn },\n }\n}\n","/** 認可管理UI 共有のプレゼンテーション部品・スタイル。 */\nimport type { CSSProperties, ReactNode } from \"react\"\n\nexport const ui: Record<string, CSSProperties> = {\n page: { padding: \"1.25rem\", maxWidth: 1280, margin: \"0 auto\", color: \"#0f172a\" },\n tableContainer: { width: \"100%\", overflowX: \"auto\", marginBottom: \"1rem\", WebkitOverflowScrolling: \"touch\" },\n table: { borderCollapse: \"collapse\", width: \"100%\", fontSize: \"0.9rem\", tableLayout: \"fixed\" },\n th: { textAlign: \"left\", borderBottom: \"2px solid #e2e8f0\", padding: \"0.45rem 0.65rem\", fontSize: \"0.78rem\", color: \"#475569\", fontWeight: 600, textTransform: \"uppercase\", letterSpacing: \"0.03em\" },\n td: { borderBottom: \"1px solid #f1f5f9\", padding: \"0.5rem 0.65rem\", verticalAlign: \"middle\", wordBreak: \"break-all\" },\n input: { padding: \"0.4rem 0.55rem\", border: \"1px solid #cbd5e1\", borderRadius: 6, fontSize: \"0.9rem\", background: \"#fff\", width: \"100%\", boxSizing: \"border-box\" },\n select: { padding: \"0.4rem 0.55rem\", border: \"1px solid #cbd5e1\", borderRadius: 6, fontSize: \"0.9rem\", background: \"#fff\", width: \"100%\", boxSizing: \"border-box\" },\n 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\" },\n button: { padding: \"0.3rem 0.7rem\", border: \"1px solid #cbd5e1\", borderRadius: 6, background: \"#fff\", cursor: \"pointer\", fontSize: \"0.82rem\", color: \"#334155\" },\n save: { padding: \"0.3rem 0.7rem\", border: \"1px solid #2563eb\", borderRadius: 6, background: \"#eff6ff\", cursor: \"pointer\", fontSize: \"0.82rem\", color: \"#2563eb\", fontWeight: 600 },\n danger: { padding: \"0.3rem 0.7rem\", border: \"1px solid #fecaca\", borderRadius: 6, background: \"#fff\", cursor: \"pointer\", fontSize: \"0.82rem\", color: \"#dc2626\" },\n 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\" },\n 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\" },\n code: { fontFamily: \"ui-monospace, SFMono-Regular, Menlo, monospace\", fontSize: \"0.78rem\", color: \"#334155\", wordBreak: \"break-all\" },\n muted: { color: \"#94a3b8\" },\n h2: { fontSize: \"1.05rem\", margin: \"0 0 0.35rem\", fontWeight: 700 },\n h3: { fontSize: \"0.92rem\", margin: \"1.25rem 0 0\", color: \"#334155\", fontWeight: 600 },\n note: { color: \"#64748b\", fontSize: \"0.82rem\", margin: \"0 0 0.75rem\" },\n empty: { color: \"#94a3b8\", padding: \"0.75rem 0.65rem\" },\n}\n\n/**\n * ラベルを上、コントロールを下に縦積みするフィールド(重なり防止・一貫レイアウト)。\n * コントロール側は `aria-label` を持つ前提なので `<div>` で構成する。\n */\nexport function Field({ label, hint, children }: { label: string; hint?: string; children: ReactNode }) {\n return (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"0.3rem\" }}>\n <span style={{ fontSize: \"0.8rem\", color: \"#475569\", fontWeight: 600 }}>\n {label}\n {hint ? <span style={{ fontWeight: 400, color: \"#94a3b8\" }}> — {hint}</span> : null}\n </span>\n {children}\n </div>\n )\n}\n\n/** エラー表示(role=\"alert\")。 */\nexport function ErrorAlert({ message }: { message?: string }) {\n if (!message) return null\n return (\n <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\" }}>\n {message}\n </p>\n )\n}\n","/**\n * 認可管理 UI のプレゼンテーション部品(client-safe)。\n * loader データ(行 + ラベル + 自己管理者ヒント)を `useLoaderData` で受け取り描画する。\n * DB/ストアには一切依存しない(サーバ結線は admin/server.ts)。\n */\nimport { AUTHZ_ACTIONS, type AuthzAssignment, type AuthzGrant, type AuthzResource, type AuthzRole, type AuthzUser } from \"@aiquants/authz-core\"\nimport { SelectBox } from \"@aiquants/select-box\"\nimport { useState } from \"react\"\nimport { Form, isRouteErrorResponse, NavLink, Outlet, useActionData, useLoaderData, useRouteError } from \"react-router\"\nimport { type MyPermissionGroupItem, MyPermissionGroupStatus } from \"../MyPermissionGroupStatus\"\nimport type { PermissionView } from \"../server\"\nimport { type AuthzAdminLabels, type PartialAuthzAdminLabels, resolveLabels } from \"./labels\"\nimport { ErrorAlert, Field, ui } from \"./ui\"\n\ntype WithLabels = { labels: AuthzAdminLabels }\ntype ActionError = { error?: string } | undefined\nconst actionError = (d: ActionError) => d?.error\n\n// ============================ Layout ============================\n\nexport type AuthzLayoutData = WithLabels & { myPermissions: Record<string, PermissionView>; adminResourceKey: string; basePath?: string }\n\n/** ヘッダ(タイトル + あなたの権限) + タブ。中身は children(splat) か Outlet(ネスト)。 */\nfunction AuthzLayoutShell({ children }: { children: React.ReactNode }) {\n const { myPermissions, labels, adminResourceKey, basePath } = useLoaderData() as AuthzLayoutData\n const base = basePath ?? \"/authz\"\n const [variant, setVariant] = useState<\"pills\" | \"popover\">(\"pills\")\n\n const tabs: ReadonlyArray<readonly [string, string]> = [\n [\"roles\", labels.tabs.roles],\n [\"resources\", labels.tabs.resources],\n [\"role_permissions\", labels.tabs.role_permissions],\n [\"user_roles\", labels.tabs.user_roles],\n ]\n\n const permissionItems: MyPermissionGroupItem[] = Object.entries(myPermissions || {}).map(([key, perm]) => ({\n resourceKey: key,\n resourceName: perm?.resourceKey || key,\n permission: perm,\n expectedResourceKey: key,\n }))\n\n const items =\n permissionItems.length > 0\n ? permissionItems\n : [\n {\n resourceKey: adminResourceKey,\n resourceName: adminResourceKey,\n permission: myPermissions?.[adminResourceKey],\n expectedResourceKey: adminResourceKey,\n },\n ]\n\n return (\n <div className=\"authz-admin\" style={ui.page}>\n <header style={{ display: \"flex\", alignItems: \"center\", justifyContent: \"space-between\", gap: \"0.75rem\", flexWrap: \"wrap\", margin: \"0 0 0.4rem\" }}>\n <h1 style={{ fontSize: \"1.15rem\", margin: 0, fontWeight: 700, color: \"#1e293b\" }}>{labels.title}</h1>\n <div style={{ display: \"flex\", alignItems: \"center\", gap: \"0.4rem\" }}>\n <MyPermissionGroupStatus prefixLabel={labels.myPermission} items={items} variant={variant} size=\"xs\" />\n <div style={{ display: \"inline-flex\", borderRadius: \"4px\", border: \"1px solid #cbd5e1\", padding: \"1px\", backgroundColor: \"#f8fafc\", fontSize: \"0.7rem\" }}>\n <button\n type=\"button\"\n onClick={() => setVariant(\"pills\")}\n data-testid=\"switch-variant-pills\"\n style={{\n padding: \"1px 5px\",\n borderRadius: \"3px\",\n border: \"none\",\n cursor: \"pointer\",\n fontSize: \"0.7rem\",\n lineHeight: \"1.2\",\n fontWeight: variant === \"pills\" ? 600 : 400,\n backgroundColor: variant === \"pills\" ? \"#ffffff\" : \"transparent\",\n color: variant === \"pills\" ? \"#1e293b\" : \"#64748b\",\n boxShadow: variant === \"pills\" ? \"0 1px 2px rgba(0,0,0,0.05)\" : \"none\",\n }}>\n Pills\n </button>\n <button\n type=\"button\"\n onClick={() => setVariant(\"popover\")}\n data-testid=\"switch-variant-popover\"\n style={{\n padding: \"1px 5px\",\n borderRadius: \"3px\",\n border: \"none\",\n cursor: \"pointer\",\n fontSize: \"0.7rem\",\n lineHeight: \"1.2\",\n fontWeight: variant === \"popover\" ? 600 : 400,\n backgroundColor: variant === \"popover\" ? \"#ffffff\" : \"transparent\",\n color: variant === \"popover\" ? \"#1e293b\" : \"#64748b\",\n boxShadow: variant === \"popover\" ? \"0 1px 2px rgba(0,0,0,0.05)\" : \"none\",\n }}>\n Popover\n </button>\n </div>\n </div>\n </header>\n <nav style={{ display: \"flex\", gap: \"0.25rem\", borderBottom: \"1px solid #e2e8f0\", margin: \"0.6rem 0 1rem\" }}>\n {tabs.map(([key, label]) => (\n <NavLink\n key={key}\n to={`${base}/${key}`}\n style={({ isActive }) => ({\n padding: \"0.5rem 0.9rem\",\n textDecoration: \"none\",\n color: isActive ? \"#2563eb\" : \"#475569\",\n borderBottom: isActive ? \"2px solid #2563eb\" : \"2px solid transparent\",\n marginBottom: -1,\n fontWeight: isActive ? 700 : 500,\n fontSize: \"0.92rem\",\n })}>\n {label}\n </NavLink>\n ))}\n </nav>\n {children}\n </div>\n )\n}\n\n/** ネストルート用レイアウト(子は Outlet)。`routes.ts` でネスト構成にする場合に使う。 */\nexport function AuthzLayout() {\n return (\n <AuthzLayoutShell>\n <Outlet />\n </AuthzLayoutShell>\n )\n}\n\n/**\n * 認可管理 UI のエラー境界。ErrorBoundary は loader データを読めないため、ラベルは\n * `makeAuthzErrorBoundary(labels)` で注入する(アプリは自分のロケールで生成する)。\n * 既定の `AuthzErrorBoundary` は英語(パッケージ既定)。\n */\nexport function makeAuthzErrorBoundary(over?: PartialAuthzAdminLabels): () => React.ReactElement {\n const L = resolveLabels(over).error\n return function AuthzErrorBoundary() {\n const error = useRouteError()\n const routeError = isRouteErrorResponse(error) ? error : null\n const is403 = routeError?.status === 403\n const title = is403 ? L.forbiddenTitle : routeError ? `${L.genericTitlePrefix} (${routeError.status})` : L.genericTitle\n const message = is403 ? L.forbiddenBody : routeError ? (typeof routeError.data === \"string\" && routeError.data ? routeError.data : routeError.statusText) : L.genericBody\n return (\n <div style={ui.page}>\n <div role=\"alert\" style={{ maxWidth: 480, margin: \"3rem auto\", padding: \"1.5rem\", border: \"1px solid #fecaca\", borderRadius: 12, background: \"#fef2f2\" }}>\n <h1 style={{ fontSize: \"1.1rem\", fontWeight: 700, color: \"#b91c1c\", margin: \"0 0 0.5rem\" }}>{title}</h1>\n <p style={{ color: \"#7f1d1d\", fontSize: \"0.9rem\", margin: 0, lineHeight: 1.7 }}>{message}</p>\n </div>\n </div>\n )\n }\n}\n\n/** 英語(既定ラベル)のエラー境界。i18n したい場合は {@link makeAuthzErrorBoundary} を使う。 */\nexport const AuthzErrorBoundary = makeAuthzErrorBoundary()\n\n/** 自分の管理権限を支える対象への破壊操作前に警告(キャンセルで送信中止)。 */\nconst confirmGuard = (active: boolean, message: string) => (e: React.MouseEvent) => {\n if (active && !window.confirm(message)) e.preventDefault()\n}\n\n// ============================ Roles ============================\n\nexport type AuthzRolesData = WithLabels & { roles: AuthzRole[]; selfAdminRoleIds?: number[] }\n\nexport function AuthzRolesView() {\n const { roles, selfAdminRoleIds, labels } = useLoaderData() as AuthzRolesData\n const L = labels.roles\n const C = labels.common\n const selfAdmin = new Set(selfAdminRoleIds ?? [])\n return (\n <section>\n <h2 style={ui.h2}>{L.heading}</h2>\n <ErrorAlert message={actionError(useActionData() as ActionError)} />\n <p style={ui.note}>{L.note}</p>\n <div style={ui.tableContainer}>\n <table style={ui.table}>\n <thead>\n <tr>\n <th style={{ ...ui.th, width: \"20%\" }}>{L.roleKey}</th>\n <th style={{ ...ui.th, width: \"25%\" }}>{L.name}</th>\n <th style={{ ...ui.th, width: \"35%\" }}>{L.description}</th>\n <th style={{ ...ui.th, width: \"10%\" }}>{L.activeHeader}</th>\n <th style={{ ...ui.th, width: \"10%\" }} />\n </tr>\n </thead>\n <tbody>\n {roles.map((r) => (\n <tr key={r.id}>\n <td style={ui.td}>\n {r.roleKey === \"@authenticated\" || r.roleKey === \"@anonymous\" ? <span style={ui.code}>{r.roleKey}</span> : <input name=\"roleKey\" defaultValue={r.roleKey} form={`save-role-${r.id}`} aria-label={`roleKey-${r.id}`} required style={ui.input} />}\n </td>\n <td style={ui.td}>\n <input name=\"name\" defaultValue={r.name} form={`save-role-${r.id}`} aria-label={`name-${r.id}`} required style={ui.input} />\n </td>\n <td style={ui.td}>\n <input name=\"description\" defaultValue={r.description ?? \"\"} form={`save-role-${r.id}`} aria-label={`description-${r.id}`} style={ui.input} />\n </td>\n <td style={ui.td}>\n <Form method=\"post\" style={{ display: \"inline\" }}>\n <input type=\"hidden\" name=\"_action\" value=\"toggle\" />\n <input type=\"hidden\" name=\"id\" value={r.id} />\n <input type=\"hidden\" name=\"isActive\" value={String(!r.isActive)} />\n <button type=\"submit\" style={ui.button} onClick={r.isActive ? confirmGuard(selfAdmin.has(r.id), labels.warn.selfRoleDisable) : undefined}>\n {r.isActive ? C.active : C.inactive}\n </button>\n </Form>\n </td>\n <td style={{ ...ui.td, whiteSpace: \"nowrap\" }}>\n <Form method=\"post\" id={`save-role-${r.id}`} style={{ display: \"inline\" }}>\n <input type=\"hidden\" name=\"_action\" value=\"save\" />\n <input type=\"hidden\" name=\"id\" value={r.id} />\n <button type=\"submit\" style={ui.save}>\n {C.save}\n </button>\n </Form>\n <Form method=\"post\" style={{ display: \"inline\", marginLeft: \"0.4rem\" }}>\n <input type=\"hidden\" name=\"_action\" value=\"delete\" />\n <input type=\"hidden\" name=\"id\" value={r.id} />\n <button type=\"submit\" style={ui.danger} onClick={confirmGuard(selfAdmin.has(r.id), labels.warn.selfRoleDelete)}>\n {C.delete}\n </button>\n </Form>\n </td>\n </tr>\n ))}\n {roles.length === 0 ? (\n <tr>\n <td style={ui.empty} colSpan={5}>\n {L.empty}\n </td>\n </tr>\n ) : null}\n </tbody>\n </table>\n </div>\n\n <h3 style={ui.h3}>{L.newHeading}</h3>\n <Form method=\"post\" style={ui.card}>\n <input type=\"hidden\" name=\"_action\" value=\"create\" />\n <Field label={L.roleKey} hint={L.hintRoleKey}>\n <input name=\"roleKey\" aria-label=\"role_key\" required style={ui.input} />\n </Field>\n <Field label={L.name}>\n <input name=\"name\" aria-label=\"name\" required style={ui.input} />\n </Field>\n <Field label={L.description} hint={C.optional}>\n <input name=\"description\" aria-label=\"description\" style={ui.input} />\n </Field>\n <button type=\"submit\" style={ui.primary}>\n {C.add}\n </button>\n </Form>\n </section>\n )\n}\n\n// ============================ Resources ============================\n\nexport type AuthzResourcesData = WithLabels & { resources: AuthzResource[] }\n\nexport function AuthzResourcesView() {\n const { resources, labels } = useLoaderData() as AuthzResourcesData\n const L = labels.resources\n const C = labels.common\n return (\n <section>\n <h2 style={ui.h2}>{L.heading}</h2>\n <ErrorAlert message={actionError(useActionData() as ActionError)} />\n <p style={ui.note}>{L.note}</p>\n <div style={ui.tableContainer}>\n <table style={ui.table}>\n <thead>\n <tr>\n <th style={{ ...ui.th, width: \"15%\" }}>{L.appKey}</th>\n <th style={{ ...ui.th, width: \"20%\" }}>{L.resourceKey}</th>\n <th style={{ ...ui.th, width: \"25%\" }}>{L.name}</th>\n <th style={{ ...ui.th, width: \"30%\" }}>{L.description}</th>\n <th style={{ ...ui.th, width: \"10%\" }} />\n </tr>\n </thead>\n <tbody>\n {resources.map((r) => (\n <tr key={r.id}>\n <td style={ui.td}>\n <span style={ui.code}>{r.appKey}</span>\n </td>\n <td style={ui.td}>\n <span style={ui.code}>{r.resourceKey}</span>\n </td>\n <td style={ui.td}>\n <input name=\"name\" defaultValue={r.name} form={`save-res-${r.id}`} aria-label={`name-${r.id}`} required style={ui.input} />\n </td>\n <td style={ui.td}>\n <input name=\"description\" defaultValue={r.description ?? \"\"} form={`save-res-${r.id}`} aria-label={`description-${r.id}`} style={ui.input} />\n </td>\n <td style={{ ...ui.td, whiteSpace: \"nowrap\" }}>\n <Form method=\"post\" id={`save-res-${r.id}`} style={{ display: \"inline\" }}>\n <input type=\"hidden\" name=\"_action\" value=\"save\" />\n <input type=\"hidden\" name=\"id\" value={r.id} />\n <button type=\"submit\" style={ui.save}>\n {C.save}\n </button>\n </Form>\n <Form method=\"post\" style={{ display: \"inline\", marginLeft: \"0.4rem\" }}>\n <input type=\"hidden\" name=\"_action\" value=\"delete\" />\n <input type=\"hidden\" name=\"id\" value={r.id} />\n <button type=\"submit\" style={ui.danger}>\n {C.delete}\n </button>\n </Form>\n </td>\n </tr>\n ))}\n {resources.length === 0 ? (\n <tr>\n <td style={ui.empty} colSpan={5}>\n {L.empty}\n </td>\n </tr>\n ) : null}\n </tbody>\n </table>\n </div>\n\n <h3 style={ui.h3}>{L.newHeading}</h3>\n <Form method=\"post\" style={ui.card}>\n <input type=\"hidden\" name=\"_action\" value=\"create\" />\n <Field label={L.appKey} hint={L.hintAppKey}>\n <input name=\"appKey\" aria-label=\"app_key\" required style={ui.input} />\n </Field>\n <Field label={L.resourceKey} hint={L.hintResourceKey}>\n <input name=\"resourceKey\" aria-label=\"resource_key\" required style={ui.input} />\n </Field>\n <Field label={L.name}>\n <input name=\"name\" aria-label=\"name\" required style={ui.input} />\n </Field>\n <Field label={L.description} hint={C.optional}>\n <input name=\"description\" aria-label=\"description\" style={ui.input} />\n </Field>\n <button type=\"submit\" style={ui.primary}>\n {C.add}\n </button>\n </Form>\n </section>\n )\n}\n\n// ============================ Grants (role_permissions) ============================\n\nexport type AuthzGrantsData = WithLabels & { grants: AuthzGrant[]; roles: Array<{ id: number; roleKey: string }>; resources: Array<{ id: number; appKey: string; resourceKey: string }> }\n\nfunction GrantRow({ g, labels }: { g: AuthzGrant; labels: AuthzAdminLabels }) {\n const C = labels.common\n const [action, setAction] = useState<{ label: string; value: string }>({ label: g.action, value: g.action })\n\n return (\n <tr>\n <td style={ui.td}>\n <span style={ui.code}>{g.roleKey}</span>\n </td>\n <td style={ui.td}>\n <span style={ui.code}>\n {g.appKey}:{g.resourceKey}\n </span>\n </td>\n <td style={ui.td}>\n {g.roleKey === \"@anonymous\" ? (\n <span style={ui.code}>{g.action}</span>\n ) : (\n <>\n <input type=\"hidden\" name=\"action\" value={action.value} form={`save-grant-${g.id}`} />\n <SelectBox\n options={AUTHZ_ACTIONS.map((a) => ({ label: a, value: a }))}\n value={action}\n onChange={(val) => {\n if (val) setAction(val as { label: string; value: string })\n }}\n />\n </>\n )}\n </td>\n <td style={ui.td}>\n <textarea name=\"rowScope\" defaultValue={g.rowScope ?? \"\"} form={`save-grant-${g.id}`} aria-label={`row_scope-${g.id}`} rows={2} placeholder={labels.grants.rowScopePlaceholder} style={ui.textarea} />\n </td>\n <td style={ui.td}>\n <textarea name=\"columnScope\" defaultValue={g.columnScope ?? \"\"} form={`save-grant-${g.id}`} aria-label={`column_scope-${g.id}`} rows={2} placeholder={labels.grants.columnScopePlaceholder} style={ui.textarea} />\n </td>\n <td style={{ ...ui.td, whiteSpace: \"nowrap\" }}>\n <Form method=\"post\" id={`save-grant-${g.id}`} style={{ display: \"inline\" }}>\n <input type=\"hidden\" name=\"_action\" value=\"save\" />\n <input type=\"hidden\" name=\"id\" value={g.id} />\n <button type=\"submit\" style={ui.save}>\n {C.save}\n </button>\n </Form>\n <Form method=\"post\" style={{ display: \"inline\", marginLeft: \"0.4rem\" }}>\n <input type=\"hidden\" name=\"_action\" value=\"delete\" />\n <input type=\"hidden\" name=\"id\" value={g.id} />\n <button type=\"submit\" style={ui.danger}>\n {C.delete}\n </button>\n </Form>\n </td>\n </tr>\n )\n}\n\nexport function AuthzGrantsView() {\n const { grants, roles, resources, labels } = useLoaderData() as AuthzGrantsData\n const L = labels.grants\n const C = labels.common\n\n const roleOptions = roles.map((r) => ({ label: r.roleKey, value: r.id }))\n const resourceOptions = resources.map((r) => ({ label: `${r.appKey}:${r.resourceKey}`, value: r.id }))\n const actionOptions = AUTHZ_ACTIONS.map((a) => ({ label: a, value: a }))\n\n const [selectedRole, setSelectedRole] = useState<{ label: string; value: number } | undefined>(undefined)\n const [selectedResource, setSelectedResource] = useState<{ label: string; value: number } | undefined>(undefined)\n const [selectedAction, setSelectedAction] = useState<{ label: string; value: string } | undefined>({ label: \"read\", value: \"read\" })\n\n return (\n <section>\n <h2 style={ui.h2}>{L.heading}</h2>\n <p style={ui.note}>{L.note}</p>\n <ErrorAlert message={actionError(useActionData() as ActionError)} />\n <div style={ui.tableContainer}>\n <table style={ui.table}>\n <thead>\n <tr>\n <th style={{ ...ui.th, width: \"15%\" }}>{L.role}</th>\n <th style={{ ...ui.th, width: \"20%\" }}>{L.resource}</th>\n <th style={{ ...ui.th, width: \"15%\" }}>{L.action}</th>\n <th style={{ ...ui.th, width: \"20%\" }}>{L.rowScope}</th>\n <th style={{ ...ui.th, width: \"20%\" }}>{L.columnScope}</th>\n <th style={{ ...ui.th, width: \"10%\" }} />\n </tr>\n </thead>\n <tbody>\n {grants.map((g) => (\n <GrantRow key={g.id} g={g} labels={labels} />\n ))}\n {grants.length === 0 ? (\n <tr>\n <td style={ui.empty} colSpan={6}>\n {L.empty}\n </td>\n </tr>\n ) : null}\n </tbody>\n </table>\n </div>\n\n <h3 style={ui.h3}>{L.newHeading}</h3>\n <Form method=\"post\" style={ui.card}>\n <input type=\"hidden\" name=\"_action\" value=\"create\" />\n <input type=\"hidden\" name=\"roleId\" value={selectedRole?.value ?? \"\"} />\n <input type=\"hidden\" name=\"resourceId\" value={selectedResource?.value ?? \"\"} />\n <input type=\"hidden\" name=\"action\" value={selectedAction?.value ?? \"\"} />\n\n <Field label={L.role}>\n <SelectBox options={roleOptions} value={selectedRole} onChange={(val) => setSelectedRole((val || undefined) as { label: string; value: number } | undefined)} placeholder={L.selectPlaceholder} />\n </Field>\n <Field label={L.resource}>\n <SelectBox options={resourceOptions} value={selectedResource} onChange={(val) => setSelectedResource((val || undefined) as { label: string; value: number } | undefined)} placeholder={L.selectPlaceholder} />\n </Field>\n <Field label={L.action}>\n <SelectBox options={actionOptions} value={selectedAction} onChange={(val) => setSelectedAction((val || undefined) as { label: string; value: string } | undefined)} />\n </Field>\n <Field label={L.rowScope} hint={L.rowScopeHint}>\n <textarea name=\"rowScope\" aria-label=\"row_scope\" rows={2} style={ui.textarea} placeholder='{\"filters\":[{\"field\":\"部門CD\",\"op\":\"in\",\"values\":[\"A\"]}]}' />\n </Field>\n <Field label={L.columnScope} hint={L.columnScopeHint}>\n <textarea name=\"columnScope\" aria-label=\"column_scope\" rows={2} style={ui.textarea} placeholder='{\"mode\":\"deny\",\"columns\":[\"金額\"]}' />\n </Field>\n <button type=\"submit\" style={ui.primary}>\n {C.grant}\n </button>\n </Form>\n </section>\n )\n}\n\n// ============================ User roles ============================\n\nexport type AuthzUserRolesData = WithLabels & { assignments: AuthzAssignment[]; roles: Array<{ id: number; roleKey: string }>; users: AuthzUser[]; actorUserId?: number; selfAdminRoleIds?: number[] }\n\nexport function AuthzUserRolesView() {\n const { assignments, roles, users, actorUserId, selfAdminRoleIds, labels } = useLoaderData() as AuthzUserRolesData\n const L = labels.userRoles\n const C = labels.common\n const selfAdmin = new Set(selfAdminRoleIds ?? [])\n\n const userOptions = users.map((u) => ({ label: `${u.email}(${u.displayName})`, value: u.id }))\n const roleOptions = roles.filter((r) => r.roleKey !== \"@authenticated\" && r.roleKey !== \"@anonymous\").map((r) => ({ label: r.roleKey, value: r.id }))\n\n const [selectedUser, setSelectedUser] = useState<{ label: string; value: number } | undefined>(undefined)\n const [selectedRole, setSelectedRole] = useState<{ label: string; value: number } | undefined>(undefined)\n\n return (\n <section>\n <h2 style={ui.h2}>{L.heading}</h2>\n <ErrorAlert message={actionError(useActionData() as ActionError)} />\n <p style={ui.note}>{L.note}</p>\n <div style={ui.tableContainer}>\n <table style={ui.table}>\n <thead>\n <tr>\n <th style={{ ...ui.th, width: \"45%\" }}>{L.user}</th>\n <th style={{ ...ui.th, width: \"45%\" }}>{L.role}</th>\n <th style={{ ...ui.th, width: \"10%\" }} />\n </tr>\n </thead>\n <tbody>\n {assignments.map((a) => (\n <tr key={`${a.userId}-${a.roleId}`}>\n <td style={ui.td}>\n {a.email}\n <span style={ui.muted}>({a.displayName})</span>\n </td>\n <td style={ui.td}>{a.roleKey}</td>\n <td style={ui.td}>\n <Form method=\"post\" style={{ display: \"inline\" }}>\n <input type=\"hidden\" name=\"_action\" value=\"remove\" />\n <input type=\"hidden\" name=\"userId\" value={a.userId} />\n <input type=\"hidden\" name=\"roleId\" value={a.roleId} />\n <button type=\"submit\" style={ui.danger} onClick={confirmGuard(a.userId === actorUserId && selfAdmin.has(a.roleId), labels.warn.selfAssignmentRemove)}>\n {C.remove}\n </button>\n </Form>\n </td>\n </tr>\n ))}\n {assignments.length === 0 ? (\n <tr>\n <td style={ui.empty} colSpan={3}>\n {L.empty}\n </td>\n </tr>\n ) : null}\n </tbody>\n </table>\n </div>\n\n <h3 style={ui.h3}>{L.newHeading}</h3>\n <Form method=\"post\" style={ui.card}>\n <input type=\"hidden\" name=\"_action\" value=\"assign\" />\n <input type=\"hidden\" name=\"userId\" value={selectedUser?.value ?? \"\"} />\n <input type=\"hidden\" name=\"roleId\" value={selectedRole?.value ?? \"\"} />\n <Field label={L.user}>\n <SelectBox options={userOptions} value={selectedUser} onChange={(val) => setSelectedUser((val || undefined) as { label: string; value: number } | undefined)} placeholder={L.selectPlaceholder} />\n </Field>\n <Field label={L.role}>\n <SelectBox options={roleOptions} value={selectedRole} onChange={(val) => setSelectedRole((val || undefined) as { label: string; value: number } | undefined)} placeholder={L.selectPlaceholder} />\n </Field>\n <button type=\"submit\" style={ui.primary}>\n {C.assign}\n </button>\n </Form>\n </section>\n )\n}\n\n// ============================ Single-file (splat) app view ============================\n\nconst SEGMENT_VIEWS: Record<string, () => React.ReactElement> = {\n roles: AuthzRolesView,\n resources: AuthzResourcesView,\n role_permissions: AuthzGrantsView,\n user_roles: AuthzUserRolesView,\n}\n\n/**\n * スプラット(`authz/*`)1 ルートで認可管理 UI 全体を描画するコンポーネント(store 非依存)。\n * loader が返す `segment` に応じて該当タブのビューを描画する。レイアウト殻と各ビューは同一の\n * loader データ(セグメントデータ + myPermissions + labels をトップレベルに統合)を読む。\n */\nexport function AuthzAdminAppView() {\n const { segment } = useLoaderData() as { segment: string }\n const View = SEGMENT_VIEWS[segment] ?? AuthzRolesView\n return (\n <AuthzLayoutShell>\n <View />\n </AuthzLayoutShell>\n )\n}\n","import { type CSSProperties, useEffect, useRef, useState } from \"react\"\nimport { MyPermissionIndicator } from \"./MyPermissionIndicator\"\nimport type { PermissionView } from \"./server\"\n\nexport type MyPermissionGroupItem = {\n /** Expected or actual resource key */\n resourceKey?: string\n /** Human-readable resource display name (e.g. \"NI\", \"KT\", \"オリジナル\") */\n resourceName: string\n /** Permission view data for this resource */\n permission: PermissionView | null | undefined\n /** Expected resource key to detect mismatches with permission.resourceKey during development */\n expectedResourceKey?: string\n /** Nesting level for hierarchical rendering (0: root, 1: child, etc.) */\n level?: number\n /** Optional child items for hierarchical rendering */\n children?: MyPermissionGroupItem[]\n}\n\n/**\n * Flattens hierarchical items tree into a single array with computed nesting levels.\n * 木構造またはフラット配列のアイテムに level 属性を付与してフラット化する処理。\n */\nexport function flattenGroupItems(items: MyPermissionGroupItem[], currentLevel = 0): MyPermissionGroupItem[] {\n const result: MyPermissionGroupItem[] = []\n for (const item of items) {\n const itemLevel = item.level ?? currentLevel\n result.push({ ...item, level: itemLevel })\n if (item.children && item.children.length > 0) {\n result.push(...flattenGroupItems(item.children, itemLevel + 1))\n }\n }\n return result\n}\n\nexport type MyPermissionGroupStatusProps = {\n /** List of resources and their permissions */\n items: MyPermissionGroupItem[]\n /** Prefix label shown before group items or inside popover header. Default: \"あなたの権限\" */\n prefixLabel?: string\n /**\n * Display style variant:\n * - \"pills\": Inline parent label + compact status tags per item\n * - \"popover\": Compact single button trigger opening detailed popup card\n * Default: \"pills\"\n */\n variant?: \"pills\" | \"popover\"\n /**\n * Component size variant:\n * - \"2xs\": Ultra micro size for extremely dense UI\n * - \"xs\": Extra small size for compact headers\n * - \"sm\": Small size\n * - \"md\": Standard default size\n * - \"lg\": Larger size\n * Default: \"md\"\n */\n size?: \"2xs\" | \"xs\" | \"sm\" | \"md\" | \"lg\"\n labels?: {\n read?: string\n write?: string\n delete?: string\n noPermission?: string\n fullWrite?: string\n partialWrite?: string\n readOnly?: string\n partialRead?: string\n }\n className?: string\n style?: CSSProperties\n}\n\nconst SIZE_CONFIGS = {\n \"2xs\": {\n fontSize: \"0.6rem\",\n pillPadding: \"0.05rem 0.25rem\",\n pillGap: \"0.15rem\",\n wrapperGap: \"0.15rem\",\n triggerPadding: \"0.1rem 0.35rem\",\n triggerFontSize: \"0.62rem\",\n badgeFontSize: \"0.58rem\",\n },\n xs: {\n fontSize: \"0.65rem\",\n pillPadding: \"0.08rem 0.35rem\",\n pillGap: \"0.18rem\",\n wrapperGap: \"0.2rem\",\n triggerPadding: \"0.12rem 0.4rem\",\n triggerFontSize: \"0.68rem\",\n badgeFontSize: \"0.62rem\",\n },\n sm: {\n fontSize: \"0.72rem\",\n pillPadding: \"0.1rem 0.4rem\",\n pillGap: \"0.2rem\",\n wrapperGap: \"0.25rem\",\n triggerPadding: \"0.15rem 0.45rem\",\n triggerFontSize: \"0.72rem\",\n badgeFontSize: \"0.65rem\",\n },\n md: {\n fontSize: \"0.78rem\",\n pillPadding: \"0.15rem 0.5rem\",\n pillGap: \"0.3rem\",\n wrapperGap: \"0.35rem\",\n triggerPadding: \"0.2rem 0.6rem\",\n triggerFontSize: \"0.78rem\",\n badgeFontSize: \"0.7rem\",\n },\n lg: {\n fontSize: \"0.85rem\",\n pillPadding: \"0.25rem 0.65rem\",\n pillGap: \"0.4rem\",\n wrapperGap: \"0.45rem\",\n triggerPadding: \"0.25rem 0.75rem\",\n triggerFontSize: \"0.85rem\",\n badgeFontSize: \"0.75rem\",\n },\n} as const\n\n/**\n * Get human-readable summary text and style for a resource permission.\n * 権限状態から簡潔なサマリテキストとスタイルを判定 (カスタムラベル対応)。\n */\nexport function getPermissionSummary(\n permission: PermissionView | null | undefined,\n customLabels?: MyPermissionGroupStatusProps[\"labels\"],\n): {\n text: string\n color: string\n bgColor: string\n borderColor: string\n} {\n const txtNoPerm = customLabels?.noPermission ?? \"権限なし\"\n const txtFullWrite = customLabels?.fullWrite ?? \"編集可\"\n const txtPartialRead = customLabels?.partialRead ?? \"一部閲覧\"\n const txtReadOnly = customLabels?.readOnly ?? \"閲覧のみ\"\n\n if (!(permission && (permission.read || permission.write || permission.delete))) {\n return { text: txtNoPerm, color: \"#64748b\", bgColor: \"#f1f5f9\", borderColor: \"#cbd5e1\" }\n }\n if (permission.write) {\n return { text: txtFullWrite, color: \"#047857\", bgColor: \"#ecfdf5\", borderColor: \"#a7f3d0\" }\n }\n if (permission.read) {\n if (permission.readPartial) {\n return { text: txtPartialRead, color: \"#b45309\", bgColor: \"#fffbeb\", borderColor: \"#fde68a\" }\n }\n return { text: txtReadOnly, color: \"#1d4ed8\", bgColor: \"#eff6ff\", borderColor: \"#bfdbfe\" }\n }\n return { text: txtNoPerm, color: \"#64748b\", bgColor: \"#f1f5f9\", borderColor: \"#cbd5e1\" }\n}\n\n/**\n * Render compact status pill for a single resource item in \"pills\" mode.\n * 「pills」モード用: リソースごとのコンパクトなステータスタグを描画。\n */\nfunction GroupItemPill({ item, size = \"md\", labels }: { item: MyPermissionGroupItem; size?: \"2xs\" | \"xs\" | \"sm\" | \"md\" | \"lg\"; labels?: MyPermissionGroupStatusProps[\"labels\"] }) {\n const summary = getPermissionSummary(item.permission, labels)\n const resKey = item.permission?.resourceKey || item.resourceKey || item.expectedResourceKey\n const resName = item.resourceName || resKey\n const hasMismatch = Boolean(item.expectedResourceKey && item.permission?.resourceKey && item.permission.resourceKey !== item.expectedResourceKey)\n const cfg = SIZE_CONFIGS[size]\n\n const tooltipText = `対象: ${resName}${resKey ? ` (${resKey})` : \"\"}${item.permission ? ` | ${labels?.read ?? \"閲覧\"}:${item.permission.read ? \"○\" : \"×\"} ${labels?.write ?? \"編集\"}:${item.permission.write ? \"○\" : \"×\"} ${labels?.delete ?? \"削除\"}:${item.permission.delete ? \"○\" : \"×\"}` : \"\"}`\n\n return (\n <span\n title={tooltipText}\n data-testid={`permission-pill-${item.resourceName}`}\n data-mismatch={hasMismatch ? \"true\" : \"false\"}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: cfg.pillGap,\n fontSize: cfg.fontSize,\n padding: cfg.pillPadding,\n borderRadius: \"9999px\",\n backgroundColor: hasMismatch ? \"#fee2e2\" : summary.bgColor,\n color: hasMismatch ? \"#991b1b\" : summary.color,\n border: `1px solid ${hasMismatch ? \"#fca5a5\" : summary.borderColor}`,\n fontWeight: 600,\n lineHeight: \"1.2\",\n }}>\n <span>{resName}:</span>\n <span>{summary.text}</span>\n {hasMismatch && <span title={`expected \"${item.expectedResourceKey}\", actual \"${item.permission?.resourceKey}\"`}>⚠️</span>}\n </span>\n )\n}\n\n/**\n * Multi-resource \"Your Permissions\" status component.\n * Supports inline compact pills (Proposal 1) and dropdown popover card (Proposal 2).\n * 複数リソースの権限状態を共通レイアウト(pills/popover)で綺麗に整列・表示するコンポーネント。\n */\nexport function MyPermissionGroupStatus({ items, prefixLabel = \"あなたの権限\", variant = \"pills\", size = \"md\", labels, className = \"authz-permission-group-status\", style }: MyPermissionGroupStatusProps) {\n const [isOpen, setIsOpen] = useState(false)\n const popoverRef = useRef<HTMLSpanElement>(null)\n const cfg = SIZE_CONFIGS[size]\n\n // Close popover when clicking outside or pressing Escape\n useEffect(() => {\n if (variant !== \"popover\" || !isOpen) return\n\n function handleClickOutside(event: MouseEvent) {\n if (popoverRef.current && !popoverRef.current.contains(event.target as Node)) {\n setIsOpen(false)\n }\n }\n function handleKeyDown(event: KeyboardEvent) {\n if (event.key === \"Escape\") {\n setIsOpen(false)\n }\n }\n\n document.addEventListener(\"mousedown\", handleClickOutside)\n document.addEventListener(\"keydown\", handleKeyDown)\n return () => {\n document.removeEventListener(\"mousedown\", handleClickOutside)\n document.removeEventListener(\"keydown\", handleKeyDown)\n }\n }, [variant, isOpen])\n\n if (variant === \"popover\") {\n // Compute brief overall summary for the trigger button\n const writeCount = items.filter((i) => i.permission?.write).length\n const totalCount = items.length\n const summaryLabel = writeCount === totalCount ? (labels?.fullWrite ?? \"編集可\") : writeCount > 0 ? (labels?.partialWrite ?? \"一部編集可\") : (labels?.readOnly ?? \"閲覧のみ\")\n\n return (\n <span ref={popoverRef} className={className} data-testid=\"my-permission-group-popover\" style={{ position: \"relative\", display: \"inline-block\", ...style }}>\n <button\n type=\"button\"\n onClick={() => setIsOpen(!isOpen)}\n data-testid=\"permission-popover-trigger\"\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: cfg.wrapperGap,\n fontSize: cfg.triggerFontSize,\n padding: cfg.triggerPadding,\n borderRadius: \"6px\",\n backgroundColor: \"#f8fafc\",\n color: \"#334155\",\n border: \"1px solid #cbd5e1\",\n fontWeight: 600,\n cursor: \"pointer\",\n }}>\n <span>🔒 {prefixLabel}</span>\n <span style={{ fontSize: cfg.badgeFontSize, color: \"#64748b\" }}>({summaryLabel})</span>\n <span style={{ fontSize: \"0.65rem\", marginLeft: \"0.1rem\" }}>{isOpen ? \"▲\" : \"▾\"}</span>\n </button>\n\n {isOpen && (\n <div\n data-testid=\"permission-popover-card\"\n style={{\n position: \"absolute\",\n top: \"calc(100% + 6px)\",\n right: 0,\n zIndex: 50,\n minWidth: \"280px\",\n whiteSpace: \"nowrap\",\n padding: \"0.75rem 0.85rem\",\n backgroundColor: \"#ffffff\",\n borderRadius: \"8px\",\n boxShadow: \"0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)\",\n border: \"1px solid #e2e8f0\",\n fontSize: \"0.82rem\",\n }}>\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n marginBottom: \"0.5rem\",\n paddingBottom: \"0.4rem\",\n borderBottom: \"1px solid #f1f5f9\",\n fontWeight: 700,\n color: \"#1e293b\",\n whiteSpace: \"nowrap\",\n }}>\n <span>🔒 {prefixLabel}</span>\n <button\n type=\"button\"\n onClick={() => setIsOpen(false)}\n style={{\n border: \"none\",\n background: \"none\",\n cursor: \"pointer\",\n color: \"#94a3b8\",\n fontSize: \"0.85rem\",\n padding: \"0 0.2rem\",\n }}>\n ✕\n </button>\n </div>\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"0.4rem\" }}>\n {flattenGroupItems(items).map((item) => {\n const level = item.level ?? 0\n const isChild = level > 0\n return (\n <div\n key={item.resourceName}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: \"1.25rem\",\n whiteSpace: \"nowrap\",\n paddingLeft: isChild ? `${level * 0.85}rem` : \"0\",\n }}>\n <div style={{ display: \"inline-flex\", alignItems: \"center\", whiteSpace: \"nowrap\" }}>\n {isChild && (\n <span\n aria-hidden=\"true\"\n style={{\n display: \"inline-block\",\n width: \"10px\",\n height: \"10px\",\n borderLeft: \"1.5px solid #cbd5e1\",\n borderBottom: \"1.5px solid #cbd5e1\",\n borderBottomLeftRadius: \"3px\",\n marginRight: \"6px\",\n marginTop: \"-4px\",\n flexShrink: 0,\n }}\n />\n )}\n <span\n style={{\n fontWeight: isChild ? 500 : 600,\n color: isChild ? \"#64748b\" : \"#1e293b\",\n fontSize: isChild ? \"0.78rem\" : \"0.82rem\",\n whiteSpace: \"nowrap\",\n }}>\n {item.resourceName}:\n </span>\n </div>\n <MyPermissionIndicator permission={item.permission} resourceName={item.resourceName} expectedResourceKey={item.expectedResourceKey} labels={labels} />\n </div>\n )\n })}\n </div>\n </div>\n )}\n </span>\n )\n }\n\n // Default \"pills\" variant\n return (\n <span\n className={className}\n data-testid=\"my-permission-group-pills\"\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n flexWrap: \"wrap\",\n gap: cfg.pillGap,\n fontSize: cfg.fontSize,\n color: \"#475569\",\n ...style,\n }}>\n {prefixLabel && <span style={{ fontWeight: 600, color: \"#334155\" }}>{prefixLabel}:</span>}\n <span style={{ display: \"inline-flex\", alignItems: \"center\", flexWrap: \"wrap\", gap: cfg.pillGap }}>\n {items.map((item) => (\n <GroupItemPill key={item.resourceName} item={item} size={size} labels={labels} />\n ))}\n </span>\n </span>\n )\n}\n","import type { PermissionView } from \"./server\"\n\nexport type PermState = \"full\" | \"partial\" | \"none\"\n\nexport type UsePermission = {\n canRead: boolean\n canWrite: boolean\n canDelete: boolean\n /** read: none(×) / partial(△, row|col restricted) / full(○). */\n readState: PermState\n /** write = create ∪ update: full(○ both) / partial(△ one) / none(×). */\n writeState: PermState\n deleteState: PermState\n}\n\n/**\n * Derive ○△× display states from a {@link PermissionView}. Pure (safe to call in render);\n * named `usePermission` for ergonomic call-sites.\n */\nexport function usePermission(view: PermissionView | null | undefined): UsePermission {\n const readState: PermState = !view?.read ? \"none\" : view.readPartial ? \"partial\" : \"full\"\n const writeState: PermState = view?.create && view?.update ? \"full\" : view?.create || view?.update ? \"partial\" : \"none\"\n const deleteState: PermState = view?.delete ? \"full\" : \"none\"\n return {\n canRead: !!view?.read,\n canWrite: !!view?.write,\n canDelete: !!view?.delete,\n readState,\n writeState,\n deleteState,\n }\n}\n","import type { PermissionView } from \"./server\"\nimport { type PermState, usePermission } from \"./usePermission\"\n\nexport type MyPermissionIndicatorProps = {\n permission: PermissionView | null | undefined\n /** Human-readable resource display name (e.g. \"文書データ\"). Falls back to permission.resourceKey. */\n resourceName?: string\n /** Expected resource key to detect mismatches with permission.resourceKey during development. */\n expectedResourceKey?: string\n /** Whether to include resource name/key tooltip. Default true. */\n showResourceTooltip?: boolean\n labels?: { read?: string; write?: string; delete?: string }\n /** Show a \"(部分)\" hint when read is partial. Default true. */\n showScopeSummary?: boolean\n className?: string\n}\n\nexport type MyPermissionStatusProps = MyPermissionIndicatorProps & {\n /** Label prefix shown before the indicator badges. Default: \"あなたの権限\" */\n prefixLabel?: string\n /** Whether to display the prefix label. Default: true */\n showPrefixLabel?: boolean\n /** Additional inline styles for wrapper element. */\n style?: React.CSSProperties\n}\n\nconst STATE_STYLE: Record<PermState, { bg: string; text: string; border: string }> = {\n full: { bg: \"#ecfdf5\", text: \"#047857\", border: \"#a7f3d0\" },\n partial: { bg: \"#fffbeb\", text: \"#b45309\", border: \"#fde68a\" },\n none: { bg: \"#f8fafc\", text: \"#94a3b8\", border: \"#cbd5e1\" },\n}\n\n/**\n * Format human-readable resource tooltip text.\n * リソース表示名およびキーからツールチップ用テキストを生成。\n */\nexport function formatResourceTooltip(resourceKey?: string, resourceName?: string): string | undefined {\n const key = resourceKey?.trim()\n const name = resourceName?.trim()\n if (name && key && name !== key) {\n return `対象リソース: ${name} (${key})`\n }\n if (name || key) {\n return `対象リソース: ${name || key}`\n }\n return undefined\n}\n\n/**\n * Render icon according to permission state.\n * 権限状態に応じた SVG アイコンをレンダリング。\n */\nfunction PermIcon({ state }: { state: PermState }) {\n if (state === \"full\") {\n return (\n <svg style={{ width: \"0.85rem\", height: \"0.85rem\", flexShrink: 0 }} fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n )\n }\n if (state === \"partial\") {\n return (\n <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\">\n <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\" />\n </svg>\n )\n }\n return (\n <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\">\n <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\" />\n </svg>\n )\n}\n\n/**\n * Display permission indicator badges for read, write, and delete capabilities.\n * 閲覧・編集・削除の権限状態バッジ群を描画。\n */\nexport function MyPermissionIndicator({\n permission,\n resourceName,\n expectedResourceKey,\n showResourceTooltip = true,\n labels,\n showScopeSummary = true,\n className = \"authz-permission-indicator\",\n}: MyPermissionIndicatorProps) {\n const p = usePermission(permission)\n const l = { read: labels?.read ?? \"閲覧\", write: labels?.write ?? \"編集\", delete: labels?.delete ?? \"削除\" }\n const resKey = permission?.resourceKey\n const resName = resourceName || resKey\n const tooltipText = showResourceTooltip ? formatResourceTooltip(resKey, resourceName) : undefined\n\n const hasMismatch = Boolean(expectedResourceKey && resKey && resKey !== expectedResourceKey)\n\n if (hasMismatch && typeof console !== \"undefined\" && typeof console.error === \"function\") {\n console.error(`[Authz Warning] Resource key mismatch in MyPermissionIndicator! Expected: \"${expectedResourceKey}\", but received permission for: \"${resKey}\".`)\n }\n\n const renderBadge = (key: \"read\" | \"write\" | \"delete\", state: PermState, label: string) => {\n const style = STATE_STYLE[state]\n const badgeTitle = tooltipText ? `${label}: ${state}\\n${tooltipText}` : `${label}: ${state}`\n return (\n <span\n data-perm={key}\n data-state={state}\n title={badgeTitle}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"0.25rem\",\n padding: \"0.2rem 0.5rem\",\n borderRadius: \"100px\",\n fontSize: \"0.75rem\",\n fontWeight: 600,\n backgroundColor: style.bg,\n color: style.text,\n border: `1px solid ${style.border}`,\n lineHeight: 1,\n userSelect: \"none\",\n }}>\n <PermIcon state={state} />\n <span>{label}</span>\n </span>\n )\n }\n\n return (\n <span\n className={className}\n title={tooltipText}\n data-resource={resKey ?? \"\"}\n data-resource-name={resName ?? \"\"}\n data-mismatch={hasMismatch ? \"true\" : undefined}\n style={{\n display: \"inline-flex\",\n gap: \"0.35rem\",\n alignItems: \"center\",\n verticalAlign: \"middle\",\n }}>\n {renderBadge(\"read\", p.readState, l.read)}\n {renderBadge(\"write\", p.writeState, l.write)}\n {renderBadge(\"delete\", p.deleteState, l.delete)}\n {showScopeSummary && p.readState === \"partial\" ? (\n <span\n data-perm=\"scope\"\n title={tooltipText}\n style={{\n fontSize: \"0.7rem\",\n color: \"#b45309\",\n backgroundColor: \"#fef3c7\",\n padding: \"0.15rem 0.35rem\",\n borderRadius: \"4px\",\n fontWeight: 600,\n }}>\n 部分制限\n </span>\n ) : null}\n {hasMismatch ? (\n <span\n data-testid=\"resource-mismatch-warning\"\n title={`expected: \"${expectedResourceKey}\", actual: \"${resKey}\"`}\n style={{\n fontSize: \"0.7rem\",\n color: \"#991b1b\",\n backgroundColor: \"#fee2e2\",\n border: \"1px solid #fca5a5\",\n padding: \"0.15rem 0.35rem\",\n borderRadius: \"4px\",\n fontWeight: 700,\n }}>\n ⚠️ リソース不一致 ({resKey} ≠ {expectedResourceKey})\n </span>\n ) : null}\n </span>\n )\n}\n\n/**\n * Reusable \"Your Permissions\" status bar component suitable for any application page.\n * 「あなたの権限」ラベルと権限状態インジケータを束ねた再利用可能なコンポーネント。\n */\nexport function MyPermissionStatus({\n permission,\n resourceName,\n expectedResourceKey,\n prefixLabel = \"あなたの権限\",\n showPrefixLabel = true,\n showResourceTooltip = true,\n labels,\n showScopeSummary = true,\n className = \"authz-permission-status\",\n style,\n}: MyPermissionStatusProps) {\n const resKey = permission?.resourceKey\n const resName = resourceName || resKey\n const tooltipText = showResourceTooltip ? formatResourceTooltip(resKey, resourceName) : undefined\n\n return (\n <span\n className={className}\n title={tooltipText}\n data-testid=\"my-permission-status\"\n data-resource={resKey ?? \"\"}\n data-resource-name={resName ?? \"\"}\n style={{\n fontSize: \"0.82rem\",\n color: \"#475569\",\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"0.4rem\",\n ...style,\n }}>\n {showPrefixLabel && <span data-testid=\"prefix-label\">{prefixLabel}:</span>}\n <MyPermissionIndicator\n permission={permission}\n resourceName={resourceName}\n expectedResourceKey={expectedResourceKey}\n showResourceTooltip={showResourceTooltip}\n labels={labels}\n showScopeSummary={showScopeSummary}\n />\n </span>\n )\n}\n","/**\n * Resource definition and registry utilities for preventing page-resource mismatches.\n * ページとリソースの表示・権限食い違いを防止するためのリソースレジストリ定義。\n */\n\nexport type ResourceDefinition = {\n /** Unique resource key used in authorization rules (e.g. \"documents\") */\n key: string\n /** Human-readable display name (e.g. \"文書管理\") */\n name: string\n /** Optional description for administration UI */\n description?: string\n}\n\nexport type ResourceDefinitionInput = {\n /** Optional explicit resource key; defaults to the object property name */\n key?: string\n /** Human-readable display name (e.g. \"文書管理\") */\n name: string\n /** Optional description for administration UI */\n description?: string\n}\n\nexport type ResourceRegistry<T extends Record<string, ResourceDefinition>> = T\n\n/**\n * Define type-safe resource registry for an application.\n * アプリ全体のリソース定義(キー・表示名・説明)を一元管理するヘルパー。\n */\nexport function defineResources<T extends Record<string, ResourceDefinitionInput>>(resources: T): { [K in keyof T & string]: ResourceDefinition } {\n const result = {} as { [K in keyof T & string]: ResourceDefinition }\n for (const k of Object.keys(resources) as Array<keyof T & string>) {\n const item = resources[k]\n result[k] = {\n key: item.key ?? k,\n name: item.name,\n description: item.description,\n }\n }\n return result\n}\n","import { type AuthzAction, can, createRequirePermission, type DenyInfo, type EffectivePermission, type GuardResult } from \"@aiquants/authz-core\"\nimport { redirect } from \"react-router\"\n\ntype Awaitable<T> = T | Promise<T>\nexport type AuthzUserId = string | number\n\nexport type AuthzConfig = {\n /** Stable app identifier (e.g. \"quants\"). Bound into every permission query. */\n appKey: string\n /** Resolve the acting user id from the request (cookie/session/openid → TDUsers.id). */\n resolveUserId: (request: Request) => Awaitable<AuthzUserId | null | undefined>\n /** Load effective permissions for (user, app, resource) — typically via @aiquants/authz-drizzle. */\n getEffectivePermissions: (args: { userId: AuthzUserId | null; appKey: string; resourceKey: string }) => Awaitable<EffectivePermission | null | undefined>\n /** Default deny handler. If omitted, denies throw AuthzDeniedError (403). */\n onDeny?: (info: DenyInfo) => void\n}\n\nexport type RequirePermissionOptions = {\n /** When set, denials `throw redirect(failureRedirect)` instead of throwing 403. */\n failureRedirect?: string\n}\n\n/** Serializable per-resource permission summary for UI (loader → component). */\nexport type PermissionView = {\n resourceKey: string\n read: boolean\n create: boolean\n update: boolean\n delete: boolean\n /** create ∪ update */\n write: boolean\n /** read granted but row and/or column restricted (→ △ partial). */\n readPartial: boolean\n actions: AuthzAction[]\n}\n\n/** Map an EffectivePermission to a serializable {@link PermissionView}. */\nexport function toPermissionView(resourceKey: string, perm: EffectivePermission | null | undefined): PermissionView {\n const read = can(perm, \"read\")\n const create = can(perm, \"create\")\n const update = can(perm, \"update\")\n const del = can(perm, \"delete\")\n const readScope = perm?.scopeByAction.read\n const readPartial = read && !!readScope && (readScope.rowScope !== null || readScope.columnScope !== null)\n return {\n resourceKey,\n read,\n create,\n update,\n delete: del,\n write: create || update,\n readPartial,\n actions: perm ? Array.from(perm.actions) : [],\n }\n}\n\n/**\n * React Router adapter. Binds `appKey` and the DI deps, exposing:\n * - `requirePermission(request, {resourceKey, action}, options?)` → `{ userId, scope }` on allow\n * (apply row WHERE / column mask with the returned scope); denies throw 403 or redirect.\n * - `getMyPermissions(request, {resourceKeys})` → `Record<resourceKey, PermissionView>` for the UI.\n */\nexport function createAuthz(config: AuthzConfig) {\n async function requirePermission(request: Request, query: { resourceKey: string; action: AuthzAction }, options?: RequirePermissionOptions): Promise<GuardResult<AuthzUserId>> {\n const onDeny: ((info: DenyInfo) => void) | undefined = options?.failureRedirect\n ? () => {\n throw redirect(options.failureRedirect as string)\n }\n : config.onDeny\n const guard = createRequirePermission<Request, AuthzUserId>({\n resolveUserId: config.resolveUserId,\n getEffectivePermissions: config.getEffectivePermissions,\n onDeny,\n })\n return guard(request, { appKey: config.appKey, resourceKey: query.resourceKey, action: query.action })\n }\n\n async function getMyPermissions(request: Request, query: { resourceKeys: string[] }): Promise<Record<string, PermissionView>> {\n const userId = await config.resolveUserId(request)\n const out: Record<string, PermissionView> = {}\n for (const resourceKey of query.resourceKeys) {\n const perm = await config.getEffectivePermissions({ userId: userId ?? null, appKey: config.appKey, resourceKey })\n out[resourceKey] = toPermissionView(resourceKey, perm)\n }\n return out\n }\n\n /**\n * Atomically require permission and return both guard result and UI PermissionView.\n * Guarantees that guarded resource and returned UI permission object remain identical.\n * ガード処理と UI 表示用権限データの取得を同一リソースキーでアトミックに実行。\n */\n async function requireAndGetPermission(\n request: Request,\n query: { resourceKey: string; action: AuthzAction },\n options?: RequirePermissionOptions,\n ): Promise<GuardResult<AuthzUserId> & { permission: PermissionView }> {\n const guard = await requirePermission(request, query, options)\n const perms = await getMyPermissions(request, { resourceKeys: [query.resourceKey] })\n return {\n ...guard,\n permission: perms[query.resourceKey],\n }\n }\n\n return { requirePermission, getMyPermissions, requireAndGetPermission }\n}\n"],"mappings":"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","names":["index_exports","__export","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","__toCommonJS","import_react_router","import_authz_core","import_react_router","defaultAuthzAdminLabels","resolveLabels","over","d","isResponse","e","toActionError","createAuthzAdminServer","opts","store","RES","labels","resolveLabels","requirePermission","request","query","userId","layoutGuard","loadMyPermissions","rolesData","roles","self","resourcesData","grantsData","grants","resources","userRolesData","assignments","users","form","intent","roleKey","name","appKey","resourceKey","roleId","resourceId","rawAction","action","actor","segmentOf","params","createAuthzAdminApp","opts","server","createAuthzAdminServer","basePath","SEGMENTS","segmentData","actions","loader","args","segment","userId","myPermissions","segData","action","act","import_jsx_runtime","ui","Field","label","hint","children","ErrorAlert","message","import_authz_core","import_select_box","import_react","import_react_router","import_react","usePermission","view","readState","writeState","deleteState","import_jsx_runtime","STATE_STYLE","formatResourceTooltip","resourceKey","resourceName","key","name","PermIcon","state","MyPermissionIndicator","permission","expectedResourceKey","showResourceTooltip","labels","showScopeSummary","className","usePermission","l","resKey","resName","tooltipText","hasMismatch","renderBadge","label","style","badgeTitle","MyPermissionStatus","prefixLabel","showPrefixLabel","import_jsx_runtime","flattenGroupItems","items","currentLevel","result","item","itemLevel","SIZE_CONFIGS","getPermissionSummary","permission","customLabels","txtNoPerm","txtFullWrite","txtPartialRead","txtReadOnly","GroupItemPill","size","labels","summary","resKey","resName","hasMismatch","cfg","tooltipText","MyPermissionGroupStatus","prefixLabel","variant","className","style","isOpen","setIsOpen","popoverRef","handleClickOutside","event","handleKeyDown","writeCount","i","totalCount","summaryLabel","level","isChild","MyPermissionIndicator","import_jsx_runtime","actionError","d","AuthzLayoutShell","children","myPermissions","labels","adminResourceKey","basePath","base","variant","setVariant","tabs","permissionItems","key","perm","items","ui","MyPermissionGroupStatus","label","isActive","AuthzLayout","makeAuthzErrorBoundary","over","L","resolveLabels","error","routeError","is403","title","message","AuthzErrorBoundary","confirmGuard","active","e","AuthzRolesView","roles","selfAdminRoleIds","C","selfAdmin","ErrorAlert","r","Field","AuthzResourcesView","resources","GrantRow","g","action","setAction","a","val","AuthzGrantsView","grants","roleOptions","resourceOptions","actionOptions","selectedRole","setSelectedRole","selectedResource","setSelectedResource","selectedAction","setSelectedAction","AuthzUserRolesView","assignments","users","actorUserId","userOptions","u","selectedUser","setSelectedUser","SEGMENT_VIEWS","AuthzAdminAppView","segment","View","defineResources","resources","result","k","item","import_authz_core","import_react_router","toPermissionView","resourceKey","perm","read","create","update","del","readScope","readPartial","createAuthz","config","requirePermission","request","query","options","onDeny","getMyPermissions","userId","out","requireAndGetPermission","guard","perms"]}