@endora-commerce/mod-admin-users 0.100.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/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/admin/index.d.ts +47 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +44 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/AdminRolesPage.d.ts +3 -0
- package/dist/admin/pages/AdminRolesPage.d.ts.map +1 -0
- package/dist/admin/pages/AdminRolesPage.js +180 -0
- package/dist/admin/pages/AdminRolesPage.js.map +1 -0
- package/dist/admin/pages/AdminUsersPage.d.ts +3 -0
- package/dist/admin/pages/AdminUsersPage.d.ts.map +1 -0
- package/dist/admin/pages/AdminUsersPage.js +151 -0
- package/dist/admin/pages/AdminUsersPage.js.map +1 -0
- package/dist/admin/permission-label.d.ts +26 -0
- package/dist/admin/permission-label.d.ts.map +1 -0
- package/dist/admin/permission-label.js +67 -0
- package/dist/admin/permission-label.js.map +1 -0
- package/dist/backend/cli/create-admin.d.ts +16 -0
- package/dist/backend/cli/create-admin.d.ts.map +1 -0
- package/dist/backend/cli/create-admin.js +101 -0
- package/dist/backend/cli/create-admin.js.map +1 -0
- package/dist/backend/demo/reset.d.ts +15 -0
- package/dist/backend/demo/reset.d.ts.map +1 -0
- package/dist/backend/demo/reset.js +13 -0
- package/dist/backend/demo/reset.js.map +1 -0
- package/dist/backend/demo/rows.d.ts +50 -0
- package/dist/backend/demo/rows.d.ts.map +1 -0
- package/dist/backend/demo/rows.js +73 -0
- package/dist/backend/demo/rows.js.map +1 -0
- package/dist/backend/demo/seed.d.ts +24 -0
- package/dist/backend/demo/seed.d.ts.map +1 -0
- package/dist/backend/demo/seed.js +43 -0
- package/dist/backend/demo/seed.js.map +1 -0
- package/dist/backend/entities/admin-user.entity.d.ts +44 -0
- package/dist/backend/entities/admin-user.entity.d.ts.map +1 -0
- package/dist/backend/entities/admin-user.entity.js +115 -0
- package/dist/backend/entities/admin-user.entity.js.map +1 -0
- package/dist/backend/index.d.ts +77 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +111 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/plugin.d.ts +70 -0
- package/dist/backend/plugin.d.ts.map +1 -0
- package/dist/backend/plugin.js +50 -0
- package/dist/backend/plugin.js.map +1 -0
- package/dist/backend/routes.admin.d.ts +32 -0
- package/dist/backend/routes.admin.d.ts.map +1 -0
- package/dist/backend/routes.admin.js +192 -0
- package/dist/backend/routes.admin.js.map +1 -0
- package/dist/backend/routes.impersonation.d.ts +25 -0
- package/dist/backend/routes.impersonation.d.ts.map +1 -0
- package/dist/backend/routes.impersonation.js +108 -0
- package/dist/backend/routes.impersonation.js.map +1 -0
- package/dist/backend/routes.public.d.ts +20 -0
- package/dist/backend/routes.public.d.ts.map +1 -0
- package/dist/backend/routes.public.js +75 -0
- package/dist/backend/routes.public.js.map +1 -0
- package/dist/backend/services/admin-auth-service.d.ts +47 -0
- package/dist/backend/services/admin-auth-service.d.ts.map +1 -0
- package/dist/backend/services/admin-auth-service.js +93 -0
- package/dist/backend/services/admin-auth-service.js.map +1 -0
- package/dist/backend/services/admin-user-ports.d.ts +75 -0
- package/dist/backend/services/admin-user-ports.d.ts.map +1 -0
- package/dist/backend/services/admin-user-ports.js +160 -0
- package/dist/backend/services/admin-user-ports.js.map +1 -0
- package/dist/backend/services/admin-user-service.d.ts +134 -0
- package/dist/backend/services/admin-user-service.d.ts.map +1 -0
- package/dist/backend/services/admin-user-service.js +241 -0
- package/dist/backend/services/admin-user-service.js.map +1 -0
- package/dist/backend/services/impersonation-service.d.ts +65 -0
- package/dist/backend/services/impersonation-service.d.ts.map +1 -0
- package/dist/backend/services/impersonation-service.js +103 -0
- package/dist/backend/services/impersonation-service.js.map +1 -0
- package/dist/backend/services/two-factor-enrolments.d.ts +19 -0
- package/dist/backend/services/two-factor-enrolments.d.ts.map +1 -0
- package/dist/backend/services/two-factor-enrolments.js +2 -0
- package/dist/backend/services/two-factor-enrolments.js.map +1 -0
- package/dist/manifest.d.ts +182 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +208 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260425T053028_admin_users_init.d.ts +11 -0
- package/dist/migrations/20260425T053028_admin_users_init.d.ts.map +1 -0
- package/dist/migrations/20260425T053028_admin_users_init.js +51 -0
- package/dist/migrations/20260425T053028_admin_users_init.js.map +1 -0
- package/dist/migrations/20260819T155150_admin_users_fold_email_case.d.ts +55 -0
- package/dist/migrations/20260819T155150_admin_users_fold_email_case.d.ts.map +1 -0
- package/dist/migrations/20260819T155150_admin_users_fold_email_case.js +106 -0
- package/dist/migrations/20260819T155150_admin_users_fold_email_case.js.map +1 -0
- package/dist/migrations/20260825T124801_admin_users_drop_legacy_two_factor_secret.d.ts +25 -0
- package/dist/migrations/20260825T124801_admin_users_drop_legacy_two_factor_secret.d.ts.map +1 -0
- package/dist/migrations/20260825T124801_admin_users_drop_legacy_two_factor_secret.js +29 -0
- package/dist/migrations/20260825T124801_admin_users_drop_legacy_two_factor_secret.js.map +1 -0
- package/dist/migrations/index.d.ts +29 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +33 -0
- package/dist/migrations/index.js.map +1 -0
- package/docs/admin_users.md +53 -0
- package/i18n/en.json +5 -0
- package/i18n/pl.json +5 -0
- package/package.json +100 -0
- package/tailwind.css +14 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Endora sp. z o.o. and the Endora Commerce contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<!-- Generated by `pnpm --filter backend run manifests:generate`. Delete this line to take the file over; a README without it is never regenerated. -->
|
|
2
|
+
|
|
3
|
+
# @endora-commerce/mod-admin-users
|
|
4
|
+
|
|
5
|
+
Admin user accounts, sessions, and impersonation flows.
|
|
6
|
+
|
|
7
|
+
## What this is
|
|
8
|
+
|
|
9
|
+
An **Endora Commerce module package**. Its module id is `admin_users` — the identity of record in the platform's registries, in its migrations and in its setting, permission and translation codes.
|
|
10
|
+
|
|
11
|
+
A module is not imported by application code. The platform discovers the extension packages an instance has installed, reads the manifest on the root subpath and composes the module from it, so installing this package and starting the instance is the whole integration.
|
|
12
|
+
|
|
13
|
+
## Entry points
|
|
14
|
+
|
|
15
|
+
| Import | Contents |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `@endora-commerce/mod-admin-users` | the module manifest — its id, version, dependencies, settings and activation |
|
|
18
|
+
| `@endora-commerce/mod-admin-users/admin` | the Admin UI contribution: the screens, navigation and palette actions it adds |
|
|
19
|
+
| `@endora-commerce/mod-admin-users/backend` | the composition root the platform calls, with the entities, services, routes and workers it registers |
|
|
20
|
+
| `@endora-commerce/mod-admin-users/migrations` | the module’s own schema migrations, in the order the platform runs them |
|
|
21
|
+
| `@endora-commerce/mod-admin-users/tailwind.css` | the Tailwind source declaration for the admin code above |
|
|
22
|
+
|
|
23
|
+
## Depends on
|
|
24
|
+
|
|
25
|
+
Everything below is a **peer** dependency, so the application resolves exactly one copy of each — two copies of a host or of React are a runtime failure rather than a type error. An entry marked *optional* is needed only by the layers that use it.
|
|
26
|
+
|
|
27
|
+
**Endora packages**
|
|
28
|
+
|
|
29
|
+
- `@endora-commerce/admin-kit` — *optional*
|
|
30
|
+
- `@endora-commerce/contracts`
|
|
31
|
+
- `@endora-commerce/platform`
|
|
32
|
+
|
|
33
|
+
**Third-party**
|
|
34
|
+
|
|
35
|
+
- `@fastify/cookie` ^11
|
|
36
|
+
- `@mikro-orm/core` ^6
|
|
37
|
+
- `@mikro-orm/migrations` ^6
|
|
38
|
+
- `@mikro-orm/postgresql` ^6
|
|
39
|
+
- `fastify` ^5
|
|
40
|
+
- `lucide-react` ^1 — *optional*
|
|
41
|
+
- `react` ^19 — *optional*
|
|
42
|
+
- `react-router-dom` ^7 — *optional*
|
|
43
|
+
|
|
44
|
+
## What the tarball carries
|
|
45
|
+
|
|
46
|
+
- `dist/` — the compiled JavaScript and its type declarations
|
|
47
|
+
- `i18n/` — the translation bundles this package ships (`en`, `pl`), loaded by the platform
|
|
48
|
+
- `docs/` — the package’s own pages in the Endora Commerce documentation site
|
|
49
|
+
- `tailwind.css` — the Tailwind source declaration
|
|
50
|
+
|
|
51
|
+
## Install
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pnpm add @endora-commerce/mod-admin-users
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Licence
|
|
58
|
+
|
|
59
|
+
MIT — the text is in `LICENSE`, beside this file.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `admin_users`' admin surface — **two routes and one sidebar entry**, declared
|
|
3
|
+
* by the module that owns them (feature 091, Phase 4, batch four;
|
|
4
|
+
* `specs/091-module-owned-admin-surfaces/contracts/admin-contribution.md`).
|
|
5
|
+
*
|
|
6
|
+
* **`/admin-roles`' route is here and its sidebar row is `admin_roles`', and
|
|
7
|
+
* that split is deliberate rather than an accident this batch preserved.** The
|
|
8
|
+
* admin's two hand-written registries disagreed about one screen: `App.tsx`
|
|
9
|
+
* imported `AdminRolesPage` out of `admin_users`' surface directory while
|
|
10
|
+
* `AppShell.tsx`'s row declared `module: 'admin_roles'`. `plan.md`'s open
|
|
11
|
+
* question 3 asked whether to force one attribution on both;
|
|
12
|
+
* `backend/scripts/ledgers/admin-registrations.ts` had already answered it for
|
|
13
|
+
* the ratchet — *"a route belongs to the module whose surface directory
|
|
14
|
+
* `App.tsx` imports its component from, and a nav entry to the `module` field
|
|
15
|
+
* it already carries"* — and the recommendation the plan makes is to keep
|
|
16
|
+
* exactly that, because the two facts are two different true statements. The
|
|
17
|
+
* screen is served by `GET /api/v1/admin/admin-roles` in **this** module's
|
|
18
|
+
* `routes.admin.ts`, so this module ships the route; the sidebar row is the
|
|
19
|
+
* *roles* capability's advertisement, so `admin_roles` ships that and the
|
|
20
|
+
* palette action beside it. Both modules declare `nonDeactivatable`, so the
|
|
21
|
+
* split is inert today and stops being inert the day either is unlocked — at
|
|
22
|
+
* which point switching `admin_roles` off withdraws the sidebar row and the
|
|
23
|
+
* palette entry while the deep link keeps working, which is the honest reading
|
|
24
|
+
* of two modules that genuinely own two halves.
|
|
25
|
+
*
|
|
26
|
+
* **`admin_users:manage` gates all three declarations, and it is read from the
|
|
27
|
+
* routes.** Every endpoint under `/api/v1/admin/admin-users` and
|
|
28
|
+
* `/api/v1/admin/admin-roles` enforces that one code
|
|
29
|
+
* (`packages/modules/admin_users/src/backend/routes.admin.ts`); there is no
|
|
30
|
+
* separate read code and no `admin_roles:*` code anywhere in the platform.
|
|
31
|
+
*
|
|
32
|
+
* **The locked-with-nav shape.** Batch two rejected this module for declaring
|
|
33
|
+
* `activation.nonDeactivatable`; `plan.md`'s Ruling 2 retires the ground and
|
|
34
|
+
* puts the off-state proof on the permission axis, which
|
|
35
|
+
* `useSurfaceVisibility` gates identically to presence —
|
|
36
|
+
* `admin/test/modules/admin-users.module-owned-surface.test.tsx` and
|
|
37
|
+
* `backend/test/integration/admin_users/off-state.test.ts`.
|
|
38
|
+
*
|
|
39
|
+
* **This entry exports data and nothing else** (R2), like every `./admin`
|
|
40
|
+
* layer: `check:module-boundary`'s D-171 rule designates a subpath as contract
|
|
41
|
+
* surface when it emits no runtime binding, and `./admin` deliberately does not
|
|
42
|
+
* qualify, so a consumer reaching into another module's `./admin` stays a
|
|
43
|
+
* counted boundary reach.
|
|
44
|
+
*/
|
|
45
|
+
import type { AdminContributions } from '@endora-commerce/admin-kit/contributions';
|
|
46
|
+
export declare const contributions: AdminContributions;
|
|
47
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AAanF,eAAO,MAAM,aAAa,EAAE,kBAiC3B,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** The module's landing route: the admin-user list. */
|
|
2
|
+
const USERS_PATH = '/admin-users';
|
|
3
|
+
/**
|
|
4
|
+
* The roles editor.
|
|
5
|
+
*
|
|
6
|
+
* Its route is this module's because the screen's API is; its sidebar entry and
|
|
7
|
+
* its palette action are `admin_roles`'. See the note above.
|
|
8
|
+
*/
|
|
9
|
+
const ROLES_PATH = '/admin-roles';
|
|
10
|
+
export const contributions = {
|
|
11
|
+
routes: [
|
|
12
|
+
{
|
|
13
|
+
path: USERS_PATH,
|
|
14
|
+
component: () => import('./pages/AdminUsersPage.js'),
|
|
15
|
+
requiredPermission: 'admin_users:manage',
|
|
16
|
+
index: true,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
path: ROLES_PATH,
|
|
20
|
+
component: () => import('./pages/AdminRolesPage.js'),
|
|
21
|
+
requiredPermission: 'admin_users:manage',
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
nav: [
|
|
25
|
+
{
|
|
26
|
+
to: USERS_PATH,
|
|
27
|
+
// Module-relative (R8), resolved in this module's own namespace out of
|
|
28
|
+
// `packages/modules/admin_users/i18n/`. It was `appShell.nav.users` in
|
|
29
|
+
// the shared `_i18n` bundle, one of the four shared files a module author
|
|
30
|
+
// had to edit.
|
|
31
|
+
labelKey: 'nav.adminUsers.label',
|
|
32
|
+
// The icon the hand-written NAV entry carried.
|
|
33
|
+
icon: 'Users',
|
|
34
|
+
section: 'system',
|
|
35
|
+
// The hand-written table's position times a hundred — see the note in
|
|
36
|
+
// `packages/modules/audit_logs/src/admin/index.ts`. `/admin-users` was
|
|
37
|
+
// second of thirteen, ahead of `/admin-roles` (300) and `/audit-log`
|
|
38
|
+
// (600), and that relative order is preserved.
|
|
39
|
+
weight: 200,
|
|
40
|
+
requiredPermission: 'admin_users:manage',
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AA8CA,uDAAuD;AACvD,MAAM,UAAU,GAAG,cAAc,CAAC;AAElC;;;;;GAKG;AACH,MAAM,UAAU,GAAG,cAAc,CAAC;AAElC,MAAM,CAAC,MAAM,aAAa,GAAuB;IAC/C,MAAM,EAAE;QACN;YACE,IAAI,EAAE,UAAU;YAChB,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,2BAA2B,CAAC;YACpD,kBAAkB,EAAE,oBAAoB;YACxC,KAAK,EAAE,IAAI;SACZ;QACD;YACE,IAAI,EAAE,UAAU;YAChB,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,2BAA2B,CAAC;YACpD,kBAAkB,EAAE,oBAAoB;SACzC;KACF;IACD,GAAG,EAAE;QACH;YACE,EAAE,EAAE,UAAU;YACd,uEAAuE;YACvE,uEAAuE;YACvE,0EAA0E;YAC1E,eAAe;YACf,QAAQ,EAAE,sBAAsB;YAChC,+CAA+C;YAC/C,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,QAAQ;YACjB,sEAAsE;YACtE,uEAAuE;YACvE,qEAAqE;YACrE,+CAA+C;YAC/C,MAAM,EAAE,GAAG;YACX,kBAAkB,EAAE,oBAAoB;SACzC;KACF;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminRolesPage.d.ts","sourceRoot":"","sources":["../../../src/admin/pages/AdminRolesPage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA6D,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAkDlG,MAAM,CAAC,OAAO,UAAU,cAAc,IAAI,SAAS,CAyLlD"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
3
|
+
import { Link } from 'react-router-dom';
|
|
4
|
+
import { Info, Plus, ShieldAlert } from 'lucide-react';
|
|
5
|
+
import { missingPermissionRequirements } from '@endora-commerce/contracts';
|
|
6
|
+
import { ApiError, apiClient, cn } from '@endora-commerce/admin-kit/lib';
|
|
7
|
+
import { Alert, AlertDescription, AlertTitle, Button, Card, CardContent, Checkbox, Input, Label, PageHeader, } from '@endora-commerce/admin-kit/ui';
|
|
8
|
+
import { useTranslation, useTranslationContext } from '@endora-commerce/admin-kit/i18n';
|
|
9
|
+
import { resolvePermissionLabel } from '../permission-label.js';
|
|
10
|
+
const NEW_ROLE_KEY = '__new__';
|
|
11
|
+
export default function AdminRolesPage() {
|
|
12
|
+
const t = useTranslation('core');
|
|
13
|
+
const [roles, setRoles] = useState([]);
|
|
14
|
+
const [permissions, setPermissions] = useState([]);
|
|
15
|
+
const [loading, setLoading] = useState(true);
|
|
16
|
+
const [error, setError] = useState(null);
|
|
17
|
+
const [info, setInfo] = useState(null);
|
|
18
|
+
const [editingCode, setEditingCode] = useState(null);
|
|
19
|
+
const refresh = useCallback(async () => {
|
|
20
|
+
setLoading(true);
|
|
21
|
+
setError(null);
|
|
22
|
+
try {
|
|
23
|
+
const [r, p] = await Promise.all([
|
|
24
|
+
apiClient.get('/api/v1/admin/admin-roles'),
|
|
25
|
+
apiClient.get('/api/v1/admin/permissions'),
|
|
26
|
+
]);
|
|
27
|
+
setRoles(r.data);
|
|
28
|
+
setPermissions(p.data);
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
setError(err instanceof ApiError ? err.envelope.error.message : t('adminRoles.error.load'));
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
setLoading(false);
|
|
35
|
+
}
|
|
36
|
+
}, [t]);
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
void refresh();
|
|
39
|
+
}, [refresh]);
|
|
40
|
+
const editing = useMemo(() => {
|
|
41
|
+
if (editingCode === NEW_ROLE_KEY) {
|
|
42
|
+
return { id: '', code: '', name: '', permissions: [], requiresTwoFactor: false };
|
|
43
|
+
}
|
|
44
|
+
if (editingCode == null)
|
|
45
|
+
return null;
|
|
46
|
+
const found = roles.find((r) => r.code === editingCode);
|
|
47
|
+
return found ?? null;
|
|
48
|
+
}, [editingCode, roles]);
|
|
49
|
+
const handleSave = useCallback(async (input) => {
|
|
50
|
+
try {
|
|
51
|
+
await apiClient.put(`/api/v1/admin/admin-roles/${input.code}`, {
|
|
52
|
+
code: input.code,
|
|
53
|
+
name: input.name,
|
|
54
|
+
permissions: input.permissions,
|
|
55
|
+
requiresTwoFactor: input.requiresTwoFactor,
|
|
56
|
+
});
|
|
57
|
+
setInfo(t('adminRoles.info.saved', { code: input.code }));
|
|
58
|
+
setEditingCode(input.code);
|
|
59
|
+
await refresh();
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
setError(err instanceof ApiError ? err.envelope.error.message : t('adminRoles.error.save'));
|
|
63
|
+
}
|
|
64
|
+
}, [refresh, t]);
|
|
65
|
+
const handleDelete = useCallback(async (role) => {
|
|
66
|
+
if (!confirm(t('adminRoles.confirmDelete', { name: role.name })))
|
|
67
|
+
return;
|
|
68
|
+
try {
|
|
69
|
+
await apiClient.delete(`/api/v1/admin/admin-roles/${role.id}`);
|
|
70
|
+
setInfo(t('adminRoles.info.deleted', { code: role.code }));
|
|
71
|
+
if (editingCode === role.code)
|
|
72
|
+
setEditingCode(null);
|
|
73
|
+
await refresh();
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
setError(err instanceof ApiError ? err.envelope.error.message : t('adminRoles.error.delete'));
|
|
77
|
+
}
|
|
78
|
+
}, [refresh, editingCode, t]);
|
|
79
|
+
return (_jsxs(_Fragment, { children: [_jsx(PageHeader, { title: t('adminRoles.page.title'), description: _jsxs(_Fragment, { children: [t('adminRoles.page.descriptionPrefix'), ' ', _jsx(Link, { to: "/admin-users", className: "underline underline-offset-2", children: t('adminRoles.usersLink') }), "."] }), actions: _jsxs(Button, { onClick: () => setEditingCode(NEW_ROLE_KEY), children: [_jsx(Plus, {}), t('adminRoles.newRole')] }) }), error ? (_jsx(Alert, { variant: "destructive", className: "mb-4", children: _jsx(AlertDescription, { children: error }) })) : null, info ? (_jsx(Alert, { variant: "success", className: "mb-4", children: _jsx(AlertDescription, { children: info }) })) : null, loading ? (_jsx("p", { className: "text-sm text-muted-foreground", children: t('adminRoles.loading') })) : (_jsxs("div", { className: "grid gap-4 lg:grid-cols-[320px_1fr]", children: [_jsx(Card, { children: _jsx(CardContent, { className: "pt-6", children: _jsxs("ul", { className: "space-y-1", children: [roles.map((r) => (_jsx("li", { children: _jsxs("button", { type: "button", onClick: () => setEditingCode(r.code), className: cn('flex w-full flex-col items-start gap-0.5 rounded-md px-3 py-2 text-left text-sm transition-colors', editingCode === r.code
|
|
80
|
+
? 'bg-primary text-primary-foreground'
|
|
81
|
+
: 'hover:bg-accent hover:text-accent-foreground'), children: [_jsx("span", { className: "font-medium", children: translateRoleName(t, r) }), _jsx("span", { className: cn('text-xs', editingCode === r.code
|
|
82
|
+
? 'text-primary-foreground/80'
|
|
83
|
+
: 'text-muted-foreground'), children: r.code })] }) }, r.id))), roles.length === 0 ? (_jsx("li", { className: "text-sm text-muted-foreground", children: t('adminRoles.empty') })) : null] }) }) }), editing ? (_jsx(RoleEditor, { role: editing, permissions: permissions, onSave: (input) => void handleSave({
|
|
84
|
+
originalCode: editingCode === NEW_ROLE_KEY ? null : editingCode,
|
|
85
|
+
code: input.code,
|
|
86
|
+
name: input.name,
|
|
87
|
+
permissions: input.permissions,
|
|
88
|
+
requiresTwoFactor: input.requiresTwoFactor,
|
|
89
|
+
}), onDelete: editingCode !== NEW_ROLE_KEY
|
|
90
|
+
? () => void handleDelete(editing)
|
|
91
|
+
: null }, editingCode)) : (_jsx(Card, { children: _jsx(CardContent, { className: "pt-6 text-sm text-muted-foreground", children: t('adminRoles.selectHint') }) }))] }))] }));
|
|
92
|
+
}
|
|
93
|
+
function RoleEditor(props) {
|
|
94
|
+
const t = useTranslation('core');
|
|
95
|
+
// Not `t`: a permission label may live in the owning module's own namespace
|
|
96
|
+
// since feature 091's Phase 3, and `t` is bound to one scope. See
|
|
97
|
+
// `permission-label.ts` for why the lookup is over the merged bundle.
|
|
98
|
+
const { language, bundle, fallbackBundle } = useTranslationContext();
|
|
99
|
+
const [code, setCode] = useState(props.role.code);
|
|
100
|
+
const [name, setName] = useState(props.role.name);
|
|
101
|
+
const [permissions, setPermissions] = useState(new Set(props.role.permissions.filter((p) => p !== '*')));
|
|
102
|
+
const [requiresTwoFactor, setRequiresTwoFactor] = useState(props.role.requiresTwoFactor);
|
|
103
|
+
// The platform_admin role is locked to full access — the toggle is forced on
|
|
104
|
+
// and disabled so it can never be downgraded (mirrors the backend invariant).
|
|
105
|
+
const isPlatformAdmin = props.role.code === 'platform_admin';
|
|
106
|
+
const [wildcard, setWildcard] = useState(isPlatformAdmin || props.role.permissions.includes('*'));
|
|
107
|
+
const grouped = useMemo(() => {
|
|
108
|
+
const byModule = new Map();
|
|
109
|
+
for (const p of props.permissions) {
|
|
110
|
+
const arr = byModule.get(p.module) ?? [];
|
|
111
|
+
arr.push(p);
|
|
112
|
+
byModule.set(p.module, arr);
|
|
113
|
+
}
|
|
114
|
+
return Array.from(byModule.entries()).sort(([a], [b]) => a.localeCompare(b));
|
|
115
|
+
}, [props.permissions]);
|
|
116
|
+
/**
|
|
117
|
+
* What this selection is short of — D-175's advisory panel.
|
|
118
|
+
*
|
|
119
|
+
* `missingPermissionRequirements` is `@endora-commerce/contracts`', not a
|
|
120
|
+
* derivation of this screen's: the same function answers the permission
|
|
121
|
+
* inventory's sweep, so the panel and the check cannot come to disagree about
|
|
122
|
+
* what a role is missing. It skips a requirement with no row here, so nothing
|
|
123
|
+
* is ever offered that has no checkbox to tick.
|
|
124
|
+
*
|
|
125
|
+
* Advisory in the strict sense: it changes no submitted value and refuses no
|
|
126
|
+
* save. A role the operator means to leave incomplete is saved incomplete.
|
|
127
|
+
*/
|
|
128
|
+
const missing = useMemo(() => (wildcard ? [] : missingPermissionRequirements(permissions, props.permissions)), [wildcard, permissions, props.permissions]);
|
|
129
|
+
return (_jsx(Card, { children: _jsxs(CardContent, { className: "space-y-4 pt-6", children: [_jsxs(Alert, { variant: "warning", children: [_jsx(ShieldAlert, { className: "size-4" }), _jsx(AlertTitle, { children: t('adminRoles.wildcardTitle') }), _jsxs(AlertDescription, { className: "space-y-2", children: [_jsxs("label", { className: "inline-flex items-center gap-2 font-medium", children: [_jsx(Checkbox, { checked: wildcard, disabled: isPlatformAdmin, onChange: (e) => setWildcard(e.target.checked) }), t('adminRoles.wildcardToggle'), " ", _jsx("code", { className: "font-mono", children: "*" })] }), _jsx("p", { children: isPlatformAdmin
|
|
130
|
+
? t('adminRoles.wildcardLocked')
|
|
131
|
+
: `${t('adminRoles.wildcardPrefix')} ${t('adminRoles.wildcardSuffix')}` })] })] }), _jsxs("form", { className: "space-y-4", onSubmit: (e) => {
|
|
132
|
+
e.preventDefault();
|
|
133
|
+
props.onSave({
|
|
134
|
+
code,
|
|
135
|
+
name,
|
|
136
|
+
permissions: wildcard ? ['*'] : Array.from(permissions),
|
|
137
|
+
requiresTwoFactor,
|
|
138
|
+
});
|
|
139
|
+
}, children: [_jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "rcode", children: t('adminRoles.field.code') }), _jsx(Input, { id: "rcode", value: code, onChange: (e) => setCode(e.target.value), disabled: !!props.role.code, required: true, maxLength: 64 })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "rname", children: t('adminRoles.field.displayName') }), _jsx(Input, { id: "rname", value: name, onChange: (e) => setName(e.target.value), required: true, maxLength: 160 })] })] }), _jsxs("label", { className: "inline-flex items-center gap-2 text-sm", children: [_jsx(Checkbox, { checked: requiresTwoFactor, onChange: (e) => setRequiresTwoFactor(e.target.checked) }), t('adminRoles.field.requires2fa')] }), _jsxs("div", { className: cn('space-y-3', wildcard && 'pointer-events-none opacity-50'), children: [_jsx("h3", { className: "text-sm font-semibold", children: t('adminRoles.permissionsHeading') }), missing.length > 0 ? (_jsxs(Alert, { children: [_jsx(Info, { className: "size-4" }), _jsx(AlertTitle, { children: t('adminRoles.dependencies.title') }), _jsxs(AlertDescription, { className: "space-y-2", children: [_jsx("p", { children: t('adminRoles.dependencies.description') }), _jsxs("div", { className: "flex flex-wrap gap-2", children: [missing.map((code) => (_jsx(Button, { type: "button", size: "sm", variant: "outline", onClick: () => setPermissions((prev) => new Set(prev).add(code)), children: t('adminRoles.dependencies.add', { code }) }, code))), missing.length > 1 ? (_jsx(Button, { type: "button", size: "sm", onClick: () => setPermissions((prev) => {
|
|
140
|
+
const next = new Set(prev);
|
|
141
|
+
for (const code of missing)
|
|
142
|
+
next.add(code);
|
|
143
|
+
return next;
|
|
144
|
+
}), children: t('adminRoles.dependencies.addAll') })) : null] })] })] })) : null, grouped.map(([module, perms]) => (_jsxs("fieldset", { className: "rounded-md border p-3", children: [_jsx("legend", { className: "px-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: module }), _jsx("div", { className: "space-y-1.5", children: perms.map((p) => (_jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx(Checkbox, { checked: wildcard || permissions.has(p.code), disabled: wildcard, onChange: (e) => {
|
|
145
|
+
setPermissions((prev) => {
|
|
146
|
+
const next = new Set(prev);
|
|
147
|
+
if (e.target.checked)
|
|
148
|
+
next.add(p.code);
|
|
149
|
+
else
|
|
150
|
+
next.delete(p.code);
|
|
151
|
+
return next;
|
|
152
|
+
});
|
|
153
|
+
} }), _jsx("code", { className: "font-mono text-xs", children: p.code }), _jsxs("span", { className: "text-muted-foreground", children: ["\u2014", ' ', resolvePermissionLabel({
|
|
154
|
+
code: p.code,
|
|
155
|
+
fallbackLabel: p.label,
|
|
156
|
+
language,
|
|
157
|
+
bundle,
|
|
158
|
+
fallbackBundle,
|
|
159
|
+
})] }), p.requires?.length ? (_jsxs("span", { className: "text-xs text-muted-foreground", children: ["(", t('adminRoles.requires', { codes: p.requires.join(', ') }), ")"] })) : null, ownersWorthShowing(p) ? (_jsxs("span", { className: "text-xs text-muted-foreground", children: ["(", t('adminRoles.owners', { modules: p.owners.join(', ') }), ")"] })) : null] }, p.code))) })] }, module)))] }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { type: "submit", children: t('adminRoles.save') }), props.onDelete ? (_jsx(Button, { type: "button", variant: "destructive", onClick: props.onDelete, children: t('adminRoles.delete') })) : null] })] })] }) }));
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Whether this row's owner set says anything its display grouping does not —
|
|
163
|
+
* T058.
|
|
164
|
+
*
|
|
165
|
+
* The model has three notions and only `module` was ever visible, so the fix is
|
|
166
|
+
* to show `owners` where the two differ: a shared code kept alive by either of
|
|
167
|
+
* two modules, or a code filed under a grouping that is no module id at all.
|
|
168
|
+
* Rendering it on every row as well would bury the cases that matter under one
|
|
169
|
+
* repeated word, which is how the distinction became invisible in the first
|
|
170
|
+
* place.
|
|
171
|
+
*/
|
|
172
|
+
function ownersWorthShowing(row) {
|
|
173
|
+
return row.owners.length > 1 || row.owners[0] !== row.module;
|
|
174
|
+
}
|
|
175
|
+
function translateRoleName(t, role) {
|
|
176
|
+
const key = `adminRoles.seeded.${role.code}`;
|
|
177
|
+
const label = t(key);
|
|
178
|
+
return label === `core.${key}` ? role.name : label;
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=AdminRolesPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminRolesPage.js","sourceRoot":"","sources":["../../../src/admin/pages/AdminRolesPage.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminUsersPage.d.ts","sourceRoot":"","sources":["../../../src/admin/pages/AdminUsersPage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA8D,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAyCnG,MAAM,CAAC,OAAO,UAAU,cAAc,IAAI,SAAS,CA+PlD"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment, useCallback, useEffect, useState } from 'react';
|
|
3
|
+
import { Link } from 'react-router-dom';
|
|
4
|
+
import { KeyRound, Trash2 } from 'lucide-react';
|
|
5
|
+
import { ApiError, apiClient, formatDateTime } from '@endora-commerce/admin-kit/lib';
|
|
6
|
+
import { Alert, AlertDescription, Button, Card, CardContent, CardHeader, CardTitle, Input, Label, PageHeader, Select, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@endora-commerce/admin-kit/ui';
|
|
7
|
+
import { useTranslation } from '@endora-commerce/admin-kit/i18n';
|
|
8
|
+
export default function AdminUsersPage() {
|
|
9
|
+
const t = useTranslation('core');
|
|
10
|
+
const [users, setUsers] = useState([]);
|
|
11
|
+
const [roles, setRoles] = useState([]);
|
|
12
|
+
const [loading, setLoading] = useState(true);
|
|
13
|
+
const [error, setError] = useState(null);
|
|
14
|
+
// Which row has its reset form open, and the last reset that succeeded.
|
|
15
|
+
const [resetFor, setResetFor] = useState(null);
|
|
16
|
+
const [resetDone, setResetDone] = useState(null);
|
|
17
|
+
const refresh = useCallback(async () => {
|
|
18
|
+
setLoading(true);
|
|
19
|
+
setError(null);
|
|
20
|
+
try {
|
|
21
|
+
// The list endpoint is paginated (default pageSize=50, max 200). Until
|
|
22
|
+
// this page grows real pagination UI, we ask for the largest single
|
|
23
|
+
// page so the visible behaviour matches the pre-server-search version.
|
|
24
|
+
const [u, r] = await Promise.all([
|
|
25
|
+
apiClient.get('/api/v1/admin/admin-users?pageSize=200'),
|
|
26
|
+
apiClient.get('/api/v1/admin/admin-roles'),
|
|
27
|
+
]);
|
|
28
|
+
setUsers(u.data);
|
|
29
|
+
setRoles(r.data);
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
setError(err instanceof ApiError ? err.envelope.error.message : t('adminUsers.error.load'));
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
setLoading(false);
|
|
36
|
+
}
|
|
37
|
+
}, [t]);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
void refresh();
|
|
40
|
+
}, [refresh]);
|
|
41
|
+
const handleCreate = useCallback(async (input) => {
|
|
42
|
+
try {
|
|
43
|
+
await apiClient.post('/api/v1/admin/admin-users', {
|
|
44
|
+
email: input.email,
|
|
45
|
+
password: input.password,
|
|
46
|
+
firstName: input.firstName,
|
|
47
|
+
lastName: input.lastName,
|
|
48
|
+
...(input.adminRoleId ? { adminRoleId: input.adminRoleId } : {}),
|
|
49
|
+
});
|
|
50
|
+
await refresh();
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
setError(err instanceof ApiError ? err.envelope.error.message : t('adminUsers.error.create'));
|
|
54
|
+
}
|
|
55
|
+
}, [refresh, t]);
|
|
56
|
+
const handleAssignRole = useCallback(async (userId, roleId) => {
|
|
57
|
+
try {
|
|
58
|
+
await apiClient.patch(`/api/v1/admin/admin-users/${userId}`, {
|
|
59
|
+
adminRoleId: roleId === '' ? null : roleId,
|
|
60
|
+
});
|
|
61
|
+
await refresh();
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
setError(err instanceof ApiError ? err.envelope.error.message : t('adminUsers.error.update'));
|
|
65
|
+
}
|
|
66
|
+
}, [refresh, t]);
|
|
67
|
+
const handleToggleStatus = useCallback(async (user) => {
|
|
68
|
+
try {
|
|
69
|
+
await apiClient.patch(`/api/v1/admin/admin-users/${user.id}`, {
|
|
70
|
+
status: user.status === 'active' ? 'inactive' : 'active',
|
|
71
|
+
});
|
|
72
|
+
await refresh();
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
setError(err instanceof ApiError ? err.envelope.error.message : t('adminUsers.error.update'));
|
|
76
|
+
}
|
|
77
|
+
}, [refresh, t]);
|
|
78
|
+
const handleResetPassword = useCallback(async (user, password) => {
|
|
79
|
+
setError(null);
|
|
80
|
+
setResetDone(null);
|
|
81
|
+
try {
|
|
82
|
+
await apiClient.post(`/api/v1/admin/admin-users/${user.id}/password`, { password });
|
|
83
|
+
setResetFor(null);
|
|
84
|
+
setResetDone(user.email);
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
setError(err instanceof ApiError
|
|
88
|
+
? err.envelope.error.message
|
|
89
|
+
: t('adminUsers.error.resetPassword'));
|
|
90
|
+
}
|
|
91
|
+
}, [t]);
|
|
92
|
+
const handleRemove = useCallback(async (user) => {
|
|
93
|
+
if (!confirm(t('adminUsers.confirmRemove', { email: user.email })))
|
|
94
|
+
return;
|
|
95
|
+
try {
|
|
96
|
+
await apiClient.delete(`/api/v1/admin/admin-users/${user.id}`);
|
|
97
|
+
await refresh();
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
setError(err instanceof ApiError ? err.envelope.error.message : t('adminUsers.error.remove'));
|
|
101
|
+
}
|
|
102
|
+
}, [refresh, t]);
|
|
103
|
+
return (_jsxs(_Fragment, { children: [_jsx(PageHeader, { title: t('adminUsers.page.title'), description: _jsxs(_Fragment, { children: [t('adminUsers.page.descriptionPrefix'), ' ', _jsx(Link, { to: "/admin-roles", className: "underline underline-offset-2", children: t('adminUsers.rolesLink') }), "."] }) }), error ? (_jsx(Alert, { variant: "destructive", className: "mb-4", children: _jsx(AlertDescription, { children: error }) })) : null, resetDone ? (_jsx(Alert, { variant: "success", className: "mb-4", children: _jsx(AlertDescription, { children: t('adminUsers.resetPassword.done', { email: resetDone }) }) })) : null, _jsxs(Card, { className: "mb-4", children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: t('adminUsers.create.title') }) }), _jsx(CardContent, { children: _jsx(CreateUserForm, { roles: roles, onSubmit: handleCreate }) })] }), _jsx(Card, { children: _jsx(CardContent, { className: "pt-6", children: loading ? (_jsx("p", { className: "text-sm text-muted-foreground", children: t('adminUsers.loading') })) : (_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: t('adminUsers.column.email') }), _jsx(TableHead, { children: t('adminUsers.column.name') }), _jsx(TableHead, { children: t('adminUsers.column.role') }), _jsx(TableHead, { children: t('adminUsers.column.status') }), _jsx(TableHead, { children: t('adminUsers.column.twoFactor') }), _jsx(TableHead, { children: t('adminUsers.column.lastLogin') }), _jsx(TableHead, {})] }) }), _jsx(TableBody, { children: users.map((u) => (
|
|
104
|
+
// Anchor target for deep-links (e.g. the audit-log actor column).
|
|
105
|
+
_jsxs(Fragment, { children: [_jsxs(TableRow, { id: `admin-user-${u.id}`, className: "scroll-mt-24", children: [_jsx(TableCell, { className: "font-medium", children: u.email }), _jsxs(TableCell, { children: [u.firstName, " ", u.lastName] }), _jsx(TableCell, { children: _jsxs(Select, { value: u.adminRoleId ?? '', onChange: (e) => void handleAssignRole(u.id, e.target.value), children: [_jsx("option", { value: "", children: t('adminUsers.unassigned') }), roles.map((r) => (_jsx("option", { value: r.id, children: translateRoleName(t, r) }, r.id)))] }) }), _jsx(TableCell, { children: t(`adminUsers.status.${u.status}`) }), _jsx(TableCell, { children: u.twoFactorEnabled ? t('adminUsers.twoFactorOn') : '—' }), _jsx(TableCell, { children: formatDateTime(u.lastLoginAt) }), _jsx(TableCell, { children: _jsxs("div", { className: "flex gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: () => setResetFor((current) => (current === u.id ? null : u.id)), "aria-expanded": resetFor === u.id, "aria-controls": `admin-user-reset-${u.id}`, children: [_jsx(KeyRound, {}), t('adminUsers.resetPassword.action')] }), _jsx(Button, { variant: "outline", size: "sm", onClick: () => void handleToggleStatus(u), children: u.status === 'active' ? t('adminUsers.deactivate') : t('adminUsers.reactivate') }), _jsxs(Button, { variant: "destructive", size: "sm", onClick: () => void handleRemove(u), children: [_jsx(Trash2, {}), t('adminUsers.remove')] })] }) })] }), resetFor === u.id ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 7, id: `admin-user-reset-${u.id}`, children: _jsx(ResetPasswordForm, { user: u, onCancel: () => setResetFor(null), onSubmit: (password) => handleResetPassword(u, password) }) }) })) : null] }, u.id))) })] })) }) })] }));
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Peer password reset (issue #252). Inline rather than in a modal: the admin
|
|
109
|
+
* design system has no dialog primitive, and Principle IX says reuse before
|
|
110
|
+
* adding one. The hint is not decoration — resetting ends every session the
|
|
111
|
+
* target holds, and an operator who resets their own account here is signed
|
|
112
|
+
* out by it.
|
|
113
|
+
*/
|
|
114
|
+
function ResetPasswordForm({ user, onCancel, onSubmit, }) {
|
|
115
|
+
const t = useTranslation('core');
|
|
116
|
+
const [password, setPassword] = useState('');
|
|
117
|
+
return (_jsxs("form", { className: "space-y-3", onSubmit: (e) => {
|
|
118
|
+
e.preventDefault();
|
|
119
|
+
void onSubmit(password).then(() => setPassword(''));
|
|
120
|
+
}, children: [_jsx("p", { className: "text-sm font-medium", children: t('adminUsers.resetPassword.title', { email: user.email }) }), _jsx("p", { className: "text-sm text-muted-foreground", children: t('adminUsers.resetPassword.hint') }), _jsxs("div", { className: "flex flex-wrap items-end gap-3", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: `reset-${user.id}`, children: t('adminUsers.field.password') }), _jsx(Input, { id: `reset-${user.id}`, type: "password", autoComplete: "new-password", value: password, onChange: (e) => setPassword(e.target.value), minLength: 12, required: true })] }), _jsx(Button, { type: "submit", size: "sm", children: t('adminUsers.resetPassword.submit') }), _jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: onCancel, children: t('adminUsers.resetPassword.cancel') })] })] }));
|
|
121
|
+
}
|
|
122
|
+
function CreateUserForm({ roles, onSubmit, }) {
|
|
123
|
+
const t = useTranslation('core');
|
|
124
|
+
const [email, setEmail] = useState('');
|
|
125
|
+
const [password, setPassword] = useState('');
|
|
126
|
+
const [firstName, setFirstName] = useState('');
|
|
127
|
+
const [lastName, setLastName] = useState('');
|
|
128
|
+
const [adminRoleId, setAdminRoleId] = useState('');
|
|
129
|
+
return (_jsxs("form", { className: "space-y-4", onSubmit: (e) => {
|
|
130
|
+
e.preventDefault();
|
|
131
|
+
void onSubmit({
|
|
132
|
+
email,
|
|
133
|
+
password,
|
|
134
|
+
firstName,
|
|
135
|
+
lastName,
|
|
136
|
+
adminRoleId: adminRoleId || null,
|
|
137
|
+
}).then(() => {
|
|
138
|
+
setEmail('');
|
|
139
|
+
setPassword('');
|
|
140
|
+
setFirstName('');
|
|
141
|
+
setLastName('');
|
|
142
|
+
setAdminRoleId('');
|
|
143
|
+
});
|
|
144
|
+
}, children: [_jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "ne", children: t('adminUsers.column.email') }), _jsx(Input, { id: "ne", type: "email", value: email, onChange: (e) => setEmail(e.target.value), required: true })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "np", children: t('adminUsers.field.password') }), _jsx(Input, { id: "np", type: "password", value: password, onChange: (e) => setPassword(e.target.value), minLength: 12, required: true })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "nf", children: t('adminUsers.field.firstName') }), _jsx(Input, { id: "nf", value: firstName, onChange: (e) => setFirstName(e.target.value), required: true })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "nl", children: t('adminUsers.field.lastName') }), _jsx(Input, { id: "nl", value: lastName, onChange: (e) => setLastName(e.target.value), required: true })] }), _jsxs("div", { className: "space-y-2 md:col-span-2", children: [_jsx(Label, { htmlFor: "nr", children: t('adminUsers.column.role') }), _jsxs(Select, { id: "nr", value: adminRoleId, onChange: (e) => setAdminRoleId(e.target.value), children: [_jsx("option", { value: "", children: t('adminUsers.assignLater') }), roles.map((r) => (_jsx("option", { value: r.id, children: translateRoleName(t, r) }, r.id)))] })] })] }), _jsx(Button, { type: "submit", children: t('adminUsers.create.title') })] }));
|
|
145
|
+
}
|
|
146
|
+
function translateRoleName(t, role) {
|
|
147
|
+
const key = `adminRoles.seeded.${role.code}`;
|
|
148
|
+
const label = t(key);
|
|
149
|
+
return label === `core.${key}` ? role.name : label;
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=AdminUsersPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminUsersPage.js","sourceRoot":"","sources":["../../../src/admin/pages/AdminUsersPage.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Bundle, SupportedAdminLanguage } from '@endora-commerce/admin-kit/i18n';
|
|
2
|
+
/** The key `/admin-roles` builds for every catalogue row. */
|
|
3
|
+
export declare const PERMISSION_LABEL_PREFIX = "adminRoles.permission.";
|
|
4
|
+
/** The namespace `_i18n`'s bundle is served under — the legacy block's home. */
|
|
5
|
+
export declare const LEGACY_PERMISSION_LABEL_SCOPE = "core";
|
|
6
|
+
/**
|
|
7
|
+
* The namespace that carries `key`, preferring the legacy block, or `null`.
|
|
8
|
+
*
|
|
9
|
+
* Sorted, so two bundles that both carried the key would resolve to the same
|
|
10
|
+
* one on every render rather than to whichever the server serialised first.
|
|
11
|
+
*/
|
|
12
|
+
export declare function scopeCarrying(bundle: Bundle | undefined, key: string): string | null;
|
|
13
|
+
export interface PermissionLabelArgs {
|
|
14
|
+
readonly code: string;
|
|
15
|
+
/** The manifest `label` — English-only, and the last resort. */
|
|
16
|
+
readonly fallbackLabel: string;
|
|
17
|
+
readonly language: SupportedAdminLanguage;
|
|
18
|
+
readonly bundle: Bundle;
|
|
19
|
+
readonly fallbackBundle?: Bundle | undefined;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The label for one permission code: the operator's language, then English,
|
|
23
|
+
* then the manifest label the API already sent.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolvePermissionLabel(args: PermissionLabelArgs): string;
|
|
26
|
+
//# sourceMappingURL=permission-label.d.ts.map
|