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