@aiquants/authz-react-router 0.6.0 → 0.7.1

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/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\", \"group_roles\", \"graph\"] 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, group_roles: server.groupRoles.data, graph: server.graph.data }\n const actions: Record<string, ((args: RouteArgs) => Promise<unknown>) | undefined> = {\n roles: server.roles.action,\n resources: server.resources.action,\n role_permissions: server.grants.action,\n user_roles: server.userRoles.action,\n group_roles: server.groupRoles.action,\n }\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, AuthzGraphData, AuthzGroupRolesData, 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 const groupRolesData = async (): Promise<AuthzGroupRolesData> => {\n const [groupRoles, roles, groups] = await Promise.all([store.listGroupRoles(), store.listRoles(), store.listGroups()])\n return { groupRoles, roles, groups, labels }\n }\n const graphData = async (): Promise<AuthzGraphData> => {\n const [users, roles, resources, grants, assignments, groupRoles, groups] = await Promise.all([store.listUsers(), store.listRoles(), store.listResources(), store.listGrants(), store.listUserRoles(), store.listGroupRoles(), store.listGroups()])\n return { users, roles, resources, grants, assignments, groupRoles, groups, 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 groupRoles: {\n data: groupRolesData,\n async loader({ request }: Req): Promise<AuthzGroupRolesData> {\n await requirePermission(request, { resourceKey: RES, action: \"read\" })\n return groupRolesData()\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 groupId = Number(form.get(\"groupId\"))\n const roleId = Number(form.get(\"roleId\"))\n if (!(groupId && roleId)) return data({ error: \"グループとロールを選択してください\" }, { status: 400 })\n await store.assignGroupRole(groupId, roleId, String(actor))\n return { ok: true }\n }\n case \"remove\": {\n await requirePermission(request, { resourceKey: RES, action: \"delete\" })\n await store.removeGroupRole(Number(form.get(\"groupId\")), 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 graph: {\n data: graphData,\n async loader({ request }: Req): Promise<AuthzGraphData> {\n await requirePermission(request, { resourceKey: RES, action: \"read\" })\n return graphData()\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; group_roles: string; graph: 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 groupRoles: { heading: string; note: string; group: 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\", group_roles: \"Group assignments\", graph: \"Graph\" },\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 groupRoles: { heading: \"Group assignments (TDGroupRole)\", note: \"Assign active roles to user groups.\", group: \"group\", role: \"role\", empty: \"No group assignments\", newHeading: \"Assign a role to group\", 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 groupRoles?: Partial<AuthzAdminLabels[\"groupRoles\"]>\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 groupRoles: { ...d.groupRoles, ...over.groupRoles },\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 AuthzGroupRoleAssignment, type AuthzGroupSummary, 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\nexport type AuthzLayoutShellProps = {\n children: React.ReactNode\n renderHeader?: (props: { title: string; annotation: React.ReactNode }) => React.ReactNode\n}\n\n/** ヘッダ(タイトル + あなたの権限) + タブ。中身は children(splat) か Outlet(ネスト)。 */\nfunction AuthzLayoutShell({ children, renderHeader }: AuthzLayoutShellProps) {\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 [\"group_roles\", labels.tabs.group_roles],\n [\"graph\", labels.tabs.graph],\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 const annotation = (\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 )\n\n return (\n <div className=\"authz-admin\" style={ui.page}>\n {renderHeader ? (\n renderHeader({ title: labels.title, annotation })\n ) : (\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 {annotation}\n </header>\n )}\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\nexport type AuthzLayoutProps = {\n renderHeader?: (props: { title: string; annotation: React.ReactNode }) => React.ReactNode\n}\n\n/** ネストルート用レイアウト(子は Outlet)。`routes.ts` でネスト構成にする場合に使う。 */\nexport function AuthzLayout({ renderHeader }: AuthzLayoutProps = {}) {\n return (\n <AuthzLayoutShell renderHeader={renderHeader}>\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// ============================ Group roles ============================\n\nexport type AuthzGroupRolesData = WithLabels & {\n groupRoles: AuthzGroupRoleAssignment[]\n roles: AuthzRole[]\n groups: AuthzGroupSummary[]\n}\n\nexport function AuthzGroupRolesView() {\n const { groupRoles, roles, groups, labels } = useLoaderData() as AuthzGroupRolesData\n const actionData = useActionData() as ActionError\n const err = actionError(actionData)\n const L = labels.groupRoles\n const C = labels.common\n\n const activeRoles = roles.filter((r) => r.isActive && r.roleKey !== \"@authenticated\" && r.roleKey !== \"@anonymous\")\n\n const groupOptions = groups.map((g) => ({ label: `${g.name} (${g.groupKey})`, value: g.id }))\n const roleOptions = activeRoles.map((r) => ({ label: `${r.name} (${r.roleKey})`, value: r.id }))\n\n const [selectedGroup, setSelectedGroup] = useState<{ label: string; value: number } | undefined>(groupOptions[0])\n const [selectedRole, setSelectedRole] = useState<{ label: string; value: number } | undefined>(roleOptions[0])\n\n return (\n <section style={{ display: \"flex\", flexDirection: \"column\", gap: \"1.25rem\" }}>\n <div>\n <h2 style={ui.h2}>{L.heading}</h2>\n <p style={ui.note}>{L.note}</p>\n </div>\n {err && <ErrorAlert message={err} />}\n\n <table style={ui.table}>\n <thead>\n <tr>\n <th style={ui.th}>{L.group}</th>\n <th style={ui.th}>{L.role}</th>\n <th style={{ ...ui.th, width: \"100px\" }} />\n </tr>\n </thead>\n <tbody>\n {groupRoles.length === 0 ? (\n <tr>\n <td colSpan={3} style={{ ...ui.td, textAlign: \"center\", color: \"#64748b\" }}>\n {L.empty}\n </td>\n </tr>\n ) : (\n groupRoles.map((a) => (\n <tr key={`${a.groupId}-${a.roleId}`}>\n <td style={ui.td}>\n <strong>{a.groupName}</strong> <span style={{ color: \"#64748b\", fontSize: \"0.85rem\" }}>({a.groupKey})</span>\n </td>\n <td style={ui.td}>\n <code>{a.roleKey}</code>\n </td>\n <td style={{ ...ui.td, textAlign: \"right\" }}>\n <Form method=\"post\" onSubmit={(e) => !confirm(\"このグループロール割当を解除しますか?\") && e.preventDefault()}>\n <input type=\"hidden\" name=\"_action\" value=\"remove\" />\n <input type=\"hidden\" name=\"groupId\" value={a.groupId} />\n <input type=\"hidden\" name=\"roleId\" value={a.roleId} />\n <button type=\"submit\" style={ui.dangerBtn}>\n {C.remove}\n </button>\n </Form>\n </td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n\n <Form method=\"post\" style={ui.card}>\n <h3 style={ui.h3}>{L.newHeading}</h3>\n <input type=\"hidden\" name=\"_action\" value=\"assign\" />\n <input type=\"hidden\" name=\"groupId\" value={selectedGroup?.value ?? \"\"} />\n <input type=\"hidden\" name=\"roleId\" value={selectedRole?.value ?? \"\"} />\n <Field label={L.group}>\n <SelectBox options={groupOptions} value={selectedGroup} onChange={(val) => setSelectedGroup((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// ============================ Graph view ============================\n\nexport type AuthzGraphData = WithLabels & {\n users: AuthzUser[]\n roles: AuthzRole[]\n resources: AuthzResource[]\n grants: AuthzGrant[]\n assignments: AuthzAssignment[]\n groupRoles?: AuthzGroupRoleAssignment[]\n groups?: AuthzGroupSummary[]\n}\n\nconst ACTION_COLORS: Record<string, { bg: string; text: string; border: string }> = {\n read: { bg: \"#ecfdf5\", text: \"#047857\", border: \"#a7f3d0\" },\n create: { bg: \"#eff6ff\", text: \"#1d4ed8\", border: \"#bfdbfe\" },\n update: { bg: \"#fffbeb\", text: \"#b45309\", border: \"#fde68a\" },\n delete: { bg: \"#fef2f2\", text: \"#b91c1c\", border: \"#fecaca\" },\n}\n\nexport type AuthzNodeType = \"user\" | \"group\" | \"role\" | \"resource\"\n\nfunction AuthzTopologyMap({\n users,\n roles,\n resources,\n grants,\n assignments,\n groupRoles = [],\n groups = [],\n selectedNode,\n onNodeClick,\n}: {\n users: AuthzUser[]\n roles: AuthzRole[]\n resources: AuthzResource[]\n grants: AuthzGrant[]\n assignments: AuthzAssignment[]\n groupRoles?: AuthzGroupRoleAssignment[]\n groups?: AuthzGroupSummary[]\n selectedNode: { type: AuthzNodeType; id: number } | null\n onNodeClick: (type: AuthzNodeType, id: number) => void\n}) {\n const [hoveredNode, setHoveredNode] = useState<{ type: AuthzNodeType; id: number } | null>(null)\n\n const connectedUserIds = new Set(assignments.map((a) => a.userId))\n const connectedGroupIds = new Set(groupRoles.map((g) => g.groupId))\n const connectedRoleIds = new Set([...assignments.map((a) => a.roleId), ...groupRoles.map((g) => g.roleId), ...grants.map((g) => g.roleId)])\n const connectedResourceIds = new Set(grants.map((g) => g.resourceId))\n\n const activeUsers = users.filter((u) => connectedUserIds.has(u.id))\n const activeGroups = groups.filter((g) => connectedGroupIds.has(g.id))\n const activeRoles = roles.filter((r) => connectedRoleIds.has(r.id))\n const activeResources = resources.filter((res) => connectedResourceIds.has(res.id))\n\n const getResourceActions = (resId: number) => {\n const resGrants = grants.filter((g) => g.resourceId === resId)\n const uniqueActions = Array.from(new Set(resGrants.map((g) => g.action)))\n return uniqueActions.length > 0 ? uniqueActions : [\"none\"]\n }\n\n const getResourceCardHeight = (resId: number) => {\n const actions = getResourceActions(resId)\n return 8 + 24 + actions.length * 24 + 6\n }\n\n const resourceCardGap = 16\n let cumulativeResY = 0\n const resourceYMap = new Map<number, { top: number; height: number; actionYMap: Map<string, number> }>()\n\n activeResources.forEach((res) => {\n const actions = getResourceActions(res.id)\n const height = getResourceCardHeight(res.id)\n const top = cumulativeResY\n const actionYMap = new Map<string, number>()\n\n actions.forEach((act, actIdx) => {\n const actY = top + 8 + 24 + actIdx * 24 + 12\n actionYMap.set(act, actY)\n })\n\n resourceYMap.set(res.id, { top, height, actionYMap })\n cumulativeResY += height + resourceCardGap\n })\n\n const totalResourceHeight = cumulativeResY > 0 ? cumulativeResY - resourceCardGap : 0\n\n const stdCardHeight = 52\n const stdCardGap = 18\n const stdItemHeight = stdCardHeight + stdCardGap\n\n const totalRoleHeight = activeRoles.length > 0 ? activeRoles.length * stdItemHeight - stdCardGap : 0\n const totalGroupHeight = activeGroups.length > 0 ? activeGroups.length * stdItemHeight - stdCardGap : 0\n const totalUserHeight = activeUsers.length > 0 ? activeUsers.length * stdItemHeight - stdCardGap : 0\n\n const maxColumnHeight = Math.max(totalResourceHeight, totalRoleHeight, totalGroupHeight, totalUserHeight, 320)\n const svgHeight = maxColumnHeight + 60\n\n const resourceStartTop = (svgHeight - totalResourceHeight) / 2\n const roleStartTop = (svgHeight - totalRoleHeight) / 2\n const groupStartTop = (svgHeight - totalGroupHeight) / 2\n const userStartTop = (svgHeight - totalUserHeight) / 2\n\n const getResourceActionCenterY = (resId: number, action: string) => {\n const info = resourceYMap.get(resId)\n if (!info) return svgHeight / 2\n const relativeActY = info.actionYMap.get(action) ?? info.height / 2\n return resourceStartTop + relativeActY\n }\n\n const getRoleCenterY = (roleIndex: number) => {\n return roleStartTop + roleIndex * stdItemHeight + stdCardHeight / 2\n }\n\n const getGroupCenterY = (groupIndex: number) => {\n return groupStartTop + groupIndex * stdItemHeight + stdCardHeight / 2\n }\n\n const getUserCenterY = (userIndex: number) => {\n return userStartTop + userIndex * stdItemHeight + stdCardHeight / 2\n }\n\n const resourceX = 140\n const roleX = 420\n const groupX = 700\n const userX = 980\n\n const activeNode = hoveredNode || selectedNode\n\n const isUserActive = (uId: number) => {\n if (!activeNode) return true\n if (activeNode.type === \"user\") return activeNode.id === uId\n if (activeNode.type === \"role\") return assignments.some((a) => a.userId === uId && a.roleId === activeNode.id)\n if (activeNode.type === \"group\") return false\n if (activeNode.type === \"resource\") {\n const roleIds = grants.filter((g) => g.resourceId === activeNode.id).map((g) => g.roleId)\n return assignments.some((a) => a.userId === uId && roleIds.includes(a.roleId))\n }\n return true\n }\n\n const isGroupActive = (gId: number) => {\n if (!activeNode) return true\n if (activeNode.type === \"group\") return activeNode.id === gId\n if (activeNode.type === \"role\") return groupRoles.some((gr) => gr.groupId === gId && gr.roleId === activeNode.id)\n if (activeNode.type === \"user\") return false\n if (activeNode.type === \"resource\") {\n const roleIds = grants.filter((g) => g.resourceId === activeNode.id).map((g) => g.roleId)\n return groupRoles.some((gr) => gr.groupId === gId && roleIds.includes(gr.roleId))\n }\n return true\n }\n\n const isRoleActive = (rId: number) => {\n if (!activeNode) return true\n if (activeNode.type === \"role\") return activeNode.id === rId\n if (activeNode.type === \"user\") return assignments.some((a) => a.userId === activeNode.id && a.roleId === rId)\n if (activeNode.type === \"group\") return groupRoles.some((gr) => gr.groupId === activeNode.id && gr.roleId === rId)\n if (activeNode.type === \"resource\") return grants.some((g) => g.resourceId === activeNode.id && g.roleId === rId)\n return true\n }\n\n const isResourceActive = (resId: number) => {\n if (!activeNode) return true\n if (activeNode.type === \"resource\") return activeNode.id === resId\n if (activeNode.type === \"role\") return grants.some((g) => g.roleId === activeNode.id && g.resourceId === resId)\n if (activeNode.type === \"group\") {\n const groupRoleIds = groupRoles.filter((gr) => gr.groupId === activeNode.id).map((gr) => gr.roleId)\n return grants.some((g) => groupRoleIds.includes(g.roleId) && g.resourceId === resId)\n }\n if (activeNode.type === \"user\") {\n const userRoleIds = assignments.filter((a) => a.userId === activeNode.id).map((a) => a.roleId)\n return grants.some((g) => userRoleIds.includes(g.roleId) && g.resourceId === resId)\n }\n return true\n }\n\n const isUserRoleLinkActive = (uId: number, rId: number) => {\n if (!activeNode) return true\n if (activeNode.type === \"user\") return activeNode.id === uId && assignments.some((a) => a.userId === uId && a.roleId === rId)\n if (activeNode.type === \"role\") return activeNode.id === rId && assignments.some((a) => a.userId === uId && a.roleId === rId)\n if (activeNode.type === \"resource\") {\n const roleIds = grants.filter((g) => g.resourceId === activeNode.id).map((g) => g.roleId)\n return roleIds.includes(rId) && assignments.some((a) => a.userId === uId && a.roleId === rId)\n }\n if (activeNode.type === \"group\") return false\n return true\n }\n\n const isGroupRoleLinkActive = (gId: number, rId: number) => {\n if (!activeNode) return true\n if (activeNode.type === \"group\") return activeNode.id === gId && groupRoles.some((gr) => gr.groupId === gId && gr.roleId === rId)\n if (activeNode.type === \"role\") return activeNode.id === rId && groupRoles.some((gr) => gr.groupId === gId && gr.roleId === rId)\n if (activeNode.type === \"resource\") {\n const roleIds = grants.filter((g) => g.resourceId === activeNode.id).map((g) => g.roleId)\n return roleIds.includes(rId) && groupRoles.some((gr) => gr.groupId === gId && gr.roleId === rId)\n }\n if (activeNode.type === \"user\") return false\n return true\n }\n\n const isRoleResourceLinkActive = (rId: number, resId: number) => {\n if (!activeNode) return true\n if (activeNode.type === \"role\") return activeNode.id === rId && grants.some((g) => g.roleId === rId && g.resourceId === resId)\n if (activeNode.type === \"resource\") return activeNode.id === resId && grants.some((g) => g.roleId === rId && g.resourceId === resId)\n if (activeNode.type === \"group\") {\n const groupRoleIds = groupRoles.filter((gr) => gr.groupId === activeNode.id).map((gr) => gr.roleId)\n return groupRoleIds.includes(rId) && grants.some((g) => g.roleId === rId && g.resourceId === resId)\n }\n if (activeNode.type === \"user\") {\n const userRoleIds = assignments.filter((a) => a.userId === activeNode.id).map((a) => a.roleId)\n return userRoleIds.includes(rId) && grants.some((g) => g.roleId === rId && g.resourceId === resId)\n }\n return true\n }\n\n const userRoleLinks: Array<{ uIdx: number; rIdx: number; active: boolean; key: string; offset: number }> = []\n assignments.forEach((a) => {\n const uIdx = activeUsers.findIndex((u) => u.id === a.userId)\n const rIdx = activeRoles.findIndex((r) => r.id === a.roleId)\n if (uIdx !== -1 && rIdx !== -1) {\n const roleAssignments = assignments.filter((item) => item.roleId === a.roleId)\n const assignIdx = roleAssignments.findIndex((item) => item.userId === a.userId && item.roleId === a.roleId)\n const totalAssigns = roleAssignments.length\n const offset = totalAssigns > 1 ? Math.min(Math.max((assignIdx - (totalAssigns - 1) / 2) * 4, -16), 16) : 0\n\n userRoleLinks.push({\n uIdx,\n rIdx,\n active: isUserRoleLinkActive(a.userId, a.roleId),\n key: `ur-${a.userId}-${a.roleId}`,\n offset,\n })\n }\n })\n\n const groupRoleLinks: Array<{ gIdx: number; rIdx: number; active: boolean; key: string; offset: number }> = []\n groupRoles.forEach((gr) => {\n const gIdx = activeGroups.findIndex((g) => g.id === gr.groupId)\n const rIdx = activeRoles.findIndex((r) => r.id === gr.roleId)\n if (gIdx !== -1 && rIdx !== -1) {\n const gRoleAssigns = groupRoles.filter((item) => item.roleId === gr.roleId)\n const assignIdx = gRoleAssigns.findIndex((item) => item.groupId === gr.groupId && item.roleId === gr.roleId)\n const totalAssigns = gRoleAssigns.length\n const offset = totalAssigns > 1 ? Math.min(Math.max((assignIdx - (totalAssigns - 1) / 2) * 4, -16), 16) : 0\n\n groupRoleLinks.push({\n gIdx,\n rIdx,\n active: isGroupRoleLinkActive(gr.groupId, gr.roleId),\n key: `gr-${gr.groupId}-${gr.roleId}`,\n offset,\n })\n }\n })\n\n const roleResourceLinks: Array<{ rIdx: number; resIdx: number; active: boolean; key: string; action: string; color: string; offset: number }> = []\n grants.forEach((g) => {\n const rIdx = activeRoles.findIndex((r) => r.id === g.roleId)\n const resIdx = activeResources.findIndex((res) => res.id === g.resourceId)\n if (rIdx !== -1 && resIdx !== -1) {\n const sameResourceActionGrants = grants.filter((item) => item.resourceId === g.resourceId && item.action === g.action)\n const actionRoleIdx = sameResourceActionGrants.findIndex((item) => item.id === g.id)\n const totalSameGrants = sameResourceActionGrants.length\n const offset = totalSameGrants > 1 ? Math.min(Math.max((actionRoleIdx - (totalSameGrants - 1) / 2) * 4, -12), 12) : 0\n\n const colorConf = ACTION_COLORS[g.action]\n const color = colorConf ? colorConf.text : \"#6366f1\"\n\n roleResourceLinks.push({\n rIdx,\n resIdx,\n active: isRoleResourceLinkActive(g.roleId, g.resourceId),\n key: `rr-grant-${g.id}`,\n action: g.action,\n color,\n offset,\n })\n }\n })\n\n return (\n <div data-testid=\"authz-topology-map\" style={{ width: \"100%\", overflowX: \"auto\", backgroundColor: \"#ffffff\", borderRadius: \"10px\", border: \"1px solid #e2e8f0\", padding: \"1rem\", boxSizing: \"border-box\" }}>\n <div style={{ position: \"relative\", minWidth: \"1160px\", height: `${svgHeight}px` }}>\n <svg style={{ position: \"absolute\", top: 0, left: 0, width: \"100%\", height: \"100%\", pointerEvents: \"none\", zIndex: 1 }}>\n <title>Topology Connections</title>\n\n {roleResourceLinks.map((link) => {\n const grantItem = grants.find((g) => `rr-grant-${g.id}` === link.key)\n if (!grantItem) return null\n\n const y1 = getResourceActionCenterY(grantItem.resourceId, grantItem.action) + link.offset\n const y2 = getRoleCenterY(link.rIdx)\n const cX1 = resourceX + 135\n const cX2 = roleX - 135\n return (\n <path\n key={link.key}\n d={`M ${resourceX + 90} ${y1} C ${cX1} ${y1}, ${cX2} ${y2}, ${roleX - 90} ${y2}`}\n fill=\"none\"\n stroke={link.active ? link.color : \"#cbd5e1\"}\n strokeWidth={link.active && activeNode ? 3 : 2}\n strokeOpacity={link.active ? (activeNode ? 1.0 : 0.75) : 0.12}\n style={{ transition: \"all 0.2s ease\" }}\n />\n )\n })}\n\n {groupRoleLinks.map((link) => {\n const y1 = getRoleCenterY(link.rIdx) + link.offset\n const y2 = getGroupCenterY(link.gIdx)\n const cX1 = roleX + 135\n const cX2 = groupX - 135\n return (\n <path\n key={link.key}\n data-testid={`topo-link-group-role-${link.key}`}\n data-active={link.active ? \"true\" : \"false\"}\n d={`M ${roleX + 90} ${y1} C ${cX1} ${y1}, ${cX2} ${y2}, ${groupX - 90} ${y2}`}\n fill=\"none\"\n stroke={link.active ? \"#8b5cf6\" : \"#cbd5e1\"}\n strokeWidth={link.active && activeNode ? 3 : 2}\n strokeDasharray=\"4 2\"\n strokeOpacity={link.active ? (activeNode ? 1.0 : 0.75) : 0.12}\n style={{ transition: \"all 0.2s ease\" }}\n />\n )\n })}\n\n {userRoleLinks.map((link) => {\n const y1 = getRoleCenterY(link.rIdx) + link.offset\n const y2 = getUserCenterY(link.uIdx)\n const cX1 = roleX + 135\n const cX2 = userX - 135\n return (\n <path\n key={link.key}\n data-testid={`topo-link-user-role-${link.key}`}\n data-active={link.active ? \"true\" : \"false\"}\n d={`M ${roleX + 90} ${y1} C ${cX1} ${y1}, ${cX2} ${y2}, ${userX - 90} ${y2}`}\n fill=\"none\"\n stroke={link.active ? \"#4f46e5\" : \"#cbd5e1\"}\n strokeWidth={link.active && activeNode ? 3 : 2}\n strokeOpacity={link.active ? (activeNode ? 1.0 : 0.75) : 0.12}\n style={{ transition: \"all 0.2s ease\" }}\n />\n )\n })}\n </svg>\n\n <div style={{ position: \"relative\", zIndex: 2, width: \"100%\", height: \"100%\" }}>\n {activeResources.map((res) => {\n const isSelected = selectedNode?.type === \"resource\" && selectedNode.id === res.id\n const active = isResourceActive(res.id)\n const cardInfo = resourceYMap.get(res.id)\n if (!cardInfo) return null\n\n const cardTop = resourceStartTop + cardInfo.top\n const actions = getResourceActions(res.id)\n\n return (\n <div\n key={res.id}\n style={{\n position: \"absolute\",\n left: `${resourceX - 90}px`,\n top: `${cardTop}px`,\n width: \"180px\",\n height: `${cardInfo.height}px`,\n borderRadius: \"8px\",\n border: isSelected ? \"2px solid #10b981\" : \"1px solid #a7f3d0\",\n backgroundColor: isSelected ? \"#d1fae5\" : active ? \"#ffffff\" : \"#f8fafc\",\n opacity: active ? 1 : 0.35,\n boxShadow: isSelected ? \"0 4px 12px rgba(16, 185, 129, 0.2)\" : \"0 1px 3px rgba(0,0,0,0.05)\",\n transition: \"all 0.15s ease\",\n padding: \"8px\",\n boxSizing: \"border-box\",\n display: \"flex\",\n flexDirection: \"column\",\n }}>\n <button\n type=\"button\"\n onClick={() => onNodeClick(\"resource\", res.id)}\n onMouseEnter={() => setHoveredNode({ type: \"resource\", id: res.id })}\n onMouseLeave={() => setHoveredNode(null)}\n data-testid={`topo-node-resource-${res.id}`}\n aria-label={`リソース: ${res.name}`}\n aria-pressed={isSelected}\n style={{\n background: \"none\",\n border: \"none\",\n padding: 0,\n margin: 0,\n cursor: \"pointer\",\n textAlign: \"left\",\n width: \"100%\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"6px\",\n marginBottom: \"6px\",\n height: \"18px\",\n }}>\n <span style={{ fontSize: \"1rem\", flexShrink: 0 }}>🔑</span>\n <span style={{ fontWeight: 600, fontSize: \"0.78rem\", color: \"#047857\", overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }}>{res.name}</span>\n </button>\n\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"2px\" }}>\n {actions.map((action) => {\n if (action === \"none\") {\n return (\n <div key=\"none\" style={{ fontSize: \"0.68rem\", color: \"#94a3b8\", height: \"22px\", display: \"flex\", alignItems: \"center\", padding: \"0 6px\" }}>\n 権限設定なし\n </div>\n )\n }\n\n const colorConf = ACTION_COLORS[action] ?? { bg: \"#ecfdf5\", text: \"#047857\", border: \"#a7f3d0\" }\n return (\n <div\n key={action}\n style={{\n height: \"22px\",\n boxSizing: \"border-box\",\n padding: \"0 8px\",\n borderRadius: \"4px\",\n backgroundColor: colorConf.bg,\n color: colorConf.text,\n border: `1px solid ${colorConf.border}`,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n fontSize: \"0.68rem\",\n fontWeight: 600,\n }}>\n <span>{action}</span>\n <span style={{ fontSize: \"0.6rem\", opacity: 0.6 }}>●</span>\n </div>\n )\n })}\n </div>\n </div>\n )\n })}\n\n {activeRoles.map((r, i) => {\n const isSelected = selectedNode?.type === \"role\" && selectedNode.id === r.id\n const active = isRoleActive(r.id)\n const y = getRoleCenterY(i)\n return (\n <button\n type=\"button\"\n key={r.id}\n onClick={() => onNodeClick(\"role\", r.id)}\n onMouseEnter={() => setHoveredNode({ type: \"role\", id: r.id })}\n onMouseLeave={() => setHoveredNode(null)}\n data-testid={`topo-node-role-${r.id}`}\n aria-label={`ロール: ${r.name}`}\n aria-pressed={isSelected}\n style={{\n position: \"absolute\",\n left: `${roleX - 90}px`,\n top: `${y - 26}px`,\n width: \"180px\",\n height: \"52px\",\n borderRadius: \"8px\",\n border: isSelected ? \"2px solid #6366f1\" : \"1px solid #c7d2fe\",\n backgroundColor: isSelected ? \"#e0e7ff\" : active ? \"#ffffff\" : \"#f8fafc\",\n opacity: active ? 1 : 0.35,\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n padding: \"0 10px\",\n gap: \"8px\",\n boxShadow: isSelected ? \"0 4px 12px rgba(99, 102, 241, 0.2)\" : \"0 1px 3px rgba(0,0,0,0.05)\",\n transition: \"all 0.15s ease\",\n textAlign: \"left\",\n boxSizing: \"border-box\",\n }}>\n <span style={{ fontSize: \"1.1rem\", flexShrink: 0 }}>🛡️</span>\n <div style={{ overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\", flex: 1, minWidth: 0 }}>\n <div style={{ fontWeight: 600, fontSize: \"0.78rem\", color: \"#4338ca\", textOverflow: \"ellipsis\", overflow: \"hidden\" }}>{r.name}</div>\n <div style={{ fontSize: \"0.68rem\", color: \"#64748b\", fontFamily: \"monospace\", textOverflow: \"ellipsis\", overflow: \"hidden\" }}>{r.roleKey}</div>\n </div>\n </button>\n )\n })}\n\n {activeGroups.map((g, i) => {\n const isSelected = selectedNode?.type === \"group\" && selectedNode.id === g.id\n const active = isGroupActive(g.id)\n const y = getGroupCenterY(i)\n return (\n <button\n type=\"button\"\n key={g.id}\n onClick={() => onNodeClick(\"group\", g.id)}\n onMouseEnter={() => setHoveredNode({ type: \"group\", id: g.id })}\n onMouseLeave={() => setHoveredNode(null)}\n data-testid={`topo-node-group-${g.id}`}\n aria-label={`グループ: ${g.name}`}\n aria-pressed={isSelected}\n style={{\n position: \"absolute\",\n left: `${groupX - 90}px`,\n top: `${y - 26}px`,\n width: \"180px\",\n height: \"52px\",\n borderRadius: \"8px\",\n border: isSelected ? \"2px solid #8b5cf6\" : \"1px solid #ddd6fe\",\n backgroundColor: isSelected ? \"#f3e8ff\" : active ? \"#ffffff\" : \"#f8fafc\",\n opacity: active ? 1 : 0.35,\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n padding: \"0 10px\",\n gap: \"8px\",\n boxShadow: isSelected ? \"0 4px 12px rgba(139, 92, 246, 0.2)\" : \"0 1px 3px rgba(0,0,0,0.05)\",\n transition: \"all 0.15s ease\",\n textAlign: \"left\",\n boxSizing: \"border-box\",\n }}>\n <span style={{ fontSize: \"1.1rem\", flexShrink: 0 }}>👥</span>\n <div style={{ overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\", flex: 1, minWidth: 0 }}>\n <div style={{ fontWeight: 600, fontSize: \"0.78rem\", color: \"#6d28d9\", textOverflow: \"ellipsis\", overflow: \"hidden\" }}>{g.name}</div>\n <div style={{ fontSize: \"0.68rem\", color: \"#64748b\", fontFamily: \"monospace\", textOverflow: \"ellipsis\", overflow: \"hidden\" }}>{g.groupKey}</div>\n </div>\n </button>\n )\n })}\n\n {activeUsers.map((u, i) => {\n const isSelected = selectedNode?.type === \"user\" && selectedNode.id === u.id\n const active = isUserActive(u.id)\n const y = getUserCenterY(i)\n return (\n <button\n type=\"button\"\n key={u.id}\n onClick={() => onNodeClick(\"user\", u.id)}\n onMouseEnter={() => setHoveredNode({ type: \"user\", id: u.id })}\n onMouseLeave={() => setHoveredNode(null)}\n data-testid={`topo-node-user-${u.id}`}\n aria-label={`ユーザー: ${u.displayName}`}\n aria-pressed={isSelected}\n style={{\n position: \"absolute\",\n left: `${userX - 90}px`,\n top: `${y - 26}px`,\n width: \"180px\",\n height: \"52px\",\n borderRadius: \"8px\",\n border: isSelected ? \"2px solid #0284c7\" : \"1px solid #bae6fd\",\n backgroundColor: isSelected ? \"#e0f2fe\" : active ? \"#ffffff\" : \"#f8fafc\",\n opacity: active ? 1 : 0.35,\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n padding: \"0 10px\",\n gap: \"8px\",\n boxShadow: isSelected ? \"0 4px 12px rgba(2, 132, 199, 0.2)\" : \"0 1px 3px rgba(0,0,0,0.05)\",\n transition: \"all 0.15s ease\",\n textAlign: \"left\",\n boxSizing: \"border-box\",\n }}>\n <span style={{ fontSize: \"1.1rem\", flexShrink: 0 }}>👤</span>\n <div style={{ overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\", flex: 1, minWidth: 0 }}>\n <div style={{ fontWeight: 600, fontSize: \"0.78rem\", color: \"#0369a1\", textOverflow: \"ellipsis\", overflow: \"hidden\" }}>{u.displayName}</div>\n <div style={{ fontSize: \"0.68rem\", color: \"#64748b\", textOverflow: \"ellipsis\", overflow: \"hidden\" }}>{u.email}</div>\n </div>\n </button>\n )\n })}\n </div>\n </div>\n </div>\n )\n}\n\nexport function AuthzGraphView() {\n const { users, roles, resources, grants, assignments, groupRoles = [], groups = [] } = useLoaderData() as AuthzGraphData\n const [selectedNode, setSelectedNode] = useState<{ type: AuthzNodeType; id: number } | null>(null)\n const [searchQuery, setSearchQuery] = useState(\"\")\n const [viewMode, setViewMode] = useState<\"topology\" | \"columns\">(\"topology\")\n\n const roleMap = new Map(roles.map((r) => [r.id, r]))\n const resourceMap = new Map(resources.map((r) => [r.id, r]))\n const groupMap = new Map(groups.map((g) => [g.id, g]))\n const userMap = new Map(users.map((u) => [u.id, u]))\n\n const isUserRelated = (userId: number): boolean => {\n if (!selectedNode) return true\n if (selectedNode.type === \"user\") return selectedNode.id === userId\n if (selectedNode.type === \"role\") return assignments.some((a) => a.userId === userId && a.roleId === selectedNode.id)\n if (selectedNode.type === \"group\") return false\n if (selectedNode.type === \"resource\") {\n const roleIdsForResource = grants.filter((g) => g.resourceId === selectedNode.id).map((g) => g.roleId)\n return assignments.some((a) => a.userId === userId && roleIdsForResource.includes(a.roleId))\n }\n return true\n }\n\n const isGroupRelated = (groupId: number): boolean => {\n if (!selectedNode) return true\n if (selectedNode.type === \"group\") return selectedNode.id === groupId\n if (selectedNode.type === \"role\") return groupRoles.some((gr) => gr.groupId === groupId && gr.roleId === selectedNode.id)\n if (selectedNode.type === \"user\") return false\n if (selectedNode.type === \"resource\") {\n const roleIdsForResource = grants.filter((g) => g.resourceId === selectedNode.id).map((g) => g.roleId)\n return groupRoles.some((gr) => gr.groupId === groupId && roleIdsForResource.includes(gr.roleId))\n }\n return true\n }\n\n const isRoleRelated = (roleId: number): boolean => {\n if (!selectedNode) return true\n if (selectedNode.type === \"role\") return selectedNode.id === roleId\n if (selectedNode.type === \"user\") return assignments.some((a) => a.userId === selectedNode.id && a.roleId === roleId)\n if (selectedNode.type === \"group\") return groupRoles.some((gr) => gr.groupId === selectedNode.id && gr.roleId === roleId)\n if (selectedNode.type === \"resource\") return grants.some((g) => g.resourceId === selectedNode.id && g.roleId === roleId)\n return true\n }\n\n const isResourceRelated = (resourceId: number): boolean => {\n if (!selectedNode) return true\n if (selectedNode.type === \"resource\") return selectedNode.id === resourceId\n if (selectedNode.type === \"role\") return grants.some((g) => g.roleId === selectedNode.id && g.resourceId === resourceId)\n if (selectedNode.type === \"group\") {\n const groupRoleIds = groupRoles.filter((gr) => gr.groupId === selectedNode.id).map((gr) => gr.roleId)\n return grants.some((g) => groupRoleIds.includes(g.roleId) && g.resourceId === resourceId)\n }\n if (selectedNode.type === \"user\") {\n const userRoleIds = assignments.filter((a) => a.userId === selectedNode.id).map((a) => a.roleId)\n return grants.some((g) => userRoleIds.includes(g.roleId) && g.resourceId === resourceId)\n }\n return true\n }\n\n const query = searchQuery.trim().toLowerCase()\n const filteredUsers = users.filter((u) => !query || u.displayName.toLowerCase().includes(query) || u.email?.toLowerCase().includes(query))\n const filteredGroups = groups.filter((g) => !query || g.name.toLowerCase().includes(query) || g.groupKey.toLowerCase().includes(query))\n const filteredRoles = roles.filter((r) => !query || r.name.toLowerCase().includes(query) || r.roleKey.toLowerCase().includes(query))\n const filteredResources = resources.filter((r) => !query || r.name.toLowerCase().includes(query) || r.resourceKey.toLowerCase().includes(query) || r.appKey.toLowerCase().includes(query))\n\n const selectedUserObj = selectedNode?.type === \"user\" ? userMap.get(selectedNode.id) : null\n const selectedGroupObj = selectedNode?.type === \"group\" ? groupMap.get(selectedNode.id) : null\n const selectedRoleObj = selectedNode?.type === \"role\" ? roleMap.get(selectedNode.id) : null\n const selectedResourceObj = selectedNode?.type === \"resource\" ? resourceMap.get(selectedNode.id) : null\n\n const handleNodeClick = (type: AuthzNodeType, id: number) => {\n if (selectedNode && selectedNode.type === type && selectedNode.id === id) {\n setSelectedNode(null)\n } else {\n setSelectedNode({ type, id })\n }\n }\n\n return (\n <section data-testid=\"authz-graph-view\" style={{ display: \"flex\", flexDirection: \"column\", gap: \"1rem\", width: \"100%\" }}>\n <div style={{ display: \"flex\", justifyContent: \"space-between\", alignItems: \"center\", flexWrap: \"wrap\", gap: \"0.75rem\", backgroundColor: \"#f8fafc\", padding: \"0.75rem 1rem\", borderRadius: \"8px\", border: \"1px solid #e2e8f0\", width: \"100%\", boxSizing: \"border-box\" }}>\n <div style={{ display: \"flex\", alignItems: \"center\", gap: \"0.75rem\", flexWrap: \"wrap\" }}>\n <div style={{ display: \"inline-flex\", borderRadius: \"6px\", border: \"1px solid #cbd5e1\", padding: \"2px\", backgroundColor: \"#ffffff\" }}>\n <button\n type=\"button\"\n onClick={() => setViewMode(\"topology\")}\n data-testid=\"switch-mode-topology\"\n style={{\n padding: \"3px 10px\",\n borderRadius: \"4px\",\n border: \"none\",\n cursor: \"pointer\",\n fontSize: \"0.75rem\",\n fontWeight: viewMode === \"topology\" ? 600 : 400,\n backgroundColor: viewMode === \"topology\" ? \"#eff6ff\" : \"transparent\",\n color: viewMode === \"topology\" ? \"#0284c7\" : \"#64748b\",\n boxShadow: viewMode === \"topology\" ? \"0 1px 2px rgba(0,0,0,0.08)\" : \"none\",\n }}>\n 🌐 トポロジマップ (Topology)\n </button>\n <button\n type=\"button\"\n onClick={() => setViewMode(\"columns\")}\n data-testid=\"switch-mode-columns\"\n style={{\n padding: \"3px 10px\",\n borderRadius: \"4px\",\n border: \"none\",\n cursor: \"pointer\",\n fontSize: \"0.75rem\",\n fontWeight: viewMode === \"columns\" ? 600 : 400,\n backgroundColor: viewMode === \"columns\" ? \"#eff6ff\" : \"transparent\",\n color: viewMode === \"columns\" ? \"#0284c7\" : \"#64748b\",\n boxShadow: viewMode === \"columns\" ? \"0 1px 2px rgba(0,0,0,0.08)\" : \"none\",\n }}>\n 📋 カラム一覧 (Columns)\n </button>\n </div>\n <div style={{ display: \"flex\", gap: \"0.4rem\", fontSize: \"0.75rem\", flexWrap: \"wrap\" }}>\n <span style={{ backgroundColor: \"#e0f2fe\", color: \"#0369a1\", padding: \"2px 8px\", borderRadius: \"12px\", fontWeight: 600 }}>👤 ユーザー: {users.length}</span>\n <span style={{ backgroundColor: \"#f3e8ff\", color: \"#6d28d9\", padding: \"2px 8px\", borderRadius: \"12px\", fontWeight: 600 }}>👥 グループ: {groups.length}</span>\n <span style={{ backgroundColor: \"#e0e7ff\", color: \"#4338ca\", padding: \"2px 8px\", borderRadius: \"12px\", fontWeight: 600 }}>🛡️ ロール: {roles.length}</span>\n <span style={{ backgroundColor: \"#d1fae5\", color: \"#047857\", padding: \"2px 8px\", borderRadius: \"12px\", fontWeight: 600 }}>🔑 リソース: {resources.length}</span>\n <span style={{ backgroundColor: \"#fef3c7\", color: \"#b45309\", padding: \"2px 8px\", borderRadius: \"12px\", fontWeight: 600 }}>⚡️ 権限設定: {grants.length}</span>\n </div>\n </div>\n <div style={{ display: \"flex\", alignItems: \"center\", gap: \"0.5rem\" }}>\n <input\n type=\"text\"\n placeholder=\"キーワードで絞り込み...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n data-testid=\"graph-search-input\"\n style={{ padding: \"5px 10px\", borderRadius: \"6px\", border: \"1px solid #cbd5e1\", fontSize: \"0.8rem\", width: \"200px\" }}\n />\n </div>\n </div>\n\n {/* 常時高さ固定のステータスバー (高さ38px固定でレイアウトシフトを防止) */}\n <div\n style={{\n minHeight: \"38px\",\n height: \"38px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n backgroundColor: selectedNode ? \"#eff6ff\" : \"#f8fafc\",\n border: `1px solid ${selectedNode ? \"#bfdbfe\" : \"#e2e8f0\"}`,\n padding: \"0 0.8rem\",\n borderRadius: \"6px\",\n fontSize: \"0.8rem\",\n color: selectedNode ? \"#1e40af\" : \"#64748b\",\n width: \"100%\",\n boxSizing: \"border-box\",\n transition: \"all 0.15s ease\",\n }}>\n <div style={{ display: \"flex\", alignItems: \"center\", gap: \"0.4rem\", overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }}>\n {selectedNode ? (\n <>\n <span>🎯</span>\n <strong>選択中のノード:</strong>\n <span>\n {selectedUserObj && `ユーザー「${selectedUserObj.displayName} (${selectedUserObj.email})」に関連するパスを表示中`}\n {selectedGroupObj && `グループ「${selectedGroupObj.name} (${selectedGroupObj.groupKey})」に関連するパスを表示中`}\n {selectedRoleObj && `ロール「${selectedRoleObj.name} (${selectedRoleObj.roleKey})」に関連するパスを表示中`}\n {selectedResourceObj && `リソース「${selectedResourceObj.name} (${selectedResourceObj.appKey}:${selectedResourceObj.resourceKey})」に関連するパスを表示中`}\n </span>\n </>\n ) : (\n <>\n <span>💡</span>\n <span>\n <strong>ヒント:</strong> ノード(リソース・ロール・グループ・ユーザー)をクリックすると、関連する全パスがハイライト表示されます\n </span>\n </>\n )}\n </div>\n {selectedNode && (\n <button\n type=\"button\"\n onClick={() => setSelectedNode(null)}\n data-testid=\"graph-reset-selection\"\n style={{\n padding: \"3px 8px\",\n borderRadius: \"4px\",\n border: \"1px solid #93c5fd\",\n backgroundColor: \"#ffffff\",\n fontSize: \"0.72rem\",\n cursor: \"pointer\",\n color: \"#1d4ed8\",\n fontWeight: 600,\n whiteSpace: \"nowrap\",\n boxShadow: \"0 1px 2px rgba(0,0,0,0.05)\",\n }}>\n ✕ 選択解除\n </button>\n )}\n </div>\n\n {viewMode === \"topology\" ? (\n <AuthzTopologyMap users={filteredUsers} roles={filteredRoles} resources={filteredResources} grants={grants} assignments={assignments} groupRoles={groupRoles} groups={filteredGroups} selectedNode={selectedNode} onNodeClick={handleNodeClick} />\n ) : (\n <div style={{ display: \"grid\", gridTemplateColumns: \"repeat(4, minmax(0, 1fr))\", gap: \"1rem\", alignItems: \"start\", width: \"100%\", boxSizing: \"border-box\" }}>\n {/* Column 1: Resources */}\n <div style={{ backgroundColor: \"#ffffff\", borderRadius: \"8px\", border: \"1px solid #e2e8f0\", padding: \"0.75rem\" }}>\n <div style={{ fontWeight: 700, fontSize: \"0.85rem\", color: \"#047857\", marginBottom: \"0.6rem\", display: \"flex\", alignItems: \"center\", gap: \"0.3rem\", borderBottom: \"2px solid #a7f3d0\", paddingBottom: \"0.4rem\" }}>\n <span>🔑</span> リソース ({filteredResources.length})\n </div>\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"0.5rem\", maxHeight: \"480px\", overflowY: \"auto\", paddingRight: \"4px\" }}>\n {filteredResources.length === 0 && <div style={{ fontSize: \"0.8rem\", color: \"#94a3b8\", textAlign: \"center\", padding: \"1rem\" }}>対象のリソースがありません</div>}\n {filteredResources.map((res) => {\n const isSelected = selectedNode?.type === \"resource\" && selectedNode.id === res.id\n const active = isResourceRelated(res.id)\n const resourceGrants = grants.filter((g) => g.resourceId === res.id)\n\n return (\n <button\n type=\"button\"\n key={res.id}\n onClick={() => handleNodeClick(\"resource\", res.id)}\n data-testid={`graph-node-resource-${res.id}`}\n style={{\n textAlign: \"left\",\n width: \"100%\",\n padding: \"0.6rem\",\n borderRadius: \"6px\",\n border: isSelected ? \"2px solid #10b981\" : \"1px solid #e2e8f0\",\n backgroundColor: isSelected ? \"#d1fae5\" : active ? \"#ffffff\" : \"#f8fafc\",\n opacity: active ? 1 : 0.4,\n cursor: \"pointer\",\n transition: \"all 0.15s ease\",\n boxShadow: isSelected ? \"0 2px 4px rgba(16, 185, 129, 0.15)\" : \"none\",\n }}>\n <div style={{ fontWeight: 600, fontSize: \"0.82rem\", color: \"#0f172a\" }}>{res.name}</div>\n <div style={{ fontSize: \"0.72rem\", color: \"#64748b\", fontFamily: \"monospace\" }}>\n {res.appKey}:{res.resourceKey}\n </div>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: \"0.25rem\", marginTop: \"0.4rem\" }}>\n {resourceGrants.map((g) => {\n const role = roleMap.get(g.roleId)\n const actStyle = ACTION_COLORS[g.action] ?? { bg: \"#f1f5f9\", text: \"#475569\", border: \"#cbd5e1\" }\n return (\n <span\n key={g.id}\n style={{\n fontSize: \"0.68rem\",\n padding: \"1px 6px\",\n borderRadius: \"4px\",\n backgroundColor: actStyle.bg,\n color: actStyle.text,\n border: `1px solid ${actStyle.border}`,\n }}>\n {role?.roleKey ?? `Role#${g.roleId}`}: <strong>{g.action}</strong>\n </span>\n )\n })}\n {resourceGrants.length === 0 && <span style={{ fontSize: \"0.68rem\", color: \"#94a3b8\" }}>権限設定なし</span>}\n </div>\n </button>\n )\n })}\n </div>\n </div>\n\n {/* Column 2: Roles */}\n <div style={{ backgroundColor: \"#ffffff\", borderRadius: \"8px\", border: \"1px solid #e2e8f0\", padding: \"0.75rem\" }}>\n <div style={{ fontWeight: 700, fontSize: \"0.85rem\", color: \"#4338ca\", marginBottom: \"0.6rem\", display: \"flex\", alignItems: \"center\", gap: \"0.3rem\", borderBottom: \"2px solid #c7d2fe\", paddingBottom: \"0.4rem\" }}>\n <span>🛡️</span> ロール ({filteredRoles.length})\n </div>\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"0.5rem\", maxHeight: \"480px\", overflowY: \"auto\", paddingRight: \"4px\" }}>\n {filteredRoles.length === 0 && <div style={{ fontSize: \"0.8rem\", color: \"#94a3b8\", textAlign: \"center\", padding: \"1rem\" }}>対象のロールがありません</div>}\n {filteredRoles.map((r) => {\n const isSelected = selectedNode?.type === \"role\" && selectedNode.id === r.id\n const active = isRoleRelated(r.id)\n const roleGrants = grants.filter((g) => g.roleId === r.id)\n const roleAssignments = assignments.filter((a) => a.roleId === r.id)\n const roleGroupAssignments = groupRoles.filter((gr) => gr.roleId === r.id)\n\n return (\n <button\n type=\"button\"\n key={r.id}\n onClick={() => handleNodeClick(\"role\", r.id)}\n data-testid={`graph-node-role-${r.id}`}\n style={{\n textAlign: \"left\",\n width: \"100%\",\n padding: \"0.6rem\",\n borderRadius: \"6px\",\n border: isSelected ? \"2px solid #6366f1\" : \"1px solid #e2e8f0\",\n backgroundColor: isSelected ? \"#e0e7ff\" : active ? \"#ffffff\" : \"#f8fafc\",\n opacity: active ? 1 : 0.4,\n cursor: \"pointer\",\n transition: \"all 0.15s ease\",\n boxShadow: isSelected ? \"0 2px 4px rgba(99, 102, 241, 0.15)\" : \"none\",\n }}>\n <div style={{ fontWeight: 600, fontSize: \"0.82rem\", color: \"#0f172a\" }}>{r.name}</div>\n <div style={{ fontSize: \"0.72rem\", color: \"#64748b\", fontFamily: \"monospace\" }}>{r.roleKey}</div>\n <div style={{ fontSize: \"0.7rem\", color: \"#475569\", marginTop: \"0.3rem\", display: \"flex\", gap: \"0.5rem\" }}>\n <span>権限: {roleGrants.length}</span>\n <span>グループ: {roleGroupAssignments.length}</span>\n <span>ユーザー: {roleAssignments.length}</span>\n </div>\n </button>\n )\n })}\n </div>\n </div>\n\n {/* Column 3: Groups */}\n <div style={{ backgroundColor: \"#ffffff\", borderRadius: \"8px\", border: \"1px solid #e2e8f0\", padding: \"0.75rem\" }}>\n <div style={{ fontWeight: 700, fontSize: \"0.85rem\", color: \"#6d28d9\", marginBottom: \"0.6rem\", display: \"flex\", alignItems: \"center\", gap: \"0.3rem\", borderBottom: \"2px solid #ddd6fe\", paddingBottom: \"0.4rem\" }}>\n <span>👥</span> グループ ({filteredGroups.length})\n </div>\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"0.5rem\", maxHeight: \"480px\", overflowY: \"auto\", paddingRight: \"4px\" }}>\n {filteredGroups.length === 0 && <div style={{ fontSize: \"0.8rem\", color: \"#94a3b8\", textAlign: \"center\", padding: \"1rem\" }}>対象のグループがありません</div>}\n {filteredGroups.map((g) => {\n const isSelected = selectedNode?.type === \"group\" && selectedNode.id === g.id\n const active = isGroupRelated(g.id)\n const assignedRoles = groupRoles.filter((gr) => gr.groupId === g.id)\n\n return (\n <button\n type=\"button\"\n key={g.id}\n onClick={() => handleNodeClick(\"group\", g.id)}\n data-testid={`graph-node-group-${g.id}`}\n style={{\n textAlign: \"left\",\n width: \"100%\",\n padding: \"0.6rem\",\n borderRadius: \"6px\",\n border: isSelected ? \"2px solid #8b5cf6\" : \"1px solid #e2e8f0\",\n backgroundColor: isSelected ? \"#f3e8ff\" : active ? \"#ffffff\" : \"#f8fafc\",\n opacity: active ? 1 : 0.4,\n cursor: \"pointer\",\n transition: \"all 0.15s ease\",\n boxShadow: isSelected ? \"0 2px 4px rgba(139, 92, 246, 0.15)\" : \"none\",\n }}>\n <div style={{ fontWeight: 600, fontSize: \"0.82rem\", color: \"#0f172a\" }}>{g.name}</div>\n <div style={{ fontSize: \"0.72rem\", color: \"#64748b\", fontFamily: \"monospace\" }}>{g.groupKey}</div>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: \"0.25rem\", marginTop: \"0.4rem\" }}>\n {assignedRoles.map((gr) => {\n const role = roleMap.get(gr.roleId)\n return (\n <span\n key={`${gr.groupId}-${gr.roleId}`}\n style={{\n fontSize: \"0.68rem\",\n padding: \"1px 6px\",\n borderRadius: \"4px\",\n backgroundColor: \"#f3e8ff\",\n color: \"#6d28d9\",\n border: \"1px solid #ddd6fe\",\n fontWeight: 600,\n }}>\n 🛡️ {role?.name ?? gr.roleKey}\n </span>\n )\n })}\n {assignedRoles.length === 0 && <span style={{ fontSize: \"0.68rem\", color: \"#94a3b8\" }}>ロール未割り当て</span>}\n </div>\n </button>\n )\n })}\n </div>\n </div>\n\n {/* Column 4: Users */}\n <div style={{ backgroundColor: \"#ffffff\", borderRadius: \"8px\", border: \"1px solid #e2e8f0\", padding: \"0.75rem\" }}>\n <div style={{ fontWeight: 700, fontSize: \"0.85rem\", color: \"#0369a1\", marginBottom: \"0.6rem\", display: \"flex\", alignItems: \"center\", gap: \"0.3rem\", borderBottom: \"2px solid #bae6fd\", paddingBottom: \"0.4rem\" }}>\n <span>👤</span> ユーザー ({filteredUsers.length})\n </div>\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"0.5rem\", maxHeight: \"480px\", overflowY: \"auto\", paddingRight: \"4px\" }}>\n {filteredUsers.length === 0 && <div style={{ fontSize: \"0.8rem\", color: \"#94a3b8\", textAlign: \"center\", padding: \"1rem\" }}>対象のユーザーがありません</div>}\n {filteredUsers.map((u) => {\n const isSelected = selectedNode?.type === \"user\" && selectedNode.id === u.id\n const active = isUserRelated(u.id)\n const userAssignments = assignments.filter((a) => a.userId === u.id)\n\n return (\n <button\n type=\"button\"\n key={u.id}\n onClick={() => handleNodeClick(\"user\", u.id)}\n data-testid={`graph-node-user-${u.id}`}\n style={{\n textAlign: \"left\",\n width: \"100%\",\n padding: \"0.6rem\",\n borderRadius: \"6px\",\n border: isSelected ? \"2px solid #0284c7\" : \"1px solid #e2e8f0\",\n backgroundColor: isSelected ? \"#e0f2fe\" : active ? \"#ffffff\" : \"#f8fafc\",\n opacity: active ? 1 : 0.4,\n cursor: \"pointer\",\n transition: \"all 0.15s ease\",\n boxShadow: isSelected ? \"0 2px 4px rgba(2, 132, 199, 0.15)\" : \"none\",\n }}>\n <div style={{ fontWeight: 600, fontSize: \"0.82rem\", color: \"#0f172a\" }}>{u.displayName}</div>\n <div style={{ fontSize: \"0.72rem\", color: \"#64748b\" }}>{u.email}</div>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: \"0.25rem\", marginTop: \"0.4rem\" }}>\n {userAssignments.map((a) => {\n const role = roleMap.get(a.roleId)\n return (\n <span\n key={`${a.userId}-${a.roleId}`}\n style={{\n fontSize: \"0.68rem\",\n padding: \"1px 6px\",\n borderRadius: \"4px\",\n backgroundColor: \"#e0f2fe\",\n color: \"#0369a1\",\n border: \"1px solid #bae6fd\",\n fontWeight: 600,\n }}>\n 🛡️ {role?.name ?? a.roleKey}\n </span>\n )\n })}\n {userAssignments.length === 0 && <span style={{ fontSize: \"0.68rem\", color: \"#94a3b8\" }}>直接ロールなし</span>}\n </div>\n </button>\n )\n })}\n </div>\n </div>\n </div>\n )}\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 group_roles: AuthzGroupRolesView,\n graph: AuthzGraphView,\n}\n\nexport type AuthzAdminAppViewProps = {\n renderHeader?: (props: { title: string; annotation: React.ReactNode }) => React.ReactNode\n}\n\n/**\n * スプラット(`authz/*`)1 ルートで認可管理 UI 全体を描画するコンポーネント(store 非依存)。\n * loader が返す `segment` に応じて該当タブのビューを描画する。レイアウト殻と各ビューは同一の\n * loader データ(セグメントデータ + myPermissions + labels をトップレベルに統合)を読む。\n */\nexport function AuthzAdminAppView({ renderHeader }: AuthzAdminAppViewProps = {}) {\n const { segment } = useLoaderData() as { segment: string }\n const View = SEGMENT_VIEWS[segment] ?? AuthzRolesView\n return (\n <AuthzLayoutShell renderHeader={renderHeader}>\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({ permission, resourceName, expectedResourceKey, showResourceTooltip = true, labels, showScopeSummary = true, className = \"authz-permission-indicator\" }: 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({ permission, resourceName, expectedResourceKey, prefixLabel = \"あなたの権限\", showPrefixLabel = true, showResourceTooltip = true, labels, showScopeSummary = true, className = \"authz-permission-status\", style }: 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 permission={permission} resourceName={resourceName} expectedResourceKey={expectedResourceKey} showResourceTooltip={showResourceTooltip} labels={labels} showScopeSummary={showScopeSummary} />\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 → the consumer's user id). */\n resolveUserId: (request: Request) => Awaitable<AuthzUserId | null | undefined>\n /** Optionally resolve acting user's group IDs from the request or session. */\n resolveGroupIds?: (request: Request) => Awaitable<(string | number)[] | null | undefined>\n /** Load effective permissions for (user, app, resource) — typically via @aiquants/authz-drizzle. */\n getEffectivePermissions: (args: { userId: AuthzUserId | null; groupIds?: (string | number)[]; 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\n const groupIds = config.resolveGroupIds ? ((await config.resolveGroupIds(request)) ?? undefined) : undefined\n\n const guard = createRequirePermission<Request, AuthzUserId>({\n resolveUserId: config.resolveUserId,\n getEffectivePermissions: (args) => config.getEffectivePermissions({ ...args, groupIds }),\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 groupIds = config.resolveGroupIds ? ((await config.resolveGroupIds(request)) ?? undefined) : undefined\n const out: Record<string, PermissionView> = {}\n for (const resourceKey of query.resourceKeys) {\n const perm = await config.getEffectivePermissions({ userId: userId ?? null, groupIds, 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(request: Request, query: { resourceKey: string; action: AuthzAction }, options?: RequirePermissionOptions): 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","AuthzGraphView","AuthzGroupRolesView","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","groupRolesData","groupRoles","groups","graphData","form","intent","roleKey","name","appKey","resourceKey","roleId","resourceId","rawAction","action","actor","groupId","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","p","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","renderHeader","myPermissions","labels","adminResourceKey","basePath","base","variant","setVariant","tabs","permissionItems","key","perm","items","annotation","MyPermissionGroupStatus","ui","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","AuthzGroupRolesView","groupRoles","groups","actionData","err","activeRoles","groupOptions","selectedGroup","setSelectedGroup","ACTION_COLORS","AuthzTopologyMap","selectedNode","onNodeClick","hoveredNode","setHoveredNode","connectedUserIds","connectedGroupIds","connectedRoleIds","connectedResourceIds","activeUsers","activeGroups","activeResources","res","getResourceActions","resId","resGrants","uniqueActions","getResourceCardHeight","resourceCardGap","cumulativeResY","resourceYMap","actions","height","top","actionYMap","act","actIdx","actY","totalResourceHeight","stdCardHeight","stdCardGap","stdItemHeight","totalRoleHeight","totalGroupHeight","totalUserHeight","svgHeight","resourceStartTop","roleStartTop","groupStartTop","userStartTop","getResourceActionCenterY","info","relativeActY","getRoleCenterY","roleIndex","getGroupCenterY","groupIndex","getUserCenterY","userIndex","resourceX","roleX","groupX","userX","activeNode","isUserActive","uId","roleIds","isGroupActive","gId","gr","isRoleActive","rId","isResourceActive","groupRoleIds","userRoleIds","isUserRoleLinkActive","isGroupRoleLinkActive","isRoleResourceLinkActive","userRoleLinks","uIdx","rIdx","roleAssignments","item","assignIdx","totalAssigns","offset","groupRoleLinks","gIdx","gRoleAssigns","roleResourceLinks","resIdx","sameResourceActionGrants","actionRoleIdx","totalSameGrants","colorConf","color","link","grantItem","y1","y2","cX1","cX2","isSelected","cardInfo","cardTop","i","y","AuthzGraphView","setSelectedNode","searchQuery","setSearchQuery","viewMode","setViewMode","roleMap","resourceMap","groupMap","userMap","isUserRelated","userId","roleIdsForResource","isGroupRelated","groupId","isRoleRelated","roleId","isResourceRelated","resourceId","query","filteredUsers","filteredGroups","filteredRoles","filteredResources","selectedUserObj","selectedGroupObj","selectedRoleObj","selectedResourceObj","handleNodeClick","type","id","resourceGrants","role","actStyle","roleGrants","roleGroupAssignments","assignedRoles","userAssignments","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","groupIds","args","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":["/**\n * Public entry point of the React Router authorization adapter.\n * React Router 向け認可アダプタの公開エントリポイント。\n */\nexport * 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/**\n * Take the leading segment out of the splat param (`roles/...` → `roles`).\n * スプラット param (\"*\") から先頭セグメントを取り出す処理。\n *\n * @returns The first path segment (empty string when absent). 先頭のパスセグメント (無ければ空文字)。\n */\nfunction segmentOf(params: Record<string, string | undefined>): string {\n return String(params[\"*\"] ?? \"\").split(\"/\")[0]\n}\n\n/**\n * Build the loader/action pair that serves the whole authorization admin UI from one splat route.\n * 認可管理 UI 全体を 1 本のスプラットルートで提供する loader/action 対を生成するファクトリ。\n *\n * @returns The route `loader` / `action` plus the underlying server for direct use. ルートの loader/action と内部サーバ。\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\", \"group_roles\", \"graph\"] 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, group_roles: server.groupRoles.data, graph: server.graph.data }\n // Map で持つ。素のオブジェクトだと `POST /authz/toString` が prototype 継承のメソッドを引き当て、\n // ガードを 1 度も通らずに「ハンドラ」が実行されてしまう。\n const actions = new Map<string, (args: RouteArgs) => Promise<unknown>>([\n [\"roles\", server.roles.action],\n [\"resources\", server.resources.action],\n [\"role_permissions\", server.grants.action],\n [\"user_roles\", server.userRoles.action],\n [\"group_roles\", server.groupRoles.action],\n ])\n\n /**\n * Splat loader: validate the segment, guard once, then load that segment's data.\n * スプラット loader。セグメントを検証し、ガードを 1 回だけ通してから該当データを読む処理。\n *\n * @returns The segment's data merged with the layout shell's fields. セグメントのデータとレイアウト用フィールド。\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 // segment は上で SEGMENTS に含まれることを確認済み (prototype 継承キーは到達しない)\n // ガードは 1 回だけ(requireUser + requirePermission(read))。userId と自己権限を取り回して再ガード/再取得しない。\n const { userId, myPermissions } = await server.layoutGuard(args.request)\n const segData = await 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 /**\n * Splat action: dispatch to the segment's own handler, or 400 when the segment has none.\n * スプラット action。セグメント固有のハンドラへ振り分け、無ければ 400 を返す処理。\n *\n * @returns The handler's result, or a 400 payload. ハンドラの結果、または 400 のペイロード。\n */\n async function action(args: RouteArgs) {\n const segment = segmentOf(args.params)\n const act = actions.get(segment)\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, AuthzGraphData, AuthzGroupRolesData, 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 * Authorization guard supplied by the app (from `createAuthz`); allow → `{ userId, permission }`.\n * 認可ガード (アプリの createAuthz 由来)。allow で { userId, permission } を返すポート。\n * `userId` は nullable(未解決/万一の public 付与)であり、createAuthzAdminServer 内で deny する\n * (管理経路は監査・自己権限計算に実 id が必須のため非 null を保証)。\n * `permission` は **同一判定から導かれた** 自己権限ビューであり、表示用に再取得しない\n * (再取得は「ガードは通るのにバッジは権限なし」という乖離の温床)。\n */\n requirePermission: (request: Request, query: PermissionQuery) => Promise<{ userId: string | number | null; permission: 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; permission: PermissionView }> => {\n const { userId, permission } = 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, permission }\n }\n\n /**\n * Layout guard: `requireUser` (302) → `requirePermission(read)` (403), run exactly once, returning the\n * user id together with the self-permission map derived from that **same** evaluation.\n * レイアウトガード。1 回だけ実行し、userId と同じ判定から導かれた自己権限マップを返す処理\n * (表示用の追加問い合わせは行わない)。\n *\n * @returns The acting user id and the admin resource's permission view. 操作ユーザー ID と管理リソースの権限ビュー。\n */\n async function layoutGuard(request: Request): Promise<{ userId: string | number; myPermissions: Record<string, PermissionView | undefined> }> {\n await opts.requireUser(request)\n try {\n const { userId, permission } = await requirePermission(request, { resourceKey: RES, action: \"read\" })\n return { userId, myPermissions: { [RES]: permission } }\n } catch (e) {\n if (e instanceof AuthzDeniedError) throw new Response(`Forbidden: ${RES}`, { status: 403 })\n throw e\n }\n }\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 const groupRolesData = async (): Promise<AuthzGroupRolesData> => {\n const [groupRoles, roles, groups] = await Promise.all([store.listGroupRoles(), store.listRoles(), store.listGroups()])\n return { groupRoles, roles, groups, labels }\n }\n const graphData = async (): Promise<AuthzGraphData> => {\n const [users, roles, resources, grants, assignments, groupRoles, groups] = await Promise.all([store.listUsers(), store.listRoles(), store.listResources(), store.listGrants(), store.listUserRoles(), store.listGroupRoles(), store.listGroups()])\n return { users, roles, resources, grants, assignments, groupRoles, groups, labels }\n }\n\n return {\n /** 露出: スプラットマウント(app.ts)がガードを 1 回だけ行うために使う。 */\n labels,\n resourceKey: RES,\n layoutGuard,\n\n /** /authz レイアウト: requireUser(302) → requirePermission(read, 403)。自己権限はガードの戻り値から得る。 */\n layout: {\n async loader({ request }: Req): Promise<AuthzLayoutData> {\n const { myPermissions } = await layoutGuard(request)\n return { myPermissions, 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 groupRoles: {\n data: groupRolesData,\n async loader({ request }: Req): Promise<AuthzGroupRolesData> {\n await requirePermission(request, { resourceKey: RES, action: \"read\" })\n return groupRolesData()\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 groupId = Number(form.get(\"groupId\"))\n const roleId = Number(form.get(\"roleId\"))\n if (!(groupId && roleId)) return data({ error: \"グループとロールを選択してください\" }, { status: 400 })\n await store.assignGroupRole(groupId, roleId, String(actor))\n return { ok: true }\n }\n case \"remove\": {\n await requirePermission(request, { resourceKey: RES, action: \"delete\" })\n await store.removeGroupRole(Number(form.get(\"groupId\")), 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 graph: {\n data: graphData,\n async loader({ request }: Req): Promise<AuthzGraphData> {\n await requirePermission(request, { resourceKey: RES, action: \"read\" })\n return graphData()\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; group_roles: string; graph: 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 groupRoles: { heading: string; note: string; group: 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\", group_roles: \"Group assignments\", graph: \"Graph\" },\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 groupRoles: { heading: \"Group assignments (TDGroupRole)\", note: \"Assign active roles to user groups.\", group: \"group\", role: \"role\", empty: \"No group assignments\", newHeading: \"Assign a role to group\", 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 groupRoles?: Partial<AuthzAdminLabels[\"groupRoles\"]>\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 groupRoles: { ...d.groupRoles, ...over.groupRoles },\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 AuthzGroupRoleAssignment, type AuthzGroupSummary, 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 | undefined>; adminResourceKey: string; basePath?: string }\n\nexport type AuthzLayoutShellProps = {\n children: React.ReactNode\n renderHeader?: (props: { title: string; annotation: React.ReactNode }) => React.ReactNode\n}\n\n/** ヘッダ(タイトル + あなたの権限) + タブ。中身は children(splat) か Outlet(ネスト)。 */\nfunction AuthzLayoutShell({ children, renderHeader }: AuthzLayoutShellProps) {\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 [\"group_roles\", labels.tabs.group_roles],\n [\"graph\", labels.tabs.graph],\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 const annotation = (\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 )\n\n return (\n <div className=\"authz-admin\" style={ui.page}>\n {renderHeader ? (\n renderHeader({ title: labels.title, annotation })\n ) : (\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 {annotation}\n </header>\n )}\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\nexport type AuthzLayoutProps = {\n renderHeader?: (props: { title: string; annotation: React.ReactNode }) => React.ReactNode\n}\n\n/** ネストルート用レイアウト(子は Outlet)。`routes.ts` でネスト構成にする場合に使う。 */\nexport function AuthzLayout({ renderHeader }: AuthzLayoutProps = {}) {\n return (\n <AuthzLayoutShell renderHeader={renderHeader}>\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// ============================ Group roles ============================\n\nexport type AuthzGroupRolesData = WithLabels & {\n groupRoles: AuthzGroupRoleAssignment[]\n roles: AuthzRole[]\n groups: AuthzGroupSummary[]\n}\n\nexport function AuthzGroupRolesView() {\n const { groupRoles, roles, groups, labels } = useLoaderData() as AuthzGroupRolesData\n const actionData = useActionData() as ActionError\n const err = actionError(actionData)\n const L = labels.groupRoles\n const C = labels.common\n\n const activeRoles = roles.filter((r) => r.isActive && r.roleKey !== \"@authenticated\" && r.roleKey !== \"@anonymous\")\n\n const groupOptions = groups.map((g) => ({ label: `${g.name} (${g.groupKey})`, value: g.id }))\n const roleOptions = activeRoles.map((r) => ({ label: `${r.name} (${r.roleKey})`, value: r.id }))\n\n const [selectedGroup, setSelectedGroup] = useState<{ label: string; value: number } | undefined>(groupOptions[0])\n const [selectedRole, setSelectedRole] = useState<{ label: string; value: number } | undefined>(roleOptions[0])\n\n return (\n <section style={{ display: \"flex\", flexDirection: \"column\", gap: \"1.25rem\" }}>\n <div>\n <h2 style={ui.h2}>{L.heading}</h2>\n <p style={ui.note}>{L.note}</p>\n </div>\n {err && <ErrorAlert message={err} />}\n\n <table style={ui.table}>\n <thead>\n <tr>\n <th style={ui.th}>{L.group}</th>\n <th style={ui.th}>{L.role}</th>\n <th style={{ ...ui.th, width: \"100px\" }} />\n </tr>\n </thead>\n <tbody>\n {groupRoles.length === 0 ? (\n <tr>\n <td colSpan={3} style={{ ...ui.td, textAlign: \"center\", color: \"#64748b\" }}>\n {L.empty}\n </td>\n </tr>\n ) : (\n groupRoles.map((a) => (\n <tr key={`${a.groupId}-${a.roleId}`}>\n <td style={ui.td}>\n <strong>{a.groupName}</strong> <span style={{ color: \"#64748b\", fontSize: \"0.85rem\" }}>({a.groupKey})</span>\n </td>\n <td style={ui.td}>\n <code>{a.roleKey}</code>\n </td>\n <td style={{ ...ui.td, textAlign: \"right\" }}>\n <Form method=\"post\" onSubmit={(e) => !confirm(\"このグループロール割当を解除しますか?\") && e.preventDefault()}>\n <input type=\"hidden\" name=\"_action\" value=\"remove\" />\n <input type=\"hidden\" name=\"groupId\" value={a.groupId} />\n <input type=\"hidden\" name=\"roleId\" value={a.roleId} />\n <button type=\"submit\" style={ui.dangerBtn}>\n {C.remove}\n </button>\n </Form>\n </td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n\n <Form method=\"post\" style={ui.card}>\n <h3 style={ui.h3}>{L.newHeading}</h3>\n <input type=\"hidden\" name=\"_action\" value=\"assign\" />\n <input type=\"hidden\" name=\"groupId\" value={selectedGroup?.value ?? \"\"} />\n <input type=\"hidden\" name=\"roleId\" value={selectedRole?.value ?? \"\"} />\n <Field label={L.group}>\n <SelectBox options={groupOptions} value={selectedGroup} onChange={(val) => setSelectedGroup((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// ============================ Graph view ============================\n\nexport type AuthzGraphData = WithLabels & {\n users: AuthzUser[]\n roles: AuthzRole[]\n resources: AuthzResource[]\n grants: AuthzGrant[]\n assignments: AuthzAssignment[]\n groupRoles?: AuthzGroupRoleAssignment[]\n groups?: AuthzGroupSummary[]\n}\n\nconst ACTION_COLORS: Record<string, { bg: string; text: string; border: string }> = {\n read: { bg: \"#ecfdf5\", text: \"#047857\", border: \"#a7f3d0\" },\n create: { bg: \"#eff6ff\", text: \"#1d4ed8\", border: \"#bfdbfe\" },\n update: { bg: \"#fffbeb\", text: \"#b45309\", border: \"#fde68a\" },\n delete: { bg: \"#fef2f2\", text: \"#b91c1c\", border: \"#fecaca\" },\n}\n\nexport type AuthzNodeType = \"user\" | \"group\" | \"role\" | \"resource\"\n\nfunction AuthzTopologyMap({\n users,\n roles,\n resources,\n grants,\n assignments,\n groupRoles = [],\n groups = [],\n selectedNode,\n onNodeClick,\n}: {\n users: AuthzUser[]\n roles: AuthzRole[]\n resources: AuthzResource[]\n grants: AuthzGrant[]\n assignments: AuthzAssignment[]\n groupRoles?: AuthzGroupRoleAssignment[]\n groups?: AuthzGroupSummary[]\n selectedNode: { type: AuthzNodeType; id: number } | null\n onNodeClick: (type: AuthzNodeType, id: number) => void\n}) {\n const [hoveredNode, setHoveredNode] = useState<{ type: AuthzNodeType; id: number } | null>(null)\n\n const connectedUserIds = new Set(assignments.map((a) => a.userId))\n const connectedGroupIds = new Set(groupRoles.map((g) => g.groupId))\n const connectedRoleIds = new Set([...assignments.map((a) => a.roleId), ...groupRoles.map((g) => g.roleId), ...grants.map((g) => g.roleId)])\n const connectedResourceIds = new Set(grants.map((g) => g.resourceId))\n\n const activeUsers = users.filter((u) => connectedUserIds.has(u.id))\n const activeGroups = groups.filter((g) => connectedGroupIds.has(g.id))\n const activeRoles = roles.filter((r) => connectedRoleIds.has(r.id))\n const activeResources = resources.filter((res) => connectedResourceIds.has(res.id))\n\n const getResourceActions = (resId: number) => {\n const resGrants = grants.filter((g) => g.resourceId === resId)\n const uniqueActions = Array.from(new Set(resGrants.map((g) => g.action)))\n return uniqueActions.length > 0 ? uniqueActions : [\"none\"]\n }\n\n const getResourceCardHeight = (resId: number) => {\n const actions = getResourceActions(resId)\n return 8 + 24 + actions.length * 24 + 6\n }\n\n const resourceCardGap = 16\n let cumulativeResY = 0\n const resourceYMap = new Map<number, { top: number; height: number; actionYMap: Map<string, number> }>()\n\n activeResources.forEach((res) => {\n const actions = getResourceActions(res.id)\n const height = getResourceCardHeight(res.id)\n const top = cumulativeResY\n const actionYMap = new Map<string, number>()\n\n actions.forEach((act, actIdx) => {\n const actY = top + 8 + 24 + actIdx * 24 + 12\n actionYMap.set(act, actY)\n })\n\n resourceYMap.set(res.id, { top, height, actionYMap })\n cumulativeResY += height + resourceCardGap\n })\n\n const totalResourceHeight = cumulativeResY > 0 ? cumulativeResY - resourceCardGap : 0\n\n const stdCardHeight = 52\n const stdCardGap = 18\n const stdItemHeight = stdCardHeight + stdCardGap\n\n const totalRoleHeight = activeRoles.length > 0 ? activeRoles.length * stdItemHeight - stdCardGap : 0\n const totalGroupHeight = activeGroups.length > 0 ? activeGroups.length * stdItemHeight - stdCardGap : 0\n const totalUserHeight = activeUsers.length > 0 ? activeUsers.length * stdItemHeight - stdCardGap : 0\n\n const maxColumnHeight = Math.max(totalResourceHeight, totalRoleHeight, totalGroupHeight, totalUserHeight, 320)\n const svgHeight = maxColumnHeight + 60\n\n const resourceStartTop = (svgHeight - totalResourceHeight) / 2\n const roleStartTop = (svgHeight - totalRoleHeight) / 2\n const groupStartTop = (svgHeight - totalGroupHeight) / 2\n const userStartTop = (svgHeight - totalUserHeight) / 2\n\n const getResourceActionCenterY = (resId: number, action: string) => {\n const info = resourceYMap.get(resId)\n if (!info) return svgHeight / 2\n const relativeActY = info.actionYMap.get(action) ?? info.height / 2\n return resourceStartTop + relativeActY\n }\n\n const getRoleCenterY = (roleIndex: number) => {\n return roleStartTop + roleIndex * stdItemHeight + stdCardHeight / 2\n }\n\n const getGroupCenterY = (groupIndex: number) => {\n return groupStartTop + groupIndex * stdItemHeight + stdCardHeight / 2\n }\n\n const getUserCenterY = (userIndex: number) => {\n return userStartTop + userIndex * stdItemHeight + stdCardHeight / 2\n }\n\n const resourceX = 140\n const roleX = 420\n const groupX = 700\n const userX = 980\n\n const activeNode = hoveredNode || selectedNode\n\n const isUserActive = (uId: number) => {\n if (!activeNode) return true\n if (activeNode.type === \"user\") return activeNode.id === uId\n if (activeNode.type === \"role\") return assignments.some((a) => a.userId === uId && a.roleId === activeNode.id)\n if (activeNode.type === \"group\") return false\n if (activeNode.type === \"resource\") {\n const roleIds = grants.filter((g) => g.resourceId === activeNode.id).map((g) => g.roleId)\n return assignments.some((a) => a.userId === uId && roleIds.includes(a.roleId))\n }\n return true\n }\n\n const isGroupActive = (gId: number) => {\n if (!activeNode) return true\n if (activeNode.type === \"group\") return activeNode.id === gId\n if (activeNode.type === \"role\") return groupRoles.some((gr) => gr.groupId === gId && gr.roleId === activeNode.id)\n if (activeNode.type === \"user\") return false\n if (activeNode.type === \"resource\") {\n const roleIds = grants.filter((g) => g.resourceId === activeNode.id).map((g) => g.roleId)\n return groupRoles.some((gr) => gr.groupId === gId && roleIds.includes(gr.roleId))\n }\n return true\n }\n\n const isRoleActive = (rId: number) => {\n if (!activeNode) return true\n if (activeNode.type === \"role\") return activeNode.id === rId\n if (activeNode.type === \"user\") return assignments.some((a) => a.userId === activeNode.id && a.roleId === rId)\n if (activeNode.type === \"group\") return groupRoles.some((gr) => gr.groupId === activeNode.id && gr.roleId === rId)\n if (activeNode.type === \"resource\") return grants.some((g) => g.resourceId === activeNode.id && g.roleId === rId)\n return true\n }\n\n const isResourceActive = (resId: number) => {\n if (!activeNode) return true\n if (activeNode.type === \"resource\") return activeNode.id === resId\n if (activeNode.type === \"role\") return grants.some((g) => g.roleId === activeNode.id && g.resourceId === resId)\n if (activeNode.type === \"group\") {\n const groupRoleIds = groupRoles.filter((gr) => gr.groupId === activeNode.id).map((gr) => gr.roleId)\n return grants.some((g) => groupRoleIds.includes(g.roleId) && g.resourceId === resId)\n }\n if (activeNode.type === \"user\") {\n const userRoleIds = assignments.filter((a) => a.userId === activeNode.id).map((a) => a.roleId)\n return grants.some((g) => userRoleIds.includes(g.roleId) && g.resourceId === resId)\n }\n return true\n }\n\n const isUserRoleLinkActive = (uId: number, rId: number) => {\n if (!activeNode) return true\n if (activeNode.type === \"user\") return activeNode.id === uId && assignments.some((a) => a.userId === uId && a.roleId === rId)\n if (activeNode.type === \"role\") return activeNode.id === rId && assignments.some((a) => a.userId === uId && a.roleId === rId)\n if (activeNode.type === \"resource\") {\n const roleIds = grants.filter((g) => g.resourceId === activeNode.id).map((g) => g.roleId)\n return roleIds.includes(rId) && assignments.some((a) => a.userId === uId && a.roleId === rId)\n }\n if (activeNode.type === \"group\") return false\n return true\n }\n\n const isGroupRoleLinkActive = (gId: number, rId: number) => {\n if (!activeNode) return true\n if (activeNode.type === \"group\") return activeNode.id === gId && groupRoles.some((gr) => gr.groupId === gId && gr.roleId === rId)\n if (activeNode.type === \"role\") return activeNode.id === rId && groupRoles.some((gr) => gr.groupId === gId && gr.roleId === rId)\n if (activeNode.type === \"resource\") {\n const roleIds = grants.filter((g) => g.resourceId === activeNode.id).map((g) => g.roleId)\n return roleIds.includes(rId) && groupRoles.some((gr) => gr.groupId === gId && gr.roleId === rId)\n }\n if (activeNode.type === \"user\") return false\n return true\n }\n\n const isRoleResourceLinkActive = (rId: number, resId: number) => {\n if (!activeNode) return true\n if (activeNode.type === \"role\") return activeNode.id === rId && grants.some((g) => g.roleId === rId && g.resourceId === resId)\n if (activeNode.type === \"resource\") return activeNode.id === resId && grants.some((g) => g.roleId === rId && g.resourceId === resId)\n if (activeNode.type === \"group\") {\n const groupRoleIds = groupRoles.filter((gr) => gr.groupId === activeNode.id).map((gr) => gr.roleId)\n return groupRoleIds.includes(rId) && grants.some((g) => g.roleId === rId && g.resourceId === resId)\n }\n if (activeNode.type === \"user\") {\n const userRoleIds = assignments.filter((a) => a.userId === activeNode.id).map((a) => a.roleId)\n return userRoleIds.includes(rId) && grants.some((g) => g.roleId === rId && g.resourceId === resId)\n }\n return true\n }\n\n const userRoleLinks: Array<{ uIdx: number; rIdx: number; active: boolean; key: string; offset: number }> = []\n assignments.forEach((a) => {\n const uIdx = activeUsers.findIndex((u) => u.id === a.userId)\n const rIdx = activeRoles.findIndex((r) => r.id === a.roleId)\n if (uIdx !== -1 && rIdx !== -1) {\n const roleAssignments = assignments.filter((item) => item.roleId === a.roleId)\n const assignIdx = roleAssignments.findIndex((item) => item.userId === a.userId && item.roleId === a.roleId)\n const totalAssigns = roleAssignments.length\n const offset = totalAssigns > 1 ? Math.min(Math.max((assignIdx - (totalAssigns - 1) / 2) * 4, -16), 16) : 0\n\n userRoleLinks.push({\n uIdx,\n rIdx,\n active: isUserRoleLinkActive(a.userId, a.roleId),\n key: `ur-${a.userId}-${a.roleId}`,\n offset,\n })\n }\n })\n\n const groupRoleLinks: Array<{ gIdx: number; rIdx: number; active: boolean; key: string; offset: number }> = []\n groupRoles.forEach((gr) => {\n const gIdx = activeGroups.findIndex((g) => g.id === gr.groupId)\n const rIdx = activeRoles.findIndex((r) => r.id === gr.roleId)\n if (gIdx !== -1 && rIdx !== -1) {\n const gRoleAssigns = groupRoles.filter((item) => item.roleId === gr.roleId)\n const assignIdx = gRoleAssigns.findIndex((item) => item.groupId === gr.groupId && item.roleId === gr.roleId)\n const totalAssigns = gRoleAssigns.length\n const offset = totalAssigns > 1 ? Math.min(Math.max((assignIdx - (totalAssigns - 1) / 2) * 4, -16), 16) : 0\n\n groupRoleLinks.push({\n gIdx,\n rIdx,\n active: isGroupRoleLinkActive(gr.groupId, gr.roleId),\n key: `gr-${gr.groupId}-${gr.roleId}`,\n offset,\n })\n }\n })\n\n const roleResourceLinks: Array<{ rIdx: number; resIdx: number; active: boolean; key: string; action: string; color: string; offset: number }> = []\n grants.forEach((g) => {\n const rIdx = activeRoles.findIndex((r) => r.id === g.roleId)\n const resIdx = activeResources.findIndex((res) => res.id === g.resourceId)\n if (rIdx !== -1 && resIdx !== -1) {\n const sameResourceActionGrants = grants.filter((item) => item.resourceId === g.resourceId && item.action === g.action)\n const actionRoleIdx = sameResourceActionGrants.findIndex((item) => item.id === g.id)\n const totalSameGrants = sameResourceActionGrants.length\n const offset = totalSameGrants > 1 ? Math.min(Math.max((actionRoleIdx - (totalSameGrants - 1) / 2) * 4, -12), 12) : 0\n\n const colorConf = ACTION_COLORS[g.action]\n const color = colorConf ? colorConf.text : \"#6366f1\"\n\n roleResourceLinks.push({\n rIdx,\n resIdx,\n active: isRoleResourceLinkActive(g.roleId, g.resourceId),\n key: `rr-grant-${g.id}`,\n action: g.action,\n color,\n offset,\n })\n }\n })\n\n return (\n <div data-testid=\"authz-topology-map\" style={{ width: \"100%\", overflowX: \"auto\", backgroundColor: \"#ffffff\", borderRadius: \"10px\", border: \"1px solid #e2e8f0\", padding: \"1rem\", boxSizing: \"border-box\" }}>\n <div style={{ position: \"relative\", minWidth: \"1160px\", height: `${svgHeight}px` }}>\n <svg style={{ position: \"absolute\", top: 0, left: 0, width: \"100%\", height: \"100%\", pointerEvents: \"none\", zIndex: 1 }}>\n <title>Topology Connections</title>\n\n {roleResourceLinks.map((link) => {\n const grantItem = grants.find((g) => `rr-grant-${g.id}` === link.key)\n if (!grantItem) return null\n\n const y1 = getResourceActionCenterY(grantItem.resourceId, grantItem.action) + link.offset\n const y2 = getRoleCenterY(link.rIdx)\n const cX1 = resourceX + 135\n const cX2 = roleX - 135\n return (\n <path\n key={link.key}\n d={`M ${resourceX + 90} ${y1} C ${cX1} ${y1}, ${cX2} ${y2}, ${roleX - 90} ${y2}`}\n fill=\"none\"\n stroke={link.active ? link.color : \"#cbd5e1\"}\n strokeWidth={link.active && activeNode ? 3 : 2}\n strokeOpacity={link.active ? (activeNode ? 1.0 : 0.75) : 0.12}\n style={{ transition: \"all 0.2s ease\" }}\n />\n )\n })}\n\n {groupRoleLinks.map((link) => {\n const y1 = getRoleCenterY(link.rIdx) + link.offset\n const y2 = getGroupCenterY(link.gIdx)\n const cX1 = roleX + 135\n const cX2 = groupX - 135\n return (\n <path\n key={link.key}\n data-testid={`topo-link-group-role-${link.key}`}\n data-active={link.active ? \"true\" : \"false\"}\n d={`M ${roleX + 90} ${y1} C ${cX1} ${y1}, ${cX2} ${y2}, ${groupX - 90} ${y2}`}\n fill=\"none\"\n stroke={link.active ? \"#8b5cf6\" : \"#cbd5e1\"}\n strokeWidth={link.active && activeNode ? 3 : 2}\n strokeDasharray=\"4 2\"\n strokeOpacity={link.active ? (activeNode ? 1.0 : 0.75) : 0.12}\n style={{ transition: \"all 0.2s ease\" }}\n />\n )\n })}\n\n {userRoleLinks.map((link) => {\n const y1 = getRoleCenterY(link.rIdx) + link.offset\n const y2 = getUserCenterY(link.uIdx)\n const cX1 = roleX + 135\n const cX2 = userX - 135\n return (\n <path\n key={link.key}\n data-testid={`topo-link-user-role-${link.key}`}\n data-active={link.active ? \"true\" : \"false\"}\n d={`M ${roleX + 90} ${y1} C ${cX1} ${y1}, ${cX2} ${y2}, ${userX - 90} ${y2}`}\n fill=\"none\"\n stroke={link.active ? \"#4f46e5\" : \"#cbd5e1\"}\n strokeWidth={link.active && activeNode ? 3 : 2}\n strokeOpacity={link.active ? (activeNode ? 1.0 : 0.75) : 0.12}\n style={{ transition: \"all 0.2s ease\" }}\n />\n )\n })}\n </svg>\n\n <div style={{ position: \"relative\", zIndex: 2, width: \"100%\", height: \"100%\" }}>\n {activeResources.map((res) => {\n const isSelected = selectedNode?.type === \"resource\" && selectedNode.id === res.id\n const active = isResourceActive(res.id)\n const cardInfo = resourceYMap.get(res.id)\n if (!cardInfo) return null\n\n const cardTop = resourceStartTop + cardInfo.top\n const actions = getResourceActions(res.id)\n\n return (\n <div\n key={res.id}\n style={{\n position: \"absolute\",\n left: `${resourceX - 90}px`,\n top: `${cardTop}px`,\n width: \"180px\",\n height: `${cardInfo.height}px`,\n borderRadius: \"8px\",\n border: isSelected ? \"2px solid #10b981\" : \"1px solid #a7f3d0\",\n backgroundColor: isSelected ? \"#d1fae5\" : active ? \"#ffffff\" : \"#f8fafc\",\n opacity: active ? 1 : 0.35,\n boxShadow: isSelected ? \"0 4px 12px rgba(16, 185, 129, 0.2)\" : \"0 1px 3px rgba(0,0,0,0.05)\",\n transition: \"all 0.15s ease\",\n padding: \"8px\",\n boxSizing: \"border-box\",\n display: \"flex\",\n flexDirection: \"column\",\n }}>\n <button\n type=\"button\"\n onClick={() => onNodeClick(\"resource\", res.id)}\n onMouseEnter={() => setHoveredNode({ type: \"resource\", id: res.id })}\n onMouseLeave={() => setHoveredNode(null)}\n data-testid={`topo-node-resource-${res.id}`}\n aria-label={`リソース: ${res.name}`}\n aria-pressed={isSelected}\n style={{\n background: \"none\",\n border: \"none\",\n padding: 0,\n margin: 0,\n cursor: \"pointer\",\n textAlign: \"left\",\n width: \"100%\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"6px\",\n marginBottom: \"6px\",\n height: \"18px\",\n }}>\n <span style={{ fontSize: \"1rem\", flexShrink: 0 }}>🔑</span>\n <span style={{ fontWeight: 600, fontSize: \"0.78rem\", color: \"#047857\", overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }}>{res.name}</span>\n </button>\n\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"2px\" }}>\n {actions.map((action) => {\n if (action === \"none\") {\n return (\n <div key=\"none\" style={{ fontSize: \"0.68rem\", color: \"#94a3b8\", height: \"22px\", display: \"flex\", alignItems: \"center\", padding: \"0 6px\" }}>\n 権限設定なし\n </div>\n )\n }\n\n const colorConf = ACTION_COLORS[action] ?? { bg: \"#ecfdf5\", text: \"#047857\", border: \"#a7f3d0\" }\n return (\n <div\n key={action}\n style={{\n height: \"22px\",\n boxSizing: \"border-box\",\n padding: \"0 8px\",\n borderRadius: \"4px\",\n backgroundColor: colorConf.bg,\n color: colorConf.text,\n border: `1px solid ${colorConf.border}`,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n fontSize: \"0.68rem\",\n fontWeight: 600,\n }}>\n <span>{action}</span>\n <span style={{ fontSize: \"0.6rem\", opacity: 0.6 }}>●</span>\n </div>\n )\n })}\n </div>\n </div>\n )\n })}\n\n {activeRoles.map((r, i) => {\n const isSelected = selectedNode?.type === \"role\" && selectedNode.id === r.id\n const active = isRoleActive(r.id)\n const y = getRoleCenterY(i)\n return (\n <button\n type=\"button\"\n key={r.id}\n onClick={() => onNodeClick(\"role\", r.id)}\n onMouseEnter={() => setHoveredNode({ type: \"role\", id: r.id })}\n onMouseLeave={() => setHoveredNode(null)}\n data-testid={`topo-node-role-${r.id}`}\n aria-label={`ロール: ${r.name}`}\n aria-pressed={isSelected}\n style={{\n position: \"absolute\",\n left: `${roleX - 90}px`,\n top: `${y - 26}px`,\n width: \"180px\",\n height: \"52px\",\n borderRadius: \"8px\",\n border: isSelected ? \"2px solid #6366f1\" : \"1px solid #c7d2fe\",\n backgroundColor: isSelected ? \"#e0e7ff\" : active ? \"#ffffff\" : \"#f8fafc\",\n opacity: active ? 1 : 0.35,\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n padding: \"0 10px\",\n gap: \"8px\",\n boxShadow: isSelected ? \"0 4px 12px rgba(99, 102, 241, 0.2)\" : \"0 1px 3px rgba(0,0,0,0.05)\",\n transition: \"all 0.15s ease\",\n textAlign: \"left\",\n boxSizing: \"border-box\",\n }}>\n <span style={{ fontSize: \"1.1rem\", flexShrink: 0 }}>🛡️</span>\n <div style={{ overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\", flex: 1, minWidth: 0 }}>\n <div style={{ fontWeight: 600, fontSize: \"0.78rem\", color: \"#4338ca\", textOverflow: \"ellipsis\", overflow: \"hidden\" }}>{r.name}</div>\n <div style={{ fontSize: \"0.68rem\", color: \"#64748b\", fontFamily: \"monospace\", textOverflow: \"ellipsis\", overflow: \"hidden\" }}>{r.roleKey}</div>\n </div>\n </button>\n )\n })}\n\n {activeGroups.map((g, i) => {\n const isSelected = selectedNode?.type === \"group\" && selectedNode.id === g.id\n const active = isGroupActive(g.id)\n const y = getGroupCenterY(i)\n return (\n <button\n type=\"button\"\n key={g.id}\n onClick={() => onNodeClick(\"group\", g.id)}\n onMouseEnter={() => setHoveredNode({ type: \"group\", id: g.id })}\n onMouseLeave={() => setHoveredNode(null)}\n data-testid={`topo-node-group-${g.id}`}\n aria-label={`グループ: ${g.name}`}\n aria-pressed={isSelected}\n style={{\n position: \"absolute\",\n left: `${groupX - 90}px`,\n top: `${y - 26}px`,\n width: \"180px\",\n height: \"52px\",\n borderRadius: \"8px\",\n border: isSelected ? \"2px solid #8b5cf6\" : \"1px solid #ddd6fe\",\n backgroundColor: isSelected ? \"#f3e8ff\" : active ? \"#ffffff\" : \"#f8fafc\",\n opacity: active ? 1 : 0.35,\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n padding: \"0 10px\",\n gap: \"8px\",\n boxShadow: isSelected ? \"0 4px 12px rgba(139, 92, 246, 0.2)\" : \"0 1px 3px rgba(0,0,0,0.05)\",\n transition: \"all 0.15s ease\",\n textAlign: \"left\",\n boxSizing: \"border-box\",\n }}>\n <span style={{ fontSize: \"1.1rem\", flexShrink: 0 }}>👥</span>\n <div style={{ overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\", flex: 1, minWidth: 0 }}>\n <div style={{ fontWeight: 600, fontSize: \"0.78rem\", color: \"#6d28d9\", textOverflow: \"ellipsis\", overflow: \"hidden\" }}>{g.name}</div>\n <div style={{ fontSize: \"0.68rem\", color: \"#64748b\", fontFamily: \"monospace\", textOverflow: \"ellipsis\", overflow: \"hidden\" }}>{g.groupKey}</div>\n </div>\n </button>\n )\n })}\n\n {activeUsers.map((u, i) => {\n const isSelected = selectedNode?.type === \"user\" && selectedNode.id === u.id\n const active = isUserActive(u.id)\n const y = getUserCenterY(i)\n return (\n <button\n type=\"button\"\n key={u.id}\n onClick={() => onNodeClick(\"user\", u.id)}\n onMouseEnter={() => setHoveredNode({ type: \"user\", id: u.id })}\n onMouseLeave={() => setHoveredNode(null)}\n data-testid={`topo-node-user-${u.id}`}\n aria-label={`ユーザー: ${u.displayName}`}\n aria-pressed={isSelected}\n style={{\n position: \"absolute\",\n left: `${userX - 90}px`,\n top: `${y - 26}px`,\n width: \"180px\",\n height: \"52px\",\n borderRadius: \"8px\",\n border: isSelected ? \"2px solid #0284c7\" : \"1px solid #bae6fd\",\n backgroundColor: isSelected ? \"#e0f2fe\" : active ? \"#ffffff\" : \"#f8fafc\",\n opacity: active ? 1 : 0.35,\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n padding: \"0 10px\",\n gap: \"8px\",\n boxShadow: isSelected ? \"0 4px 12px rgba(2, 132, 199, 0.2)\" : \"0 1px 3px rgba(0,0,0,0.05)\",\n transition: \"all 0.15s ease\",\n textAlign: \"left\",\n boxSizing: \"border-box\",\n }}>\n <span style={{ fontSize: \"1.1rem\", flexShrink: 0 }}>👤</span>\n <div style={{ overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\", flex: 1, minWidth: 0 }}>\n <div style={{ fontWeight: 600, fontSize: \"0.78rem\", color: \"#0369a1\", textOverflow: \"ellipsis\", overflow: \"hidden\" }}>{u.displayName}</div>\n <div style={{ fontSize: \"0.68rem\", color: \"#64748b\", textOverflow: \"ellipsis\", overflow: \"hidden\" }}>{u.email}</div>\n </div>\n </button>\n )\n })}\n </div>\n </div>\n </div>\n )\n}\n\nexport function AuthzGraphView() {\n const { users, roles, resources, grants, assignments, groupRoles = [], groups = [] } = useLoaderData() as AuthzGraphData\n const [selectedNode, setSelectedNode] = useState<{ type: AuthzNodeType; id: number } | null>(null)\n const [searchQuery, setSearchQuery] = useState(\"\")\n const [viewMode, setViewMode] = useState<\"topology\" | \"columns\">(\"topology\")\n\n const roleMap = new Map(roles.map((r) => [r.id, r]))\n const resourceMap = new Map(resources.map((r) => [r.id, r]))\n const groupMap = new Map(groups.map((g) => [g.id, g]))\n const userMap = new Map(users.map((u) => [u.id, u]))\n\n const isUserRelated = (userId: number): boolean => {\n if (!selectedNode) return true\n if (selectedNode.type === \"user\") return selectedNode.id === userId\n if (selectedNode.type === \"role\") return assignments.some((a) => a.userId === userId && a.roleId === selectedNode.id)\n if (selectedNode.type === \"group\") return false\n if (selectedNode.type === \"resource\") {\n const roleIdsForResource = grants.filter((g) => g.resourceId === selectedNode.id).map((g) => g.roleId)\n return assignments.some((a) => a.userId === userId && roleIdsForResource.includes(a.roleId))\n }\n return true\n }\n\n const isGroupRelated = (groupId: number): boolean => {\n if (!selectedNode) return true\n if (selectedNode.type === \"group\") return selectedNode.id === groupId\n if (selectedNode.type === \"role\") return groupRoles.some((gr) => gr.groupId === groupId && gr.roleId === selectedNode.id)\n if (selectedNode.type === \"user\") return false\n if (selectedNode.type === \"resource\") {\n const roleIdsForResource = grants.filter((g) => g.resourceId === selectedNode.id).map((g) => g.roleId)\n return groupRoles.some((gr) => gr.groupId === groupId && roleIdsForResource.includes(gr.roleId))\n }\n return true\n }\n\n const isRoleRelated = (roleId: number): boolean => {\n if (!selectedNode) return true\n if (selectedNode.type === \"role\") return selectedNode.id === roleId\n if (selectedNode.type === \"user\") return assignments.some((a) => a.userId === selectedNode.id && a.roleId === roleId)\n if (selectedNode.type === \"group\") return groupRoles.some((gr) => gr.groupId === selectedNode.id && gr.roleId === roleId)\n if (selectedNode.type === \"resource\") return grants.some((g) => g.resourceId === selectedNode.id && g.roleId === roleId)\n return true\n }\n\n const isResourceRelated = (resourceId: number): boolean => {\n if (!selectedNode) return true\n if (selectedNode.type === \"resource\") return selectedNode.id === resourceId\n if (selectedNode.type === \"role\") return grants.some((g) => g.roleId === selectedNode.id && g.resourceId === resourceId)\n if (selectedNode.type === \"group\") {\n const groupRoleIds = groupRoles.filter((gr) => gr.groupId === selectedNode.id).map((gr) => gr.roleId)\n return grants.some((g) => groupRoleIds.includes(g.roleId) && g.resourceId === resourceId)\n }\n if (selectedNode.type === \"user\") {\n const userRoleIds = assignments.filter((a) => a.userId === selectedNode.id).map((a) => a.roleId)\n return grants.some((g) => userRoleIds.includes(g.roleId) && g.resourceId === resourceId)\n }\n return true\n }\n\n const query = searchQuery.trim().toLowerCase()\n const filteredUsers = users.filter((u) => !query || u.displayName.toLowerCase().includes(query) || u.email?.toLowerCase().includes(query))\n const filteredGroups = groups.filter((g) => !query || g.name.toLowerCase().includes(query) || g.groupKey.toLowerCase().includes(query))\n const filteredRoles = roles.filter((r) => !query || r.name.toLowerCase().includes(query) || r.roleKey.toLowerCase().includes(query))\n const filteredResources = resources.filter((r) => !query || r.name.toLowerCase().includes(query) || r.resourceKey.toLowerCase().includes(query) || r.appKey.toLowerCase().includes(query))\n\n const selectedUserObj = selectedNode?.type === \"user\" ? userMap.get(selectedNode.id) : null\n const selectedGroupObj = selectedNode?.type === \"group\" ? groupMap.get(selectedNode.id) : null\n const selectedRoleObj = selectedNode?.type === \"role\" ? roleMap.get(selectedNode.id) : null\n const selectedResourceObj = selectedNode?.type === \"resource\" ? resourceMap.get(selectedNode.id) : null\n\n const handleNodeClick = (type: AuthzNodeType, id: number) => {\n if (selectedNode && selectedNode.type === type && selectedNode.id === id) {\n setSelectedNode(null)\n } else {\n setSelectedNode({ type, id })\n }\n }\n\n return (\n <section data-testid=\"authz-graph-view\" style={{ display: \"flex\", flexDirection: \"column\", gap: \"1rem\", width: \"100%\" }}>\n <div style={{ display: \"flex\", justifyContent: \"space-between\", alignItems: \"center\", flexWrap: \"wrap\", gap: \"0.75rem\", backgroundColor: \"#f8fafc\", padding: \"0.75rem 1rem\", borderRadius: \"8px\", border: \"1px solid #e2e8f0\", width: \"100%\", boxSizing: \"border-box\" }}>\n <div style={{ display: \"flex\", alignItems: \"center\", gap: \"0.75rem\", flexWrap: \"wrap\" }}>\n <div style={{ display: \"inline-flex\", borderRadius: \"6px\", border: \"1px solid #cbd5e1\", padding: \"2px\", backgroundColor: \"#ffffff\" }}>\n <button\n type=\"button\"\n onClick={() => setViewMode(\"topology\")}\n data-testid=\"switch-mode-topology\"\n style={{\n padding: \"3px 10px\",\n borderRadius: \"4px\",\n border: \"none\",\n cursor: \"pointer\",\n fontSize: \"0.75rem\",\n fontWeight: viewMode === \"topology\" ? 600 : 400,\n backgroundColor: viewMode === \"topology\" ? \"#eff6ff\" : \"transparent\",\n color: viewMode === \"topology\" ? \"#0284c7\" : \"#64748b\",\n boxShadow: viewMode === \"topology\" ? \"0 1px 2px rgba(0,0,0,0.08)\" : \"none\",\n }}>\n 🌐 トポロジマップ (Topology)\n </button>\n <button\n type=\"button\"\n onClick={() => setViewMode(\"columns\")}\n data-testid=\"switch-mode-columns\"\n style={{\n padding: \"3px 10px\",\n borderRadius: \"4px\",\n border: \"none\",\n cursor: \"pointer\",\n fontSize: \"0.75rem\",\n fontWeight: viewMode === \"columns\" ? 600 : 400,\n backgroundColor: viewMode === \"columns\" ? \"#eff6ff\" : \"transparent\",\n color: viewMode === \"columns\" ? \"#0284c7\" : \"#64748b\",\n boxShadow: viewMode === \"columns\" ? \"0 1px 2px rgba(0,0,0,0.08)\" : \"none\",\n }}>\n 📋 カラム一覧 (Columns)\n </button>\n </div>\n <div style={{ display: \"flex\", gap: \"0.4rem\", fontSize: \"0.75rem\", flexWrap: \"wrap\" }}>\n <span style={{ backgroundColor: \"#e0f2fe\", color: \"#0369a1\", padding: \"2px 8px\", borderRadius: \"12px\", fontWeight: 600 }}>👤 ユーザー: {users.length}</span>\n <span style={{ backgroundColor: \"#f3e8ff\", color: \"#6d28d9\", padding: \"2px 8px\", borderRadius: \"12px\", fontWeight: 600 }}>👥 グループ: {groups.length}</span>\n <span style={{ backgroundColor: \"#e0e7ff\", color: \"#4338ca\", padding: \"2px 8px\", borderRadius: \"12px\", fontWeight: 600 }}>🛡️ ロール: {roles.length}</span>\n <span style={{ backgroundColor: \"#d1fae5\", color: \"#047857\", padding: \"2px 8px\", borderRadius: \"12px\", fontWeight: 600 }}>🔑 リソース: {resources.length}</span>\n <span style={{ backgroundColor: \"#fef3c7\", color: \"#b45309\", padding: \"2px 8px\", borderRadius: \"12px\", fontWeight: 600 }}>⚡️ 権限設定: {grants.length}</span>\n </div>\n </div>\n <div style={{ display: \"flex\", alignItems: \"center\", gap: \"0.5rem\" }}>\n <input\n type=\"text\"\n placeholder=\"キーワードで絞り込み...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n data-testid=\"graph-search-input\"\n style={{ padding: \"5px 10px\", borderRadius: \"6px\", border: \"1px solid #cbd5e1\", fontSize: \"0.8rem\", width: \"200px\" }}\n />\n </div>\n </div>\n\n {/* 常時高さ固定のステータスバー (高さ38px固定でレイアウトシフトを防止) */}\n <div\n style={{\n minHeight: \"38px\",\n height: \"38px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n backgroundColor: selectedNode ? \"#eff6ff\" : \"#f8fafc\",\n border: `1px solid ${selectedNode ? \"#bfdbfe\" : \"#e2e8f0\"}`,\n padding: \"0 0.8rem\",\n borderRadius: \"6px\",\n fontSize: \"0.8rem\",\n color: selectedNode ? \"#1e40af\" : \"#64748b\",\n width: \"100%\",\n boxSizing: \"border-box\",\n transition: \"all 0.15s ease\",\n }}>\n <div style={{ display: \"flex\", alignItems: \"center\", gap: \"0.4rem\", overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }}>\n {selectedNode ? (\n <>\n <span>🎯</span>\n <strong>選択中のノード:</strong>\n <span>\n {selectedUserObj && `ユーザー「${selectedUserObj.displayName} (${selectedUserObj.email})」に関連するパスを表示中`}\n {selectedGroupObj && `グループ「${selectedGroupObj.name} (${selectedGroupObj.groupKey})」に関連するパスを表示中`}\n {selectedRoleObj && `ロール「${selectedRoleObj.name} (${selectedRoleObj.roleKey})」に関連するパスを表示中`}\n {selectedResourceObj && `リソース「${selectedResourceObj.name} (${selectedResourceObj.appKey}:${selectedResourceObj.resourceKey})」に関連するパスを表示中`}\n </span>\n </>\n ) : (\n <>\n <span>💡</span>\n <span>\n <strong>ヒント:</strong> ノード(リソース・ロール・グループ・ユーザー)をクリックすると、関連する全パスがハイライト表示されます\n </span>\n </>\n )}\n </div>\n {selectedNode && (\n <button\n type=\"button\"\n onClick={() => setSelectedNode(null)}\n data-testid=\"graph-reset-selection\"\n style={{\n padding: \"3px 8px\",\n borderRadius: \"4px\",\n border: \"1px solid #93c5fd\",\n backgroundColor: \"#ffffff\",\n fontSize: \"0.72rem\",\n cursor: \"pointer\",\n color: \"#1d4ed8\",\n fontWeight: 600,\n whiteSpace: \"nowrap\",\n boxShadow: \"0 1px 2px rgba(0,0,0,0.05)\",\n }}>\n ✕ 選択解除\n </button>\n )}\n </div>\n\n {viewMode === \"topology\" ? (\n <AuthzTopologyMap users={filteredUsers} roles={filteredRoles} resources={filteredResources} grants={grants} assignments={assignments} groupRoles={groupRoles} groups={filteredGroups} selectedNode={selectedNode} onNodeClick={handleNodeClick} />\n ) : (\n <div style={{ display: \"grid\", gridTemplateColumns: \"repeat(4, minmax(0, 1fr))\", gap: \"1rem\", alignItems: \"start\", width: \"100%\", boxSizing: \"border-box\" }}>\n {/* Column 1: Resources */}\n <div style={{ backgroundColor: \"#ffffff\", borderRadius: \"8px\", border: \"1px solid #e2e8f0\", padding: \"0.75rem\" }}>\n <div style={{ fontWeight: 700, fontSize: \"0.85rem\", color: \"#047857\", marginBottom: \"0.6rem\", display: \"flex\", alignItems: \"center\", gap: \"0.3rem\", borderBottom: \"2px solid #a7f3d0\", paddingBottom: \"0.4rem\" }}>\n <span>🔑</span> リソース ({filteredResources.length})\n </div>\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"0.5rem\", maxHeight: \"480px\", overflowY: \"auto\", paddingRight: \"4px\" }}>\n {filteredResources.length === 0 && <div style={{ fontSize: \"0.8rem\", color: \"#94a3b8\", textAlign: \"center\", padding: \"1rem\" }}>対象のリソースがありません</div>}\n {filteredResources.map((res) => {\n const isSelected = selectedNode?.type === \"resource\" && selectedNode.id === res.id\n const active = isResourceRelated(res.id)\n const resourceGrants = grants.filter((g) => g.resourceId === res.id)\n\n return (\n <button\n type=\"button\"\n key={res.id}\n onClick={() => handleNodeClick(\"resource\", res.id)}\n data-testid={`graph-node-resource-${res.id}`}\n style={{\n textAlign: \"left\",\n width: \"100%\",\n padding: \"0.6rem\",\n borderRadius: \"6px\",\n border: isSelected ? \"2px solid #10b981\" : \"1px solid #e2e8f0\",\n backgroundColor: isSelected ? \"#d1fae5\" : active ? \"#ffffff\" : \"#f8fafc\",\n opacity: active ? 1 : 0.4,\n cursor: \"pointer\",\n transition: \"all 0.15s ease\",\n boxShadow: isSelected ? \"0 2px 4px rgba(16, 185, 129, 0.15)\" : \"none\",\n }}>\n <div style={{ fontWeight: 600, fontSize: \"0.82rem\", color: \"#0f172a\" }}>{res.name}</div>\n <div style={{ fontSize: \"0.72rem\", color: \"#64748b\", fontFamily: \"monospace\" }}>\n {res.appKey}:{res.resourceKey}\n </div>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: \"0.25rem\", marginTop: \"0.4rem\" }}>\n {resourceGrants.map((g) => {\n const role = roleMap.get(g.roleId)\n const actStyle = ACTION_COLORS[g.action] ?? { bg: \"#f1f5f9\", text: \"#475569\", border: \"#cbd5e1\" }\n return (\n <span\n key={g.id}\n style={{\n fontSize: \"0.68rem\",\n padding: \"1px 6px\",\n borderRadius: \"4px\",\n backgroundColor: actStyle.bg,\n color: actStyle.text,\n border: `1px solid ${actStyle.border}`,\n }}>\n {role?.roleKey ?? `Role#${g.roleId}`}: <strong>{g.action}</strong>\n </span>\n )\n })}\n {resourceGrants.length === 0 && <span style={{ fontSize: \"0.68rem\", color: \"#94a3b8\" }}>権限設定なし</span>}\n </div>\n </button>\n )\n })}\n </div>\n </div>\n\n {/* Column 2: Roles */}\n <div style={{ backgroundColor: \"#ffffff\", borderRadius: \"8px\", border: \"1px solid #e2e8f0\", padding: \"0.75rem\" }}>\n <div style={{ fontWeight: 700, fontSize: \"0.85rem\", color: \"#4338ca\", marginBottom: \"0.6rem\", display: \"flex\", alignItems: \"center\", gap: \"0.3rem\", borderBottom: \"2px solid #c7d2fe\", paddingBottom: \"0.4rem\" }}>\n <span>🛡️</span> ロール ({filteredRoles.length})\n </div>\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"0.5rem\", maxHeight: \"480px\", overflowY: \"auto\", paddingRight: \"4px\" }}>\n {filteredRoles.length === 0 && <div style={{ fontSize: \"0.8rem\", color: \"#94a3b8\", textAlign: \"center\", padding: \"1rem\" }}>対象のロールがありません</div>}\n {filteredRoles.map((r) => {\n const isSelected = selectedNode?.type === \"role\" && selectedNode.id === r.id\n const active = isRoleRelated(r.id)\n const roleGrants = grants.filter((g) => g.roleId === r.id)\n const roleAssignments = assignments.filter((a) => a.roleId === r.id)\n const roleGroupAssignments = groupRoles.filter((gr) => gr.roleId === r.id)\n\n return (\n <button\n type=\"button\"\n key={r.id}\n onClick={() => handleNodeClick(\"role\", r.id)}\n data-testid={`graph-node-role-${r.id}`}\n style={{\n textAlign: \"left\",\n width: \"100%\",\n padding: \"0.6rem\",\n borderRadius: \"6px\",\n border: isSelected ? \"2px solid #6366f1\" : \"1px solid #e2e8f0\",\n backgroundColor: isSelected ? \"#e0e7ff\" : active ? \"#ffffff\" : \"#f8fafc\",\n opacity: active ? 1 : 0.4,\n cursor: \"pointer\",\n transition: \"all 0.15s ease\",\n boxShadow: isSelected ? \"0 2px 4px rgba(99, 102, 241, 0.15)\" : \"none\",\n }}>\n <div style={{ fontWeight: 600, fontSize: \"0.82rem\", color: \"#0f172a\" }}>{r.name}</div>\n <div style={{ fontSize: \"0.72rem\", color: \"#64748b\", fontFamily: \"monospace\" }}>{r.roleKey}</div>\n <div style={{ fontSize: \"0.7rem\", color: \"#475569\", marginTop: \"0.3rem\", display: \"flex\", gap: \"0.5rem\" }}>\n <span>権限: {roleGrants.length}</span>\n <span>グループ: {roleGroupAssignments.length}</span>\n <span>ユーザー: {roleAssignments.length}</span>\n </div>\n </button>\n )\n })}\n </div>\n </div>\n\n {/* Column 3: Groups */}\n <div style={{ backgroundColor: \"#ffffff\", borderRadius: \"8px\", border: \"1px solid #e2e8f0\", padding: \"0.75rem\" }}>\n <div style={{ fontWeight: 700, fontSize: \"0.85rem\", color: \"#6d28d9\", marginBottom: \"0.6rem\", display: \"flex\", alignItems: \"center\", gap: \"0.3rem\", borderBottom: \"2px solid #ddd6fe\", paddingBottom: \"0.4rem\" }}>\n <span>👥</span> グループ ({filteredGroups.length})\n </div>\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"0.5rem\", maxHeight: \"480px\", overflowY: \"auto\", paddingRight: \"4px\" }}>\n {filteredGroups.length === 0 && <div style={{ fontSize: \"0.8rem\", color: \"#94a3b8\", textAlign: \"center\", padding: \"1rem\" }}>対象のグループがありません</div>}\n {filteredGroups.map((g) => {\n const isSelected = selectedNode?.type === \"group\" && selectedNode.id === g.id\n const active = isGroupRelated(g.id)\n const assignedRoles = groupRoles.filter((gr) => gr.groupId === g.id)\n\n return (\n <button\n type=\"button\"\n key={g.id}\n onClick={() => handleNodeClick(\"group\", g.id)}\n data-testid={`graph-node-group-${g.id}`}\n style={{\n textAlign: \"left\",\n width: \"100%\",\n padding: \"0.6rem\",\n borderRadius: \"6px\",\n border: isSelected ? \"2px solid #8b5cf6\" : \"1px solid #e2e8f0\",\n backgroundColor: isSelected ? \"#f3e8ff\" : active ? \"#ffffff\" : \"#f8fafc\",\n opacity: active ? 1 : 0.4,\n cursor: \"pointer\",\n transition: \"all 0.15s ease\",\n boxShadow: isSelected ? \"0 2px 4px rgba(139, 92, 246, 0.15)\" : \"none\",\n }}>\n <div style={{ fontWeight: 600, fontSize: \"0.82rem\", color: \"#0f172a\" }}>{g.name}</div>\n <div style={{ fontSize: \"0.72rem\", color: \"#64748b\", fontFamily: \"monospace\" }}>{g.groupKey}</div>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: \"0.25rem\", marginTop: \"0.4rem\" }}>\n {assignedRoles.map((gr) => {\n const role = roleMap.get(gr.roleId)\n return (\n <span\n key={`${gr.groupId}-${gr.roleId}`}\n style={{\n fontSize: \"0.68rem\",\n padding: \"1px 6px\",\n borderRadius: \"4px\",\n backgroundColor: \"#f3e8ff\",\n color: \"#6d28d9\",\n border: \"1px solid #ddd6fe\",\n fontWeight: 600,\n }}>\n 🛡️ {role?.name ?? gr.roleKey}\n </span>\n )\n })}\n {assignedRoles.length === 0 && <span style={{ fontSize: \"0.68rem\", color: \"#94a3b8\" }}>ロール未割り当て</span>}\n </div>\n </button>\n )\n })}\n </div>\n </div>\n\n {/* Column 4: Users */}\n <div style={{ backgroundColor: \"#ffffff\", borderRadius: \"8px\", border: \"1px solid #e2e8f0\", padding: \"0.75rem\" }}>\n <div style={{ fontWeight: 700, fontSize: \"0.85rem\", color: \"#0369a1\", marginBottom: \"0.6rem\", display: \"flex\", alignItems: \"center\", gap: \"0.3rem\", borderBottom: \"2px solid #bae6fd\", paddingBottom: \"0.4rem\" }}>\n <span>👤</span> ユーザー ({filteredUsers.length})\n </div>\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"0.5rem\", maxHeight: \"480px\", overflowY: \"auto\", paddingRight: \"4px\" }}>\n {filteredUsers.length === 0 && <div style={{ fontSize: \"0.8rem\", color: \"#94a3b8\", textAlign: \"center\", padding: \"1rem\" }}>対象のユーザーがありません</div>}\n {filteredUsers.map((u) => {\n const isSelected = selectedNode?.type === \"user\" && selectedNode.id === u.id\n const active = isUserRelated(u.id)\n const userAssignments = assignments.filter((a) => a.userId === u.id)\n\n return (\n <button\n type=\"button\"\n key={u.id}\n onClick={() => handleNodeClick(\"user\", u.id)}\n data-testid={`graph-node-user-${u.id}`}\n style={{\n textAlign: \"left\",\n width: \"100%\",\n padding: \"0.6rem\",\n borderRadius: \"6px\",\n border: isSelected ? \"2px solid #0284c7\" : \"1px solid #e2e8f0\",\n backgroundColor: isSelected ? \"#e0f2fe\" : active ? \"#ffffff\" : \"#f8fafc\",\n opacity: active ? 1 : 0.4,\n cursor: \"pointer\",\n transition: \"all 0.15s ease\",\n boxShadow: isSelected ? \"0 2px 4px rgba(2, 132, 199, 0.15)\" : \"none\",\n }}>\n <div style={{ fontWeight: 600, fontSize: \"0.82rem\", color: \"#0f172a\" }}>{u.displayName}</div>\n <div style={{ fontSize: \"0.72rem\", color: \"#64748b\" }}>{u.email}</div>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: \"0.25rem\", marginTop: \"0.4rem\" }}>\n {userAssignments.map((a) => {\n const role = roleMap.get(a.roleId)\n return (\n <span\n key={`${a.userId}-${a.roleId}`}\n style={{\n fontSize: \"0.68rem\",\n padding: \"1px 6px\",\n borderRadius: \"4px\",\n backgroundColor: \"#e0f2fe\",\n color: \"#0369a1\",\n border: \"1px solid #bae6fd\",\n fontWeight: 600,\n }}>\n 🛡️ {role?.name ?? a.roleKey}\n </span>\n )\n })}\n {userAssignments.length === 0 && <span style={{ fontSize: \"0.68rem\", color: \"#94a3b8\" }}>直接ロールなし</span>}\n </div>\n </button>\n )\n })}\n </div>\n </div>\n </div>\n )}\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 group_roles: AuthzGroupRolesView,\n graph: AuthzGraphView,\n}\n\nexport type AuthzAdminAppViewProps = {\n renderHeader?: (props: { title: string; annotation: React.ReactNode }) => React.ReactNode\n}\n\n/**\n * スプラット(`authz/*`)1 ルートで認可管理 UI 全体を描画するコンポーネント(store 非依存)。\n * loader が返す `segment` に応じて該当タブのビューを描画する。レイアウト殻と各ビューは同一の\n * loader データ(セグメントデータ + myPermissions + labels をトップレベルに統合)を読む。\n */\nexport function AuthzAdminAppView({ renderHeader }: AuthzAdminAppViewProps = {}) {\n const { segment } = useLoaderData() as { segment: string }\n const View = SEGMENT_VIEWS[segment] ?? AuthzRolesView\n return (\n <AuthzLayoutShell renderHeader={renderHeader}>\n <View />\n </AuthzLayoutShell>\n )\n}\n","/**\n * Multi-resource permission widget (inline pills or a popover card) for pages spanning several resources.\n * 複数リソースにまたがる画面向けの権限表示ウィジェット (インラインのタグ表示とポップオーバー表示)。\n */\nimport { 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.canRead || permission.canWrite || permission.canDelete))) {\n return { text: txtNoPerm, color: \"#64748b\", bgColor: \"#f1f5f9\", borderColor: \"#cbd5e1\" }\n }\n if (permission.canWrite) {\n return { text: txtFullWrite, color: \"#047857\", bgColor: \"#ecfdf5\", borderColor: \"#a7f3d0\" }\n }\n if (permission.canRead) {\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.canRead ? \"○\" : \"×\"} ${labels?.write ?? \"編集\"}:${item.permission.canWrite ? \"○\" : \"×\"} ${labels?.delete ?? \"削除\"}:${item.permission.canDelete ? \"○\" : \"×\"}` : \"\"}`\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 // トリガーの総括文言。**権限が無い/データが無いときに許可を名乗らない** ことが要件。\n // 以前は項目 0 件で `0 === 0` が成立して「編集可」、全項目が権限なしでも「閲覧のみ」と表示していた。\n // 子要素 (`children`) も対象に含める。トップレベルだけを数えると、書き込み可の親の下に\n // 権限なしの子がぶら下がっていても「編集可」と名乗ってしまう。\n const allItems = flattenGroupItems(items)\n const writeCount = allItems.filter((i) => i.permission?.canWrite).length\n const readCount = allItems.filter((i) => i.permission?.canRead).length\n const totalCount = allItems.length\n const summaryLabel = totalCount === 0 || (writeCount === 0 && readCount === 0) ? (labels?.noPermission ?? \"権限なし\") : 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","/**\n * Display-state derivation for a {@link PermissionView} (pure, no React state involved).\n * {@link PermissionView} から表示状態を導出するモジュール (React の状態は一切持たない純粋関数)。\n */\nimport type { PermissionView } from \"./server\"\n\nexport type PermState = \"full\" | \"partial\" | \"none\"\n\n/**\n * Display-oriented reading of a {@link PermissionView}: the same `can*` booleans (safe defaults when the\n * view is absent) plus the ○△× tri-state used by the indicator components.\n * {@link PermissionView} の表示向け読み取り結果。同名の `can*` 真偽値と ○△× の三値状態を併せ持つ形。\n */\nexport type UsePermission = {\n canRead: boolean\n canCreate: boolean\n canUpdate: boolean\n canDelete: boolean\n /** create ∪ update */\n canWrite: 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 * {@link PermissionView} から ○△× の表示状態を導出する純粋関数 (レンダー内から安全に呼べる形)。\n *\n * @returns The permission booleans plus their display states. 権限の真偽値と表示状態の組。\n */\nexport function usePermission(view: PermissionView | null | undefined): UsePermission {\n const readState: PermState = !view?.canRead ? \"none\" : view.readPartial ? \"partial\" : \"full\"\n const writeState: PermState = view?.canCreate && view?.canUpdate ? \"full\" : view?.canCreate || view?.canUpdate ? \"partial\" : \"none\"\n const deleteState: PermState = view?.canDelete ? \"full\" : \"none\"\n return {\n canRead: !!view?.canRead,\n canCreate: !!view?.canCreate,\n canUpdate: !!view?.canUpdate,\n canDelete: !!view?.canDelete,\n canWrite: !!view?.canWrite,\n readState,\n writeState,\n deleteState,\n }\n}\n","/**\n * Badge components that show the acting user their own permissions for one resource.\n * 操作ユーザー自身の権限を 1 リソース分バッジ表示するコンポーネント群。\n */\nimport type { PermissionView } from \"./server\"\nimport { type PermState, usePermission } from \"./usePermission\"\n\nexport type MyPermissionIndicatorProps<K extends string = string> = {\n permission: PermissionView<K> | null | undefined\n /** Human-readable resource display name (e.g. \"文書データ\"). Falls back to permission.resourceKey. */\n resourceName?: string\n /**\n * Expected resource key. Typed as `NoInfer<K>`, so when the permission carries a literal key\n * (`getMyPermissions` / `requirePermission` both do) a mismatch is a **compile error**; the runtime\n * detector below stays for dynamically-keyed and JavaScript callers.\n */\n expectedResourceKey?: NoInfer<K>\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<K extends string = string> = MyPermissionIndicatorProps<K> & {\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<K extends string = string>({ permission, resourceName, expectedResourceKey, showResourceTooltip = true, labels, showScopeSummary = true, className = \"authz-permission-indicator\" }: MyPermissionIndicatorProps<K>) {\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<K extends string = string>({\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<K>) {\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 permission={permission} resourceName={resourceName} expectedResourceKey={expectedResourceKey} showResourceTooltip={showResourceTooltip} labels={labels} showScopeSummary={showScopeSummary} />\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 * The resource key an entry resolves to: its explicit `key`, otherwise the property name.\n * `key` を明示していればそれ、無ければプロパティ名。\n *\n * `Extract<…, string>` を挟むのは `key?: string` (省略可) が `string | undefined` になり、素の\n * `extends string` では偽になってプロパティ名を名乗ってしまうため (実行時は `key` を使うので型が嘘になる)。\n * `key` を書いていないエントリでは `Extract` が `never` になり、プロパティ名へ落ちる。\n */\ntype ResolvedResourceKey<PropertyName extends string, Input extends ResourceDefinitionInput> = [Extract<Input[\"key\"], string>] extends [never] ? PropertyName : Extract<Input[\"key\"], string>\n\n/**\n * Define type-safe resource registry for an application.\n * アプリ全体のリソース定義(キー・表示名・説明)を一元管理するヘルパー。\n *\n * 各エントリの `key` はリテラル型のまま保持する。`Record<string, …>` へ広げてしまうと\n * {@link resourceKeysOf} が `string[]` に落ち、権限マップのキー型検査が効かなくなるため。\n *\n * @returns The registry with literal-typed resource keys. リソースキーをリテラル型で保持したレジストリ。\n */\nexport function defineResources<const T extends Record<string, ResourceDefinitionInput>>(resources: T): { [K in keyof T & string]: { key: ResolvedResourceKey<K, T[K]>; name: string; description?: string } } {\n const result = {} as { [K in keyof T & string]: { key: ResolvedResourceKey<K, T[K]>; name: string; description?: string } }\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) as ResolvedResourceKey<typeof k, T[typeof k]>,\n name: item.name,\n description: item.description,\n }\n }\n return result\n}\n\n/**\n * Extract a registry's resource keys with their literal types preserved.\n * レジストリのリソースキーをリテラル型を保ったまま取り出す処理。\n *\n * `Object.keys(registry)` は `string[]` になり、`getMyPermissions` の戻り値も索引型へ落ちてキーの誤りを\n * 検出できなくなる。加えて `Object.keys` は **プロパティ名** を返すため、`key` を明示したエントリでは\n * 実際のリソースキーと食い違う。\n *\n * ⚠️ 1 エントリでもリテラルでない `key` (例: 変数由来の `string`) を持つと、合併の性質上レジストリ全体の\n * キー型が `string` へ広がり、他のエントリ分のコンパイル時検査も無効になる。`key` は必ずリテラルで書くこと。\n *\n * @returns The registry's resource keys as a literal union array. リテラル合併型のリソースキー配列。\n */\nexport function resourceKeysOf<T extends Record<string, { key: string }>>(registry: T): Array<T[keyof T & string][\"key\"]> {\n return Object.values(registry).map((r) => r.key) as Array<T[keyof T & string][\"key\"]>\n}\n","/**\n * React Router (v7) adapter: binds `appKey` + the DI ports and exposes the loader/action authorization API.\n * React Router (v7) 向けアダプタ。`appKey` と DI ポートを束ね、loader/action 用の認可 API を公開するモジュール。\n *\n * 設計上の中心的な不変条件は **判定は 1 回だけ** ということ。ガード (`requirePermission`) と\n * UI 表示用の権限ビューは同一の実効権限から導出されるため、「画面は開けるのに一覧では false」\n * という乖離が構造的に起こり得ない。\n */\nimport { AUTHZ_ACTIONS, type AuthzAction, can, createRequirePermission, type DenyInfo, type EffectivePermission, type MergedScope } from \"@aiquants/authz-core\"\nimport { redirect } from \"react-router\"\n\ntype Awaitable<T> = T | Promise<T>\nexport type AuthzUserId = string | number\n\nconst PKG = \"@aiquants/authz-react-router\"\n\n/**\n * Thrown when the API itself is called incorrectly (bad arguments, missing port) — a programmer error,\n * never an authorization decision. It is deliberately NOT an `AuthzDeniedError`: a misuse must surface as a\n * loud 500, not as a silent 403 that looks like a permission problem.\n * API の使い方が誤っている場合に送出される例外。認可拒否 (403) とは明確に区別されるプログラマ向けエラー。\n */\nexport class AuthzUsageError extends Error {\n constructor(message: string) {\n super(`[${PKG}] ${message}`)\n this.name = \"AuthzUsageError\"\n }\n}\n\n/** Arguments handed to the {@link AuthzConfig.getEffectivePermissions} port. 実効権限ポートへ渡す引数。 */\nexport type EffectivePermissionsQuery = {\n userId: AuthzUserId | null\n groupIds?: (string | number)[]\n appKey: string\n /** Always a de-duplicated, non-empty list — the port may load them all in one round-trip. Read-only: the adapter reports on exactly these keys. */\n resourceKeys: readonly string[]\n}\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 → the consumer's user id). */\n resolveUserId: (request: Request) => Awaitable<AuthzUserId | null | undefined>\n /** Optionally resolve acting user's group IDs from the request or session. */\n resolveGroupIds?: (request: Request) => Awaitable<(string | number)[] | null | undefined>\n /**\n * Load effective permissions for (user, app, resources) — **one call, many resources** (typically\n * `getEffectivePermissionsMany` from `@aiquants/authz-drizzle`). A key with no grants may be omitted or\n * mapped to `null`; both mean \"no permission\" (fail-close).\n */\n getEffectivePermissions: (args: EffectivePermissionsQuery) => Awaitable<Record<string, EffectivePermission | null | undefined> | null | undefined>\n /**\n * Optional: every resource key registered for this app (typically `listResourceKeys` from\n * `@aiquants/authz-drizzle`). Configuring it is what makes `getMyPermissions(request)` — with no resource\n * list — legal; without it that call throws {@link AuthzUsageError} instead of guessing.\n */\n listResourceKeys?: (request: Request) => Awaitable<readonly string[] | 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/**\n * Serializable per-resource permission summary for UI (loader → component).\n * UI 向けの直列化可能なリソース単位権限サマリ (loader からコンポーネントへ受け渡す形)。\n *\n * 真偽値は `can` 接頭辞で統一されている。`delete` のような素の動詞名は分割代入できず\n * (`const { delete } = view` は構文エラー)、フックの戻り値との二重語彙も生むため採用しない。\n */\nexport type PermissionView<K extends string = string> = {\n resourceKey: K\n canRead: boolean\n canCreate: boolean\n canUpdate: boolean\n canDelete: boolean\n /** create ∪ update */\n canWrite: boolean\n /** read granted but row and/or column restricted (→ △ partial). */\n readPartial: boolean\n actions: AuthzAction[]\n}\n\n/** Result of a successful {@link createAuthz} guard. ガード成功時の戻り値。 */\nexport type RequirePermissionResult<K extends string = string> = {\n userId: AuthzUserId | null\n /** Effective row/column scope for the guarded action — apply as WHERE / column mask. */\n scope: MergedScope\n /** UI view derived from the **same** evaluation as the guard decision (no second lookup). */\n permission: PermissionView<K>\n}\n\n/**\n * Permission views keyed by the exact resource keys that were requested.\n * 要求したキーで型付けした権限ビュー群。\n *\n * リテラルのキーを渡した場合だけ「そのキーは必ず存在する」形になる。`string[]` のようにキーが実行時に\n * しか分からない場合は `| undefined` を含む索引型へ落ち、存在チェックを強制する (総和型の索引を\n * 名乗ると、要求していないキーが型の上では必ず存在することになり、元の不具合と同じ罠に戻る)。\n *\n * ⚠️ キーは配列の **要素型** から導かれる。`flag ? [\"a\"] : [\"b\"]` のように要素型が合併になる式では、\n * 実行時に片方しか無くても型の上では両方が存在する扱いになる。リテラル配列を直接渡すか\n * `resourceKeysOf(registry)` を使うこと。\n * ⚠️ 戻り値を `Record<string, …>` 型の変数へ代入すると、その文脈から `K` が `string` へ広がり\n * 索引型 (値は `| undefined`) に落ちる。リテラルキーの保証が要る箇所では代入先を広げないこと。\n * ⚠️ 戻り値は素のオブジェクト。要求していない `toString` などのキーを読むと `Object.prototype` の\n * メンバが返る (索引型の `| undefined` とは一致しない)。要求したキーだけを読むこと。\n */\nexport type PermissionViewMap<K extends string> = string extends K ? Record<string, PermissionView | undefined> : { [P in K]: PermissionView<P> }\n\n/**\n * Map an EffectivePermission to a serializable {@link PermissionView}.\n * 実効権限を直列化可能な {@link PermissionView} へ変換する処理。\n *\n * @returns The UI-facing permission summary (all-false when `perm` is absent). UI 表示用の権限サマリ。\n */\nexport function toPermissionView<K extends string>(resourceKey: K, perm: EffectivePermission | null | undefined): PermissionView<K> {\n const canRead = can(perm, \"read\")\n const canCreate = can(perm, \"create\")\n const canUpdate = can(perm, \"update\")\n const canDelete = can(perm, \"delete\")\n const readScope = perm?.scopeByAction.read\n // read が許可されていても行/列のいずれかが絞られていれば「部分」扱い (△)。\n // スコープ自体が欠けている場合、ガードは DENY_ALL_SCOPE (0 行 0 列) に倒すため、表示も「制限あり」に\n // 揃える。ここで「制限なし」に倒すと、1 行も見えないのにバッジだけ全閲覧可を示す乖離になる。\n const readPartial = canRead && (!readScope || readScope.rowScope !== null || readScope.columnScope !== null)\n return {\n resourceKey,\n canRead,\n canCreate,\n canUpdate,\n canDelete,\n canWrite: canCreate || canUpdate,\n readPartial,\n actions: perm ? Array.from(perm.actions) : [],\n }\n}\n\n/**\n * Describe a runtime value for an error message without dumping the whole object.\n * エラーメッセージ用に値の型と概要を短く表現する処理。\n *\n * @returns A short human-readable description of the value. 値を要約した短い説明文字列。\n */\nfunction describe(value: unknown): string {\n if (value === null) return \"null\"\n if (typeof value === \"string\") return `a string (${JSON.stringify(value)})`\n if (Array.isArray(value)) return `an array`\n return `${typeof value} (${String(value)})`\n}\n\n/**\n * Validate a caller-supplied resource-key list, failing loudly on every shape that would otherwise\n * degrade silently — most importantly a bare string, which `for...of` would iterate character by character.\n * 呼び出し側が渡したリソースキー配列を検証する処理。無言で劣化する形 (特に素の文字列) を全て明示的に弾く。\n *\n * @returns The validated keys, de-duplicated and order-preserving. 重複を除いた検証済みのキー配列。\n */\nfunction assertResourceKeys(value: unknown, label: string): string[] {\n if (!Array.isArray(value)) {\n const hint = typeof value === \"string\" ? ` A bare string would be iterated character by character; pass \\`{ resourceKeys: [${JSON.stringify(value)}] }\\` instead.` : \"\"\n throw new AuthzUsageError(`${label} must be an array of resource keys, but received ${describe(value)}.${hint}`)\n }\n const seen = new Set<string>()\n const keys: string[] = []\n value.forEach((key, index) => {\n if (typeof key !== \"string\" || key.trim() === \"\") {\n throw new AuthzUsageError(`${label}[${index}] must be a non-empty resource key string, but received ${describe(key)}.`)\n }\n if (seen.has(key)) return\n seen.add(key)\n keys.push(key)\n })\n return keys\n}\n\n/**\n * Reject a port result that is a single {@link EffectivePermission} instead of a per-resource record.\n * 実効権限ポートが「1 件の実効権限」を返した場合を明示的に弾く処理。\n *\n * このポートは 1 回の呼び出しで **複数リソース分** を返す契約。旧契約 (1 リソース 1 件) のまま\n * 移行し忘れると、キー参照が全て `undefined` になり **全リソース拒否が沈黙して**成立してしまう。\n * 形で見分けられるうちに落とす。\n */\nfunction assertPermissionRecord(loaded: unknown): void {\n if (loaded === null || loaded === undefined) return\n const shape = loaded as { actions?: unknown; scopeByAction?: unknown }\n if (shape.actions instanceof Set && typeof shape.scopeByAction === \"object\") {\n throw new AuthzUsageError(\n \"createAuthz({ getEffectivePermissions }) must resolve to a record keyed by resource key (e.g. getEffectivePermissionsMany from @aiquants/authz-drizzle), but it resolved to a single EffectivePermission. Keeping the single-resource port would deny every resource silently.\",\n )\n }\n}\n\n/**\n * Validate the guard query so a typo surfaces as an explicit error instead of an unexplained 403.\n * ガードの問い合わせ内容を検証する処理。誤記が「理由の分からない 403」ではなく明示的な例外になる形。\n *\n * @returns The validated resource key and action. 検証済みのリソースキーとアクション。\n */\nfunction assertPermissionQuery<K extends string>(query: unknown): { resourceKey: K; action: AuthzAction } {\n if (typeof query !== \"object\" || query === null) {\n throw new AuthzUsageError(`requirePermission(request, query) requires a query object like { resourceKey: \"documents\", action: \"read\" }, but received ${describe(query)}.`)\n }\n const { resourceKey, action } = query as { resourceKey?: unknown; action?: unknown }\n if (typeof resourceKey !== \"string\" || resourceKey.trim() === \"\") {\n throw new AuthzUsageError(`query.resourceKey must be a non-empty string, but received ${describe(resourceKey)}.`)\n }\n if (typeof action !== \"string\" || !(AUTHZ_ACTIONS as readonly string[]).includes(action)) {\n const extra = action === \"write\" ? ` \"write\" is a derived concept (create ∪ update) and is never guarded directly — guard \"create\" or \"update\".` : \"\"\n throw new AuthzUsageError(`query.action must be one of ${AUTHZ_ACTIONS.join(\" | \")}, but received ${describe(action)}.${extra}`)\n }\n return { resourceKey: resourceKey as K, action: action as AuthzAction }\n}\n\n/**\n * React Router adapter. Binds `appKey` and the DI deps, exposing:\n * - `requirePermission(request, {resourceKey, action}, options?)` → `{ userId, scope, permission }` on allow\n * (apply row WHERE / column mask with `scope`; render `permission` in the UI); denies throw 403 or redirect.\n * - `getMyPermissions(request, {resourceKeys})` → `Record<resourceKey, PermissionView>` for the UI,\n * or `getMyPermissions(request)` for every registered resource when `listResourceKeys` is configured.\n * `appKey` と DI ポートを束ね、ガードと自己権限取得の 2 面だけを公開するファクトリ。\n *\n * @returns The bound `requirePermission` / `getMyPermissions` pair. 結線済みの認可 API 一式。\n */\nexport function createAuthz(config: AuthzConfig) {\n /**\n * Resolve the acting user's group ids once per call, normalizing \"no groups port\" to `undefined`.\n * 1 回の呼び出しにつき 1 度だけグループ ID を解決する処理 (ポート未設定は `undefined` へ正規化)。\n *\n * @returns The group ids, or `undefined` when no port is configured. グループ ID 配列、または未設定を表す `undefined`。\n */\n async function resolveGroupIds(request: Request): Promise<(string | number)[] | undefined> {\n return config.resolveGroupIds ? ((await config.resolveGroupIds(request)) ?? undefined) : undefined\n }\n\n /**\n * Load effective permissions for a set of resources through the single batch port.\n * 一括ポートを通じて複数リソースの実効権限をまとめて読み込む処理。\n *\n * @returns A permission (or `null`) for every requested key. 要求した全キー分の実効権限 (無い場合は `null`)。\n */\n async function loadPermissions(request: Request, resourceKeys: string[], userId: AuthzUserId | null): Promise<Record<string, EffectivePermission | null>> {\n if (resourceKeys.length === 0) return {}\n\n const groupIds = await resolveGroupIds(request)\n const loaded = await config.getEffectivePermissions({ userId, groupIds, appKey: config.appKey, resourceKeys })\n assertPermissionRecord(loaded)\n // ポートがキーを落としても undefined を漏らさず null (= 権限なし) に倒す。\n // 自前プロパティのみを見るのは、`constructor` 等の継承プロパティを実効権限と取り違えないため。\n // 組み立てに fromEntries を使うのは、`__proto__` というキーが素の代入では黙って落ちるため。\n return Object.fromEntries(resourceKeys.map((key) => [key, (loaded && Object.hasOwn(loaded, key) ? loaded[key] : null) ?? null]))\n }\n\n /**\n * Guard a loader/action: deny (403 or redirect) unless the acting user holds `action` on `resourceKey`.\n * loader / action 用のガード。指定アクションを保持しない限り拒否 (403 またはリダイレクト) する処理。\n *\n * @returns The user id, the effective scope, and the matching UI view. ユーザー ID・実効スコープ・UI 表示用ビュー。\n */\n async function requirePermission<K extends string>(request: Request, query: { resourceKey: K; action: AuthzAction }, options?: RequirePermissionOptions): Promise<RequirePermissionResult<K>> {\n const { resourceKey, action } = assertPermissionQuery<K>(query)\n\n const onDeny: ((info: DenyInfo) => void) | undefined = options?.failureRedirect\n ? () => {\n throw redirect(options.failureRedirect as string)\n }\n : config.onDeny\n\n const guard = createRequirePermission<Request, AuthzUserId>({\n resolveUserId: config.resolveUserId,\n getEffectivePermissions: async (args) => (await loadPermissions(request, [args.resourceKey], args.userId))[args.resourceKey],\n onDeny,\n })\n const result = await guard(request, { appKey: config.appKey, resourceKey, action })\n // ガードが判定に用いた実効権限をそのままビュー化する (再取得しないので乖離し得ない)\n return { userId: result.userId, scope: result.scope, permission: toPermissionView(resourceKey, result.effectivePermission) }\n }\n\n /**\n * Resolve the resource keys to report on when the caller did not name any.\n * 呼び出し側がリソースを指定しなかった場合に対象キーを解決する処理。\n *\n * @returns Every resource key registered for the app. アプリに登録済みの全リソースキー。\n */\n async function resolveAllResourceKeys(request: Request): Promise<string[]> {\n if (!config.listResourceKeys) {\n throw new AuthzUsageError(\n 'getMyPermissions(request) needs to know which resources exist. Either pass them explicitly — getMyPermissions(request, { resourceKeys: [\"documents\"] }) — or configure createAuthz({ listResourceKeys }) (e.g. listResourceKeys from @aiquants/authz-drizzle) to report on every registered resource.',\n )\n }\n return assertResourceKeys((await config.listResourceKeys(request)) ?? [], \"the listResourceKeys port result\")\n }\n\n function getMyPermissions<K extends string>(request: Request, options: { resourceKeys: readonly K[] }): Promise<PermissionViewMap<K>>\n // キーを指定しない形は実行時に決まるキーを返すため、値は `| undefined` を含む\n // (`Record<string, PermissionView>` にすると、要求していないキーが型の上では必ず存在することになる)。\n function getMyPermissions(request: Request, options?: { resourceKeys?: readonly string[] }): Promise<Record<string, PermissionView | undefined>>\n /**\n * Report the acting user's permissions for the UI — for the named resources, or for every registered\n * resource when `resourceKeys` is omitted (requires the `listResourceKeys` port).\n * UI 表示用に操作ユーザーの権限を返す処理。キー省略時は登録済みの全リソースが対象 (要 `listResourceKeys`)。\n *\n * @returns A view per requested resource key; requested keys are never missing. リソースキーごとの権限ビュー。\n */\n async function getMyPermissions(request: Request, options?: { resourceKeys?: readonly string[] }): Promise<Record<string, PermissionView>> {\n const resourceKeys = options?.resourceKeys === undefined ? await resolveAllResourceKeys(request) : assertResourceKeys(options.resourceKeys, \"getMyPermissions options.resourceKeys\")\n\n const userId = (await config.resolveUserId(request)) ?? null\n const permissions = await loadPermissions(request, resourceKeys, userId)\n\n // `__proto__` を含むどんなキーでも必ず自前プロパティとして現れるようにする (素の代入では落ちる)\n return Object.fromEntries(resourceKeys.map((key) => [key, toPermissionView(key, permissions[key])]))\n }\n\n return { requirePermission, getMyPermissions }\n}\n"],"mappings":"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","names":["index_exports","__export","AuthzAdminAppView","AuthzErrorBoundary","AuthzGrantsView","AuthzGraphView","AuthzGroupRolesView","AuthzLayout","AuthzResourcesView","AuthzRolesView","AuthzUsageError","AuthzUserRolesView","ErrorAlert","Field","MyPermissionGroupStatus","MyPermissionIndicator","MyPermissionStatus","createAuthz","createAuthzAdminApp","createAuthzAdminServer","defaultAuthzAdminLabels","defineResources","flattenGroupItems","formatResourceTooltip","getPermissionSummary","makeAuthzErrorBoundary","resolveLabels","resourceKeysOf","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","permission","layoutGuard","rolesData","roles","self","resourcesData","grantsData","grants","resources","userRolesData","assignments","users","groupRolesData","groupRoles","groups","graphData","myPermissions","form","intent","roleKey","name","appKey","resourceKey","roleId","resourceId","rawAction","action","actor","groupId","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","p","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","allItems","writeCount","i","readCount","totalCount","summaryLabel","level","isChild","MyPermissionIndicator","import_jsx_runtime","actionError","d","AuthzLayoutShell","children","renderHeader","myPermissions","labels","adminResourceKey","basePath","base","variant","setVariant","tabs","permissionItems","key","perm","items","annotation","MyPermissionGroupStatus","ui","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","AuthzGroupRolesView","groupRoles","groups","actionData","err","activeRoles","groupOptions","selectedGroup","setSelectedGroup","ACTION_COLORS","AuthzTopologyMap","selectedNode","onNodeClick","hoveredNode","setHoveredNode","connectedUserIds","connectedGroupIds","connectedRoleIds","connectedResourceIds","activeUsers","activeGroups","activeResources","res","getResourceActions","resId","resGrants","uniqueActions","getResourceCardHeight","resourceCardGap","cumulativeResY","resourceYMap","actions","height","top","actionYMap","act","actIdx","actY","totalResourceHeight","stdCardHeight","stdCardGap","stdItemHeight","totalRoleHeight","totalGroupHeight","totalUserHeight","svgHeight","resourceStartTop","roleStartTop","groupStartTop","userStartTop","getResourceActionCenterY","info","relativeActY","getRoleCenterY","roleIndex","getGroupCenterY","groupIndex","getUserCenterY","userIndex","resourceX","roleX","groupX","userX","activeNode","isUserActive","uId","roleIds","isGroupActive","gId","gr","isRoleActive","rId","isResourceActive","groupRoleIds","userRoleIds","isUserRoleLinkActive","isGroupRoleLinkActive","isRoleResourceLinkActive","userRoleLinks","uIdx","rIdx","roleAssignments","item","assignIdx","totalAssigns","offset","groupRoleLinks","gIdx","gRoleAssigns","roleResourceLinks","resIdx","sameResourceActionGrants","actionRoleIdx","totalSameGrants","colorConf","color","link","grantItem","y1","y2","cX1","cX2","isSelected","cardInfo","cardTop","i","y","AuthzGraphView","setSelectedNode","searchQuery","setSearchQuery","viewMode","setViewMode","roleMap","resourceMap","groupMap","userMap","isUserRelated","userId","roleIdsForResource","isGroupRelated","groupId","isRoleRelated","roleId","isResourceRelated","resourceId","query","filteredUsers","filteredGroups","filteredRoles","filteredResources","selectedUserObj","selectedGroupObj","selectedRoleObj","selectedResourceObj","handleNodeClick","type","id","resourceGrants","role","actStyle","roleGrants","roleGroupAssignments","assignedRoles","userAssignments","SEGMENT_VIEWS","AuthzAdminAppView","segment","View","defineResources","resources","result","k","item","resourceKeysOf","registry","r","import_authz_core","import_react_router","PKG","AuthzUsageError","message","toPermissionView","resourceKey","perm","canRead","canCreate","canUpdate","canDelete","readScope","readPartial","describe","value","assertResourceKeys","label","hint","seen","keys","key","index","assertPermissionRecord","loaded","shape","assertPermissionQuery","query","action","extra","createAuthz","config","resolveGroupIds","request","loadPermissions","resourceKeys","userId","groupIds","requirePermission","options","onDeny","result","args","resolveAllResourceKeys","getMyPermissions","permissions"]}