@jini-ai/user-management 0.2.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/CHANGELOG.md +77 -0
- package/LICENSE +201 -0
- package/README.md +104 -0
- package/dist/admin/adapters/http.d.ts +29 -0
- package/dist/admin/adapters/http.js +69 -0
- package/dist/admin/adapters/memory.d.ts +61 -0
- package/dist/admin/adapters/memory.js +217 -0
- package/dist/admin/auth.module.d.ts +30 -0
- package/dist/admin/auth.module.js +12 -0
- package/dist/admin/conformance/index.d.ts +56 -0
- package/dist/admin/conformance/index.js +156 -0
- package/dist/admin/controllers/auth.controller.d.ts +23 -0
- package/dist/admin/controllers/auth.controller.js +33 -0
- package/dist/admin/controllers/controller-store.d.ts +18 -0
- package/dist/admin/controllers/controller-store.js +23 -0
- package/dist/admin/controllers/members.controller.d.ts +33 -0
- package/dist/admin/controllers/members.controller.js +119 -0
- package/dist/admin/controllers/roles.controller.d.ts +47 -0
- package/dist/admin/controllers/roles.controller.js +282 -0
- package/dist/admin/controllers/users.controller.d.ts +53 -0
- package/dist/admin/controllers/users.controller.js +220 -0
- package/dist/admin/index.d.ts +21 -0
- package/dist/admin/index.js +15 -0
- package/dist/admin/members.module.d.ts +34 -0
- package/dist/admin/members.module.js +13 -0
- package/dist/admin/messages.en.d.ts +37 -0
- package/dist/admin/messages.en.js +21 -0
- package/dist/admin/models.d.ts +133 -0
- package/dist/admin/models.js +2 -0
- package/dist/admin/people.rules.d.ts +29 -0
- package/dist/admin/people.rules.js +51 -0
- package/dist/admin/ports.d.ts +187 -0
- package/dist/admin/ports.js +17 -0
- package/dist/admin/react/components/DestructiveDialog.d.ts +5 -0
- package/dist/admin/react/components/DestructiveDialog.js +6 -0
- package/dist/admin/react/components/MemberRow.d.ts +5 -0
- package/dist/admin/react/components/MemberRow.js +8 -0
- package/dist/admin/react/components/MembersConfirmation.d.ts +2 -0
- package/dist/admin/react/components/MembersConfirmation.js +8 -0
- package/dist/admin/react/components/PermissionPanel.d.ts +5 -0
- package/dist/admin/react/components/PermissionPanel.js +9 -0
- package/dist/admin/react/components/PolicyRow.d.ts +5 -0
- package/dist/admin/react/components/PolicyRow.js +11 -0
- package/dist/admin/react/components/RoleRow.d.ts +5 -0
- package/dist/admin/react/components/RoleRow.js +10 -0
- package/dist/admin/react/components/UserRow.d.ts +5 -0
- package/dist/admin/react/components/UserRow.js +8 -0
- package/dist/admin/react/components/UsersConfirmation.d.ts +3 -0
- package/dist/admin/react/components/UsersConfirmation.js +9 -0
- package/dist/admin/react/hooks/AuthBinding.hooks.d.ts +39 -0
- package/dist/admin/react/hooks/AuthBinding.hooks.js +21 -0
- package/dist/admin/react/hooks/LoginPage.hooks.d.ts +54 -0
- package/dist/admin/react/hooks/LoginPage.hooks.js +23 -0
- package/dist/admin/react/hooks/MembersBinding.hooks.d.ts +35 -0
- package/dist/admin/react/hooks/MembersBinding.hooks.js +21 -0
- package/dist/admin/react/hooks/MembersPage.hooks.d.ts +99 -0
- package/dist/admin/react/hooks/MembersPage.hooks.js +38 -0
- package/dist/admin/react/hooks/PeopleController.hooks.d.ts +18 -0
- package/dist/admin/react/hooks/PeopleController.hooks.js +20 -0
- package/dist/admin/react/hooks/PermissionPanel.hooks.d.ts +30 -0
- package/dist/admin/react/hooks/PermissionPanel.hooks.js +15 -0
- package/dist/admin/react/hooks/PoliciesTab.hooks.d.ts +47 -0
- package/dist/admin/react/hooks/PoliciesTab.hooks.js +26 -0
- package/dist/admin/react/hooks/RolesBinding.hooks.d.ts +39 -0
- package/dist/admin/react/hooks/RolesBinding.hooks.js +23 -0
- package/dist/admin/react/hooks/RolesController.hooks.d.ts +43 -0
- package/dist/admin/react/hooks/RolesController.hooks.js +25 -0
- package/dist/admin/react/hooks/RolesPage.hooks.d.ts +105 -0
- package/dist/admin/react/hooks/RolesPage.hooks.js +33 -0
- package/dist/admin/react/hooks/RolesTab.hooks.d.ts +35 -0
- package/dist/admin/react/hooks/RolesTab.hooks.js +19 -0
- package/dist/admin/react/hooks/UsersBinding.hooks.d.ts +36 -0
- package/dist/admin/react/hooks/UsersBinding.hooks.js +21 -0
- package/dist/admin/react/hooks/UsersPage.hooks.d.ts +106 -0
- package/dist/admin/react/hooks/UsersPage.hooks.js +22 -0
- package/dist/admin/react/hooks/UsersTab.hooks.d.ts +101 -0
- package/dist/admin/react/hooks/UsersTab.hooks.js +53 -0
- package/dist/admin/react/index.d.ts +203 -0
- package/dist/admin/react/index.js +32 -0
- package/dist/admin/react/pages/LoginPage.d.ts +3 -0
- package/dist/admin/react/pages/LoginPage.js +13 -0
- package/dist/admin/react/pages/MembersPage.d.ts +3 -0
- package/dist/admin/react/pages/MembersPage.js +19 -0
- package/dist/admin/react/pages/RolesPage.d.ts +3 -0
- package/dist/admin/react/pages/RolesPage.js +19 -0
- package/dist/admin/react/pages/UsersPage.d.ts +3 -0
- package/dist/admin/react/pages/UsersPage.js +19 -0
- package/dist/admin/react/tabs/AuthTab.d.ts +4 -0
- package/dist/admin/react/tabs/AuthTab.js +8 -0
- package/dist/admin/react/tabs/MembersTab.d.ts +4 -0
- package/dist/admin/react/tabs/MembersTab.js +9 -0
- package/dist/admin/react/tabs/PoliciesTab.d.ts +4 -0
- package/dist/admin/react/tabs/PoliciesTab.js +9 -0
- package/dist/admin/react/tabs/RolesTab.d.ts +4 -0
- package/dist/admin/react/tabs/RolesTab.js +9 -0
- package/dist/admin/react/tabs/UsersTab.d.ts +4 -0
- package/dist/admin/react/tabs/UsersTab.js +9 -0
- package/dist/admin/roles.module.d.ts +48 -0
- package/dist/admin/roles.module.js +15 -0
- package/dist/admin/rules.d.ts +32 -0
- package/dist/admin/rules.js +32 -0
- package/dist/admin/users.module.d.ts +39 -0
- package/dist/admin/users.module.js +14 -0
- package/dist/core/builtin-permissions.d.ts +10 -0
- package/dist/core/builtin-permissions.js +402 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.js +9 -0
- package/dist/core/permissions.d.ts +40 -0
- package/dist/core/permissions.js +52 -0
- package/dist/core/ports.d.ts +237 -0
- package/dist/core/ports.js +2 -0
- package/dist/core/runtime-ports.d.ts +8 -0
- package/dist/core/runtime-ports.js +2 -0
- package/dist/core/types.d.ts +224 -0
- package/dist/core/types.js +93 -0
- package/dist/react/auth/Login.d.ts +9 -0
- package/dist/react/auth/Login.js +8 -0
- package/dist/react/auth/hooks/use-login.hooks.d.ts +22 -0
- package/dist/react/auth/hooks/use-login.hooks.js +24 -0
- package/dist/react/errors.d.ts +10 -0
- package/dist/react/errors.js +13 -0
- package/dist/react/index.d.ts +18 -0
- package/dist/react/index.js +9 -0
- package/dist/react/members/Members.d.ts +6 -0
- package/dist/react/members/Members.js +38 -0
- package/dist/react/members/hooks/use-members.hooks.d.ts +32 -0
- package/dist/react/members/hooks/use-members.hooks.js +120 -0
- package/dist/react/members/rules.d.ts +26 -0
- package/dist/react/members/rules.js +35 -0
- package/dist/react/models.d.ts +50 -0
- package/dist/react/models.js +2 -0
- package/dist/react/ports.d.ts +157 -0
- package/dist/react/ports.js +2 -0
- package/dist/react/roles/Roles.d.ts +100 -0
- package/dist/react/roles/Roles.hooks.d.ts +17 -0
- package/dist/react/roles/Roles.hooks.js +40 -0
- package/dist/react/roles/Roles.js +150 -0
- package/dist/react/roles/hooks/use-roles.hooks.d.ts +80 -0
- package/dist/react/roles/hooks/use-roles.hooks.js +303 -0
- package/dist/react/roles/rules.d.ts +35 -0
- package/dist/react/roles/rules.js +31 -0
- package/dist/react/roles/text.d.ts +27 -0
- package/dist/react/roles/text.js +13 -0
- package/dist/react/testing.d.ts +51 -0
- package/dist/react/testing.js +275 -0
- package/dist/react/users/Users.d.ts +72 -0
- package/dist/react/users/Users.js +129 -0
- package/dist/react/users/hooks/use-reset-password-fields.hooks.d.ts +16 -0
- package/dist/react/users/hooks/use-reset-password-fields.hooks.js +21 -0
- package/dist/react/users/hooks/use-users.hooks.d.ts +77 -0
- package/dist/react/users/hooks/use-users.hooks.js +286 -0
- package/dist/react/users/rules.d.ts +33 -0
- package/dist/react/users/rules.js +61 -0
- package/dist/server/admin-crud-service.d.ts +295 -0
- package/dist/server/admin-crud-service.js +561 -0
- package/dist/server/agent-tool-input.d.ts +58 -0
- package/dist/server/agent-tool-input.js +158 -0
- package/dist/server/agent-tool-registrations.d.ts +51 -0
- package/dist/server/agent-tool-registrations.js +417 -0
- package/dist/server/agent-tools.d.ts +88 -0
- package/dist/server/agent-tools.js +229 -0
- package/dist/server/auth-service.d.ts +107 -0
- package/dist/server/auth-service.js +170 -0
- package/dist/server/authorize.d.ts +92 -0
- package/dist/server/authorize.js +96 -0
- package/dist/server/grant-service.d.ts +219 -0
- package/dist/server/grant-service.js +419 -0
- package/dist/server/hasher.d.ts +64 -0
- package/dist/server/hasher.js +53 -0
- package/dist/server/identity-transaction.d.ts +9 -0
- package/dist/server/identity-transaction.js +8 -0
- package/dist/server/index.d.ts +18 -0
- package/dist/server/index.js +20 -0
- package/dist/server/messages.d.ts +7 -0
- package/dist/server/messages.js +5 -0
- package/dist/server/password-policy.d.ts +59 -0
- package/dist/server/password-policy.js +66 -0
- package/dist/server/permission-migrations.d.ts +84 -0
- package/dist/server/permission-migrations.js +77 -0
- package/dist/server/repo.memory-transactions.d.ts +16 -0
- package/dist/server/repo.memory-transactions.js +79 -0
- package/dist/server/repo.memory.d.ts +186 -0
- package/dist/server/repo.memory.js +230 -0
- package/dist/server/seed.d.ts +56 -0
- package/dist/server/seed.js +435 -0
- package/dist/server/session-tokens.d.ts +10 -0
- package/dist/server/session-tokens.js +12 -0
- package/dist/server/username.d.ts +14 -0
- package/dist/server/username.js +14 -0
- package/package.json +144 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createElement, createContext, useContext, useMemo } from 'react';
|
|
2
|
+
import { createMembersController } from '../../controllers/members.controller.js';
|
|
3
|
+
import { hasAdminGrant } from '../../people.rules.js';
|
|
4
|
+
import { useMembersScope } from './MembersBinding.hooks.js';
|
|
5
|
+
import { usePeopleController } from './PeopleController.hooks.js';
|
|
6
|
+
export const MembersViewContext = createContext(null);
|
|
7
|
+
export function useMembersView(_required = {}, _optional = {}) { const v = useContext(MembersViewContext); if (!v)
|
|
8
|
+
throw new Error('Members controller unavailable.'); return v; }
|
|
9
|
+
export function useMembersPage(props, _optional = {}) {
|
|
10
|
+
const { api, permissions } = useMembersScope({});
|
|
11
|
+
const scope = useMemo(() => ({ api, refresh: props.refresh }), [api, props.refresh]);
|
|
12
|
+
const key = JSON.stringify(permissions);
|
|
13
|
+
const { controller, state } = usePeopleController({ scope, key,
|
|
14
|
+
create: () => createMembersController({ api }, { permissions, ...(props.refresh ? { refresh: props.refresh } : {}) }), start: c => { void c.load({}); },
|
|
15
|
+
});
|
|
16
|
+
const canManage = hasAdminGrant({ permissions, permission: 'member.manage' });
|
|
17
|
+
return { content: props.tabs.members ? createElement(props.tabs.members, {}) : null, state, controller, canManage, visible: props.description.visible && props.description.tabs.some(t => t.visible),
|
|
18
|
+
view: state && controller ? { state, controller, canManage } : null, retry: () => { void controller?.load({}); } };
|
|
19
|
+
}
|
|
20
|
+
export function useMemberRow({ member }, _optional = {}) {
|
|
21
|
+
const { state: s, controller: c, canManage } = useMembersView({}), id = member.id;
|
|
22
|
+
const rs = c.stateFor({ id }), items = [];
|
|
23
|
+
if (canManage) {
|
|
24
|
+
items.push({ id: 'resend', label: 'Resend sign-in link', disabled: rs.resending, onPress: () => { void c.resendSignInLink({ id }); } });
|
|
25
|
+
if (member.status !== 'disabled')
|
|
26
|
+
items.push({ id: 'disable', label: 'Disable', disabled: rs.disabling, onPress: () => c.requestDestructive({ id }) });
|
|
27
|
+
}
|
|
28
|
+
return { s, rs, items, menuLabel: `Actions for member "${member.email}"`, expanded: s.expandedId === id,
|
|
29
|
+
detail: s.detailById[id], loading: s.detailLoadingId === id, toggle: () => { void c.toggleDetail({ id }); },
|
|
30
|
+
verified: s.detailById[id]?.emailVerifiedAt ?? 'not verified', created: member.createdAt, };
|
|
31
|
+
}
|
|
32
|
+
export function useMembersConfirmation(_required = {}, _optional = {}) {
|
|
33
|
+
const { state: s, controller: c } = useMembersView({});
|
|
34
|
+
return { open: s.pending !== null, title: 'Disable this member?', body: s.pending ? `Disable "${s.pending.email}"? They will no longer be able to sign in.` : '',
|
|
35
|
+
confirmLabel: 'Disable', tone: 'warning', consequence: 'revokes sign-in access', pending: s.confirming, agentMayConfirm: false,
|
|
36
|
+
onConfirm: async () => { await c.confirmDestructive({}); }, onCancel: () => c.cancelDestructive({}) };
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=MembersPage.hooks.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** StrictMode gets a fresh effect-owned controller. Scope changes drop old data synchronously,
|
|
2
|
+
* before the replacement effect runs; retired controllers abort requests and unsubscribe refresh. */
|
|
3
|
+
export declare function usePeopleController<S, C extends {
|
|
4
|
+
getSnapshot(required?: Record<string, never>, optional?: Record<string, never>): S;
|
|
5
|
+
subscribe(required: {
|
|
6
|
+
listener: () => void;
|
|
7
|
+
}, optional?: Record<string, never>): () => void;
|
|
8
|
+
dispose(required: Record<string, never>, optional?: Record<string, never>): void;
|
|
9
|
+
}>({ scope, key, create, start }: {
|
|
10
|
+
scope: object;
|
|
11
|
+
key: string;
|
|
12
|
+
create: () => C;
|
|
13
|
+
start: (controller: C) => void;
|
|
14
|
+
}, _optional?: Record<string, never>): {
|
|
15
|
+
controller: C | null;
|
|
16
|
+
state: NonNullable<S> | null;
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=PeopleController.hooks.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState, useSyncExternalStore } from 'react';
|
|
2
|
+
/** StrictMode gets a fresh effect-owned controller. Scope changes drop old data synchronously,
|
|
3
|
+
* before the replacement effect runs; retired controllers abort requests and unsubscribe refresh. */
|
|
4
|
+
export function usePeopleController({ scope, key, create, start }, _optional = {}) {
|
|
5
|
+
const [attachment, setAttachment] = useState(null);
|
|
6
|
+
const controller = attachment?.scope === scope && attachment.key === key ? attachment.controller : null;
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
const current = create();
|
|
9
|
+
setAttachment({ scope, key, controller: current });
|
|
10
|
+
start(current);
|
|
11
|
+
return () => current.dispose({});
|
|
12
|
+
// create/start are render closures; scope and key encode their entire injected dependency set.
|
|
13
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
14
|
+
}, [scope, key]);
|
|
15
|
+
const subscribe = useCallback((listener) => controller?.subscribe({ listener }) ?? (() => { }), [controller]);
|
|
16
|
+
const read = useCallback(() => controller?.getSnapshot({}) ?? null, [controller]);
|
|
17
|
+
const state = useSyncExternalStore(subscribe, read, () => null);
|
|
18
|
+
return { controller, state };
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=PeopleController.hooks.js.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { PolicyRecord } from '../../models.js';
|
|
2
|
+
export declare function usePermissionPanel({ policy }: {
|
|
3
|
+
policy: PolicyRecord;
|
|
4
|
+
}, _optional?: Record<string, never>): {
|
|
5
|
+
editable: boolean;
|
|
6
|
+
loading: boolean;
|
|
7
|
+
empty: boolean;
|
|
8
|
+
rows: {
|
|
9
|
+
id: string;
|
|
10
|
+
permission: string;
|
|
11
|
+
resourceType: string;
|
|
12
|
+
pending: boolean;
|
|
13
|
+
removeLabel: string;
|
|
14
|
+
requestRemove: () => void;
|
|
15
|
+
}[];
|
|
16
|
+
permission: string;
|
|
17
|
+
resourceType: string;
|
|
18
|
+
pending: boolean;
|
|
19
|
+
addDisabled: boolean;
|
|
20
|
+
changePermission: ({ value }: {
|
|
21
|
+
value: string;
|
|
22
|
+
}) => void;
|
|
23
|
+
changeResourceType: ({ value }: {
|
|
24
|
+
value: string;
|
|
25
|
+
}) => void;
|
|
26
|
+
submit: (event: {
|
|
27
|
+
preventDefault(): void;
|
|
28
|
+
}) => void;
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=PermissionPanel.hooks.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useRolesView } from './RolesPage.hooks.js';
|
|
2
|
+
export function usePermissionPanel({ policy }, _optional = {}) {
|
|
3
|
+
const { state, controller: c, canManage } = useRolesView({});
|
|
4
|
+
const editable = canManage && !policy.isBuiltin && !policy.isFrozen;
|
|
5
|
+
return { editable, loading: state.permissionsLoading, empty: state.permissionRows.length === 0,
|
|
6
|
+
rows: state.permissionRows.map(row => ({ id: row.id, permission: row.permission, resourceType: row.resourceType ?? '',
|
|
7
|
+
pending: state.removingPermissionId === row.id, removeLabel: `Remove permission ${row.permission}`,
|
|
8
|
+
requestRemove: () => c.requestDestructive({ target: { kind: 'permission', policyId: policy.id, row } }) })),
|
|
9
|
+
permission: state.permissionInput, resourceType: state.resourceTypeInput, pending: state.rowSavingId === policy.id,
|
|
10
|
+
addDisabled: state.rowSavingId !== null || !state.permissionInput.trim(),
|
|
11
|
+
changePermission: ({ value }) => c.setDraft({ patch: { permissionInput: value } }),
|
|
12
|
+
changeResourceType: ({ value }) => c.setDraft({ patch: { resourceTypeInput: value } }),
|
|
13
|
+
submit: (event) => { event.preventDefault(); void c.writePermission({}); } };
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=PermissionPanel.hooks.js.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { PolicyRecord } from '../../models.js';
|
|
2
|
+
import type { MenuItem } from '@jini-ai/ui-kit/react';
|
|
3
|
+
export declare function usePoliciesTab(_required?: Record<string, never>, _optional?: Record<string, never>): {
|
|
4
|
+
rows: readonly PolicyRecord[];
|
|
5
|
+
canManage: boolean;
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
saving: boolean;
|
|
9
|
+
error: string | null;
|
|
10
|
+
changeName: ({ value }: {
|
|
11
|
+
value: string;
|
|
12
|
+
}) => void;
|
|
13
|
+
changeDescription: ({ value }: {
|
|
14
|
+
value: string;
|
|
15
|
+
}) => void;
|
|
16
|
+
submit: (event: {
|
|
17
|
+
preventDefault(): void;
|
|
18
|
+
}) => void;
|
|
19
|
+
createDisabled: boolean;
|
|
20
|
+
};
|
|
21
|
+
export declare function usePolicyRow({ policy }: {
|
|
22
|
+
policy: PolicyRecord;
|
|
23
|
+
}, _optional?: Record<string, never>): {
|
|
24
|
+
name: string;
|
|
25
|
+
description: string;
|
|
26
|
+
type: string;
|
|
27
|
+
editable: boolean;
|
|
28
|
+
open: boolean;
|
|
29
|
+
editing: boolean;
|
|
30
|
+
draft: string;
|
|
31
|
+
draftDescription: string;
|
|
32
|
+
pending: boolean;
|
|
33
|
+
saveDisabled: boolean;
|
|
34
|
+
changeName: ({ value }: {
|
|
35
|
+
value: string;
|
|
36
|
+
}) => void;
|
|
37
|
+
changeDescription: ({ value }: {
|
|
38
|
+
value: string;
|
|
39
|
+
}) => void;
|
|
40
|
+
save: () => void;
|
|
41
|
+
cancel: () => void;
|
|
42
|
+
menu: MenuItem[];
|
|
43
|
+
menuLabel: string;
|
|
44
|
+
viewPermissions: () => void;
|
|
45
|
+
readLabel: string;
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=PoliciesTab.hooks.d.ts.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useRolesView } from './RolesPage.hooks.js';
|
|
2
|
+
export function usePoliciesTab(_required = {}, _optional = {}) {
|
|
3
|
+
const { state, controller: c, canManage } = useRolesView({});
|
|
4
|
+
return { rows: state.policies ?? [], canManage, name: state.policyName, description: state.policyDescription, saving: state.policySaving, error: state.policyError,
|
|
5
|
+
changeName: ({ value }) => c.setDraft({ patch: { policyName: value } }),
|
|
6
|
+
changeDescription: ({ value }) => c.setDraft({ patch: { policyDescription: value } }),
|
|
7
|
+
submit: (event) => { event.preventDefault(); void c.createPolicy({}); },
|
|
8
|
+
createDisabled: state.policySaving || !state.policyName.trim() };
|
|
9
|
+
}
|
|
10
|
+
export function usePolicyRow({ policy }, _optional = {}) {
|
|
11
|
+
const { state, controller: c, canManage } = useRolesView({});
|
|
12
|
+
const editable = canManage && !policy.isBuiltin && !policy.isFrozen;
|
|
13
|
+
const open = state.permissionPolicyId === policy.id;
|
|
14
|
+
const menu = [{ id: 'rename', label: 'Rename', onPress: () => c.editPolicy({ policy }) },
|
|
15
|
+
{ id: 'permission', label: open ? 'Close' : 'Add permission', onPress: () => { void c.togglePermissions({ policyId: policy.id }); } },
|
|
16
|
+
{ id: 'delete', label: 'Delete', onPress: () => c.requestDestructive({ target: { kind: 'policy', policy } }) }];
|
|
17
|
+
return { name: policy.name, description: policy.description ?? '—', type: `${policy.isBuiltin ? 'Built-in' : 'Custom'}${policy.isFrozen ? ' (frozen)' : ''}`,
|
|
18
|
+
editable, open, editing: state.editingPolicyId === policy.id, draft: state.editingPolicyName, draftDescription: state.editingPolicyDescription,
|
|
19
|
+
pending: state.rowSavingId === policy.id, saveDisabled: state.rowSavingId !== null || !state.editingPolicyName.trim(),
|
|
20
|
+
changeName: ({ value }) => c.setDraft({ patch: { editingPolicyName: value } }),
|
|
21
|
+
changeDescription: ({ value }) => c.setDraft({ patch: { editingPolicyDescription: value } }),
|
|
22
|
+
save: () => { void c.savePolicy({}); }, cancel: () => c.cancelEdit({ kind: 'policy' }), menu, menuLabel: `Actions for policy "${policy.name}"`,
|
|
23
|
+
viewPermissions: () => { void c.togglePermissions({ policyId: policy.id }); },
|
|
24
|
+
readLabel: open ? 'Close permissions' : 'View permissions' };
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=PoliciesTab.hooks.js.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ComponentType, LazyExoticComponent, ReactNode } from 'react';
|
|
2
|
+
import type { AdminInstance } from '@jini-ai/admin/core/module';
|
|
3
|
+
import { rolesModule } from '../../roles.module.js';
|
|
4
|
+
import type { RolesApiPort } from '../../ports.js';
|
|
5
|
+
export interface RolesScope {
|
|
6
|
+
readonly api: RolesApiPort;
|
|
7
|
+
readonly permissions: readonly string[];
|
|
8
|
+
}
|
|
9
|
+
export interface RolesTabProps {
|
|
10
|
+
readonly params?: Readonly<Record<string, unknown>>;
|
|
11
|
+
}
|
|
12
|
+
export interface RolesPageProps {
|
|
13
|
+
readonly tabs: Readonly<Record<string, LazyExoticComponent<ComponentType<RolesTabProps>>>>;
|
|
14
|
+
readonly description: ReturnType<AdminInstance['describe']>['pages'][number];
|
|
15
|
+
readonly requestedTab?: string;
|
|
16
|
+
readonly onTabChange?: (required: {
|
|
17
|
+
tab: string;
|
|
18
|
+
}, optional?: Record<string, never>) => void;
|
|
19
|
+
}
|
|
20
|
+
export declare function useRolesScope(_required?: Record<string, never>, _optional?: Record<string, never>): RolesScope;
|
|
21
|
+
/** A private scope binds only this module's declared ports. No admin React internals are needed. */
|
|
22
|
+
export declare function createRolesBinding({ module }: {
|
|
23
|
+
module: typeof rolesModule;
|
|
24
|
+
}, _optional?: Record<string, never>): {
|
|
25
|
+
pages: {
|
|
26
|
+
roles: {
|
|
27
|
+
Page: LazyExoticComponent<typeof import("../pages/RolesPage.js").default>;
|
|
28
|
+
tabs: {
|
|
29
|
+
roles: LazyExoticComponent<typeof import("../tabs/RolesTab.js").default>;
|
|
30
|
+
policies: LazyExoticComponent<typeof import("../tabs/PoliciesTab.js").default>;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
Provider: ({ admin, children }: {
|
|
35
|
+
admin: AdminInstance;
|
|
36
|
+
children: ReactNode;
|
|
37
|
+
}, _optional?: Record<string, never>) => import("react").FunctionComponentElement<import("react").ProviderProps<RolesScope | null>>;
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=RolesBinding.hooks.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createContext, createElement, lazy, useContext } from 'react';
|
|
2
|
+
import { rolesModule } from '../../roles.module.js';
|
|
3
|
+
const ScopeContext = createContext(null);
|
|
4
|
+
export function useRolesScope(_required = {}, _optional = {}) {
|
|
5
|
+
const scope = useContext(ScopeContext);
|
|
6
|
+
if (!scope)
|
|
7
|
+
throw new Error('Roles admin scope is unavailable.');
|
|
8
|
+
return scope;
|
|
9
|
+
}
|
|
10
|
+
/** A private scope binds only this module's declared ports. No admin React internals are needed. */
|
|
11
|
+
export function createRolesBinding({ module }, _optional = {}) {
|
|
12
|
+
const pages = { roles: { Page: lazy(() => import('../pages/RolesPage.js')), tabs: {
|
|
13
|
+
roles: lazy(() => import('../tabs/RolesTab.js')), policies: lazy(() => import('../tabs/PoliciesTab.js')),
|
|
14
|
+
} } };
|
|
15
|
+
function Provider({ admin, children }, _optional = {}) {
|
|
16
|
+
const ports = admin.scope({ module });
|
|
17
|
+
const description = admin.describe().pages.find(p => p.id === 'roles.roles');
|
|
18
|
+
const value = { api: ports.rolesApi, permissions: description?.grants ?? [] };
|
|
19
|
+
return createElement(ScopeContext.Provider, { value }, children);
|
|
20
|
+
}
|
|
21
|
+
return { pages, Provider };
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=RolesBinding.hooks.js.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** Controller creation belongs to the effect, so StrictMode replay gets a fresh instance.
|
|
2
|
+
* Both tabs read the page-owned controller; neither tab starts its own duplicate fetches. */
|
|
3
|
+
export declare function useRolesController(_required?: Record<string, never>, _optional?: Record<string, never>): {
|
|
4
|
+
controller: {
|
|
5
|
+
getSnapshot(_required?: Record<string, never>, _optional?: Record<string, never>): import("../../models.js").RolesState;
|
|
6
|
+
subscribe({ listener }: {
|
|
7
|
+
listener: () => void;
|
|
8
|
+
}, _optional?: Record<string, never>): () => void;
|
|
9
|
+
dispose(_required?: Record<string, never>, _optional?: Record<string, never>): void;
|
|
10
|
+
setDraft({ patch }: {
|
|
11
|
+
patch: Partial<import("../../models.js").RolesDraft>;
|
|
12
|
+
}, _optional?: Record<string, never>): void;
|
|
13
|
+
cancelEdit({ kind }: {
|
|
14
|
+
kind: "role" | "policy";
|
|
15
|
+
}, _optional?: Record<string, never>): void;
|
|
16
|
+
load: (_required: Record<string, never>, _optional?: Record<string, never>) => Promise<void>;
|
|
17
|
+
loadPermissions: ({ policyId }: {
|
|
18
|
+
policyId: string;
|
|
19
|
+
}, _optional?: Record<string, never>) => Promise<void>;
|
|
20
|
+
togglePermissions: ({ policyId }: {
|
|
21
|
+
policyId: string;
|
|
22
|
+
}, _optional?: Record<string, never>) => Promise<void>;
|
|
23
|
+
createRole: (_required: Record<string, never>, _optional?: Record<string, never>) => Promise<boolean>;
|
|
24
|
+
createPolicy: (_required: Record<string, never>, _optional?: Record<string, never>) => Promise<boolean>;
|
|
25
|
+
editRole: ({ role: r }: {
|
|
26
|
+
role: import("../../models.js").RoleRecord;
|
|
27
|
+
}, _optional?: Record<string, never>) => void;
|
|
28
|
+
editPolicy: ({ policy: p }: {
|
|
29
|
+
policy: import("../../models.js").PolicyRecord;
|
|
30
|
+
}, _optional?: Record<string, never>) => void;
|
|
31
|
+
saveRole: (_required: Record<string, never>, _optional?: Record<string, never>) => Promise<boolean>;
|
|
32
|
+
savePolicy: (_required: Record<string, never>, _optional?: Record<string, never>) => Promise<boolean>;
|
|
33
|
+
writePermission: (_required: Record<string, never>, _optional?: Record<string, never>) => Promise<boolean>;
|
|
34
|
+
requestDestructive: ({ target }: {
|
|
35
|
+
target: import("../../models.js").DestructiveTarget;
|
|
36
|
+
}, _optional?: Record<string, never>) => void;
|
|
37
|
+
cancelDestructive: (_required: Record<string, never>, _optional?: Record<string, never>) => void;
|
|
38
|
+
confirmDestructive: (_required: Record<string, never>, _optional?: Record<string, never>) => Promise<boolean>;
|
|
39
|
+
} | null;
|
|
40
|
+
state: import("../../models.js").RolesState | null;
|
|
41
|
+
permissions: readonly string[];
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=RolesController.hooks.d.ts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState, useSyncExternalStore } from 'react';
|
|
2
|
+
import { createRolesController } from '../../controllers/roles.controller.js';
|
|
3
|
+
import { useRolesScope } from './RolesBinding.hooks.js';
|
|
4
|
+
/** Controller creation belongs to the effect, so StrictMode replay gets a fresh instance.
|
|
5
|
+
* Both tabs read the page-owned controller; neither tab starts its own duplicate fetches. */
|
|
6
|
+
export function useRolesController(_required = {}, _optional = {}) {
|
|
7
|
+
const { api, permissions } = useRolesScope({});
|
|
8
|
+
const grantKey = JSON.stringify(permissions);
|
|
9
|
+
const [attachment, setAttachment] = useState(null);
|
|
10
|
+
// A host/workspace swap cannot render the previous scope's data while its new effect attaches.
|
|
11
|
+
const controller = attachment?.api === api && attachment.grantKey === grantKey ? attachment.controller : null;
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
const current = createRolesController({ api }, { permissions });
|
|
14
|
+
setAttachment({ controller: current, api, grantKey });
|
|
15
|
+
void current.load({});
|
|
16
|
+
return () => current.dispose({});
|
|
17
|
+
// grantKey is the immutable grant value, independent of a Provider's object identity.
|
|
18
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
19
|
+
}, [api, grantKey]);
|
|
20
|
+
const subscribe = useCallback((listener) => controller?.subscribe({ listener }) ?? (() => { }), [controller]);
|
|
21
|
+
const read = useCallback(() => controller?.getSnapshot() ?? null, [controller]);
|
|
22
|
+
const state = useSyncExternalStore(subscribe, read, () => null);
|
|
23
|
+
return { controller, state, permissions };
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=RolesController.hooks.js.map
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { RolesPageProps } from './RolesBinding.hooks.js';
|
|
2
|
+
import type { RolesController } from '../../controllers/roles.controller.js';
|
|
3
|
+
import type { RolesState } from '../../models.js';
|
|
4
|
+
import type { ConfirmDialogProps } from '@jini-ai/ui-kit/react';
|
|
5
|
+
export interface RolesView {
|
|
6
|
+
readonly controller: RolesController;
|
|
7
|
+
readonly state: RolesState;
|
|
8
|
+
readonly canManage: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare const RolesViewContext: import("react").Context<RolesView | null>;
|
|
11
|
+
export declare function useRolesView(_required?: Record<string, never>, _optional?: Record<string, never>): RolesView;
|
|
12
|
+
export declare function useRolesPage(props: RolesPageProps, _optional?: Record<string, never>): {
|
|
13
|
+
controller: {
|
|
14
|
+
getSnapshot(_required?: Record<string, never>, _optional?: Record<string, never>): RolesState;
|
|
15
|
+
subscribe({ listener }: {
|
|
16
|
+
listener: () => void;
|
|
17
|
+
}, _optional?: Record<string, never>): () => void;
|
|
18
|
+
dispose(_required?: Record<string, never>, _optional?: Record<string, never>): void;
|
|
19
|
+
setDraft({ patch }: {
|
|
20
|
+
patch: Partial<import("../../models.js").RolesDraft>;
|
|
21
|
+
}, _optional?: Record<string, never>): void;
|
|
22
|
+
cancelEdit({ kind }: {
|
|
23
|
+
kind: "role" | "policy";
|
|
24
|
+
}, _optional?: Record<string, never>): void;
|
|
25
|
+
load: (_required: Record<string, never>, _optional?: Record<string, never>) => Promise<void>;
|
|
26
|
+
loadPermissions: ({ policyId }: {
|
|
27
|
+
policyId: string;
|
|
28
|
+
}, _optional?: Record<string, never>) => Promise<void>;
|
|
29
|
+
togglePermissions: ({ policyId }: {
|
|
30
|
+
policyId: string;
|
|
31
|
+
}, _optional?: Record<string, never>) => Promise<void>;
|
|
32
|
+
createRole: (_required: Record<string, never>, _optional?: Record<string, never>) => Promise<boolean>;
|
|
33
|
+
createPolicy: (_required: Record<string, never>, _optional?: Record<string, never>) => Promise<boolean>;
|
|
34
|
+
editRole: ({ role: r }: {
|
|
35
|
+
role: import("../../models.js").RoleRecord;
|
|
36
|
+
}, _optional?: Record<string, never>) => void;
|
|
37
|
+
editPolicy: ({ policy: p }: {
|
|
38
|
+
policy: import("../../models.js").PolicyRecord;
|
|
39
|
+
}, _optional?: Record<string, never>) => void;
|
|
40
|
+
saveRole: (_required: Record<string, never>, _optional?: Record<string, never>) => Promise<boolean>;
|
|
41
|
+
savePolicy: (_required: Record<string, never>, _optional?: Record<string, never>) => Promise<boolean>;
|
|
42
|
+
writePermission: (_required: Record<string, never>, _optional?: Record<string, never>) => Promise<boolean>;
|
|
43
|
+
requestDestructive: ({ target }: {
|
|
44
|
+
target: import("../../models.js").DestructiveTarget;
|
|
45
|
+
}, _optional?: Record<string, never>) => void;
|
|
46
|
+
cancelDestructive: (_required: Record<string, never>, _optional?: Record<string, never>) => void;
|
|
47
|
+
confirmDestructive: (_required: Record<string, never>, _optional?: Record<string, never>) => Promise<boolean>;
|
|
48
|
+
} | null;
|
|
49
|
+
state: RolesState | null;
|
|
50
|
+
canManage: boolean;
|
|
51
|
+
items: {
|
|
52
|
+
id: string;
|
|
53
|
+
label: string;
|
|
54
|
+
content: import("react").FunctionComponentElement<import("./RolesBinding.hooks.js").RolesTabProps | (import("./RolesBinding.hooks.js").RolesTabProps & import("react").RefAttributes<import("react").Component<import("./RolesBinding.hooks.js").RolesTabProps, any, any>>)> | null;
|
|
55
|
+
}[];
|
|
56
|
+
tab: string;
|
|
57
|
+
confirm: ConfirmDialogProps;
|
|
58
|
+
hidden: boolean;
|
|
59
|
+
noTabs: boolean;
|
|
60
|
+
view: {
|
|
61
|
+
controller: {
|
|
62
|
+
getSnapshot(_required?: Record<string, never>, _optional?: Record<string, never>): RolesState;
|
|
63
|
+
subscribe({ listener }: {
|
|
64
|
+
listener: () => void;
|
|
65
|
+
}, _optional?: Record<string, never>): () => void;
|
|
66
|
+
dispose(_required?: Record<string, never>, _optional?: Record<string, never>): void;
|
|
67
|
+
setDraft({ patch }: {
|
|
68
|
+
patch: Partial<import("../../models.js").RolesDraft>;
|
|
69
|
+
}, _optional?: Record<string, never>): void;
|
|
70
|
+
cancelEdit({ kind }: {
|
|
71
|
+
kind: "role" | "policy";
|
|
72
|
+
}, _optional?: Record<string, never>): void;
|
|
73
|
+
load: (_required: Record<string, never>, _optional?: Record<string, never>) => Promise<void>;
|
|
74
|
+
loadPermissions: ({ policyId }: {
|
|
75
|
+
policyId: string;
|
|
76
|
+
}, _optional?: Record<string, never>) => Promise<void>;
|
|
77
|
+
togglePermissions: ({ policyId }: {
|
|
78
|
+
policyId: string;
|
|
79
|
+
}, _optional?: Record<string, never>) => Promise<void>;
|
|
80
|
+
createRole: (_required: Record<string, never>, _optional?: Record<string, never>) => Promise<boolean>;
|
|
81
|
+
createPolicy: (_required: Record<string, never>, _optional?: Record<string, never>) => Promise<boolean>;
|
|
82
|
+
editRole: ({ role: r }: {
|
|
83
|
+
role: import("../../models.js").RoleRecord;
|
|
84
|
+
}, _optional?: Record<string, never>) => void;
|
|
85
|
+
editPolicy: ({ policy: p }: {
|
|
86
|
+
policy: import("../../models.js").PolicyRecord;
|
|
87
|
+
}, _optional?: Record<string, never>) => void;
|
|
88
|
+
saveRole: (_required: Record<string, never>, _optional?: Record<string, never>) => Promise<boolean>;
|
|
89
|
+
savePolicy: (_required: Record<string, never>, _optional?: Record<string, never>) => Promise<boolean>;
|
|
90
|
+
writePermission: (_required: Record<string, never>, _optional?: Record<string, never>) => Promise<boolean>;
|
|
91
|
+
requestDestructive: ({ target }: {
|
|
92
|
+
target: import("../../models.js").DestructiveTarget;
|
|
93
|
+
}, _optional?: Record<string, never>) => void;
|
|
94
|
+
cancelDestructive: (_required: Record<string, never>, _optional?: Record<string, never>) => void;
|
|
95
|
+
confirmDestructive: (_required: Record<string, never>, _optional?: Record<string, never>) => Promise<boolean>;
|
|
96
|
+
};
|
|
97
|
+
state: RolesState;
|
|
98
|
+
canManage: boolean;
|
|
99
|
+
} | null;
|
|
100
|
+
changeTab: ({ value }: {
|
|
101
|
+
value: string;
|
|
102
|
+
}) => void;
|
|
103
|
+
retry: () => void;
|
|
104
|
+
};
|
|
105
|
+
//# sourceMappingURL=RolesPage.hooks.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createContext, createElement, useContext, useState } from 'react';
|
|
2
|
+
import { useRolesController } from './RolesController.hooks.js';
|
|
3
|
+
import { canManageRoles, destructiveCopy } from '../../rules.js';
|
|
4
|
+
export const RolesViewContext = createContext(null);
|
|
5
|
+
export function useRolesView(_required = {}, _optional = {}) {
|
|
6
|
+
const view = useContext(RolesViewContext);
|
|
7
|
+
if (!view)
|
|
8
|
+
throw new Error('Roles page controller unavailable.');
|
|
9
|
+
return view;
|
|
10
|
+
}
|
|
11
|
+
export function useRolesPage(props, _optional = {}) {
|
|
12
|
+
const { controller, state, permissions } = useRolesController({});
|
|
13
|
+
const [selected, setSelected] = useState('roles');
|
|
14
|
+
const canManage = canManageRoles({ permissions });
|
|
15
|
+
const visible = props.description.visible ? props.description.tabs.filter(t => t.visible && props.tabs[t.id.slice(t.id.lastIndexOf('.') + 1)]) : [];
|
|
16
|
+
const ids = visible.map(t => t.id.slice(t.id.lastIndexOf('.') + 1));
|
|
17
|
+
// A stale bookmark opens a real visible tab; omitted/forbidden tabs cannot be rendered directly.
|
|
18
|
+
const requested = props.requestedTab ?? selected;
|
|
19
|
+
const tab = ids.includes(requested) ? requested : ids[0] ?? '';
|
|
20
|
+
const items = visible.map(t => { const id = t.id.slice(t.id.lastIndexOf('.') + 1), Component = props.tabs[id]; return { id, label: t.label, content: id === tab ? createElement(Component, { params: t.params }) : null }; });
|
|
21
|
+
const copy = destructiveCopy({ target: state?.pending ?? null });
|
|
22
|
+
const confirm = { open: state?.pending != null, title: copy.title, body: copy.body, confirmLabel: copy.label,
|
|
23
|
+
tone: copy.tone, consequence: copy.consequence, pending: state?.confirming ?? false, agentMayConfirm: false,
|
|
24
|
+
onConfirm: async () => { await controller?.confirmDestructive({}); }, onCancel: () => controller?.cancelDestructive({}) };
|
|
25
|
+
return {
|
|
26
|
+
controller, state, canManage, items, tab, confirm,
|
|
27
|
+
hidden: !props.description.visible, noTabs: visible.length === 0,
|
|
28
|
+
view: controller && state ? { controller, state, canManage } : null,
|
|
29
|
+
changeTab: ({ value }) => { setSelected(value); props.onTabChange?.({ tab: value }); },
|
|
30
|
+
retry: () => { void controller?.load({}); },
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=RolesPage.hooks.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { RoleRecord } from '../../models.js';
|
|
2
|
+
import type { MenuItem } from '@jini-ai/ui-kit/react';
|
|
3
|
+
export declare function useRolesTab(_required?: Record<string, never>, _optional?: Record<string, never>): {
|
|
4
|
+
rows: readonly RoleRecord[];
|
|
5
|
+
canManage: boolean;
|
|
6
|
+
name: string;
|
|
7
|
+
saving: boolean;
|
|
8
|
+
error: string | null;
|
|
9
|
+
changeName: ({ value }: {
|
|
10
|
+
value: string;
|
|
11
|
+
}) => void;
|
|
12
|
+
submit: (event: {
|
|
13
|
+
preventDefault(): void;
|
|
14
|
+
}) => void;
|
|
15
|
+
createDisabled: boolean;
|
|
16
|
+
};
|
|
17
|
+
export declare function useRoleRow({ role }: {
|
|
18
|
+
role: RoleRecord;
|
|
19
|
+
}, _optional?: Record<string, never>): {
|
|
20
|
+
name: string;
|
|
21
|
+
type: string;
|
|
22
|
+
editable: boolean;
|
|
23
|
+
editing: boolean;
|
|
24
|
+
draft: string;
|
|
25
|
+
pending: boolean;
|
|
26
|
+
saveDisabled: boolean;
|
|
27
|
+
changeName: ({ value }: {
|
|
28
|
+
value: string;
|
|
29
|
+
}) => void;
|
|
30
|
+
save: () => void;
|
|
31
|
+
cancel: () => void;
|
|
32
|
+
menu: MenuItem[];
|
|
33
|
+
menuLabel: string;
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=RolesTab.hooks.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useRolesView } from './RolesPage.hooks.js';
|
|
2
|
+
export function useRolesTab(_required = {}, _optional = {}) {
|
|
3
|
+
const { state, controller: c, canManage } = useRolesView({});
|
|
4
|
+
return { rows: state.roles ?? [], canManage, name: state.roleName, saving: state.roleSaving, error: state.roleError,
|
|
5
|
+
changeName: ({ value }) => c.setDraft({ patch: { roleName: value } }),
|
|
6
|
+
submit: (event) => { event.preventDefault(); void c.createRole({}); },
|
|
7
|
+
createDisabled: state.roleSaving || !state.roleName.trim() };
|
|
8
|
+
}
|
|
9
|
+
export function useRoleRow({ role }, _optional = {}) {
|
|
10
|
+
const { state, controller: c, canManage } = useRolesView({});
|
|
11
|
+
const editable = canManage && !role.isBuiltin;
|
|
12
|
+
const menu = [{ id: 'rename', label: 'Rename', onPress: () => c.editRole({ role }) }, { id: 'delete', label: 'Delete', onPress: () => c.requestDestructive({ target: { kind: 'role', role } }) }];
|
|
13
|
+
return { name: role.name, type: role.isBuiltin ? 'Built-in' : 'Custom', editable, editing: state.editingRoleId === role.id,
|
|
14
|
+
draft: state.editingRoleName, pending: state.rowSavingId === role.id,
|
|
15
|
+
saveDisabled: state.rowSavingId !== null || !state.editingRoleName.trim(),
|
|
16
|
+
changeName: ({ value }) => c.setDraft({ patch: { editingRoleName: value } }),
|
|
17
|
+
save: () => { void c.saveRole({}); }, cancel: () => c.cancelEdit({ kind: 'role' }), menu, menuLabel: `Actions for role "${role.name}"` };
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=RolesTab.hooks.js.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ComponentType, LazyExoticComponent, ReactNode } from 'react';
|
|
2
|
+
import type { AdminInstance } from '@jini-ai/admin/core/module';
|
|
3
|
+
import type { UsersApiPort, UsersSafetyPort } from '../../ports.js';
|
|
4
|
+
import { usersModule } from '../../users.module.js';
|
|
5
|
+
export interface UsersScope {
|
|
6
|
+
readonly api: UsersApiPort;
|
|
7
|
+
readonly permissions: readonly string[];
|
|
8
|
+
readonly safety: UsersSafetyPort;
|
|
9
|
+
}
|
|
10
|
+
export interface UsersPageProps {
|
|
11
|
+
readonly tabs: Readonly<Record<string, LazyExoticComponent<ComponentType<{
|
|
12
|
+
readonly params?: Readonly<Record<string, unknown>>;
|
|
13
|
+
}>>>>;
|
|
14
|
+
readonly description: ReturnType<AdminInstance['describe']>['pages'][number];
|
|
15
|
+
readonly openOwnPasswordReset?: boolean;
|
|
16
|
+
readonly onOwnPasswordResetClosed?: (required: Record<string, never>, optional?: Record<string, never>) => void;
|
|
17
|
+
}
|
|
18
|
+
export declare function useUsersScope(_required?: Record<string, never>, _optional?: Record<string, never>): UsersScope;
|
|
19
|
+
/** Descriptor identity must be the exact enriched object supplied to createAdmin. */
|
|
20
|
+
export declare function createUsersBinding({ module }: {
|
|
21
|
+
module: typeof usersModule;
|
|
22
|
+
}, _optional?: Record<string, never>): {
|
|
23
|
+
pages: {
|
|
24
|
+
users: {
|
|
25
|
+
Page: LazyExoticComponent<typeof import("../pages/UsersPage.js").default>;
|
|
26
|
+
tabs: {
|
|
27
|
+
users: LazyExoticComponent<typeof import("../tabs/UsersTab.js").default>;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
Provider: ({ admin, children }: {
|
|
32
|
+
admin: AdminInstance;
|
|
33
|
+
children: ReactNode;
|
|
34
|
+
}, _optional?: Record<string, never>) => import("react").FunctionComponentElement<import("react").ProviderProps<UsersScope | null>>;
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=UsersBinding.hooks.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createContext, createElement, lazy, useContext } from 'react';
|
|
2
|
+
import { usersModule } from '../../users.module.js';
|
|
3
|
+
const ScopeContext = createContext(null);
|
|
4
|
+
export function useUsersScope(_required = {}, _optional = {}) {
|
|
5
|
+
const scope = useContext(ScopeContext);
|
|
6
|
+
if (!scope)
|
|
7
|
+
throw new Error('Users admin scope is unavailable.');
|
|
8
|
+
return scope;
|
|
9
|
+
}
|
|
10
|
+
/** Descriptor identity must be the exact enriched object supplied to createAdmin. */
|
|
11
|
+
export function createUsersBinding({ module }, _optional = {}) {
|
|
12
|
+
const pages = { users: { Page: lazy(() => import('../pages/UsersPage.js')), tabs: { users: lazy(() => import('../tabs/UsersTab.js')) } } };
|
|
13
|
+
function Provider({ admin, children }, _optional = {}) {
|
|
14
|
+
const ports = admin.scope({ module });
|
|
15
|
+
const description = admin.describe().pages.find(p => p.id === 'users.users');
|
|
16
|
+
const value = { api: ports.usersApi, permissions: description?.grants ?? [], safety: ports.usersSafety };
|
|
17
|
+
return createElement(ScopeContext.Provider, { value }, children);
|
|
18
|
+
}
|
|
19
|
+
return { pages, Provider };
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=UsersBinding.hooks.js.map
|