@aiquants/auth-react-router 0.6.0 → 0.7.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 +22 -0
- package/dist/admin.d.mts +46 -7
- package/dist/admin.d.ts +46 -7
- package/dist/admin.js +1 -1
- package/dist/admin.js.map +1 -1
- package/dist/admin.mjs +1 -1
- package/dist/admin.mjs.map +1 -1
- package/package.json +3 -1
- package/src/admin/server.ts +47 -6
- package/src/admin/ui.tsx +32 -17
- package/src/admin/server.spec.ts +0 -300
- package/src/admin/views.spec.tsx +0 -307
- package/src/server/authenticate-in-loader.spec.ts +0 -152
- package/src/server/authenticate.spec.ts +0 -146
- package/src/server/google-strategy-impl.spec.ts +0 -116
- package/src/server/google-strategy.spec.ts +0 -271
- package/src/server/handlers.spec.ts +0 -154
- package/src/server/session.spec.ts +0 -165
package/README.md
CHANGED
|
@@ -10,6 +10,28 @@ pnpm add @aiquants/auth-core @aiquants/auth-react-router
|
|
|
10
10
|
|
|
11
11
|
Peers: `react`, `react-router@^7`, `remix-auth@^4`, `remix-auth-oauth2@^3`, `react-icons`.
|
|
12
12
|
|
|
13
|
+
## User admin shell: the self-permission badge
|
|
14
|
+
|
|
15
|
+
The admin shell (`createUserAdminApp`) renders a "your permissions" badge in its header. Two optional ports feed it,
|
|
16
|
+
and both are **fail-closed by design**:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
createUserAdminApp({
|
|
20
|
+
store, guards,
|
|
21
|
+
// resolves to a map of { canRead, canWrite, canDelete } per resource key.
|
|
22
|
+
// Any authz view carrying those three booleans satisfies it structurally — no import from an authz package.
|
|
23
|
+
getMyPermissions: (request) => myAuthz.getMyPermissions(request, { resourceKeys: ["authz_admin"] }),
|
|
24
|
+
// display names for those keys; unlisted keys render as the raw key
|
|
25
|
+
resourceLabels: { authz_admin: "ユーザー管理 UI" },
|
|
26
|
+
})
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- Query **the resource your guards actually check**. Asking about a different key makes the badge disagree with the
|
|
30
|
+
guard — the user is admitted but told they have no permission.
|
|
31
|
+
- If the port is absent, rejects, or returns no entries, the badge renders an explicit "unknown" state
|
|
32
|
+
(`data-testid="user-admin-permission-unavailable"`) and the failure is logged. It never renders a permissive value:
|
|
33
|
+
a badge that claims "editable" when the answer is unknown is worse than no badge at all.
|
|
34
|
+
|
|
13
35
|
## Wiring (single composition point — `app/services/auth/config.server.ts`)
|
|
14
36
|
|
|
15
37
|
```ts
|
package/dist/admin.d.mts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { AuthUser, AuthGroup, AuthGroupMember, AuthAllowlistEntry } from '@aiquants/auth-core';
|
|
2
|
-
import { LoaderFunctionArgs, ActionFunctionArgs } from 'react-router';
|
|
3
2
|
import React__default from 'react';
|
|
4
3
|
|
|
5
4
|
/**
|
|
@@ -166,6 +165,15 @@ declare function createInMemoryUserAdminStore(initial?: {
|
|
|
166
165
|
* independent of any particular authorization library.
|
|
167
166
|
* 操作が行う CRUD 種別。特定の認可ライブラリに依存しないよう素の文字列 union で表現する。
|
|
168
167
|
*/
|
|
168
|
+
/**
|
|
169
|
+
* The only route-args field this module reads. React Router's full `LoaderFunctionArgs` satisfies it, so
|
|
170
|
+
* route wiring is unchanged — but declaring the minimum keeps callers (and tests) from fabricating fields
|
|
171
|
+
* that are never looked at.
|
|
172
|
+
* このモジュールが実際に読むルート引数の全て。React Router の完全な引数はこれを満たすため結線は不変。
|
|
173
|
+
*/
|
|
174
|
+
type RouteArgs = {
|
|
175
|
+
request: Request;
|
|
176
|
+
};
|
|
169
177
|
type UserAdminAccess = "read" | "create" | "update" | "delete";
|
|
170
178
|
/**
|
|
171
179
|
* Access guard the user-admin surface is mounted behind. Deny by throwing
|
|
@@ -187,6 +195,19 @@ type UserAdminGuards = {
|
|
|
187
195
|
intent: string;
|
|
188
196
|
}) => Promise<void> | void;
|
|
189
197
|
};
|
|
198
|
+
/**
|
|
199
|
+
* Neutral per-resource permission summary the admin shell renders in its header badge.
|
|
200
|
+
* 管理シェルのヘッダーバッジが描画する、リソース単位の中立な権限サマリ。
|
|
201
|
+
*
|
|
202
|
+
* この形はこのパッケージ自身の契約であり、特定の認可ライブラリの型を import しない
|
|
203
|
+
* (`AGENTS.md` のクロスパッケージ・ハードコード禁止)。`canRead` / `canWrite` / `canDelete` を持つ
|
|
204
|
+
* ビューであれば構造的にそのまま渡せる。
|
|
205
|
+
*/
|
|
206
|
+
type UserAdminPermission = {
|
|
207
|
+
canRead: boolean;
|
|
208
|
+
canWrite: boolean;
|
|
209
|
+
canDelete: boolean;
|
|
210
|
+
};
|
|
190
211
|
type UserAdminAppConfig = {
|
|
191
212
|
store: UserAdminStore;
|
|
192
213
|
/** セクション単位の部分上書き。既定は英語 (`defaultUserAdminLabels`)。 */
|
|
@@ -196,8 +217,21 @@ type UserAdminAppConfig = {
|
|
|
196
217
|
* 必須。省略を許すとユーザー名簿と全更新操作が無防備に露出するため、型で強制する。
|
|
197
218
|
*/
|
|
198
219
|
guards: UserAdminGuards;
|
|
199
|
-
/**
|
|
200
|
-
|
|
220
|
+
/**
|
|
221
|
+
* Per-request self-permission lookup for the header annotation. Resolving to a map of
|
|
222
|
+
* {@link UserAdminPermission} shows the badge; rejecting shows an explicit "unknown" badge — never a
|
|
223
|
+
* permissive one. Any authz library whose view carries `canRead` / `canWrite` / `canDelete` satisfies it.
|
|
224
|
+
* ヘッダー注釈に自分の実効権限を表示するためのリクエスト別権限取得関数。失敗時は「権限不明」表示。
|
|
225
|
+
*/
|
|
226
|
+
getMyPermissions?: (request: Request) => Promise<Record<string, UserAdminPermission | undefined>>;
|
|
227
|
+
/**
|
|
228
|
+
* Display names for the resource keys the badge shows, e.g. `{ authz_admin: "ユーザー管理 UI" }`.
|
|
229
|
+
* バッジに出すリソースキーの表示名。未指定のキーはキー文字列をそのまま表示。
|
|
230
|
+
*
|
|
231
|
+
* 表示名をこのパッケージ側に埋め込むと、別パッケージのリソースキーを名指しすることになる
|
|
232
|
+
* (`AGENTS.md` のクロスパッケージ・ハードコード禁止)。中立な差し込み口として受け取る。
|
|
233
|
+
*/
|
|
234
|
+
resourceLabels?: Record<string, string>;
|
|
201
235
|
};
|
|
202
236
|
/**
|
|
203
237
|
* Creates React Router loader & action handler for user administration.
|
|
@@ -206,16 +240,17 @@ type UserAdminAppConfig = {
|
|
|
206
240
|
* `config.guards` は必須。loader / action の双方が、処理を始める前にガードを通過させる。
|
|
207
241
|
*/
|
|
208
242
|
declare function createUserAdminApp(config: UserAdminAppConfig): {
|
|
209
|
-
loader: ({ request }:
|
|
243
|
+
loader: ({ request }: RouteArgs) => Promise<{
|
|
244
|
+
resourceLabels: Record<string, string> | undefined;
|
|
210
245
|
segment: string;
|
|
211
246
|
users: AuthUser[];
|
|
212
247
|
groups: AuthGroup[];
|
|
213
248
|
groupMembers: AuthGroupMember[];
|
|
214
249
|
allowlist: AuthAllowlistEntry[];
|
|
215
|
-
myPermissions: Record<string,
|
|
250
|
+
myPermissions: Record<string, UserAdminPermission | undefined> | null;
|
|
216
251
|
labels: UserAdminLabels;
|
|
217
252
|
}>;
|
|
218
|
-
action: ({ request }:
|
|
253
|
+
action: ({ request }: RouteArgs) => Promise<{
|
|
219
254
|
ok: boolean;
|
|
220
255
|
error?: undefined;
|
|
221
256
|
} | {
|
|
@@ -231,6 +266,10 @@ type UserAdminShellProps = {
|
|
|
231
266
|
annotation: React__default.ReactNode;
|
|
232
267
|
}) => React__default.ReactNode;
|
|
233
268
|
};
|
|
269
|
+
/**
|
|
270
|
+
* Shell layout for user administration pages with header annotation delegation.
|
|
271
|
+
* ヘッダー注釈委譲を備えたユーザー管理ページのシェルレイアウト。
|
|
272
|
+
*/
|
|
234
273
|
declare function UserAdminShell({ children, renderHeader }: UserAdminShellProps): React__default.JSX.Element;
|
|
235
274
|
|
|
236
275
|
type UserAdminLoaderData = {
|
|
@@ -264,4 +303,4 @@ type AuthUserAdminAppViewProps = UserAdminShellProps;
|
|
|
264
303
|
*/
|
|
265
304
|
declare function AuthUserAdminAppView({ renderHeader }?: AuthUserAdminAppViewProps): React__default.JSX.Element;
|
|
266
305
|
|
|
267
|
-
export { AllowlistView, AuthUserAdminAppView, type AuthUserAdminAppViewProps, GroupMembersView, GroupsView, type PartialUserAdminLabels, type UserAdminAccess, type UserAdminAppConfig, type UserAdminGuards, type UserAdminLabels, type UserAdminLoaderData, UserAdminShell, type UserAdminShellProps, type UserAdminStore, UsersView, createInMemoryUserAdminStore, createUserAdminApp, defaultUserAdminLabels, jaUserAdminLabels, resolveUserAdminLabels };
|
|
306
|
+
export { AllowlistView, AuthUserAdminAppView, type AuthUserAdminAppViewProps, GroupMembersView, GroupsView, type PartialUserAdminLabels, type UserAdminAccess, type UserAdminAppConfig, type UserAdminGuards, type UserAdminLabels, type UserAdminLoaderData, type UserAdminPermission, UserAdminShell, type UserAdminShellProps, type UserAdminStore, UsersView, createInMemoryUserAdminStore, createUserAdminApp, defaultUserAdminLabels, jaUserAdminLabels, resolveUserAdminLabels };
|
package/dist/admin.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { AuthUser, AuthGroup, AuthGroupMember, AuthAllowlistEntry } from '@aiquants/auth-core';
|
|
2
|
-
import { LoaderFunctionArgs, ActionFunctionArgs } from 'react-router';
|
|
3
2
|
import React__default from 'react';
|
|
4
3
|
|
|
5
4
|
/**
|
|
@@ -166,6 +165,15 @@ declare function createInMemoryUserAdminStore(initial?: {
|
|
|
166
165
|
* independent of any particular authorization library.
|
|
167
166
|
* 操作が行う CRUD 種別。特定の認可ライブラリに依存しないよう素の文字列 union で表現する。
|
|
168
167
|
*/
|
|
168
|
+
/**
|
|
169
|
+
* The only route-args field this module reads. React Router's full `LoaderFunctionArgs` satisfies it, so
|
|
170
|
+
* route wiring is unchanged — but declaring the minimum keeps callers (and tests) from fabricating fields
|
|
171
|
+
* that are never looked at.
|
|
172
|
+
* このモジュールが実際に読むルート引数の全て。React Router の完全な引数はこれを満たすため結線は不変。
|
|
173
|
+
*/
|
|
174
|
+
type RouteArgs = {
|
|
175
|
+
request: Request;
|
|
176
|
+
};
|
|
169
177
|
type UserAdminAccess = "read" | "create" | "update" | "delete";
|
|
170
178
|
/**
|
|
171
179
|
* Access guard the user-admin surface is mounted behind. Deny by throwing
|
|
@@ -187,6 +195,19 @@ type UserAdminGuards = {
|
|
|
187
195
|
intent: string;
|
|
188
196
|
}) => Promise<void> | void;
|
|
189
197
|
};
|
|
198
|
+
/**
|
|
199
|
+
* Neutral per-resource permission summary the admin shell renders in its header badge.
|
|
200
|
+
* 管理シェルのヘッダーバッジが描画する、リソース単位の中立な権限サマリ。
|
|
201
|
+
*
|
|
202
|
+
* この形はこのパッケージ自身の契約であり、特定の認可ライブラリの型を import しない
|
|
203
|
+
* (`AGENTS.md` のクロスパッケージ・ハードコード禁止)。`canRead` / `canWrite` / `canDelete` を持つ
|
|
204
|
+
* ビューであれば構造的にそのまま渡せる。
|
|
205
|
+
*/
|
|
206
|
+
type UserAdminPermission = {
|
|
207
|
+
canRead: boolean;
|
|
208
|
+
canWrite: boolean;
|
|
209
|
+
canDelete: boolean;
|
|
210
|
+
};
|
|
190
211
|
type UserAdminAppConfig = {
|
|
191
212
|
store: UserAdminStore;
|
|
192
213
|
/** セクション単位の部分上書き。既定は英語 (`defaultUserAdminLabels`)。 */
|
|
@@ -196,8 +217,21 @@ type UserAdminAppConfig = {
|
|
|
196
217
|
* 必須。省略を許すとユーザー名簿と全更新操作が無防備に露出するため、型で強制する。
|
|
197
218
|
*/
|
|
198
219
|
guards: UserAdminGuards;
|
|
199
|
-
/**
|
|
200
|
-
|
|
220
|
+
/**
|
|
221
|
+
* Per-request self-permission lookup for the header annotation. Resolving to a map of
|
|
222
|
+
* {@link UserAdminPermission} shows the badge; rejecting shows an explicit "unknown" badge — never a
|
|
223
|
+
* permissive one. Any authz library whose view carries `canRead` / `canWrite` / `canDelete` satisfies it.
|
|
224
|
+
* ヘッダー注釈に自分の実効権限を表示するためのリクエスト別権限取得関数。失敗時は「権限不明」表示。
|
|
225
|
+
*/
|
|
226
|
+
getMyPermissions?: (request: Request) => Promise<Record<string, UserAdminPermission | undefined>>;
|
|
227
|
+
/**
|
|
228
|
+
* Display names for the resource keys the badge shows, e.g. `{ authz_admin: "ユーザー管理 UI" }`.
|
|
229
|
+
* バッジに出すリソースキーの表示名。未指定のキーはキー文字列をそのまま表示。
|
|
230
|
+
*
|
|
231
|
+
* 表示名をこのパッケージ側に埋め込むと、別パッケージのリソースキーを名指しすることになる
|
|
232
|
+
* (`AGENTS.md` のクロスパッケージ・ハードコード禁止)。中立な差し込み口として受け取る。
|
|
233
|
+
*/
|
|
234
|
+
resourceLabels?: Record<string, string>;
|
|
201
235
|
};
|
|
202
236
|
/**
|
|
203
237
|
* Creates React Router loader & action handler for user administration.
|
|
@@ -206,16 +240,17 @@ type UserAdminAppConfig = {
|
|
|
206
240
|
* `config.guards` は必須。loader / action の双方が、処理を始める前にガードを通過させる。
|
|
207
241
|
*/
|
|
208
242
|
declare function createUserAdminApp(config: UserAdminAppConfig): {
|
|
209
|
-
loader: ({ request }:
|
|
243
|
+
loader: ({ request }: RouteArgs) => Promise<{
|
|
244
|
+
resourceLabels: Record<string, string> | undefined;
|
|
210
245
|
segment: string;
|
|
211
246
|
users: AuthUser[];
|
|
212
247
|
groups: AuthGroup[];
|
|
213
248
|
groupMembers: AuthGroupMember[];
|
|
214
249
|
allowlist: AuthAllowlistEntry[];
|
|
215
|
-
myPermissions: Record<string,
|
|
250
|
+
myPermissions: Record<string, UserAdminPermission | undefined> | null;
|
|
216
251
|
labels: UserAdminLabels;
|
|
217
252
|
}>;
|
|
218
|
-
action: ({ request }:
|
|
253
|
+
action: ({ request }: RouteArgs) => Promise<{
|
|
219
254
|
ok: boolean;
|
|
220
255
|
error?: undefined;
|
|
221
256
|
} | {
|
|
@@ -231,6 +266,10 @@ type UserAdminShellProps = {
|
|
|
231
266
|
annotation: React__default.ReactNode;
|
|
232
267
|
}) => React__default.ReactNode;
|
|
233
268
|
};
|
|
269
|
+
/**
|
|
270
|
+
* Shell layout for user administration pages with header annotation delegation.
|
|
271
|
+
* ヘッダー注釈委譲を備えたユーザー管理ページのシェルレイアウト。
|
|
272
|
+
*/
|
|
234
273
|
declare function UserAdminShell({ children, renderHeader }: UserAdminShellProps): React__default.JSX.Element;
|
|
235
274
|
|
|
236
275
|
type UserAdminLoaderData = {
|
|
@@ -264,4 +303,4 @@ type AuthUserAdminAppViewProps = UserAdminShellProps;
|
|
|
264
303
|
*/
|
|
265
304
|
declare function AuthUserAdminAppView({ renderHeader }?: AuthUserAdminAppViewProps): React__default.JSX.Element;
|
|
266
305
|
|
|
267
|
-
export { AllowlistView, AuthUserAdminAppView, type AuthUserAdminAppViewProps, GroupMembersView, GroupsView, type PartialUserAdminLabels, type UserAdminAccess, type UserAdminAppConfig, type UserAdminGuards, type UserAdminLabels, type UserAdminLoaderData, UserAdminShell, type UserAdminShellProps, type UserAdminStore, UsersView, createInMemoryUserAdminStore, createUserAdminApp, defaultUserAdminLabels, jaUserAdminLabels, resolveUserAdminLabels };
|
|
306
|
+
export { AllowlistView, AuthUserAdminAppView, type AuthUserAdminAppViewProps, GroupMembersView, GroupsView, type PartialUserAdminLabels, type UserAdminAccess, type UserAdminAppConfig, type UserAdminGuards, type UserAdminLabels, type UserAdminLoaderData, type UserAdminPermission, UserAdminShell, type UserAdminShellProps, type UserAdminStore, UsersView, createInMemoryUserAdminStore, createUserAdminApp, defaultUserAdminLabels, jaUserAdminLabels, resolveUserAdminLabels };
|
package/dist/admin.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var G=Object.defineProperty;var T=Object.getOwnPropertyDescriptor;var F=Object.getOwnPropertyNames;var W=Object.prototype.hasOwnProperty;var $=(r,i)=>{for(var t in i)G(r,t,{get:i[t],enumerable:!0})},K=(r,i,t,l)=>{if(i&&typeof i=="object"||typeof i=="function")for(let c of F(i))!W.call(r,c)&&c!==t&&G(r,c,{get:()=>i[c],enumerable:!(l=T(i,c))||l.enumerable});return r};var q=r=>K(G({},"__esModule",{value:!0}),r);var Y={};$(Y,{AllowlistView:()=>N,AuthUserAdminAppView:()=>X,GroupMembersView:()=>E,GroupsView:()=>P,UserAdminShell:()=>z,UsersView:()=>M,createInMemoryUserAdminStore:()=>O,createUserAdminApp:()=>H,defaultUserAdminLabels:()=>w,jaUserAdminLabels:()=>j,resolveUserAdminLabels:()=>R});module.exports=q(Y);var w={title:"Users & Groups",heading:"\u{1F464} User administration",tabs:{users:"\u{1F464} Users",groups:"\u{1F465} Groups",groupMembers:"\u{1F517} Members",allowlist:"\u2709\uFE0F Allowlist"},usersView:{title:"Users",searchPlaceholder:"Search by name or email...",addUser:"\uFF0B Add user",editUser:"Edit user",id:"ID",displayName:"Name",email:"Email",status:"Status",active:"Active",inactive:"Inactive",actions:"Actions",edit:"Edit",activate:"Activate",deactivate:"Deactivate",empty:"No matching users",save:"Save",cancel:"Cancel"},groupsView:{title:"Groups",searchPlaceholder:"Search by group name or key...",addGroup:"\uFF0B Add group",editGroup:"Edit group",id:"ID",groupKey:"Group key",name:"Name",description:"Description",memberCount:"Members",status:"Status",actions:"Actions",edit:"Edit",delete:"Delete",confirmDelete:"Delete this group?",noDescription:"No description",groupKeyPlaceholder:"e.g. dev-team",namePlaceholder:"e.g. Development team",empty:"No groups registered",save:"Save",cancel:"Cancel"},groupMembersView:{selectGroup:"Select a group",selectPrompt:"Select a group to manage its members",actionAdd:"Add",actionRemove:"Remove"},allowlistView:{title:"Sign-in allowlist",addEntry:"\uFF0B Add pattern",pattern:"Pattern (e.g. @example.com or user@example.com)",type:"Type",emailType:"Exact email match",domainType:"Domain match",emailTypeShort:"Email",domainTypeShort:"Domain",description:"Description",actions:"Actions",readOnly:"Read-only",delete:"Delete",empty:"No allowlist entries registered",save:"Add",cancel:"Cancel"}},j={title:"\u30E6\u30FC\u30B6\u30FC\u30FB\u30B0\u30EB\u30FC\u30D7\u7BA1\u7406",heading:"\u{1F464} \u30E6\u30FC\u30B6\u30FC\u7BA1\u7406",tabs:{users:"\u{1F464} \u30E6\u30FC\u30B6\u30FC\u4E00\u89A7",groups:"\u{1F465} \u30E6\u30FC\u30B6\u30FC\u30B0\u30EB\u30FC\u30D7",groupMembers:"\u{1F517} \u30B0\u30EB\u30FC\u30D7\u30E1\u30F3\u30D0\u30FC",allowlist:"\u2709\uFE0F \u30A2\u30AF\u30BB\u30B9\u8A31\u53EF\u30EA\u30B9\u30C8"},usersView:{title:"\u30E6\u30FC\u30B6\u30FC\u7BA1\u7406",searchPlaceholder:"\u8868\u793A\u540D\u3084 Email \u3067\u691C\u7D22...",addUser:"\uFF0B \u30E6\u30FC\u30B6\u30FC\u8FFD\u52A0",editUser:"\u30E6\u30FC\u30B6\u30FC\u306E\u7DE8\u96C6",id:"ID",displayName:"\u8868\u793A\u540D",email:"\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9",status:"\u30B9\u30C6\u30FC\u30BF\u30B9",active:"\u6709\u52B9",inactive:"\u7121\u52B9",actions:"\u64CD\u4F5C",edit:"\u7DE8\u96C6",activate:"\u6709\u52B9\u5316",deactivate:"\u7121\u52B9\u5316",empty:"\u8A72\u5F53\u3059\u308B\u30E6\u30FC\u30B6\u30FC\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093",save:"\u4FDD\u5B58",cancel:"\u30AD\u30E3\u30F3\u30BB\u30EB"},groupsView:{title:"\u30E6\u30FC\u30B6\u30FC\u30B0\u30EB\u30FC\u30D7\u7BA1\u7406",searchPlaceholder:"\u30B0\u30EB\u30FC\u30D7\u540D\u3084\u30AD\u30FC\u3067\u691C\u7D22...",addGroup:"\uFF0B \u30B0\u30EB\u30FC\u30D7\u4F5C\u6210",editGroup:"\u30B0\u30EB\u30FC\u30D7\u306E\u7DE8\u96C6",id:"ID",groupKey:"\u30B0\u30EB\u30FC\u30D7\u30AD\u30FC",name:"\u30B0\u30EB\u30FC\u30D7\u540D",description:"\u8AAC\u660E",memberCount:"\u30E1\u30F3\u30D0\u30FC\u6570",status:"\u30B9\u30C6\u30FC\u30BF\u30B9",actions:"\u64CD\u4F5C",edit:"\u7DE8\u96C6",delete:"\u524A\u9664",confirmDelete:"\u3053\u306E\u30B0\u30EB\u30FC\u30D7\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B\uFF1F",noDescription:"\u8AAC\u660E\u306A\u3057",groupKeyPlaceholder:"\u4F8B: dev-team",namePlaceholder:"\u4F8B: \u958B\u767A\u30C1\u30FC\u30E0",empty:"\u30B0\u30EB\u30FC\u30D7\u304C\u767B\u9332\u3055\u308C\u3066\u3044\u307E\u305B\u3093",save:"\u4FDD\u5B58",cancel:"\u30AD\u30E3\u30F3\u30BB\u30EB"},groupMembersView:{selectGroup:"\u30B0\u30EB\u30FC\u30D7\u9078\u629E",selectPrompt:"\u30B0\u30EB\u30FC\u30D7\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044",actionAdd:"\u8FFD\u52A0",actionRemove:"\u9664\u5916"},allowlistView:{title:"\u30A2\u30AF\u30BB\u30B9\u8A31\u53EF\u30EA\u30B9\u30C8 (Allowlist)",addEntry:"\uFF0B \u8A31\u53EF\u30D1\u30BF\u30FC\u30F3\u8FFD\u52A0",pattern:"\u30D1\u30BF\u30FC\u30F3 (\u4F8B: @example.com \u307E\u305F\u306F user@example.com)",type:"\u7A2E\u5225",emailType:"\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u5B8C\u5168\u4E00\u81F4",domainType:"\u30C9\u30E1\u30A4\u30F3\u4E00\u81F4",emailTypeShort:"Email \u5B8C\u5168\u4E00\u81F4",domainTypeShort:"\u30C9\u30E1\u30A4\u30F3\u4E00\u81F4",description:"\u8AAC\u660E / \u5099\u8003",actions:"\u64CD\u4F5C",readOnly:"\u5909\u66F4\u4E0D\u53EF",delete:"\u524A\u9664",empty:"\u30A2\u30ED\u30EF\u30EA\u30B9\u30C8\u30A8\u30F3\u30C8\u30EA\u304C\u767B\u9332\u3055\u308C\u3066\u3044\u307E\u305B\u3093",save:"\u767B\u9332",cancel:"\u30AD\u30E3\u30F3\u30BB\u30EB"}};function R(r){let i=w;return r?{title:r.title??i.title,heading:r.heading??i.heading,tabs:{...i.tabs,...r.tabs},usersView:{...i.usersView,...r.usersView},groupsView:{...i.groupsView,...r.groupsView},groupMembersView:{...i.groupMembersView,...r.groupMembersView},allowlistView:{...i.allowlistView,...r.allowlistView}}:i}function O(r){let i=r?.users??[{id:1,email:"admin@example.com",displayName:"\u30B7\u30B9\u30C6\u30E0\u7BA1\u7406\u8005",isActive:!0},{id:2,email:"user1@example.com",displayName:"\u958B\u767A \u592A\u90CE",isActive:!0},{id:3,email:"user2@example.com",displayName:"\u55B6\u696D \u82B1\u5B50",isActive:!0}],t=r?.groups??[{id:1,groupKey:"dev-team",name:"\u958B\u767A\u30C1\u30FC\u30E0",description:"\u30B7\u30B9\u30C6\u30E0\u958B\u767A\u62C5\u5F53\u30B0\u30EB\u30FC\u30D7",isActive:!0},{id:2,groupKey:"sales-dept",name:"\u55B6\u696D\u90E8",description:"\u55B6\u696D\u30BD\u30EA\u30E5\u30FC\u30B7\u30E7\u30F3\u62C5\u5F53",isActive:!0}],l=r?.groupMembers??[{id:1,groupId:1,userId:2},{id:2,groupId:2,userId:3}],c=r?.allowlist??[{id:1,pattern:"admin@example.com",type:"email",description:"\u521D\u671F\u7BA1\u7406\u8005"},{id:2,pattern:"@example.com",type:"domain",description:"\u793E\u5185\u30C9\u30E1\u30A4\u30F3"}];return{async listUsers(){return[...i]},async createUser(s){let o={id:Math.max(...i.map(n=>n.id),0)+1,email:s.email,displayName:s.displayName,isActive:!0};return i.push(o),o},async updateUser(s,o){let n=i.findIndex(a=>a.id===s);if(n===-1)throw new Error(`User not found: ${s}`);return i[n]={...i[n],displayName:o.displayName,email:o.email},i[n]},async toggleUserActive(s,o){let n=i.findIndex(a=>a.id===s);if(n===-1)throw new Error(`User not found: ${s}`);return i[n]={...i[n],isActive:o},i[n]},async listGroups(){return[...t]},async createGroup(s){let o={id:Math.max(...t.map(n=>n.id),0)+1,groupKey:s.groupKey,name:s.name,description:s.description,isActive:!0};return t.push(o),o},async updateGroup(s,o){let n=t.findIndex(a=>a.id===s);if(n===-1)throw new Error(`Group not found: ${s}`);return t[n]={...t[n],name:o.name,description:o.description},t[n]},async deleteGroup(s){t=t.filter(o=>o.id!==s),l=l.filter(o=>o.groupId!==s)},async listGroupMembers(){return[...l]},async addGroupMember(s,o){let n=l.find(p=>p.groupId===s&&p.userId===o);if(n)return n;let a={id:Math.max(...l.map(p=>p.id),0)+1,groupId:s,userId:o};return l.push(a),a},async removeGroupMember(s,o){l=l.filter(n=>!(n.groupId===s&&n.userId===o))},async listAllowlist(){return[...c]},async addAllowlistEntry(s){let o={id:Math.max(...c.map(n=>n.id),0)+1,pattern:s.pattern,type:s.type,description:s.description};return c.push(o),o},async removeAllowlistEntry(s){c=c.filter(o=>o.id!==s)}}}var _=new Map([["createUser","create"],["updateUser","update"],["toggleUserActive","update"],["createGroup","create"],["updateGroup","update"],["deleteGroup","delete"],["addGroupMember","create"],["removeGroupMember","delete"],["addAllowlistEntry","create"],["removeAllowlistEntry","delete"]]);function v(r,i){let t=r.get(i),l=Number(t);if(t===null||String(t).trim()===""||!Number.isInteger(l)||l<=0)throw new Error(`Invalid or missing "${i}"`);return l}function A(r,i){let t=String(r.get(i)??"").trim();if(t==="")throw new Error(`Invalid or missing "${i}"`);return t}function I(r,i){let t=String(r.get(i)??"").trim();return t===""?void 0:t}function H(r){let i=R(r.labels);async function t({request:s}){await r.guards.requireAccess(s,{action:"read",intent:"loader"});let n=new URL(s.url).pathname.split("/").filter(Boolean),a=n[n.length-1]??"users",[p,x,d,g,y]=await Promise.all([r.store.listUsers(),r.store.listGroups(),r.store.listGroupMembers(),r.store.listAllowlist(),r.getMyPermissions?r.getMyPermissions(s).catch(()=>({})):Promise.resolve({})]);return{segment:["groups","group_members","allowlist"].includes(a)?a:"users",users:p,groups:x,groupMembers:d,allowlist:g,myPermissions:y,labels:i}}async function l({request:s}){let o=await s.formData(),n=String(o.get("intent")??""),a=_.get(n);if(!a)return{ok:!1,error:`Unknown intent: ${n}`};await r.guards.requireAccess(s,{action:a,intent:n});try{return await c(n,o)}catch(p){if(p instanceof Response)throw p;return{ok:!1,error:p instanceof Error?p.message:String(p)}}}async function c(s,o){if(s==="createUser")return await r.store.createUser({displayName:A(o,"displayName"),email:A(o,"email")}),{ok:!0};if(s==="updateUser")return await r.store.updateUser(v(o,"userId"),{displayName:A(o,"displayName"),email:A(o,"email")}),{ok:!0};if(s==="toggleUserActive"){let n=String(o.get("isActive")??"");if(n!=="true"&&n!=="false")throw new Error('Invalid or missing "isActive"');return await r.store.toggleUserActive(v(o,"userId"),n==="true"),{ok:!0}}if(s==="createGroup")return await r.store.createGroup({groupKey:A(o,"groupKey"),name:A(o,"name"),description:I(o,"description")}),{ok:!0};if(s==="updateGroup")return await r.store.updateGroup(v(o,"groupId"),{name:A(o,"name"),description:I(o,"description")}),{ok:!0};if(s==="deleteGroup")return await r.store.deleteGroup(v(o,"groupId")),{ok:!0};if(s==="addGroupMember")return await r.store.addGroupMember(v(o,"groupId"),v(o,"userId")),{ok:!0};if(s==="removeGroupMember")return await r.store.removeGroupMember(v(o,"groupId"),v(o,"userId")),{ok:!0};if(s==="addAllowlistEntry"){let n=o.get("type")==="domain"?"domain":"email";return await r.store.addAllowlistEntry({pattern:A(o,"pattern"),type:n,description:I(o,"description")}),{ok:!0}}return s==="removeAllowlistEntry"?(await r.store.removeAllowlistEntry(v(o,"entryId")),{ok:!0}):{ok:!1,error:`Unknown intent: ${s}`}}return{loader:t,action:l}}var U=require("react-router");var b=require("react/jsx-runtime");function Q({label:r,summary:i}){return(0,b.jsxs)("span",{style:{display:"inline-flex",alignItems:"center",gap:"0.18rem",fontSize:"0.65rem",padding:"0.08rem 0.35rem",borderRadius:"9999px",backgroundColor:i.bgColor,color:i.color,border:`1px solid ${i.borderColor}`,fontWeight:600,lineHeight:"1.2"},children:[(0,b.jsxs)("span",{children:[r,":"]}),(0,b.jsx)("span",{children:i.text})]})}function z({children:r,renderHeader:i}){let t=(0,U.useLoaderData)(),l=t?.segment??"users",c=t?.labels??w,s=t?.myPermissions??{},o=[{key:"users",label:c.tabs.users,href:"/users"},{key:"groups",label:c.tabs.groups,href:"/users/groups"},{key:"group_members",label:c.tabs.groupMembers,href:"/users/group_members"},{key:"allowlist",label:c.tabs.allowlist,href:"/users/allowlist"}],n=Object.entries(s),a=n.length>0?n:[["user_admin",{read:!0,write:!0,delete:!0,allowedActions:["read","create","update","delete"]}]],p=d=>{let g=d,y=g?.allowedActions??[],S=g?.write??(y.includes("create")||y.includes("update")||y.includes("delete")),C=g?.read??y.includes("read");return S?{text:"\u7DE8\u96C6\u53EF",color:"#047857",bgColor:"#ecfdf5",borderColor:"#a7f3d0"}:C?{text:"\u95B2\u89A7\u306E\u307F",color:"#1d4ed8",bgColor:"#eff6ff",borderColor:"#bfdbfe"}:{text:"\u6A29\u9650\u306A\u3057",color:"#64748b",bgColor:"#f1f5f9",borderColor:"#cbd5e1"}},x=(0,b.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:"0.4rem"},"data-testid":"user-admin-header-annotation",children:[(0,b.jsx)("span",{style:{fontSize:"0.75rem",backgroundColor:"#e0f2fe",color:"#0369a1",padding:"2px 8px",borderRadius:"12px",fontWeight:600},children:c.heading}),(0,b.jsxs)("div",{style:{display:"inline-flex",alignItems:"center",gap:"0.25rem",fontSize:"0.68rem",color:"#475569"},"data-testid":"user-admin-permissions-badge",children:[(0,b.jsx)("span",{style:{fontWeight:600,color:"#334155"},children:"\u3042\u306A\u305F\u306E\u6A29\u9650:"}),(0,b.jsx)("span",{style:{display:"inline-flex",alignItems:"center",gap:"0.18rem"},children:a.map(([d,g],y)=>(0,b.jsx)(Q,{label:d==="user_admin"?"\u30E6\u30FC\u30B6\u30FC\u7BA1\u7406UI":String(d),summary:p(g)},String(d||y)))})]})]});return(0,b.jsxs)("div",{"data-testid":"user-admin-shell",style:{width:"100%",minHeight:"100vh",backgroundColor:"#f8fafc",padding:"1.5rem",boxSizing:"border-box"},children:[i?i({title:c.title,annotation:x}):(0,b.jsxs)("div",{style:{marginBottom:"1.5rem",display:"flex",justifyContent:"space-between",alignItems:"center"},children:[(0,b.jsx)("h1",{style:{margin:0,fontSize:"1.5rem",fontWeight:700,color:"#0f172a"},children:c.title}),x]}),(0,b.jsx)("div",{style:{display:"flex",gap:"0.5rem",marginBottom:"1.2rem",borderBottom:"2px solid #e2e8f0",paddingBottom:"0.5rem"},children:o.map(d=>{let g=l===d.key;return(0,b.jsx)(U.Link,{to:d.href,"data-testid":`user-admin-tab-${d.key}`,style:{padding:"0.5rem 1rem",borderRadius:"6px 6px 0 0",fontSize:"0.88rem",fontWeight:g?700:500,color:g?"#0284c7":"#64748b",backgroundColor:g?"#ffffff":"transparent",textDecoration:"none",borderBottom:g?"3px solid #0284c7":"3px solid transparent",transition:"all 0.15s ease"},children:d.label},d.key)})}),(0,b.jsx)("main",{children:r})]})}var f=require("react"),h=require("react-router");var e=require("react/jsx-runtime");function k({fetcher:r}){let i=r.data;return i?.ok!==!1||!i.error?null:(0,e.jsx)("div",{"data-testid":"user-admin-action-error",role:"alert",style:{padding:"0.7rem 1rem",borderRadius:"6px",border:"1px solid #fecaca",backgroundColor:"#fef2f2",color:"#b91c1c",fontSize:"0.85rem"},children:i.error})}function M(){let r=(0,h.useLoaderData)(),i=(0,h.useFetcher)(),t=r.labels??w,[l,c]=(0,f.useState)(""),[s,o]=(0,f.useState)(null),[n,a]=(0,f.useState)(!1),[p,x]=(0,f.useState)(""),[d,g]=(0,f.useState)(""),y=r.users.filter(u=>u.displayName.toLowerCase().includes(l.toLowerCase())||u.email.toLowerCase().includes(l.toLowerCase())),S=u=>{i.submit({intent:"toggleUserActive",userId:String(u.id),isActive:String(!u.isActive)},{method:"post"})},C=u=>{u.preventDefault(),p&&d&&(i.submit({intent:"createUser",displayName:p,email:d},{method:"post"}),x(""),g(""),a(!1))},V=u=>{u.preventDefault(),s&&(i.submit({intent:"updateUser",userId:String(s.id),displayName:s.displayName,email:s.email},{method:"post"}),o(null))};return(0,e.jsxs)("section",{"data-testid":"users-view-section",style:{display:"flex",flexDirection:"column",gap:"1rem"},children:[(0,e.jsx)(k,{fetcher:i}),(0,e.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",backgroundColor:"#ffffff",padding:"1rem",borderRadius:"8px",border:"1px solid #e2e8f0"},children:[(0,e.jsx)("input",{type:"text",placeholder:t.usersView.searchPlaceholder,value:l,onChange:u=>c(u.target.value),"data-testid":"users-search-input",style:{padding:"6px 12px",borderRadius:"6px",border:"1px solid #cbd5e1",fontSize:"0.85rem",width:"260px"}}),(0,e.jsx)("button",{type:"button",onClick:()=>a(!0),"data-testid":"users-add-button",style:{padding:"6px 14px",borderRadius:"6px",backgroundColor:"#0284c7",color:"#ffffff",border:"none",fontSize:"0.85rem",fontWeight:600,cursor:"pointer"},children:t.usersView.addUser})]}),(0,e.jsx)("div",{style:{backgroundColor:"#ffffff",borderRadius:"8px",border:"1px solid #e2e8f0",overflow:"hidden"},children:(0,e.jsxs)("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:"0.85rem",textAlign:"left"},children:[(0,e.jsx)("thead",{children:(0,e.jsxs)("tr",{style:{backgroundColor:"#f8fafc",borderBottom:"1px solid #e2e8f0",color:"#475569"},children:[(0,e.jsx)("th",{style:{padding:"10px 14px"},children:t.usersView.id}),(0,e.jsx)("th",{style:{padding:"10px 14px"},children:t.usersView.displayName}),(0,e.jsx)("th",{style:{padding:"10px 14px"},children:t.usersView.email}),(0,e.jsx)("th",{style:{padding:"10px 14px"},children:t.usersView.status}),(0,e.jsx)("th",{style:{padding:"10px 14px",textAlign:"right"},children:t.usersView.actions})]})}),(0,e.jsxs)("tbody",{children:[y.map(u=>(0,e.jsxs)("tr",{style:{borderBottom:"1px solid #f1f5f9"},"data-testid":`user-row-${u.id}`,children:[(0,e.jsxs)("td",{style:{padding:"10px 14px",color:"#64748b"},children:["#",u.id]}),(0,e.jsx)("td",{style:{padding:"10px 14px",fontWeight:600,color:"#0f172a"},children:u.displayName}),(0,e.jsx)("td",{style:{padding:"10px 14px",color:"#475569"},children:u.email}),(0,e.jsx)("td",{style:{padding:"10px 14px"},children:(0,e.jsx)("span",{style:{fontSize:"0.75rem",padding:"2px 8px",borderRadius:"10px",backgroundColor:u.isActive?"#dcfce7":"#fee2e2",color:u.isActive?"#15803d":"#b91c1c",fontWeight:600},children:u.isActive?t.usersView.active:t.usersView.inactive})}),(0,e.jsxs)("td",{style:{padding:"10px 14px",textAlign:"right"},children:[(0,e.jsx)("button",{type:"button",onClick:()=>o(u),"data-testid":`edit-user-btn-${u.id}`,style:{padding:"3px 8px",borderRadius:"4px",border:"1px solid #cbd5e1",backgroundColor:"#ffffff",fontSize:"0.78rem",cursor:"pointer",marginRight:"6px"},children:t.usersView.edit}),(0,e.jsx)("button",{type:"button",onClick:()=>S(u),"data-testid":`toggle-user-btn-${u.id}`,style:{padding:"3px 8px",borderRadius:"4px",border:"1px solid #cbd5e1",backgroundColor:"#ffffff",fontSize:"0.78rem",cursor:"pointer",color:u.isActive?"#b91c1c":"#15803d"},children:u.isActive?t.usersView.deactivate:t.usersView.activate})]})]},u.id)),y.length===0&&(0,e.jsx)("tr",{children:(0,e.jsx)("td",{colSpan:5,style:{padding:"2rem",textAlign:"center",color:"#94a3b8"},children:t.usersView.empty})})]})]})}),n&&(0,e.jsx)("div",{style:{position:"fixed",inset:0,backgroundColor:"rgba(0,0,0,0.4)",display:"flex",justifyContent:"center",alignItems:"center",zIndex:100},"data-testid":"user-create-modal",children:(0,e.jsxs)("form",{onSubmit:C,style:{backgroundColor:"#ffffff",padding:"1.5rem",borderRadius:"8px",width:"360px",boxShadow:"0 10px 25px rgba(0,0,0,0.15)"},children:[(0,e.jsx)("h3",{style:{margin:"0 0 1rem 0",fontSize:"1.1rem"},children:t.usersView.addUser}),(0,e.jsxs)("div",{style:{marginBottom:"1rem"},children:[(0,e.jsx)("label",{htmlFor:"create-user-display-name-input",style:{display:"block",fontSize:"0.8rem",color:"#475569",marginBottom:"4px"},children:t.usersView.displayName}),(0,e.jsx)("input",{id:"create-user-display-name-input",type:"text",value:p,onChange:u=>x(u.target.value),required:!0,"data-testid":"create-user-display-name",style:{width:"100%",padding:"6px",borderRadius:"4px",border:"1px solid #cbd5e1",boxSizing:"border-box"}})]}),(0,e.jsxs)("div",{style:{marginBottom:"1.2rem"},children:[(0,e.jsx)("label",{htmlFor:"create-user-email-input",style:{display:"block",fontSize:"0.8rem",color:"#475569",marginBottom:"4px"},children:t.usersView.email}),(0,e.jsx)("input",{id:"create-user-email-input",type:"email",value:d,onChange:u=>g(u.target.value),required:!0,"data-testid":"create-user-email",style:{width:"100%",padding:"6px",borderRadius:"4px",border:"1px solid #cbd5e1",boxSizing:"border-box"}})]}),(0,e.jsxs)("div",{style:{display:"flex",justifyContent:"flex-end",gap:"0.5rem"},children:[(0,e.jsx)("button",{type:"button",onClick:()=>a(!1),style:{padding:"6px 12px",borderRadius:"4px",border:"1px solid #cbd5e1",backgroundColor:"#ffffff",cursor:"pointer"},children:"\u30AD\u30E3\u30F3\u30BB\u30EB"}),(0,e.jsx)("button",{type:"submit","data-testid":"submit-create-user",style:{padding:"6px 12px",borderRadius:"4px",backgroundColor:"#0284c7",color:"#ffffff",border:"none",cursor:"pointer"},children:"\u4F5C\u6210"})]})]})}),s&&(0,e.jsx)("div",{style:{position:"fixed",inset:0,backgroundColor:"rgba(0,0,0,0.4)",display:"flex",justifyContent:"center",alignItems:"center",zIndex:100},"data-testid":"user-edit-modal",children:(0,e.jsxs)("form",{onSubmit:V,style:{backgroundColor:"#ffffff",padding:"1.5rem",borderRadius:"8px",width:"360px",boxShadow:"0 10px 25px rgba(0,0,0,0.15)"},children:[(0,e.jsx)("h3",{style:{margin:"0 0 1rem 0",fontSize:"1.1rem"},children:t.usersView.editUser}),(0,e.jsxs)("div",{style:{marginBottom:"1rem"},children:[(0,e.jsx)("label",{htmlFor:"edit-user-display-name-input",style:{display:"block",fontSize:"0.8rem",color:"#475569",marginBottom:"4px"},children:t.usersView.displayName}),(0,e.jsx)("input",{id:"edit-user-display-name-input",type:"text",value:s.displayName,onChange:u=>o({...s,displayName:u.target.value}),required:!0,"data-testid":"edit-user-display-name",style:{width:"100%",padding:"6px",borderRadius:"4px",border:"1px solid #cbd5e1",boxSizing:"border-box"}})]}),(0,e.jsxs)("div",{style:{marginBottom:"1.2rem"},children:[(0,e.jsx)("label",{htmlFor:"edit-user-email-input",style:{display:"block",fontSize:"0.8rem",color:"#475569",marginBottom:"4px"},children:t.usersView.email}),(0,e.jsx)("input",{id:"edit-user-email-input",type:"email",value:s.email,onChange:u=>o({...s,email:u.target.value}),required:!0,"data-testid":"edit-user-email",style:{width:"100%",padding:"6px",borderRadius:"4px",border:"1px solid #cbd5e1",boxSizing:"border-box"}})]}),(0,e.jsxs)("div",{style:{display:"flex",justifyContent:"flex-end",gap:"0.5rem"},children:[(0,e.jsx)("button",{type:"button",onClick:()=>o(null),style:{padding:"6px 12px",borderRadius:"4px",border:"1px solid #cbd5e1",backgroundColor:"#ffffff",cursor:"pointer"},children:t.usersView.cancel}),(0,e.jsx)("button",{type:"submit","data-testid":"submit-edit-user",style:{padding:"6px 12px",borderRadius:"4px",backgroundColor:"#0284c7",color:"#ffffff",border:"none",cursor:"pointer"},children:t.usersView.save})]})]})})]})}function P(){let r=(0,h.useLoaderData)(),i=(0,h.useFetcher)(),t=r.labels??w,[l,c]=(0,f.useState)(""),[s,o]=(0,f.useState)(!1),[n,a]=(0,f.useState)(null),[p,x]=(0,f.useState)(""),[d,g]=(0,f.useState)(""),[y,S]=(0,f.useState)(""),C=r.groups.filter(m=>m.name.toLowerCase().includes(l.toLowerCase())||m.groupKey.toLowerCase().includes(l.toLowerCase())),V=m=>{m.preventDefault(),p&&d&&(i.submit({intent:"createGroup",groupKey:p,name:d,description:y},{method:"post"}),x(""),g(""),S(""),o(!1))},u=m=>{m.preventDefault(),n&&(i.submit({intent:"updateGroup",groupId:String(n.id),name:n.name,description:n.description??""},{method:"post"}),a(null))},L=m=>{window.confirm(t.groupsView.confirmDelete)&&i.submit({intent:"deleteGroup",groupId:String(m)},{method:"post"})};return(0,e.jsxs)("section",{"data-testid":"groups-view-section",style:{display:"flex",flexDirection:"column",gap:"1rem"},children:[(0,e.jsx)(k,{fetcher:i}),(0,e.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",backgroundColor:"#ffffff",padding:"1rem",borderRadius:"8px",border:"1px solid #e2e8f0"},children:[(0,e.jsx)("input",{type:"text",placeholder:t.groupsView.searchPlaceholder,value:l,onChange:m=>c(m.target.value),"data-testid":"groups-search-input",style:{padding:"6px 12px",borderRadius:"6px",border:"1px solid #cbd5e1",fontSize:"0.85rem",width:"260px"}}),(0,e.jsx)("button",{type:"button",onClick:()=>o(!0),"data-testid":"groups-add-button",style:{padding:"6px 14px",borderRadius:"6px",backgroundColor:"#4338ca",color:"#ffffff",border:"none",fontSize:"0.85rem",fontWeight:600,cursor:"pointer"},children:t.groupsView.addGroup})]}),(0,e.jsx)("div",{style:{display:"grid",gridTemplateColumns:"repeat(auto-fill, minmax(280px, 1fr))",gap:"1rem"},children:C.map(m=>{let B=r.groupMembers.filter(D=>D.groupId===m.id).length;return(0,e.jsxs)("div",{style:{backgroundColor:"#ffffff",borderRadius:"8px",border:"1px solid #e2e8f0",padding:"1rem",display:"flex",flexDirection:"column",justifyContent:"space-between"},"data-testid":`group-card-${m.id}`,children:[(0,e.jsxs)("div",{children:[(0,e.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"0.5rem"},children:[(0,e.jsx)("h4",{style:{margin:0,fontSize:"1rem",color:"#0f172a"},children:m.name}),(0,e.jsx)("span",{style:{fontSize:"0.72rem",backgroundColor:"#e0e7ff",color:"#4338ca",padding:"2px 6px",borderRadius:"4px",fontFamily:"monospace"},children:m.groupKey})]}),(0,e.jsx)("p",{style:{margin:"0 0 0.8rem 0",fontSize:"0.82rem",color:"#64748b",minHeight:"2.4em"},children:m.description||t.groupsView.noDescription})]}),(0,e.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",borderTop:"1px solid #f1f5f9",paddingTop:"0.6rem"},children:[(0,e.jsxs)("span",{style:{fontSize:"0.78rem",color:"#475569"},children:["\u{1F465} \u30E1\u30F3\u30D0\u30FC: ",(0,e.jsx)("strong",{children:B})," \u4EBA"]}),(0,e.jsxs)("div",{children:[(0,e.jsx)("button",{type:"button",onClick:()=>a(m),"data-testid":`edit-group-btn-${m.id}`,style:{padding:"3px 8px",borderRadius:"4px",border:"1px solid #cbd5e1",backgroundColor:"#ffffff",fontSize:"0.75rem",cursor:"pointer",marginRight:"4px"},children:t.usersView.edit}),(0,e.jsx)("button",{type:"button",onClick:()=>L(m.id),"data-testid":`delete-group-btn-${m.id}`,style:{padding:"3px 8px",borderRadius:"4px",border:"1px solid #fee2e2",backgroundColor:"#fff5f5",color:"#b91c1c",fontSize:"0.75rem",cursor:"pointer"},children:"\u524A\u9664"})]})]})]},m.id)})}),s&&(0,e.jsx)("div",{style:{position:"fixed",inset:0,backgroundColor:"rgba(0,0,0,0.4)",display:"flex",justifyContent:"center",alignItems:"center",zIndex:100},"data-testid":"group-create-modal",children:(0,e.jsxs)("form",{onSubmit:V,style:{backgroundColor:"#ffffff",padding:"1.5rem",borderRadius:"8px",width:"360px",boxShadow:"0 10px 25px rgba(0,0,0,0.15)"},children:[(0,e.jsx)("h3",{style:{margin:"0 0 1rem 0",fontSize:"1.1rem"},children:t.groupsView.addGroup}),(0,e.jsxs)("div",{style:{marginBottom:"1rem"},children:[(0,e.jsx)("label",{htmlFor:"create-group-key-input",style:{display:"block",fontSize:"0.8rem",color:"#475569",marginBottom:"4px"},children:t.groupsView.groupKey}),(0,e.jsx)("input",{id:"create-group-key-input",type:"text",value:p,onChange:m=>x(m.target.value),placeholder:t.groupsView.groupKeyPlaceholder,required:!0,"data-testid":"create-group-key",style:{width:"100%",padding:"6px",borderRadius:"4px",border:"1px solid #cbd5e1",boxSizing:"border-box"}})]}),(0,e.jsxs)("div",{style:{marginBottom:"1rem"},children:[(0,e.jsx)("label",{htmlFor:"create-group-name-input",style:{display:"block",fontSize:"0.8rem",color:"#475569",marginBottom:"4px"},children:t.groupsView.name}),(0,e.jsx)("input",{id:"create-group-name-input",type:"text",value:d,onChange:m=>g(m.target.value),placeholder:t.groupsView.namePlaceholder,required:!0,"data-testid":"create-group-name",style:{width:"100%",padding:"6px",borderRadius:"4px",border:"1px solid #cbd5e1",boxSizing:"border-box"}})]}),(0,e.jsxs)("div",{style:{marginBottom:"1.2rem"},children:[(0,e.jsx)("label",{htmlFor:"create-group-desc-input",style:{display:"block",fontSize:"0.8rem",color:"#475569",marginBottom:"4px"},children:t.groupsView.description}),(0,e.jsx)("textarea",{id:"create-group-desc-input",value:y,onChange:m=>S(m.target.value),"data-testid":"create-group-description",style:{width:"100%",padding:"6px",borderRadius:"4px",border:"1px solid #cbd5e1",boxSizing:"border-box",height:"60px"}})]}),(0,e.jsxs)("div",{style:{display:"flex",justifyContent:"flex-end",gap:"0.5rem"},children:[(0,e.jsx)("button",{type:"button",onClick:()=>o(!1),style:{padding:"6px 12px",borderRadius:"4px",border:"1px solid #cbd5e1",backgroundColor:"#ffffff",cursor:"pointer"},children:"\u30AD\u30E3\u30F3\u30BB\u30EB"}),(0,e.jsx)("button",{type:"submit","data-testid":"submit-create-group",style:{padding:"6px 12px",borderRadius:"4px",backgroundColor:"#4338ca",color:"#ffffff",border:"none",cursor:"pointer"},children:"\u4F5C\u6210"})]})]})}),n&&(0,e.jsx)("div",{style:{position:"fixed",inset:0,backgroundColor:"rgba(0,0,0,0.4)",display:"flex",justifyContent:"center",alignItems:"center",zIndex:100},"data-testid":"group-edit-modal",children:(0,e.jsxs)("form",{onSubmit:u,style:{backgroundColor:"#ffffff",padding:"1.5rem",borderRadius:"8px",width:"360px",boxShadow:"0 10px 25px rgba(0,0,0,0.15)"},children:[(0,e.jsx)("h3",{style:{margin:"0 0 1rem 0",fontSize:"1.1rem"},children:t.groupsView.editGroup}),(0,e.jsxs)("div",{style:{marginBottom:"1rem"},children:[(0,e.jsx)("label",{htmlFor:"edit-group-name-input",style:{display:"block",fontSize:"0.8rem",color:"#475569",marginBottom:"4px"},children:t.groupsView.name}),(0,e.jsx)("input",{id:"edit-group-name-input",type:"text",value:n.name,onChange:m=>a({...n,name:m.target.value}),required:!0,"data-testid":"edit-group-name",style:{width:"100%",padding:"6px",borderRadius:"4px",border:"1px solid #cbd5e1",boxSizing:"border-box"}})]}),(0,e.jsxs)("div",{style:{marginBottom:"1.2rem"},children:[(0,e.jsx)("label",{htmlFor:"edit-group-desc-input",style:{display:"block",fontSize:"0.8rem",color:"#475569",marginBottom:"4px"},children:t.groupsView.description}),(0,e.jsx)("textarea",{id:"edit-group-desc-input",value:n.description??"",onChange:m=>a({...n,description:m.target.value}),"data-testid":"edit-group-description",style:{width:"100%",padding:"6px",borderRadius:"4px",border:"1px solid #cbd5e1",boxSizing:"border-box",height:"60px"}})]}),(0,e.jsxs)("div",{style:{display:"flex",justifyContent:"flex-end",gap:"0.5rem"},children:[(0,e.jsx)("button",{type:"button",onClick:()=>a(null),style:{padding:"6px 12px",borderRadius:"4px",border:"1px solid #cbd5e1",backgroundColor:"#ffffff",cursor:"pointer"},children:t.groupsView.cancel}),(0,e.jsx)("button",{type:"submit","data-testid":"submit-edit-group",style:{padding:"6px 12px",borderRadius:"4px",backgroundColor:"#4338ca",color:"#ffffff",border:"none",cursor:"pointer"},children:t.groupsView.save})]})]})})]})}function E(){let r=(0,h.useLoaderData)(),i=(0,h.useFetcher)(),t=r.labels??w,[l,c]=(0,f.useState)(r.groups[0]?.id??0),s=r.groups.find(a=>a.id===l),o=new Set(r.groupMembers.filter(a=>a.groupId===l).map(a=>a.userId)),n=(a,p)=>{p?i.submit({intent:"removeGroupMember",groupId:String(l),userId:String(a)},{method:"post"}):i.submit({intent:"addGroupMember",groupId:String(l),userId:String(a)},{method:"post"})};return(0,e.jsxs)("section",{"data-testid":"group-members-view-section",style:{display:"grid",gridTemplateColumns:"240px 1fr",gap:"1.2rem"},children:[(0,e.jsx)(k,{fetcher:i}),(0,e.jsxs)("div",{style:{backgroundColor:"#ffffff",padding:"1rem",borderRadius:"8px",border:"1px solid #e2e8f0"},children:[(0,e.jsx)("h4",{style:{margin:"0 0 0.8rem 0",fontSize:"0.9rem",color:"#475569"},children:t.groupMembersView.selectGroup}),(0,e.jsx)("div",{style:{display:"flex",flexDirection:"column",gap:"0.4rem"},children:r.groups.map(a=>{let p=a.id===l;return(0,e.jsx)("button",{type:"button",onClick:()=>c(a.id),"data-testid":`select-group-btn-${a.id}`,style:{textAlign:"left",padding:"8px 10px",borderRadius:"6px",border:p?"1px solid #6366f1":"1px solid #e2e8f0",backgroundColor:p?"#e0e7ff":"#ffffff",color:p?"#3730a3":"#0f172a",cursor:"pointer",fontWeight:p?600:400,fontSize:"0.85rem"},children:a.name},a.id)})})]}),(0,e.jsx)("div",{style:{backgroundColor:"#ffffff",padding:"1.2rem",borderRadius:"8px",border:"1px solid #e2e8f0"},children:s?(0,e.jsxs)(e.Fragment,{children:[(0,e.jsxs)("div",{style:{marginBottom:"1rem",borderBottom:"1px solid #e2e8f0",paddingBottom:"0.8rem"},children:[(0,e.jsxs)("h3",{style:{margin:0,fontSize:"1.1rem",color:"#0f172a"},children:[s.name," \u306E\u6240\u5C5E\u30E1\u30F3\u30D0\u30FC"]}),(0,e.jsxs)("span",{style:{fontSize:"0.8rem",color:"#64748b"},children:["\u30B0\u30EB\u30FC\u30D7\u30AD\u30FC: ",s.groupKey]})]}),(0,e.jsx)("div",{style:{display:"flex",flexDirection:"column",gap:"0.5rem"},children:r.users.map(a=>{let p=o.has(a.id);return(0,e.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"8px 12px",borderRadius:"6px",border:"1px solid #f1f5f9",backgroundColor:p?"#f0fdf4":"#ffffff"},"data-testid":`member-row-${a.id}`,children:[(0,e.jsxs)("div",{children:[(0,e.jsx)("span",{style:{fontWeight:600,fontSize:"0.88rem",color:"#0f172a",marginRight:"8px"},children:a.displayName}),(0,e.jsxs)("span",{style:{fontSize:"0.78rem",color:"#64748b"},children:["(",a.email,")"]})]}),(0,e.jsx)("button",{type:"button",onClick:()=>n(a.id,p),"data-testid":`toggle-member-btn-${a.id}`,style:{padding:"4px 12px",borderRadius:"4px",border:p?"1px solid #b91c1c":"1px solid #0284c7",backgroundColor:p?"#ffffff":"#0284c7",color:p?"#b91c1c":"#ffffff",fontSize:"0.78rem",fontWeight:600,cursor:"pointer"},children:p?t.groupMembersView.actionRemove:t.groupMembersView.actionAdd})]},a.id)})})]}):(0,e.jsx)("div",{style:{color:"#94a3b8",textAlign:"center",padding:"2rem"},children:t.groupMembersView.selectPrompt})})]})}function N(){let r=(0,h.useLoaderData)(),i=(0,h.useFetcher)(),t=r.labels??w,[l,c]=(0,f.useState)(""),[s,o]=(0,f.useState)("email"),[n,a]=(0,f.useState)(""),p=d=>{d.preventDefault(),l&&(i.submit({intent:"addAllowlistEntry",pattern:l,type:s,description:n},{method:"post"}),c(""),a(""))},x=d=>{i.submit({intent:"removeAllowlistEntry",entryId:String(d)},{method:"post"})};return(0,e.jsxs)("section",{"data-testid":"allowlist-view-section",style:{display:"flex",flexDirection:"column",gap:"1.2rem"},children:[(0,e.jsx)(k,{fetcher:i}),(0,e.jsxs)("form",{onSubmit:p,style:{backgroundColor:"#ffffff",padding:"1.2rem",borderRadius:"8px",border:"1px solid #e2e8f0",display:"flex",flexWrap:"wrap",gap:"0.8rem",alignItems:"flex-end"},children:[(0,e.jsxs)("div",{style:{flex:2,minWidth:"220px"},children:[(0,e.jsx)("label",{htmlFor:"allowlist-pattern-input-field",style:{display:"block",fontSize:"0.78rem",color:"#475569",marginBottom:"4px"},children:t.allowlistView.pattern}),(0,e.jsx)("input",{id:"allowlist-pattern-input-field",type:"text",value:l,onChange:d=>c(d.target.value),required:!0,"data-testid":"allowlist-pattern-input",style:{width:"100%",padding:"6px 10px",borderRadius:"6px",border:"1px solid #cbd5e1",fontSize:"0.85rem",boxSizing:"border-box"}})]}),(0,e.jsxs)("div",{style:{flex:1,minWidth:"140px"},children:[(0,e.jsx)("label",{htmlFor:"allowlist-type-select-field",style:{display:"block",fontSize:"0.78rem",color:"#475569",marginBottom:"4px"},children:t.allowlistView.type}),(0,e.jsxs)("select",{id:"allowlist-type-select-field",value:s,onChange:d=>o(d.target.value),"data-testid":"allowlist-type-select",style:{width:"100%",padding:"6px 10px",borderRadius:"6px",border:"1px solid #cbd5e1",fontSize:"0.85rem",boxSizing:"border-box"},children:[(0,e.jsx)("option",{value:"email",children:t.allowlistView.emailType}),(0,e.jsx)("option",{value:"domain",children:t.allowlistView.domainType})]})]}),(0,e.jsxs)("div",{style:{flex:2,minWidth:"200px"},children:[(0,e.jsx)("label",{htmlFor:"allowlist-desc-input-field",style:{display:"block",fontSize:"0.78rem",color:"#475569",marginBottom:"4px"},children:t.allowlistView.description}),(0,e.jsx)("input",{id:"allowlist-desc-input-field",type:"text",value:n,onChange:d=>a(d.target.value),"data-testid":"allowlist-desc-input",style:{width:"100%",padding:"6px 10px",borderRadius:"6px",border:"1px solid #cbd5e1",fontSize:"0.85rem",boxSizing:"border-box"}})]}),(0,e.jsx)("button",{type:"submit","data-testid":"submit-allowlist-add",style:{padding:"7px 16px",borderRadius:"6px",backgroundColor:"#047857",color:"#ffffff",border:"none",fontSize:"0.85rem",fontWeight:600,cursor:"pointer"},children:t.allowlistView.addEntry})]}),(0,e.jsx)("div",{style:{backgroundColor:"#ffffff",borderRadius:"8px",border:"1px solid #e2e8f0",overflow:"hidden"},children:(0,e.jsxs)("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:"0.85rem",textAlign:"left"},children:[(0,e.jsx)("thead",{children:(0,e.jsxs)("tr",{style:{backgroundColor:"#f8fafc",borderBottom:"1px solid #e2e8f0",color:"#475569"},children:[(0,e.jsx)("th",{style:{padding:"10px 14px"},children:"ID"}),(0,e.jsx)("th",{style:{padding:"10px 14px"},children:t.allowlistView.pattern}),(0,e.jsx)("th",{style:{padding:"10px 14px"},children:t.allowlistView.type}),(0,e.jsx)("th",{style:{padding:"10px 14px"},children:t.allowlistView.description}),(0,e.jsx)("th",{style:{padding:"10px 14px",textAlign:"right"},children:t.allowlistView.actions})]})}),(0,e.jsxs)("tbody",{children:[r.allowlist.map(d=>(0,e.jsxs)("tr",{style:{borderBottom:"1px solid #f1f5f9"},"data-testid":`allowlist-row-${d.id}`,children:[(0,e.jsxs)("td",{style:{padding:"10px 14px",color:"#64748b"},children:["#",d.id]}),(0,e.jsx)("td",{style:{padding:"10px 14px",fontWeight:600,color:"#0f172a",fontFamily:"monospace"},children:d.pattern}),(0,e.jsx)("td",{style:{padding:"10px 14px"},children:(0,e.jsx)("span",{style:{fontSize:"0.75rem",padding:"2px 8px",borderRadius:"10px",backgroundColor:d.type==="email"?"#e0f2fe":"#fef3c7",color:d.type==="email"?"#0369a1":"#b45309",fontWeight:600},children:d.type==="email"?t.allowlistView.emailTypeShort:t.allowlistView.domainTypeShort})}),(0,e.jsx)("td",{style:{padding:"10px 14px",color:"#475569"},children:d.description||"-"}),(0,e.jsx)("td",{style:{padding:"10px 14px",textAlign:"right"},children:d.readOnly?(0,e.jsx)("span",{"data-testid":`readonly-allowlist-${d.id}`,style:{fontSize:"0.75rem",color:"#94a3b8"},children:t.allowlistView.readOnly}):(0,e.jsx)("button",{type:"button",onClick:()=>x(d.id),"data-testid":`remove-allowlist-btn-${d.id}`,style:{padding:"3px 8px",borderRadius:"4px",border:"1px solid #fee2e2",backgroundColor:"#fff5f5",color:"#b91c1c",fontSize:"0.78rem",cursor:"pointer"},children:"\u524A\u9664"})})]},d.id)),r.allowlist.length===0&&(0,e.jsx)("tr",{children:(0,e.jsx)("td",{colSpan:5,style:{padding:"2rem",textAlign:"center",color:"#94a3b8"},children:t.allowlistView.empty})})]})]})})]})}var J={users:M,groups:P,group_members:E,allowlist:N};function X({renderHeader:r}={}){let t=(0,h.useLoaderData)()?.segment??"users",l=J[t]??M;return(0,e.jsx)(z,{renderHeader:r,children:(0,e.jsx)(l,{})})}0&&(module.exports={AllowlistView,AuthUserAdminAppView,GroupMembersView,GroupsView,UserAdminShell,UsersView,createInMemoryUserAdminStore,createUserAdminApp,defaultUserAdminLabels,jaUserAdminLabels,resolveUserAdminLabels});
|
|
1
|
+
"use strict";var R=Object.defineProperty;var F=Object.getOwnPropertyDescriptor;var W=Object.getOwnPropertyNames;var $=Object.prototype.hasOwnProperty;var q=(r,i)=>{for(var t in i)R(r,t,{get:i[t],enumerable:!0})},K=(r,i,t,d)=>{if(i&&typeof i=="object"||typeof i=="function")for(let m of W(i))!$.call(r,m)&&m!==t&&R(r,m,{get:()=>i[m],enumerable:!(d=F(i,m))||d.enumerable});return r};var j=r=>K(R({},"__esModule",{value:!0}),r);var Y={};q(Y,{AllowlistView:()=>L,AuthUserAdminAppView:()=>X,GroupMembersView:()=>N,GroupsView:()=>E,UserAdminShell:()=>P,UsersView:()=>z,createInMemoryUserAdminStore:()=>_,createUserAdminApp:()=>Q,defaultUserAdminLabels:()=>v,jaUserAdminLabels:()=>O,resolveUserAdminLabels:()=>G});module.exports=j(Y);var v={title:"Users & Groups",heading:"\u{1F464} User administration",tabs:{users:"\u{1F464} Users",groups:"\u{1F465} Groups",groupMembers:"\u{1F517} Members",allowlist:"\u2709\uFE0F Allowlist"},usersView:{title:"Users",searchPlaceholder:"Search by name or email...",addUser:"\uFF0B Add user",editUser:"Edit user",id:"ID",displayName:"Name",email:"Email",status:"Status",active:"Active",inactive:"Inactive",actions:"Actions",edit:"Edit",activate:"Activate",deactivate:"Deactivate",empty:"No matching users",save:"Save",cancel:"Cancel"},groupsView:{title:"Groups",searchPlaceholder:"Search by group name or key...",addGroup:"\uFF0B Add group",editGroup:"Edit group",id:"ID",groupKey:"Group key",name:"Name",description:"Description",memberCount:"Members",status:"Status",actions:"Actions",edit:"Edit",delete:"Delete",confirmDelete:"Delete this group?",noDescription:"No description",groupKeyPlaceholder:"e.g. dev-team",namePlaceholder:"e.g. Development team",empty:"No groups registered",save:"Save",cancel:"Cancel"},groupMembersView:{selectGroup:"Select a group",selectPrompt:"Select a group to manage its members",actionAdd:"Add",actionRemove:"Remove"},allowlistView:{title:"Sign-in allowlist",addEntry:"\uFF0B Add pattern",pattern:"Pattern (e.g. @example.com or user@example.com)",type:"Type",emailType:"Exact email match",domainType:"Domain match",emailTypeShort:"Email",domainTypeShort:"Domain",description:"Description",actions:"Actions",readOnly:"Read-only",delete:"Delete",empty:"No allowlist entries registered",save:"Add",cancel:"Cancel"}},O={title:"\u30E6\u30FC\u30B6\u30FC\u30FB\u30B0\u30EB\u30FC\u30D7\u7BA1\u7406",heading:"\u{1F464} \u30E6\u30FC\u30B6\u30FC\u7BA1\u7406",tabs:{users:"\u{1F464} \u30E6\u30FC\u30B6\u30FC\u4E00\u89A7",groups:"\u{1F465} \u30E6\u30FC\u30B6\u30FC\u30B0\u30EB\u30FC\u30D7",groupMembers:"\u{1F517} \u30B0\u30EB\u30FC\u30D7\u30E1\u30F3\u30D0\u30FC",allowlist:"\u2709\uFE0F \u30A2\u30AF\u30BB\u30B9\u8A31\u53EF\u30EA\u30B9\u30C8"},usersView:{title:"\u30E6\u30FC\u30B6\u30FC\u7BA1\u7406",searchPlaceholder:"\u8868\u793A\u540D\u3084 Email \u3067\u691C\u7D22...",addUser:"\uFF0B \u30E6\u30FC\u30B6\u30FC\u8FFD\u52A0",editUser:"\u30E6\u30FC\u30B6\u30FC\u306E\u7DE8\u96C6",id:"ID",displayName:"\u8868\u793A\u540D",email:"\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9",status:"\u30B9\u30C6\u30FC\u30BF\u30B9",active:"\u6709\u52B9",inactive:"\u7121\u52B9",actions:"\u64CD\u4F5C",edit:"\u7DE8\u96C6",activate:"\u6709\u52B9\u5316",deactivate:"\u7121\u52B9\u5316",empty:"\u8A72\u5F53\u3059\u308B\u30E6\u30FC\u30B6\u30FC\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093",save:"\u4FDD\u5B58",cancel:"\u30AD\u30E3\u30F3\u30BB\u30EB"},groupsView:{title:"\u30E6\u30FC\u30B6\u30FC\u30B0\u30EB\u30FC\u30D7\u7BA1\u7406",searchPlaceholder:"\u30B0\u30EB\u30FC\u30D7\u540D\u3084\u30AD\u30FC\u3067\u691C\u7D22...",addGroup:"\uFF0B \u30B0\u30EB\u30FC\u30D7\u4F5C\u6210",editGroup:"\u30B0\u30EB\u30FC\u30D7\u306E\u7DE8\u96C6",id:"ID",groupKey:"\u30B0\u30EB\u30FC\u30D7\u30AD\u30FC",name:"\u30B0\u30EB\u30FC\u30D7\u540D",description:"\u8AAC\u660E",memberCount:"\u30E1\u30F3\u30D0\u30FC\u6570",status:"\u30B9\u30C6\u30FC\u30BF\u30B9",actions:"\u64CD\u4F5C",edit:"\u7DE8\u96C6",delete:"\u524A\u9664",confirmDelete:"\u3053\u306E\u30B0\u30EB\u30FC\u30D7\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B\uFF1F",noDescription:"\u8AAC\u660E\u306A\u3057",groupKeyPlaceholder:"\u4F8B: dev-team",namePlaceholder:"\u4F8B: \u958B\u767A\u30C1\u30FC\u30E0",empty:"\u30B0\u30EB\u30FC\u30D7\u304C\u767B\u9332\u3055\u308C\u3066\u3044\u307E\u305B\u3093",save:"\u4FDD\u5B58",cancel:"\u30AD\u30E3\u30F3\u30BB\u30EB"},groupMembersView:{selectGroup:"\u30B0\u30EB\u30FC\u30D7\u9078\u629E",selectPrompt:"\u30B0\u30EB\u30FC\u30D7\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044",actionAdd:"\u8FFD\u52A0",actionRemove:"\u9664\u5916"},allowlistView:{title:"\u30A2\u30AF\u30BB\u30B9\u8A31\u53EF\u30EA\u30B9\u30C8 (Allowlist)",addEntry:"\uFF0B \u8A31\u53EF\u30D1\u30BF\u30FC\u30F3\u8FFD\u52A0",pattern:"\u30D1\u30BF\u30FC\u30F3 (\u4F8B: @example.com \u307E\u305F\u306F user@example.com)",type:"\u7A2E\u5225",emailType:"\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u5B8C\u5168\u4E00\u81F4",domainType:"\u30C9\u30E1\u30A4\u30F3\u4E00\u81F4",emailTypeShort:"Email \u5B8C\u5168\u4E00\u81F4",domainTypeShort:"\u30C9\u30E1\u30A4\u30F3\u4E00\u81F4",description:"\u8AAC\u660E / \u5099\u8003",actions:"\u64CD\u4F5C",readOnly:"\u5909\u66F4\u4E0D\u53EF",delete:"\u524A\u9664",empty:"\u30A2\u30ED\u30EF\u30EA\u30B9\u30C8\u30A8\u30F3\u30C8\u30EA\u304C\u767B\u9332\u3055\u308C\u3066\u3044\u307E\u305B\u3093",save:"\u767B\u9332",cancel:"\u30AD\u30E3\u30F3\u30BB\u30EB"}};function G(r){let i=v;return r?{title:r.title??i.title,heading:r.heading??i.heading,tabs:{...i.tabs,...r.tabs},usersView:{...i.usersView,...r.usersView},groupsView:{...i.groupsView,...r.groupsView},groupMembersView:{...i.groupMembersView,...r.groupMembersView},allowlistView:{...i.allowlistView,...r.allowlistView}}:i}function _(r){let i=r?.users??[{id:1,email:"admin@example.com",displayName:"\u30B7\u30B9\u30C6\u30E0\u7BA1\u7406\u8005",isActive:!0},{id:2,email:"user1@example.com",displayName:"\u958B\u767A \u592A\u90CE",isActive:!0},{id:3,email:"user2@example.com",displayName:"\u55B6\u696D \u82B1\u5B50",isActive:!0}],t=r?.groups??[{id:1,groupKey:"dev-team",name:"\u958B\u767A\u30C1\u30FC\u30E0",description:"\u30B7\u30B9\u30C6\u30E0\u958B\u767A\u62C5\u5F53\u30B0\u30EB\u30FC\u30D7",isActive:!0},{id:2,groupKey:"sales-dept",name:"\u55B6\u696D\u90E8",description:"\u55B6\u696D\u30BD\u30EA\u30E5\u30FC\u30B7\u30E7\u30F3\u62C5\u5F53",isActive:!0}],d=r?.groupMembers??[{id:1,groupId:1,userId:2},{id:2,groupId:2,userId:3}],m=r?.allowlist??[{id:1,pattern:"admin@example.com",type:"email",description:"\u521D\u671F\u7BA1\u7406\u8005"},{id:2,pattern:"@example.com",type:"domain",description:"\u793E\u5185\u30C9\u30E1\u30A4\u30F3"}];return{async listUsers(){return[...i]},async createUser(s){let o={id:Math.max(...i.map(n=>n.id),0)+1,email:s.email,displayName:s.displayName,isActive:!0};return i.push(o),o},async updateUser(s,o){let n=i.findIndex(a=>a.id===s);if(n===-1)throw new Error(`User not found: ${s}`);return i[n]={...i[n],displayName:o.displayName,email:o.email},i[n]},async toggleUserActive(s,o){let n=i.findIndex(a=>a.id===s);if(n===-1)throw new Error(`User not found: ${s}`);return i[n]={...i[n],isActive:o},i[n]},async listGroups(){return[...t]},async createGroup(s){let o={id:Math.max(...t.map(n=>n.id),0)+1,groupKey:s.groupKey,name:s.name,description:s.description,isActive:!0};return t.push(o),o},async updateGroup(s,o){let n=t.findIndex(a=>a.id===s);if(n===-1)throw new Error(`Group not found: ${s}`);return t[n]={...t[n],name:o.name,description:o.description},t[n]},async deleteGroup(s){t=t.filter(o=>o.id!==s),d=d.filter(o=>o.groupId!==s)},async listGroupMembers(){return[...d]},async addGroupMember(s,o){let n=d.find(l=>l.groupId===s&&l.userId===o);if(n)return n;let a={id:Math.max(...d.map(l=>l.id),0)+1,groupId:s,userId:o};return d.push(a),a},async removeGroupMember(s,o){d=d.filter(n=>!(n.groupId===s&&n.userId===o))},async listAllowlist(){return[...m]},async addAllowlistEntry(s){let o={id:Math.max(...m.map(n=>n.id),0)+1,pattern:s.pattern,type:s.type,description:s.description};return m.push(o),o},async removeAllowlistEntry(s){m=m.filter(o=>o.id!==s)}}}var H=new Map([["createUser","create"],["updateUser","update"],["toggleUserActive","update"],["createGroup","create"],["updateGroup","update"],["deleteGroup","delete"],["addGroupMember","create"],["removeGroupMember","delete"],["addAllowlistEntry","create"],["removeAllowlistEntry","delete"]]);function A(r,i){let t=r.get(i),d=Number(t);if(t===null||String(t).trim()===""||!Number.isInteger(d)||d<=0)throw new Error(`Invalid or missing "${i}"`);return d}function S(r,i){let t=String(r.get(i)??"").trim();if(t==="")throw new Error(`Invalid or missing "${i}"`);return t}function I(r,i){let t=String(r.get(i)??"").trim();return t===""?void 0:t}function Q(r){let i=G(r.labels);async function t({request:s}){await r.guards.requireAccess(s,{action:"read",intent:"loader"});let n=new URL(s.url).pathname.split("/").filter(Boolean),a=n[n.length-1]??"users",[l,x,u,w,g]=await Promise.all([r.store.listUsers(),r.store.listGroups(),r.store.listGroupMembers(),r.store.listAllowlist(),r.getMyPermissions?r.getMyPermissions(s).catch(y=>(console.error("[@aiquants/auth-react-router] getMyPermissions failed; rendering the permission badge as unknown:",y),null)):Promise.resolve(null)]);return{resourceLabels:r.resourceLabels,segment:["groups","group_members","allowlist"].includes(a)?a:"users",users:l,groups:x,groupMembers:u,allowlist:w,myPermissions:g,labels:i}}async function d({request:s}){let o=await s.formData(),n=String(o.get("intent")??""),a=H.get(n);if(!a)return{ok:!1,error:`Unknown intent: ${n}`};await r.guards.requireAccess(s,{action:a,intent:n});try{return await m(n,o)}catch(l){if(l instanceof Response)throw l;return{ok:!1,error:l instanceof Error?l.message:String(l)}}}async function m(s,o){if(s==="createUser")return await r.store.createUser({displayName:S(o,"displayName"),email:S(o,"email")}),{ok:!0};if(s==="updateUser")return await r.store.updateUser(A(o,"userId"),{displayName:S(o,"displayName"),email:S(o,"email")}),{ok:!0};if(s==="toggleUserActive"){let n=String(o.get("isActive")??"");if(n!=="true"&&n!=="false")throw new Error('Invalid or missing "isActive"');return await r.store.toggleUserActive(A(o,"userId"),n==="true"),{ok:!0}}if(s==="createGroup")return await r.store.createGroup({groupKey:S(o,"groupKey"),name:S(o,"name"),description:I(o,"description")}),{ok:!0};if(s==="updateGroup")return await r.store.updateGroup(A(o,"groupId"),{name:S(o,"name"),description:I(o,"description")}),{ok:!0};if(s==="deleteGroup")return await r.store.deleteGroup(A(o,"groupId")),{ok:!0};if(s==="addGroupMember")return await r.store.addGroupMember(A(o,"groupId"),A(o,"userId")),{ok:!0};if(s==="removeGroupMember")return await r.store.removeGroupMember(A(o,"groupId"),A(o,"userId")),{ok:!0};if(s==="addAllowlistEntry"){let n=o.get("type")==="domain"?"domain":"email";return await r.store.addAllowlistEntry({pattern:S(o,"pattern"),type:n,description:I(o,"description")}),{ok:!0}}return s==="removeAllowlistEntry"?(await r.store.removeAllowlistEntry(A(o,"entryId")),{ok:!0}):{ok:!1,error:`Unknown intent: ${s}`}}return{loader:t,action:d}}var C=require("react-router");var b=require("react/jsx-runtime");function M({label:r,summary:i}){return(0,b.jsxs)("span",{style:{display:"inline-flex",alignItems:"center",gap:"0.18rem",fontSize:"0.65rem",padding:"0.08rem 0.35rem",borderRadius:"9999px",backgroundColor:i.bgColor,color:i.color,border:`1px solid ${i.borderColor}`,fontWeight:600,lineHeight:"1.2"},children:[(0,b.jsxs)("span",{children:[r,":"]}),(0,b.jsx)("span",{children:i.text})]})}function P({children:r,renderHeader:i}){let t=(0,C.useLoaderData)(),d=t?.segment??"users",m=t?.labels??v,s=t?.myPermissions??null,o=t?.resourceLabels??{},n=g=>Object.hasOwn(o,g)?o[g]:g,a=[{key:"users",label:m.tabs.users,href:"/users"},{key:"groups",label:m.tabs.groups,href:"/users/groups"},{key:"group_members",label:m.tabs.groupMembers,href:"/users/group_members"},{key:"allowlist",label:m.tabs.allowlist,href:"/users/allowlist"}],l=Object.entries(s??{}),x=g=>g?.canWrite?{text:"\u7DE8\u96C6\u53EF",color:"#047857",bgColor:"#ecfdf5",borderColor:"#a7f3d0"}:g?.canRead?{text:"\u95B2\u89A7\u306E\u307F",color:"#1d4ed8",bgColor:"#eff6ff",borderColor:"#bfdbfe"}:{text:"\u6A29\u9650\u306A\u3057",color:"#64748b",bgColor:"#f1f5f9",borderColor:"#cbd5e1"},u={text:"\u6A29\u9650\u4E0D\u660E",color:"#92400e",bgColor:"#fffbeb",borderColor:"#fde68a"},w=(0,b.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:"0.4rem"},"data-testid":"user-admin-header-annotation",children:[(0,b.jsx)("span",{style:{fontSize:"0.75rem",backgroundColor:"#e0f2fe",color:"#0369a1",padding:"2px 8px",borderRadius:"12px",fontWeight:600},children:m.heading}),(0,b.jsxs)("div",{style:{display:"inline-flex",alignItems:"center",gap:"0.25rem",fontSize:"0.68rem",color:"#475569"},"data-testid":"user-admin-permissions-badge",children:[(0,b.jsx)("span",{style:{fontWeight:600,color:"#334155"},children:"\u3042\u306A\u305F\u306E\u6A29\u9650:"}),(0,b.jsx)("span",{style:{display:"inline-flex",alignItems:"center",gap:"0.18rem"},children:l.length===0?(0,b.jsx)("span",{"data-testid":"user-admin-permission-unavailable",children:(0,b.jsx)(M,{label:m.heading,summary:u})}):l.map(([g,y])=>(0,b.jsx)(M,{label:n(g),summary:x(y)},g))})]})]});return(0,b.jsxs)("div",{"data-testid":"user-admin-shell",style:{width:"100%",minHeight:"100vh",backgroundColor:"#f8fafc",padding:"1.5rem",boxSizing:"border-box"},children:[i?i({title:m.title,annotation:w}):(0,b.jsxs)("div",{style:{marginBottom:"1.5rem",display:"flex",justifyContent:"space-between",alignItems:"center"},children:[(0,b.jsx)("h1",{style:{margin:0,fontSize:"1.5rem",fontWeight:700,color:"#0f172a"},children:m.title}),w]}),(0,b.jsx)("div",{style:{display:"flex",gap:"0.5rem",marginBottom:"1.2rem",borderBottom:"2px solid #e2e8f0",paddingBottom:"0.5rem"},children:a.map(g=>{let y=d===g.key;return(0,b.jsx)(C.Link,{to:g.href,"data-testid":`user-admin-tab-${g.key}`,style:{padding:"0.5rem 1rem",borderRadius:"6px 6px 0 0",fontSize:"0.88rem",fontWeight:y?700:500,color:y?"#0284c7":"#64748b",backgroundColor:y?"#ffffff":"transparent",textDecoration:"none",borderBottom:y?"3px solid #0284c7":"3px solid transparent",transition:"all 0.15s ease"},children:g.label},g.key)})}),(0,b.jsx)("main",{children:r})]})}var f=require("react"),h=require("react-router");var e=require("react/jsx-runtime");function U({fetcher:r}){let i=r.data;return i?.ok!==!1||!i.error?null:(0,e.jsx)("div",{"data-testid":"user-admin-action-error",role:"alert",style:{padding:"0.7rem 1rem",borderRadius:"6px",border:"1px solid #fecaca",backgroundColor:"#fef2f2",color:"#b91c1c",fontSize:"0.85rem"},children:i.error})}function z(){let r=(0,h.useLoaderData)(),i=(0,h.useFetcher)(),t=r.labels??v,[d,m]=(0,f.useState)(""),[s,o]=(0,f.useState)(null),[n,a]=(0,f.useState)(!1),[l,x]=(0,f.useState)(""),[u,w]=(0,f.useState)(""),g=r.users.filter(p=>p.displayName.toLowerCase().includes(d.toLowerCase())||p.email.toLowerCase().includes(d.toLowerCase())),y=p=>{i.submit({intent:"toggleUserActive",userId:String(p.id),isActive:String(!p.isActive)},{method:"post"})},k=p=>{p.preventDefault(),l&&u&&(i.submit({intent:"createUser",displayName:l,email:u},{method:"post"}),x(""),w(""),a(!1))},V=p=>{p.preventDefault(),s&&(i.submit({intent:"updateUser",userId:String(s.id),displayName:s.displayName,email:s.email},{method:"post"}),o(null))};return(0,e.jsxs)("section",{"data-testid":"users-view-section",style:{display:"flex",flexDirection:"column",gap:"1rem"},children:[(0,e.jsx)(U,{fetcher:i}),(0,e.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",backgroundColor:"#ffffff",padding:"1rem",borderRadius:"8px",border:"1px solid #e2e8f0"},children:[(0,e.jsx)("input",{type:"text",placeholder:t.usersView.searchPlaceholder,value:d,onChange:p=>m(p.target.value),"data-testid":"users-search-input",style:{padding:"6px 12px",borderRadius:"6px",border:"1px solid #cbd5e1",fontSize:"0.85rem",width:"260px"}}),(0,e.jsx)("button",{type:"button",onClick:()=>a(!0),"data-testid":"users-add-button",style:{padding:"6px 14px",borderRadius:"6px",backgroundColor:"#0284c7",color:"#ffffff",border:"none",fontSize:"0.85rem",fontWeight:600,cursor:"pointer"},children:t.usersView.addUser})]}),(0,e.jsx)("div",{style:{backgroundColor:"#ffffff",borderRadius:"8px",border:"1px solid #e2e8f0",overflow:"hidden"},children:(0,e.jsxs)("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:"0.85rem",textAlign:"left"},children:[(0,e.jsx)("thead",{children:(0,e.jsxs)("tr",{style:{backgroundColor:"#f8fafc",borderBottom:"1px solid #e2e8f0",color:"#475569"},children:[(0,e.jsx)("th",{style:{padding:"10px 14px"},children:t.usersView.id}),(0,e.jsx)("th",{style:{padding:"10px 14px"},children:t.usersView.displayName}),(0,e.jsx)("th",{style:{padding:"10px 14px"},children:t.usersView.email}),(0,e.jsx)("th",{style:{padding:"10px 14px"},children:t.usersView.status}),(0,e.jsx)("th",{style:{padding:"10px 14px",textAlign:"right"},children:t.usersView.actions})]})}),(0,e.jsxs)("tbody",{children:[g.map(p=>(0,e.jsxs)("tr",{style:{borderBottom:"1px solid #f1f5f9"},"data-testid":`user-row-${p.id}`,children:[(0,e.jsxs)("td",{style:{padding:"10px 14px",color:"#64748b"},children:["#",p.id]}),(0,e.jsx)("td",{style:{padding:"10px 14px",fontWeight:600,color:"#0f172a"},children:p.displayName}),(0,e.jsx)("td",{style:{padding:"10px 14px",color:"#475569"},children:p.email}),(0,e.jsx)("td",{style:{padding:"10px 14px"},children:(0,e.jsx)("span",{style:{fontSize:"0.75rem",padding:"2px 8px",borderRadius:"10px",backgroundColor:p.isActive?"#dcfce7":"#fee2e2",color:p.isActive?"#15803d":"#b91c1c",fontWeight:600},children:p.isActive?t.usersView.active:t.usersView.inactive})}),(0,e.jsxs)("td",{style:{padding:"10px 14px",textAlign:"right"},children:[(0,e.jsx)("button",{type:"button",onClick:()=>o(p),"data-testid":`edit-user-btn-${p.id}`,style:{padding:"3px 8px",borderRadius:"4px",border:"1px solid #cbd5e1",backgroundColor:"#ffffff",fontSize:"0.78rem",cursor:"pointer",marginRight:"6px"},children:t.usersView.edit}),(0,e.jsx)("button",{type:"button",onClick:()=>y(p),"data-testid":`toggle-user-btn-${p.id}`,style:{padding:"3px 8px",borderRadius:"4px",border:"1px solid #cbd5e1",backgroundColor:"#ffffff",fontSize:"0.78rem",cursor:"pointer",color:p.isActive?"#b91c1c":"#15803d"},children:p.isActive?t.usersView.deactivate:t.usersView.activate})]})]},p.id)),g.length===0&&(0,e.jsx)("tr",{children:(0,e.jsx)("td",{colSpan:5,style:{padding:"2rem",textAlign:"center",color:"#94a3b8"},children:t.usersView.empty})})]})]})}),n&&(0,e.jsx)("div",{style:{position:"fixed",inset:0,backgroundColor:"rgba(0,0,0,0.4)",display:"flex",justifyContent:"center",alignItems:"center",zIndex:100},"data-testid":"user-create-modal",children:(0,e.jsxs)("form",{onSubmit:k,style:{backgroundColor:"#ffffff",padding:"1.5rem",borderRadius:"8px",width:"360px",boxShadow:"0 10px 25px rgba(0,0,0,0.15)"},children:[(0,e.jsx)("h3",{style:{margin:"0 0 1rem 0",fontSize:"1.1rem"},children:t.usersView.addUser}),(0,e.jsxs)("div",{style:{marginBottom:"1rem"},children:[(0,e.jsx)("label",{htmlFor:"create-user-display-name-input",style:{display:"block",fontSize:"0.8rem",color:"#475569",marginBottom:"4px"},children:t.usersView.displayName}),(0,e.jsx)("input",{id:"create-user-display-name-input",type:"text",value:l,onChange:p=>x(p.target.value),required:!0,"data-testid":"create-user-display-name",style:{width:"100%",padding:"6px",borderRadius:"4px",border:"1px solid #cbd5e1",boxSizing:"border-box"}})]}),(0,e.jsxs)("div",{style:{marginBottom:"1.2rem"},children:[(0,e.jsx)("label",{htmlFor:"create-user-email-input",style:{display:"block",fontSize:"0.8rem",color:"#475569",marginBottom:"4px"},children:t.usersView.email}),(0,e.jsx)("input",{id:"create-user-email-input",type:"email",value:u,onChange:p=>w(p.target.value),required:!0,"data-testid":"create-user-email",style:{width:"100%",padding:"6px",borderRadius:"4px",border:"1px solid #cbd5e1",boxSizing:"border-box"}})]}),(0,e.jsxs)("div",{style:{display:"flex",justifyContent:"flex-end",gap:"0.5rem"},children:[(0,e.jsx)("button",{type:"button",onClick:()=>a(!1),style:{padding:"6px 12px",borderRadius:"4px",border:"1px solid #cbd5e1",backgroundColor:"#ffffff",cursor:"pointer"},children:"\u30AD\u30E3\u30F3\u30BB\u30EB"}),(0,e.jsx)("button",{type:"submit","data-testid":"submit-create-user",style:{padding:"6px 12px",borderRadius:"4px",backgroundColor:"#0284c7",color:"#ffffff",border:"none",cursor:"pointer"},children:"\u4F5C\u6210"})]})]})}),s&&(0,e.jsx)("div",{style:{position:"fixed",inset:0,backgroundColor:"rgba(0,0,0,0.4)",display:"flex",justifyContent:"center",alignItems:"center",zIndex:100},"data-testid":"user-edit-modal",children:(0,e.jsxs)("form",{onSubmit:V,style:{backgroundColor:"#ffffff",padding:"1.5rem",borderRadius:"8px",width:"360px",boxShadow:"0 10px 25px rgba(0,0,0,0.15)"},children:[(0,e.jsx)("h3",{style:{margin:"0 0 1rem 0",fontSize:"1.1rem"},children:t.usersView.editUser}),(0,e.jsxs)("div",{style:{marginBottom:"1rem"},children:[(0,e.jsx)("label",{htmlFor:"edit-user-display-name-input",style:{display:"block",fontSize:"0.8rem",color:"#475569",marginBottom:"4px"},children:t.usersView.displayName}),(0,e.jsx)("input",{id:"edit-user-display-name-input",type:"text",value:s.displayName,onChange:p=>o({...s,displayName:p.target.value}),required:!0,"data-testid":"edit-user-display-name",style:{width:"100%",padding:"6px",borderRadius:"4px",border:"1px solid #cbd5e1",boxSizing:"border-box"}})]}),(0,e.jsxs)("div",{style:{marginBottom:"1.2rem"},children:[(0,e.jsx)("label",{htmlFor:"edit-user-email-input",style:{display:"block",fontSize:"0.8rem",color:"#475569",marginBottom:"4px"},children:t.usersView.email}),(0,e.jsx)("input",{id:"edit-user-email-input",type:"email",value:s.email,onChange:p=>o({...s,email:p.target.value}),required:!0,"data-testid":"edit-user-email",style:{width:"100%",padding:"6px",borderRadius:"4px",border:"1px solid #cbd5e1",boxSizing:"border-box"}})]}),(0,e.jsxs)("div",{style:{display:"flex",justifyContent:"flex-end",gap:"0.5rem"},children:[(0,e.jsx)("button",{type:"button",onClick:()=>o(null),style:{padding:"6px 12px",borderRadius:"4px",border:"1px solid #cbd5e1",backgroundColor:"#ffffff",cursor:"pointer"},children:t.usersView.cancel}),(0,e.jsx)("button",{type:"submit","data-testid":"submit-edit-user",style:{padding:"6px 12px",borderRadius:"4px",backgroundColor:"#0284c7",color:"#ffffff",border:"none",cursor:"pointer"},children:t.usersView.save})]})]})})]})}function E(){let r=(0,h.useLoaderData)(),i=(0,h.useFetcher)(),t=r.labels??v,[d,m]=(0,f.useState)(""),[s,o]=(0,f.useState)(!1),[n,a]=(0,f.useState)(null),[l,x]=(0,f.useState)(""),[u,w]=(0,f.useState)(""),[g,y]=(0,f.useState)(""),k=r.groups.filter(c=>c.name.toLowerCase().includes(d.toLowerCase())||c.groupKey.toLowerCase().includes(d.toLowerCase())),V=c=>{c.preventDefault(),l&&u&&(i.submit({intent:"createGroup",groupKey:l,name:u,description:g},{method:"post"}),x(""),w(""),y(""),o(!1))},p=c=>{c.preventDefault(),n&&(i.submit({intent:"updateGroup",groupId:String(n.id),name:n.name,description:n.description??""},{method:"post"}),a(null))},B=c=>{window.confirm(t.groupsView.confirmDelete)&&i.submit({intent:"deleteGroup",groupId:String(c)},{method:"post"})};return(0,e.jsxs)("section",{"data-testid":"groups-view-section",style:{display:"flex",flexDirection:"column",gap:"1rem"},children:[(0,e.jsx)(U,{fetcher:i}),(0,e.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",backgroundColor:"#ffffff",padding:"1rem",borderRadius:"8px",border:"1px solid #e2e8f0"},children:[(0,e.jsx)("input",{type:"text",placeholder:t.groupsView.searchPlaceholder,value:d,onChange:c=>m(c.target.value),"data-testid":"groups-search-input",style:{padding:"6px 12px",borderRadius:"6px",border:"1px solid #cbd5e1",fontSize:"0.85rem",width:"260px"}}),(0,e.jsx)("button",{type:"button",onClick:()=>o(!0),"data-testid":"groups-add-button",style:{padding:"6px 14px",borderRadius:"6px",backgroundColor:"#4338ca",color:"#ffffff",border:"none",fontSize:"0.85rem",fontWeight:600,cursor:"pointer"},children:t.groupsView.addGroup})]}),(0,e.jsx)("div",{style:{display:"grid",gridTemplateColumns:"repeat(auto-fill, minmax(280px, 1fr))",gap:"1rem"},children:k.map(c=>{let D=r.groupMembers.filter(T=>T.groupId===c.id).length;return(0,e.jsxs)("div",{style:{backgroundColor:"#ffffff",borderRadius:"8px",border:"1px solid #e2e8f0",padding:"1rem",display:"flex",flexDirection:"column",justifyContent:"space-between"},"data-testid":`group-card-${c.id}`,children:[(0,e.jsxs)("div",{children:[(0,e.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"0.5rem"},children:[(0,e.jsx)("h4",{style:{margin:0,fontSize:"1rem",color:"#0f172a"},children:c.name}),(0,e.jsx)("span",{style:{fontSize:"0.72rem",backgroundColor:"#e0e7ff",color:"#4338ca",padding:"2px 6px",borderRadius:"4px",fontFamily:"monospace"},children:c.groupKey})]}),(0,e.jsx)("p",{style:{margin:"0 0 0.8rem 0",fontSize:"0.82rem",color:"#64748b",minHeight:"2.4em"},children:c.description||t.groupsView.noDescription})]}),(0,e.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",borderTop:"1px solid #f1f5f9",paddingTop:"0.6rem"},children:[(0,e.jsxs)("span",{style:{fontSize:"0.78rem",color:"#475569"},children:["\u{1F465} \u30E1\u30F3\u30D0\u30FC: ",(0,e.jsx)("strong",{children:D})," \u4EBA"]}),(0,e.jsxs)("div",{children:[(0,e.jsx)("button",{type:"button",onClick:()=>a(c),"data-testid":`edit-group-btn-${c.id}`,style:{padding:"3px 8px",borderRadius:"4px",border:"1px solid #cbd5e1",backgroundColor:"#ffffff",fontSize:"0.75rem",cursor:"pointer",marginRight:"4px"},children:t.usersView.edit}),(0,e.jsx)("button",{type:"button",onClick:()=>B(c.id),"data-testid":`delete-group-btn-${c.id}`,style:{padding:"3px 8px",borderRadius:"4px",border:"1px solid #fee2e2",backgroundColor:"#fff5f5",color:"#b91c1c",fontSize:"0.75rem",cursor:"pointer"},children:"\u524A\u9664"})]})]})]},c.id)})}),s&&(0,e.jsx)("div",{style:{position:"fixed",inset:0,backgroundColor:"rgba(0,0,0,0.4)",display:"flex",justifyContent:"center",alignItems:"center",zIndex:100},"data-testid":"group-create-modal",children:(0,e.jsxs)("form",{onSubmit:V,style:{backgroundColor:"#ffffff",padding:"1.5rem",borderRadius:"8px",width:"360px",boxShadow:"0 10px 25px rgba(0,0,0,0.15)"},children:[(0,e.jsx)("h3",{style:{margin:"0 0 1rem 0",fontSize:"1.1rem"},children:t.groupsView.addGroup}),(0,e.jsxs)("div",{style:{marginBottom:"1rem"},children:[(0,e.jsx)("label",{htmlFor:"create-group-key-input",style:{display:"block",fontSize:"0.8rem",color:"#475569",marginBottom:"4px"},children:t.groupsView.groupKey}),(0,e.jsx)("input",{id:"create-group-key-input",type:"text",value:l,onChange:c=>x(c.target.value),placeholder:t.groupsView.groupKeyPlaceholder,required:!0,"data-testid":"create-group-key",style:{width:"100%",padding:"6px",borderRadius:"4px",border:"1px solid #cbd5e1",boxSizing:"border-box"}})]}),(0,e.jsxs)("div",{style:{marginBottom:"1rem"},children:[(0,e.jsx)("label",{htmlFor:"create-group-name-input",style:{display:"block",fontSize:"0.8rem",color:"#475569",marginBottom:"4px"},children:t.groupsView.name}),(0,e.jsx)("input",{id:"create-group-name-input",type:"text",value:u,onChange:c=>w(c.target.value),placeholder:t.groupsView.namePlaceholder,required:!0,"data-testid":"create-group-name",style:{width:"100%",padding:"6px",borderRadius:"4px",border:"1px solid #cbd5e1",boxSizing:"border-box"}})]}),(0,e.jsxs)("div",{style:{marginBottom:"1.2rem"},children:[(0,e.jsx)("label",{htmlFor:"create-group-desc-input",style:{display:"block",fontSize:"0.8rem",color:"#475569",marginBottom:"4px"},children:t.groupsView.description}),(0,e.jsx)("textarea",{id:"create-group-desc-input",value:g,onChange:c=>y(c.target.value),"data-testid":"create-group-description",style:{width:"100%",padding:"6px",borderRadius:"4px",border:"1px solid #cbd5e1",boxSizing:"border-box",height:"60px"}})]}),(0,e.jsxs)("div",{style:{display:"flex",justifyContent:"flex-end",gap:"0.5rem"},children:[(0,e.jsx)("button",{type:"button",onClick:()=>o(!1),style:{padding:"6px 12px",borderRadius:"4px",border:"1px solid #cbd5e1",backgroundColor:"#ffffff",cursor:"pointer"},children:"\u30AD\u30E3\u30F3\u30BB\u30EB"}),(0,e.jsx)("button",{type:"submit","data-testid":"submit-create-group",style:{padding:"6px 12px",borderRadius:"4px",backgroundColor:"#4338ca",color:"#ffffff",border:"none",cursor:"pointer"},children:"\u4F5C\u6210"})]})]})}),n&&(0,e.jsx)("div",{style:{position:"fixed",inset:0,backgroundColor:"rgba(0,0,0,0.4)",display:"flex",justifyContent:"center",alignItems:"center",zIndex:100},"data-testid":"group-edit-modal",children:(0,e.jsxs)("form",{onSubmit:p,style:{backgroundColor:"#ffffff",padding:"1.5rem",borderRadius:"8px",width:"360px",boxShadow:"0 10px 25px rgba(0,0,0,0.15)"},children:[(0,e.jsx)("h3",{style:{margin:"0 0 1rem 0",fontSize:"1.1rem"},children:t.groupsView.editGroup}),(0,e.jsxs)("div",{style:{marginBottom:"1rem"},children:[(0,e.jsx)("label",{htmlFor:"edit-group-name-input",style:{display:"block",fontSize:"0.8rem",color:"#475569",marginBottom:"4px"},children:t.groupsView.name}),(0,e.jsx)("input",{id:"edit-group-name-input",type:"text",value:n.name,onChange:c=>a({...n,name:c.target.value}),required:!0,"data-testid":"edit-group-name",style:{width:"100%",padding:"6px",borderRadius:"4px",border:"1px solid #cbd5e1",boxSizing:"border-box"}})]}),(0,e.jsxs)("div",{style:{marginBottom:"1.2rem"},children:[(0,e.jsx)("label",{htmlFor:"edit-group-desc-input",style:{display:"block",fontSize:"0.8rem",color:"#475569",marginBottom:"4px"},children:t.groupsView.description}),(0,e.jsx)("textarea",{id:"edit-group-desc-input",value:n.description??"",onChange:c=>a({...n,description:c.target.value}),"data-testid":"edit-group-description",style:{width:"100%",padding:"6px",borderRadius:"4px",border:"1px solid #cbd5e1",boxSizing:"border-box",height:"60px"}})]}),(0,e.jsxs)("div",{style:{display:"flex",justifyContent:"flex-end",gap:"0.5rem"},children:[(0,e.jsx)("button",{type:"button",onClick:()=>a(null),style:{padding:"6px 12px",borderRadius:"4px",border:"1px solid #cbd5e1",backgroundColor:"#ffffff",cursor:"pointer"},children:t.groupsView.cancel}),(0,e.jsx)("button",{type:"submit","data-testid":"submit-edit-group",style:{padding:"6px 12px",borderRadius:"4px",backgroundColor:"#4338ca",color:"#ffffff",border:"none",cursor:"pointer"},children:t.groupsView.save})]})]})})]})}function N(){let r=(0,h.useLoaderData)(),i=(0,h.useFetcher)(),t=r.labels??v,[d,m]=(0,f.useState)(r.groups[0]?.id??0),s=r.groups.find(a=>a.id===d),o=new Set(r.groupMembers.filter(a=>a.groupId===d).map(a=>a.userId)),n=(a,l)=>{l?i.submit({intent:"removeGroupMember",groupId:String(d),userId:String(a)},{method:"post"}):i.submit({intent:"addGroupMember",groupId:String(d),userId:String(a)},{method:"post"})};return(0,e.jsxs)("section",{"data-testid":"group-members-view-section",style:{display:"grid",gridTemplateColumns:"240px 1fr",gap:"1.2rem"},children:[(0,e.jsx)(U,{fetcher:i}),(0,e.jsxs)("div",{style:{backgroundColor:"#ffffff",padding:"1rem",borderRadius:"8px",border:"1px solid #e2e8f0"},children:[(0,e.jsx)("h4",{style:{margin:"0 0 0.8rem 0",fontSize:"0.9rem",color:"#475569"},children:t.groupMembersView.selectGroup}),(0,e.jsx)("div",{style:{display:"flex",flexDirection:"column",gap:"0.4rem"},children:r.groups.map(a=>{let l=a.id===d;return(0,e.jsx)("button",{type:"button",onClick:()=>m(a.id),"data-testid":`select-group-btn-${a.id}`,style:{textAlign:"left",padding:"8px 10px",borderRadius:"6px",border:l?"1px solid #6366f1":"1px solid #e2e8f0",backgroundColor:l?"#e0e7ff":"#ffffff",color:l?"#3730a3":"#0f172a",cursor:"pointer",fontWeight:l?600:400,fontSize:"0.85rem"},children:a.name},a.id)})})]}),(0,e.jsx)("div",{style:{backgroundColor:"#ffffff",padding:"1.2rem",borderRadius:"8px",border:"1px solid #e2e8f0"},children:s?(0,e.jsxs)(e.Fragment,{children:[(0,e.jsxs)("div",{style:{marginBottom:"1rem",borderBottom:"1px solid #e2e8f0",paddingBottom:"0.8rem"},children:[(0,e.jsxs)("h3",{style:{margin:0,fontSize:"1.1rem",color:"#0f172a"},children:[s.name," \u306E\u6240\u5C5E\u30E1\u30F3\u30D0\u30FC"]}),(0,e.jsxs)("span",{style:{fontSize:"0.8rem",color:"#64748b"},children:["\u30B0\u30EB\u30FC\u30D7\u30AD\u30FC: ",s.groupKey]})]}),(0,e.jsx)("div",{style:{display:"flex",flexDirection:"column",gap:"0.5rem"},children:r.users.map(a=>{let l=o.has(a.id);return(0,e.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"8px 12px",borderRadius:"6px",border:"1px solid #f1f5f9",backgroundColor:l?"#f0fdf4":"#ffffff"},"data-testid":`member-row-${a.id}`,children:[(0,e.jsxs)("div",{children:[(0,e.jsx)("span",{style:{fontWeight:600,fontSize:"0.88rem",color:"#0f172a",marginRight:"8px"},children:a.displayName}),(0,e.jsxs)("span",{style:{fontSize:"0.78rem",color:"#64748b"},children:["(",a.email,")"]})]}),(0,e.jsx)("button",{type:"button",onClick:()=>n(a.id,l),"data-testid":`toggle-member-btn-${a.id}`,style:{padding:"4px 12px",borderRadius:"4px",border:l?"1px solid #b91c1c":"1px solid #0284c7",backgroundColor:l?"#ffffff":"#0284c7",color:l?"#b91c1c":"#ffffff",fontSize:"0.78rem",fontWeight:600,cursor:"pointer"},children:l?t.groupMembersView.actionRemove:t.groupMembersView.actionAdd})]},a.id)})})]}):(0,e.jsx)("div",{style:{color:"#94a3b8",textAlign:"center",padding:"2rem"},children:t.groupMembersView.selectPrompt})})]})}function L(){let r=(0,h.useLoaderData)(),i=(0,h.useFetcher)(),t=r.labels??v,[d,m]=(0,f.useState)(""),[s,o]=(0,f.useState)("email"),[n,a]=(0,f.useState)(""),l=u=>{u.preventDefault(),d&&(i.submit({intent:"addAllowlistEntry",pattern:d,type:s,description:n},{method:"post"}),m(""),a(""))},x=u=>{i.submit({intent:"removeAllowlistEntry",entryId:String(u)},{method:"post"})};return(0,e.jsxs)("section",{"data-testid":"allowlist-view-section",style:{display:"flex",flexDirection:"column",gap:"1.2rem"},children:[(0,e.jsx)(U,{fetcher:i}),(0,e.jsxs)("form",{onSubmit:l,style:{backgroundColor:"#ffffff",padding:"1.2rem",borderRadius:"8px",border:"1px solid #e2e8f0",display:"flex",flexWrap:"wrap",gap:"0.8rem",alignItems:"flex-end"},children:[(0,e.jsxs)("div",{style:{flex:2,minWidth:"220px"},children:[(0,e.jsx)("label",{htmlFor:"allowlist-pattern-input-field",style:{display:"block",fontSize:"0.78rem",color:"#475569",marginBottom:"4px"},children:t.allowlistView.pattern}),(0,e.jsx)("input",{id:"allowlist-pattern-input-field",type:"text",value:d,onChange:u=>m(u.target.value),required:!0,"data-testid":"allowlist-pattern-input",style:{width:"100%",padding:"6px 10px",borderRadius:"6px",border:"1px solid #cbd5e1",fontSize:"0.85rem",boxSizing:"border-box"}})]}),(0,e.jsxs)("div",{style:{flex:1,minWidth:"140px"},children:[(0,e.jsx)("label",{htmlFor:"allowlist-type-select-field",style:{display:"block",fontSize:"0.78rem",color:"#475569",marginBottom:"4px"},children:t.allowlistView.type}),(0,e.jsxs)("select",{id:"allowlist-type-select-field",value:s,onChange:u=>o(u.target.value),"data-testid":"allowlist-type-select",style:{width:"100%",padding:"6px 10px",borderRadius:"6px",border:"1px solid #cbd5e1",fontSize:"0.85rem",boxSizing:"border-box"},children:[(0,e.jsx)("option",{value:"email",children:t.allowlistView.emailType}),(0,e.jsx)("option",{value:"domain",children:t.allowlistView.domainType})]})]}),(0,e.jsxs)("div",{style:{flex:2,minWidth:"200px"},children:[(0,e.jsx)("label",{htmlFor:"allowlist-desc-input-field",style:{display:"block",fontSize:"0.78rem",color:"#475569",marginBottom:"4px"},children:t.allowlistView.description}),(0,e.jsx)("input",{id:"allowlist-desc-input-field",type:"text",value:n,onChange:u=>a(u.target.value),"data-testid":"allowlist-desc-input",style:{width:"100%",padding:"6px 10px",borderRadius:"6px",border:"1px solid #cbd5e1",fontSize:"0.85rem",boxSizing:"border-box"}})]}),(0,e.jsx)("button",{type:"submit","data-testid":"submit-allowlist-add",style:{padding:"7px 16px",borderRadius:"6px",backgroundColor:"#047857",color:"#ffffff",border:"none",fontSize:"0.85rem",fontWeight:600,cursor:"pointer"},children:t.allowlistView.addEntry})]}),(0,e.jsx)("div",{style:{backgroundColor:"#ffffff",borderRadius:"8px",border:"1px solid #e2e8f0",overflow:"hidden"},children:(0,e.jsxs)("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:"0.85rem",textAlign:"left"},children:[(0,e.jsx)("thead",{children:(0,e.jsxs)("tr",{style:{backgroundColor:"#f8fafc",borderBottom:"1px solid #e2e8f0",color:"#475569"},children:[(0,e.jsx)("th",{style:{padding:"10px 14px"},children:"ID"}),(0,e.jsx)("th",{style:{padding:"10px 14px"},children:t.allowlistView.pattern}),(0,e.jsx)("th",{style:{padding:"10px 14px"},children:t.allowlistView.type}),(0,e.jsx)("th",{style:{padding:"10px 14px"},children:t.allowlistView.description}),(0,e.jsx)("th",{style:{padding:"10px 14px",textAlign:"right"},children:t.allowlistView.actions})]})}),(0,e.jsxs)("tbody",{children:[r.allowlist.map(u=>(0,e.jsxs)("tr",{style:{borderBottom:"1px solid #f1f5f9"},"data-testid":`allowlist-row-${u.id}`,children:[(0,e.jsxs)("td",{style:{padding:"10px 14px",color:"#64748b"},children:["#",u.id]}),(0,e.jsx)("td",{style:{padding:"10px 14px",fontWeight:600,color:"#0f172a",fontFamily:"monospace"},children:u.pattern}),(0,e.jsx)("td",{style:{padding:"10px 14px"},children:(0,e.jsx)("span",{style:{fontSize:"0.75rem",padding:"2px 8px",borderRadius:"10px",backgroundColor:u.type==="email"?"#e0f2fe":"#fef3c7",color:u.type==="email"?"#0369a1":"#b45309",fontWeight:600},children:u.type==="email"?t.allowlistView.emailTypeShort:t.allowlistView.domainTypeShort})}),(0,e.jsx)("td",{style:{padding:"10px 14px",color:"#475569"},children:u.description||"-"}),(0,e.jsx)("td",{style:{padding:"10px 14px",textAlign:"right"},children:u.readOnly?(0,e.jsx)("span",{"data-testid":`readonly-allowlist-${u.id}`,style:{fontSize:"0.75rem",color:"#94a3b8"},children:t.allowlistView.readOnly}):(0,e.jsx)("button",{type:"button",onClick:()=>x(u.id),"data-testid":`remove-allowlist-btn-${u.id}`,style:{padding:"3px 8px",borderRadius:"4px",border:"1px solid #fee2e2",backgroundColor:"#fff5f5",color:"#b91c1c",fontSize:"0.78rem",cursor:"pointer"},children:"\u524A\u9664"})})]},u.id)),r.allowlist.length===0&&(0,e.jsx)("tr",{children:(0,e.jsx)("td",{colSpan:5,style:{padding:"2rem",textAlign:"center",color:"#94a3b8"},children:t.allowlistView.empty})})]})]})})]})}var J={users:z,groups:E,group_members:N,allowlist:L};function X({renderHeader:r}={}){let t=(0,h.useLoaderData)()?.segment??"users",d=J[t]??z;return(0,e.jsx)(P,{renderHeader:r,children:(0,e.jsx)(d,{})})}0&&(module.exports={AllowlistView,AuthUserAdminAppView,GroupMembersView,GroupsView,UserAdminShell,UsersView,createInMemoryUserAdminStore,createUserAdminApp,defaultUserAdminLabels,jaUserAdminLabels,resolveUserAdminLabels});
|
|
2
2
|
//# sourceMappingURL=admin.js.map
|