@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.
Files changed (190) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/LICENSE +201 -0
  3. package/README.md +104 -0
  4. package/dist/admin/adapters/http.d.ts +29 -0
  5. package/dist/admin/adapters/http.js +69 -0
  6. package/dist/admin/adapters/memory.d.ts +61 -0
  7. package/dist/admin/adapters/memory.js +217 -0
  8. package/dist/admin/auth.module.d.ts +30 -0
  9. package/dist/admin/auth.module.js +12 -0
  10. package/dist/admin/conformance/index.d.ts +56 -0
  11. package/dist/admin/conformance/index.js +156 -0
  12. package/dist/admin/controllers/auth.controller.d.ts +23 -0
  13. package/dist/admin/controllers/auth.controller.js +33 -0
  14. package/dist/admin/controllers/controller-store.d.ts +18 -0
  15. package/dist/admin/controllers/controller-store.js +23 -0
  16. package/dist/admin/controllers/members.controller.d.ts +33 -0
  17. package/dist/admin/controllers/members.controller.js +119 -0
  18. package/dist/admin/controllers/roles.controller.d.ts +47 -0
  19. package/dist/admin/controllers/roles.controller.js +282 -0
  20. package/dist/admin/controllers/users.controller.d.ts +53 -0
  21. package/dist/admin/controllers/users.controller.js +220 -0
  22. package/dist/admin/index.d.ts +21 -0
  23. package/dist/admin/index.js +15 -0
  24. package/dist/admin/members.module.d.ts +34 -0
  25. package/dist/admin/members.module.js +13 -0
  26. package/dist/admin/messages.en.d.ts +37 -0
  27. package/dist/admin/messages.en.js +21 -0
  28. package/dist/admin/models.d.ts +133 -0
  29. package/dist/admin/models.js +2 -0
  30. package/dist/admin/people.rules.d.ts +29 -0
  31. package/dist/admin/people.rules.js +51 -0
  32. package/dist/admin/ports.d.ts +187 -0
  33. package/dist/admin/ports.js +17 -0
  34. package/dist/admin/react/components/DestructiveDialog.d.ts +5 -0
  35. package/dist/admin/react/components/DestructiveDialog.js +6 -0
  36. package/dist/admin/react/components/MemberRow.d.ts +5 -0
  37. package/dist/admin/react/components/MemberRow.js +8 -0
  38. package/dist/admin/react/components/MembersConfirmation.d.ts +2 -0
  39. package/dist/admin/react/components/MembersConfirmation.js +8 -0
  40. package/dist/admin/react/components/PermissionPanel.d.ts +5 -0
  41. package/dist/admin/react/components/PermissionPanel.js +9 -0
  42. package/dist/admin/react/components/PolicyRow.d.ts +5 -0
  43. package/dist/admin/react/components/PolicyRow.js +11 -0
  44. package/dist/admin/react/components/RoleRow.d.ts +5 -0
  45. package/dist/admin/react/components/RoleRow.js +10 -0
  46. package/dist/admin/react/components/UserRow.d.ts +5 -0
  47. package/dist/admin/react/components/UserRow.js +8 -0
  48. package/dist/admin/react/components/UsersConfirmation.d.ts +3 -0
  49. package/dist/admin/react/components/UsersConfirmation.js +9 -0
  50. package/dist/admin/react/hooks/AuthBinding.hooks.d.ts +39 -0
  51. package/dist/admin/react/hooks/AuthBinding.hooks.js +21 -0
  52. package/dist/admin/react/hooks/LoginPage.hooks.d.ts +54 -0
  53. package/dist/admin/react/hooks/LoginPage.hooks.js +23 -0
  54. package/dist/admin/react/hooks/MembersBinding.hooks.d.ts +35 -0
  55. package/dist/admin/react/hooks/MembersBinding.hooks.js +21 -0
  56. package/dist/admin/react/hooks/MembersPage.hooks.d.ts +99 -0
  57. package/dist/admin/react/hooks/MembersPage.hooks.js +38 -0
  58. package/dist/admin/react/hooks/PeopleController.hooks.d.ts +18 -0
  59. package/dist/admin/react/hooks/PeopleController.hooks.js +20 -0
  60. package/dist/admin/react/hooks/PermissionPanel.hooks.d.ts +30 -0
  61. package/dist/admin/react/hooks/PermissionPanel.hooks.js +15 -0
  62. package/dist/admin/react/hooks/PoliciesTab.hooks.d.ts +47 -0
  63. package/dist/admin/react/hooks/PoliciesTab.hooks.js +26 -0
  64. package/dist/admin/react/hooks/RolesBinding.hooks.d.ts +39 -0
  65. package/dist/admin/react/hooks/RolesBinding.hooks.js +23 -0
  66. package/dist/admin/react/hooks/RolesController.hooks.d.ts +43 -0
  67. package/dist/admin/react/hooks/RolesController.hooks.js +25 -0
  68. package/dist/admin/react/hooks/RolesPage.hooks.d.ts +105 -0
  69. package/dist/admin/react/hooks/RolesPage.hooks.js +33 -0
  70. package/dist/admin/react/hooks/RolesTab.hooks.d.ts +35 -0
  71. package/dist/admin/react/hooks/RolesTab.hooks.js +19 -0
  72. package/dist/admin/react/hooks/UsersBinding.hooks.d.ts +36 -0
  73. package/dist/admin/react/hooks/UsersBinding.hooks.js +21 -0
  74. package/dist/admin/react/hooks/UsersPage.hooks.d.ts +106 -0
  75. package/dist/admin/react/hooks/UsersPage.hooks.js +22 -0
  76. package/dist/admin/react/hooks/UsersTab.hooks.d.ts +101 -0
  77. package/dist/admin/react/hooks/UsersTab.hooks.js +53 -0
  78. package/dist/admin/react/index.d.ts +203 -0
  79. package/dist/admin/react/index.js +32 -0
  80. package/dist/admin/react/pages/LoginPage.d.ts +3 -0
  81. package/dist/admin/react/pages/LoginPage.js +13 -0
  82. package/dist/admin/react/pages/MembersPage.d.ts +3 -0
  83. package/dist/admin/react/pages/MembersPage.js +19 -0
  84. package/dist/admin/react/pages/RolesPage.d.ts +3 -0
  85. package/dist/admin/react/pages/RolesPage.js +19 -0
  86. package/dist/admin/react/pages/UsersPage.d.ts +3 -0
  87. package/dist/admin/react/pages/UsersPage.js +19 -0
  88. package/dist/admin/react/tabs/AuthTab.d.ts +4 -0
  89. package/dist/admin/react/tabs/AuthTab.js +8 -0
  90. package/dist/admin/react/tabs/MembersTab.d.ts +4 -0
  91. package/dist/admin/react/tabs/MembersTab.js +9 -0
  92. package/dist/admin/react/tabs/PoliciesTab.d.ts +4 -0
  93. package/dist/admin/react/tabs/PoliciesTab.js +9 -0
  94. package/dist/admin/react/tabs/RolesTab.d.ts +4 -0
  95. package/dist/admin/react/tabs/RolesTab.js +9 -0
  96. package/dist/admin/react/tabs/UsersTab.d.ts +4 -0
  97. package/dist/admin/react/tabs/UsersTab.js +9 -0
  98. package/dist/admin/roles.module.d.ts +48 -0
  99. package/dist/admin/roles.module.js +15 -0
  100. package/dist/admin/rules.d.ts +32 -0
  101. package/dist/admin/rules.js +32 -0
  102. package/dist/admin/users.module.d.ts +39 -0
  103. package/dist/admin/users.module.js +14 -0
  104. package/dist/core/builtin-permissions.d.ts +10 -0
  105. package/dist/core/builtin-permissions.js +402 -0
  106. package/dist/core/index.d.ts +6 -0
  107. package/dist/core/index.js +9 -0
  108. package/dist/core/permissions.d.ts +40 -0
  109. package/dist/core/permissions.js +52 -0
  110. package/dist/core/ports.d.ts +237 -0
  111. package/dist/core/ports.js +2 -0
  112. package/dist/core/runtime-ports.d.ts +8 -0
  113. package/dist/core/runtime-ports.js +2 -0
  114. package/dist/core/types.d.ts +224 -0
  115. package/dist/core/types.js +93 -0
  116. package/dist/react/auth/Login.d.ts +9 -0
  117. package/dist/react/auth/Login.js +8 -0
  118. package/dist/react/auth/hooks/use-login.hooks.d.ts +22 -0
  119. package/dist/react/auth/hooks/use-login.hooks.js +24 -0
  120. package/dist/react/errors.d.ts +10 -0
  121. package/dist/react/errors.js +13 -0
  122. package/dist/react/index.d.ts +18 -0
  123. package/dist/react/index.js +9 -0
  124. package/dist/react/members/Members.d.ts +6 -0
  125. package/dist/react/members/Members.js +38 -0
  126. package/dist/react/members/hooks/use-members.hooks.d.ts +32 -0
  127. package/dist/react/members/hooks/use-members.hooks.js +120 -0
  128. package/dist/react/members/rules.d.ts +26 -0
  129. package/dist/react/members/rules.js +35 -0
  130. package/dist/react/models.d.ts +50 -0
  131. package/dist/react/models.js +2 -0
  132. package/dist/react/ports.d.ts +157 -0
  133. package/dist/react/ports.js +2 -0
  134. package/dist/react/roles/Roles.d.ts +100 -0
  135. package/dist/react/roles/Roles.hooks.d.ts +17 -0
  136. package/dist/react/roles/Roles.hooks.js +40 -0
  137. package/dist/react/roles/Roles.js +150 -0
  138. package/dist/react/roles/hooks/use-roles.hooks.d.ts +80 -0
  139. package/dist/react/roles/hooks/use-roles.hooks.js +303 -0
  140. package/dist/react/roles/rules.d.ts +35 -0
  141. package/dist/react/roles/rules.js +31 -0
  142. package/dist/react/roles/text.d.ts +27 -0
  143. package/dist/react/roles/text.js +13 -0
  144. package/dist/react/testing.d.ts +51 -0
  145. package/dist/react/testing.js +275 -0
  146. package/dist/react/users/Users.d.ts +72 -0
  147. package/dist/react/users/Users.js +129 -0
  148. package/dist/react/users/hooks/use-reset-password-fields.hooks.d.ts +16 -0
  149. package/dist/react/users/hooks/use-reset-password-fields.hooks.js +21 -0
  150. package/dist/react/users/hooks/use-users.hooks.d.ts +77 -0
  151. package/dist/react/users/hooks/use-users.hooks.js +286 -0
  152. package/dist/react/users/rules.d.ts +33 -0
  153. package/dist/react/users/rules.js +61 -0
  154. package/dist/server/admin-crud-service.d.ts +295 -0
  155. package/dist/server/admin-crud-service.js +561 -0
  156. package/dist/server/agent-tool-input.d.ts +58 -0
  157. package/dist/server/agent-tool-input.js +158 -0
  158. package/dist/server/agent-tool-registrations.d.ts +51 -0
  159. package/dist/server/agent-tool-registrations.js +417 -0
  160. package/dist/server/agent-tools.d.ts +88 -0
  161. package/dist/server/agent-tools.js +229 -0
  162. package/dist/server/auth-service.d.ts +107 -0
  163. package/dist/server/auth-service.js +170 -0
  164. package/dist/server/authorize.d.ts +92 -0
  165. package/dist/server/authorize.js +96 -0
  166. package/dist/server/grant-service.d.ts +219 -0
  167. package/dist/server/grant-service.js +419 -0
  168. package/dist/server/hasher.d.ts +64 -0
  169. package/dist/server/hasher.js +53 -0
  170. package/dist/server/identity-transaction.d.ts +9 -0
  171. package/dist/server/identity-transaction.js +8 -0
  172. package/dist/server/index.d.ts +18 -0
  173. package/dist/server/index.js +20 -0
  174. package/dist/server/messages.d.ts +7 -0
  175. package/dist/server/messages.js +5 -0
  176. package/dist/server/password-policy.d.ts +59 -0
  177. package/dist/server/password-policy.js +66 -0
  178. package/dist/server/permission-migrations.d.ts +84 -0
  179. package/dist/server/permission-migrations.js +77 -0
  180. package/dist/server/repo.memory-transactions.d.ts +16 -0
  181. package/dist/server/repo.memory-transactions.js +79 -0
  182. package/dist/server/repo.memory.d.ts +186 -0
  183. package/dist/server/repo.memory.js +230 -0
  184. package/dist/server/seed.d.ts +56 -0
  185. package/dist/server/seed.js +435 -0
  186. package/dist/server/session-tokens.d.ts +10 -0
  187. package/dist/server/session-tokens.js +12 -0
  188. package/dist/server/username.d.ts +14 -0
  189. package/dist/server/username.js +14 -0
  190. package/package.json +144 -0
@@ -0,0 +1,150 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { rolesDescriptionParts, roleDeleteBodyParts, policyDeleteBodyParts, permissionRemoveBodyParts } from "./text.js";
3
+ import { Fragment } from "react";
4
+ import { DataTable, RowMenu, ConfirmDialog } from "@jini-ai/admin/react";
5
+ import { agentHandle } from "@jini-ai/agentic";
6
+ import { buildAgentListHandles } from "@jini-ai/ui/panel-kit";
7
+ import { TabBar } from "@jini-ai/ui/tab-strip";
8
+ import { roleMenuItems, policyMenuItems } from "./rules.js";
9
+ import { useRoles } from "./hooks/use-roles.hooks.js";
10
+ import { resolveRolesTabId, resolveRolesTabs } from "./Roles.hooks.js";
11
+ export function RolesSection({ roles, create, row, t, translate }) {
12
+ const roleMenuHandles = buildAgentListHandles({ prefix: "roles-row", ids: roles.map((role) => role.id) });
13
+ return (_jsxs(_Fragment, { children: [_jsx("h2", { className: "visually-hidden", children: t("Roles") }), _jsxs("form", { onSubmit: create.submit, className: "notice integrations-form form-measure", children: [create.error ? _jsx("span", { className: "save-error", children: create.error }) : null, _jsxs("label", { children: [t("Role name"), _jsx("input", { value: create.name, onChange: (e) => create.setName(e.target.value), required: true, ...agentHandle({ handle: "roles-create-name" }, { role: "field", label: t("New role's name") }) })] }), _jsx("button", { type: "submit", disabled: create.saving || !create.name, ...agentHandle({ handle: "roles-create-submit" }, { role: "button", label: t("Create this new role") }), children: create.saving ? t("Creating…") : t("Create role") })] }), _jsx(DataTable, { rows: roles, rowKey: (role) => role.id, empty: _jsx("div", { className: "card", children: _jsx("div", { className: "empty-state", children: _jsx("p", { children: t("No roles yet.") }) }) }), columns: [
14
+ {
15
+ key: "name",
16
+ header: t("Name"),
17
+ cell: (role, index) => row.editingId === role.id ? (_jsx("input", { value: row.draftName, onChange: (e) => row.setDraftName(e.target.value), ...agentHandle({ handle: `${roleMenuHandles[index]}-rename-name` }, { role: "field", label: t("This role's new name") }) })) : (role.name),
18
+ },
19
+ { key: "type", header: t("Type"), cell: (role) => (role.isBuiltin ? t("Built-in") : t("Custom")) },
20
+ {
21
+ key: "actions",
22
+ header: t("More"),
23
+ cell: (role, index) => role.isBuiltin ? (_jsx("span", { className: "muted-cell", children: "\u2014" })) : row.editingId === role.id ? (_jsxs("span", { className: "editor-actions", children: [_jsx("button", { type: "button", disabled: row.savingId === role.id, onClick: () => row.saveRename({ roleId: role.id }), ...agentHandle({ handle: `${roleMenuHandles[index]}-save` }, { role: "button", label: t(`Save this role's new name`) }), children: row.savingId === role.id ? t("Saving…") : t("Save") }), _jsx("button", { type: "button", onClick: () => row.setEditingId(null), ...agentHandle({ handle: `${roleMenuHandles[index]}-cancel` }, { role: "button", label: t("Cancel renaming this role") }), children: t("Cancel") })] })) : (_jsx(RowMenu, { triggerLabel: `${t("Actions for role")} "${role.name}"`, agentHandle: `${roleMenuHandles[index]}-menu`, items: roleMenuItems({ role, handlers: { onRename: row.startRename, onDelete: row.requestDelete }, translate }) })),
24
+ },
25
+ ] })] }));
26
+ }
27
+ function PolicyRowActions({ policy, row, permission, agentBase, t, translate }) {
28
+ if (policy.isBuiltin || policy.isFrozen)
29
+ return _jsx("span", { className: "muted-cell", children: "\u2014" });
30
+ if (row.editingId === policy.id) {
31
+ return (_jsxs("span", { className: "editor-actions", children: [_jsx("button", { type: "button", disabled: row.savingId === policy.id, onClick: () => row.saveRename({ policyId: policy.id }), ...agentHandle({ handle: `${agentBase}-save` }, { role: "button", label: t("Save this policy's new name and description") }), children: row.savingId === policy.id ? t("Saving…") : t("Save") }), _jsx("button", { type: "button", onClick: () => row.setEditingId(null), ...agentHandle({ handle: `${agentBase}-cancel` }, { role: "button", label: t("Cancel renaming this policy") }), children: t("Cancel") })] }));
32
+ }
33
+ return (_jsx(RowMenu, { triggerLabel: `${t("Actions for policy")} "${policy.name}"`, agentHandle: `${agentBase}-menu`, items: policyMenuItems({
34
+ policy,
35
+ permissionPolicyId: permission.openForPolicyId,
36
+ handlers: {
37
+ onRename: row.startRename,
38
+ onTogglePermissionForm: permission.toggleForm,
39
+ onDelete: row.requestDelete,
40
+ },
41
+ translate,
42
+ }) }));
43
+ }
44
+ function PolicyPermissionList({ policyId, permission, t }) {
45
+ if (permission.loading)
46
+ return _jsx("p", { className: "muted-cell", children: t("Loading permissions…") });
47
+ if (permission.rows.length === 0)
48
+ return _jsx("p", { className: "muted-cell", children: t("No permissions yet.") });
49
+ const removeHandles = buildAgentListHandles({
50
+ prefix: `policy-permission-remove-${policyId}`,
51
+ ids: permission.rows.map((row) => row.id),
52
+ });
53
+ return (_jsx("ul", { className: "permission-list", children: permission.rows.map((row, index) => (_jsxs("li", { children: [_jsx("code", { children: row.permission }), row.resourceType ? _jsxs("span", { className: "muted-cell", children: [" (", row.resourceType, ")"] }) : null, _jsx("button", { type: "button", disabled: permission.removingId === row.id, "aria-label": `${t("Remove permission")} ${row.permission}`, onClick: () => permission.requestRemove({ policyId, row }), ...agentHandle({ handle: removeHandles[index] }, { role: "button", label: t(`Remove the "${row.permission}" permission from this policy`) }), children: permission.removingId === row.id ? t("Removing…") : t("Remove") })] }, row.id))) }));
54
+ }
55
+ function PolicyPermissionForm({ policyId, savingId, permission, t }) {
56
+ const formHandleBase = buildAgentListHandles({ prefix: "policy-permission-form", ids: [policyId] })[0];
57
+ return (_jsx("tr", { children: _jsx("td", { colSpan: 4, children: _jsxs("div", { className: "notice integrations-form", children: [_jsx("p", { children: t("Current permissions") }), _jsx(PolicyPermissionList, { policyId: policyId, permission: permission, t: t }), _jsxs("label", { children: [t("Permission"), _jsxs("span", { className: "editor-actions permission-form-fields", children: [_jsx("input", { value: permission.permission, onChange: (e) => permission.setPermission(e.target.value), placeholder: t("e.g. content.write"), ...agentHandle({ handle: `${formHandleBase}-permission` }, { role: "field", label: t("Permission string to grant, e.g. content.write") }) }), _jsx("input", { value: permission.resourceType, onChange: (e) => permission.setResourceType(e.target.value), placeholder: t("resource type (optional)"), ...agentHandle({ handle: `${formHandleBase}-resource-type` }, { role: "field", label: t("Optional resource type this permission is scoped to") }) }), _jsx("button", { type: "button", disabled: !permission.permission || savingId === policyId, onClick: () => permission.write({ policyId }), ...agentHandle({ handle: `${formHandleBase}-add` }, { role: "button", label: t("Add this permission to the policy") }), children: savingId === policyId ? t("Saving…") : t("Add") })] })] })] }) }) }));
58
+ }
59
+ export function PolicyRow({ policy, row, permission, agentBase, t, translate }) {
60
+ const renaming = row.editingId === policy.id;
61
+ return (_jsxs(_Fragment, { children: [_jsxs("tr", { children: [_jsx("td", { children: renaming ? (_jsx("input", { value: row.draftName, onChange: (e) => row.setDraftName(e.target.value), ...agentHandle({ handle: `${agentBase}-rename-name` }, { role: "field", label: t("This policy's new name") }) })) : (policy.name) }), _jsx("td", { children: renaming ? (_jsx("input", { value: row.draftDescription, onChange: (e) => row.setDraftDescription(e.target.value), ...agentHandle({ handle: `${agentBase}-rename-description` }, { role: "field", label: t("This policy's new description") }) })) : (policy.description ?? _jsx("span", { className: "muted-cell", children: "\u2014" })) }), _jsxs("td", { children: [policy.isBuiltin ? t("Built-in") : t("Custom"), policy.isFrozen ? ` ${t("(frozen)")}` : ""] }), _jsx("td", { children: _jsx(PolicyRowActions, { policy: policy, row: row, permission: permission, agentBase: agentBase, t: t, translate: translate }) })] }), permission.openForPolicyId === policy.id ? (_jsx(PolicyPermissionForm, { policyId: policy.id, savingId: row.savingId, permission: permission, t: t })) : null] }));
62
+ }
63
+ export function PoliciesSection({ policies, create, row, permission, t, translate }) {
64
+ const policyMenuBases = buildAgentListHandles({ prefix: "policies-row", ids: policies.map((policy) => policy.id) });
65
+ return (_jsxs(_Fragment, { children: [_jsx("h2", { className: "visually-hidden", children: t("Policies") }), _jsxs("form", { onSubmit: create.submit, className: "notice integrations-form form-measure", children: [create.error ? _jsx("span", { className: "save-error", children: create.error }) : null, _jsxs("label", { children: [t("Policy name"), _jsx("input", { value: create.name, onChange: (e) => create.setName(e.target.value), required: true, ...agentHandle({ handle: "policies-create-name" }, { role: "field", label: t("New policy's name") }) })] }), _jsxs("label", { children: [t("Description (optional)"), _jsx("input", { value: create.description, onChange: (e) => create.setDescription(e.target.value), ...agentHandle({ handle: "policies-create-description" }, { role: "field", label: t("New policy's optional description") }) })] }), _jsx("button", { type: "submit", disabled: create.saving || !create.name, ...agentHandle({ handle: "policies-create-submit" }, { role: "button", label: t("Create this new policy") }), children: create.saving ? t("Creating…") : t("Create policy") })] }), policies.length === 0 ? (_jsx("div", { className: "card", children: _jsx("div", { className: "empty-state", children: _jsx("p", { children: t("No policies yet.") }) }) })) : (_jsx("div", { className: "table-scroll", children: _jsxs("table", { className: "list-table", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: t("Name") }), _jsx("th", { children: t("Description") }), _jsx("th", { children: t("Type") }), _jsx("th", { children: t("More") })] }) }), _jsx("tbody", { children: policies.map((policy, index) => (_jsx(Fragment, { children: _jsx(PolicyRow, { policy: policy, row: row, permission: permission, agentBase: policyMenuBases[index], t: t, translate: translate }) }, policy.id))) })] }) }))] }));
66
+ }
67
+ function RoleDeleteDialog({ pendingRoleDelete, setPendingRoleDelete, rowSavingId, onDeleteRole, t, translate }) {
68
+ const { prefix, suffix } = roleDeleteBodyParts({ translate });
69
+ return (_jsx(ConfirmDialog, { cancelLabel: t("Cancel"), open: pendingRoleDelete !== null, agentHandle: "roles-delete-role", title: t("Delete role?"), body: pendingRoleDelete ? (_jsxs("p", { children: [prefix, pendingRoleDelete.name, suffix] })) : null, confirmLabel: t("Delete"), destructive: true, pending: pendingRoleDelete !== null && rowSavingId === pendingRoleDelete.id, onConfirm: onDeleteRole, onCancel: () => setPendingRoleDelete(null) }));
70
+ }
71
+ function PolicyDeleteDialog({ pendingPolicyDelete, setPendingPolicyDelete, rowSavingId, onDeletePolicy, t, translate }) {
72
+ const { prefix, suffix } = policyDeleteBodyParts({ translate });
73
+ return (_jsx(ConfirmDialog, { cancelLabel: t("Cancel"), open: pendingPolicyDelete !== null, agentHandle: "roles-delete-policy", title: t("Delete policy?"), body: pendingPolicyDelete ? (_jsxs("p", { children: [prefix, pendingPolicyDelete.name, suffix] })) : null, confirmLabel: t("Delete"), destructive: true, pending: pendingPolicyDelete !== null && rowSavingId === pendingPolicyDelete.id, onConfirm: onDeletePolicy, onCancel: () => setPendingPolicyDelete(null) }));
74
+ }
75
+ function PermissionRemoveDialog({ pendingPermissionRemove, setPendingPermissionRemove, removingPermissionId, onConfirmRemovePermission, t, translate, }) {
76
+ const { prefix, suffix } = permissionRemoveBodyParts({ translate });
77
+ const pending = pendingPermissionRemove;
78
+ return (_jsx(ConfirmDialog, { cancelLabel: t("Cancel"), open: pending !== null, agentHandle: "roles-remove-permission", title: t("Remove permission?"), body: pending ? (_jsxs("p", { children: [prefix, _jsx("code", { children: pending.row.permission }), pending.row.resourceType ? ` (${pending.row.resourceType})` : "", suffix] })) : null, confirmLabel: t("Remove"), tone: "warning", pending: pending !== null && removingPermissionId === pending.row.id, onConfirm: onConfirmRemovePermission, onCancel: () => setPendingPermissionRemove(null) }));
79
+ }
80
+ function RolesTab({ controller }) {
81
+ const c = controller;
82
+ return (_jsx(RolesSection, { roles: c.roles ?? [], create: {
83
+ name: c.roleName,
84
+ setName: c.setRoleName,
85
+ saving: c.roleSaving,
86
+ error: c.roleError,
87
+ submit: c.onCreateRole,
88
+ }, row: {
89
+ editingId: c.editingRoleId,
90
+ setEditingId: c.setEditingRoleId,
91
+ draftName: c.editingRoleName,
92
+ setDraftName: c.setEditingRoleName,
93
+ startRename: c.startEditRole,
94
+ saveRename: c.onSaveRole,
95
+ savingId: c.rowSavingId,
96
+ requestDelete: c.setPendingRoleDelete,
97
+ }, t: c.t, translate: c.translate }));
98
+ }
99
+ function PoliciesTab({ controller }) {
100
+ const c = controller;
101
+ return (_jsx(PoliciesSection, { policies: c.policies ?? [], create: {
102
+ name: c.policyName,
103
+ setName: c.setPolicyName,
104
+ description: c.policyDescription,
105
+ setDescription: c.setPolicyDescription,
106
+ saving: c.policySaving,
107
+ error: c.policyError,
108
+ submit: c.onCreatePolicy,
109
+ }, row: {
110
+ editingId: c.editingPolicyId,
111
+ setEditingId: c.setEditingPolicyId,
112
+ draftName: c.editingPolicyName,
113
+ setDraftName: c.setEditingPolicyName,
114
+ draftDescription: c.editingPolicyDescription,
115
+ setDraftDescription: c.setEditingPolicyDescription,
116
+ startRename: c.startEditPolicy,
117
+ saveRename: c.onSavePolicy,
118
+ savingId: c.rowSavingId,
119
+ requestDelete: c.setPendingPolicyDelete,
120
+ }, permission: {
121
+ openForPolicyId: c.permissionPolicyId,
122
+ permission: c.permissionInput,
123
+ setPermission: c.setPermissionInput,
124
+ resourceType: c.resourceTypeInput,
125
+ setResourceType: c.setResourceTypeInput,
126
+ toggleForm: c.togglePermissionForm,
127
+ write: c.onWritePermission,
128
+ rows: c.permissionRows,
129
+ loading: c.permissionsLoading,
130
+ removingId: c.removingPermissionId,
131
+ requestRemove: c.setPendingPermissionRemove,
132
+ }, t: c.t, translate: c.translate }));
133
+ }
134
+ function rolesTabPanel(activeTabId, controller) {
135
+ if (activeTabId === "policies")
136
+ return _jsx(PoliciesTab, { controller: controller });
137
+ return _jsx(RolesTab, { controller: controller });
138
+ }
139
+ export function Roles({ tabId, useRolesHook = useRoles, port, translate: injectedTranslate, queryScope, onTabChange, usersHref }) {
140
+ const controller = useRolesHook({ port, translate: injectedTranslate, queryScope });
141
+ const { roles, policies, error, rowError, rowSavingId, pendingRoleDelete, setPendingRoleDelete, onDeleteRole, pendingPolicyDelete, setPendingPolicyDelete, onDeletePolicy, pendingPermissionRemove, setPendingPermissionRemove, removingPermissionId, onConfirmRemovePermission, t, translate, } = controller;
142
+ const { prefix: descriptionPrefix, linkLabel: descriptionLinkLabel, suffix: descriptionSuffix } = rolesDescriptionParts({ translate });
143
+ if (error)
144
+ return _jsx("div", { className: "notice error", children: error });
145
+ if (!roles || !policies)
146
+ return _jsx("div", { className: "notice", children: t("Loading roles & permissions…") });
147
+ const activeTabId = resolveRolesTabId({ tabId });
148
+ return (_jsxs("div", { className: "page", children: [_jsx("div", { className: "page-header", children: _jsxs("div", { className: "page-header-text", children: [_jsx("p", { className: "page-kicker", children: t("People") }), _jsx("h1", { className: "page-title", children: t("Roles & Permissions") }), _jsxs("p", { className: "page-description", children: [descriptionPrefix, _jsx("a", { href: usersHref, children: descriptionLinkLabel }), descriptionSuffix] })] }) }), rowError ? _jsx("div", { className: "notice error", children: rowError }) : null, _jsx(TabBar, { ariaLabel: t("Roles & Permissions"), tabs: resolveRolesTabs({ translate: t }), activeId: activeTabId, onChange: (next) => onTabChange({ tabId: resolveRolesTabId({ tabId: next }) }), containerHandle: "roles-tab-bar" }), rolesTabPanel(activeTabId, controller), _jsx(RoleDeleteDialog, { pendingRoleDelete: pendingRoleDelete, setPendingRoleDelete: setPendingRoleDelete, rowSavingId: rowSavingId, t: t, translate: translate, onDeleteRole: onDeleteRole }), _jsx(PolicyDeleteDialog, { pendingPolicyDelete: pendingPolicyDelete, setPendingPolicyDelete: setPendingPolicyDelete, rowSavingId: rowSavingId, t: t, translate: translate, onDeletePolicy: onDeletePolicy }), _jsx(PermissionRemoveDialog, { pendingPermissionRemove: pendingPermissionRemove, setPendingPermissionRemove: setPendingPermissionRemove, removingPermissionId: removingPermissionId, onConfirmRemovePermission: onConfirmRemovePermission, t: t, translate: translate })] }));
149
+ }
150
+ //# sourceMappingURL=Roles.js.map
@@ -0,0 +1,80 @@
1
+ import type { Translate } from "@jini-ai/ui/panel-kit";
2
+ import { type AdminPolicy, type AdminPolicyPermission, type AdminRole } from "../../models.js";
3
+ import type { RolesPort } from "../../ports.js";
4
+ export interface PendingPermissionRemove {
5
+ policyId: string;
6
+ row: AdminPolicyPermission;
7
+ }
8
+ export interface RolesController {
9
+ roles: AdminRole[] | null;
10
+ policies: AdminPolicy[] | null;
11
+ error: string | null;
12
+ rowError: string | null;
13
+ roleName: string;
14
+ setRoleName: (name: string) => void;
15
+ roleSaving: boolean;
16
+ roleError: string | null;
17
+ onCreateRole: (e: React.FormEvent) => Promise<void>;
18
+ policyName: string;
19
+ setPolicyName: (name: string) => void;
20
+ policyDescription: string;
21
+ setPolicyDescription: (description: string) => void;
22
+ policySaving: boolean;
23
+ policyError: string | null;
24
+ onCreatePolicy: (e: React.FormEvent) => Promise<void>;
25
+ editingRoleId: string | null;
26
+ setEditingRoleId: (roleId: string | null) => void;
27
+ editingRoleName: string;
28
+ setEditingRoleName: (name: string) => void;
29
+ startEditRole: (role: AdminRole) => void;
30
+ onSaveRole: (required: {
31
+ roleId: string;
32
+ }) => Promise<void>;
33
+ editingPolicyId: string | null;
34
+ setEditingPolicyId: (policyId: string | null) => void;
35
+ editingPolicyName: string;
36
+ setEditingPolicyName: (name: string) => void;
37
+ editingPolicyDescription: string;
38
+ setEditingPolicyDescription: (description: string) => void;
39
+ startEditPolicy: (policy: AdminPolicy) => void;
40
+ onSavePolicy: (required: {
41
+ policyId: string;
42
+ }) => Promise<void>;
43
+ rowSavingId: string | null;
44
+ permissionPolicyId: string | null;
45
+ permissionInput: string;
46
+ setPermissionInput: (permission: string) => void;
47
+ resourceTypeInput: string;
48
+ setResourceTypeInput: (resourceType: string) => void;
49
+ togglePermissionForm: (required: {
50
+ policyId: string;
51
+ }) => void;
52
+ onWritePermission: (required: {
53
+ policyId: string;
54
+ }) => Promise<void>;
55
+ permissionRows: AdminPolicyPermission[];
56
+ permissionsLoading: boolean;
57
+ removingPermissionId: string | null;
58
+ onRemovePermission: (required: {
59
+ policyId: string;
60
+ policyPermissionId: string;
61
+ }) => Promise<void>;
62
+ pendingPermissionRemove: PendingPermissionRemove | null;
63
+ setPendingPermissionRemove: (target: PendingPermissionRemove | null) => void;
64
+ onConfirmRemovePermission: () => Promise<void>;
65
+ pendingRoleDelete: AdminRole | null;
66
+ setPendingRoleDelete: (role: AdminRole | null) => void;
67
+ onDeleteRole: () => Promise<void>;
68
+ pendingPolicyDelete: AdminPolicy | null;
69
+ setPendingPolicyDelete: (policy: AdminPolicy | null) => void;
70
+ onDeletePolicy: () => Promise<void>;
71
+ t: (key: string) => string;
72
+ translate: Translate;
73
+ }
74
+ export interface RolesDependencies {
75
+ port: RolesPort;
76
+ translate: Translate;
77
+ queryScope: string;
78
+ }
79
+ export declare function useRoles(deps: RolesDependencies): RolesController;
80
+ //# sourceMappingURL=use-roles.hooks.d.ts.map
@@ -0,0 +1,303 @@
1
+ import { useRef, useState } from "react";
2
+ import {} from "../../models.js";
3
+ import { useFetchMutation, useFetchQuery } from "@jini-ai/ui/panel-kit";
4
+ import { describeApiError as describeFeatureError, KEYS } from "../rules.js";
5
+ async function runRowDelete(id, mutate, setRowSavingId, setRowError, clearPending, describeError) {
6
+ setRowSavingId(id);
7
+ setRowError(null);
8
+ try {
9
+ await mutate(id);
10
+ }
11
+ catch (e) {
12
+ setRowError(describeError(e));
13
+ }
14
+ finally {
15
+ setRowSavingId((current) => (current === id ? null : current));
16
+ clearPending();
17
+ }
18
+ }
19
+ export function useRoles(deps) {
20
+ const { port, translate, queryScope } = deps;
21
+ const describeApiError = (error, fallback) => describeFeatureError({ error, fallback, translate });
22
+ const t = translate;
23
+ const boundT = translate;
24
+ const list = useFetchQuery({
25
+ key: [queryScope, ...KEYS.list],
26
+ fetch: async () => {
27
+ const [r, p] = await Promise.all([port.listRoles({}), port.listPolicies({})]);
28
+ return { roles: r.roles, policies: p.policies };
29
+ },
30
+ });
31
+ const roles = list.data?.roles ?? null;
32
+ const policies = list.data?.policies ?? null;
33
+ const error = list.error ? describeApiError(list.error, t("failed to load roles/policies")) : null;
34
+ const [rowError, setRowError] = useState(null);
35
+ const [roleName, setRoleName] = useState("");
36
+ const [policyName, setPolicyName] = useState("");
37
+ const [policyDescription, setPolicyDescription] = useState("");
38
+ const [editingRoleId, setEditingRoleId] = useState(null);
39
+ const [editingRoleName, setEditingRoleName] = useState("");
40
+ const [editingPolicyId, setEditingPolicyId] = useState(null);
41
+ const [editingPolicyName, setEditingPolicyName] = useState("");
42
+ const [editingPolicyDescription, setEditingPolicyDescription] = useState("");
43
+ const [rowSavingId, setRowSavingId] = useState(null);
44
+ const [permissionPolicyId, setPermissionPolicyId] = useState(null);
45
+ const [permissionInput, setPermissionInput] = useState("");
46
+ const [resourceTypeInput, setResourceTypeInput] = useState("");
47
+ const [permissionRows, setPermissionRows] = useState([]);
48
+ const [permissionsLoading, setPermissionsLoading] = useState(false);
49
+ const [removingPermissionId, setRemovingPermissionId] = useState(null);
50
+ const permissionsGenerationRef = useRef(0);
51
+ const permissionPolicyIdRef = useRef(null);
52
+ const [pendingRoleDelete, setPendingRoleDelete] = useState(null);
53
+ const [pendingPolicyDelete, setPendingPolicyDelete] = useState(null);
54
+ const [pendingPermissionRemove, setPendingPermissionRemove] = useState(null);
55
+ const createRoleMutation = useFetchMutation({
56
+ run: ({ input: name }) => port.createRole({ name: name })
57
+ }, {
58
+ invalidates: [[queryScope, ...KEYS.list]],
59
+ });
60
+ const createPolicyMutation = useFetchMutation({
61
+ run: ({ input }) => port.createPolicy({ name: input.name }, { description: input.description })
62
+ }, {
63
+ invalidates: [[queryScope, ...KEYS.list]],
64
+ });
65
+ const saveRoleMutation = useFetchMutation({
66
+ run: ({ input }) => port.updateRole(input)
67
+ }, {
68
+ invalidates: [[queryScope, ...KEYS.list]],
69
+ });
70
+ const deleteRoleMutation = useFetchMutation({
71
+ run: ({ input: id }) => port.deleteRole({ roleId: id })
72
+ }, {
73
+ invalidates: [[queryScope, ...KEYS.list]],
74
+ });
75
+ const savePolicyMutation = useFetchMutation({
76
+ run: ({ input }) => port.updatePolicy({ policyId: input.policyId }, { name: input.name, description: input.description })
77
+ }, {
78
+ invalidates: [[queryScope, ...KEYS.list]],
79
+ });
80
+ const deletePolicyMutation = useFetchMutation({
81
+ run: ({ input: id }) => port.deletePolicy({ policyId: id })
82
+ }, {
83
+ invalidates: [[queryScope, ...KEYS.list]],
84
+ });
85
+ const writePermissionMutation = useFetchMutation({
86
+ run: ({ input }) => port.writePolicyPermission({ policyId: input.policyId, permission: input.permission }, { resourceType: input.resourceType }),
87
+ });
88
+ const removePermissionMutation = useFetchMutation({
89
+ run: ({ input }) => port.removePolicyPermission(input),
90
+ });
91
+ async function onCreateRole(e) {
92
+ e.preventDefault();
93
+ try {
94
+ await createRoleMutation.mutate({ input: roleName });
95
+ setRoleName("");
96
+ }
97
+ catch {
98
+ }
99
+ }
100
+ async function onCreatePolicy(e) {
101
+ e.preventDefault();
102
+ try {
103
+ await createPolicyMutation.mutate({ input: { name: policyName, description: policyDescription || undefined } });
104
+ setPolicyName("");
105
+ setPolicyDescription("");
106
+ }
107
+ catch {
108
+ }
109
+ }
110
+ function startEditRole(role) {
111
+ setRowError(null);
112
+ setEditingRoleId(role.id);
113
+ setEditingRoleName(role.name);
114
+ }
115
+ async function onSaveRole({ roleId }) {
116
+ setRowSavingId(roleId);
117
+ setRowError(null);
118
+ try {
119
+ await saveRoleMutation.mutate({ input: { roleId, name: editingRoleName } });
120
+ setEditingRoleId((current) => (current === roleId ? null : current));
121
+ }
122
+ catch (e) {
123
+ setRowError(describeApiError(e, t("failed to rename role")));
124
+ }
125
+ finally {
126
+ setRowSavingId((current) => (current === roleId ? null : current));
127
+ }
128
+ }
129
+ async function onDeleteRole() {
130
+ if (!pendingRoleDelete)
131
+ return;
132
+ const role = pendingRoleDelete;
133
+ await runRowDelete(role.id, (id) => deleteRoleMutation.mutate({ input: id }), setRowSavingId, setRowError, () => setPendingRoleDelete((current) => (current?.id === role.id ? null : current)), (e) => describeApiError(e, t("failed to delete role")));
134
+ }
135
+ function startEditPolicy(policy) {
136
+ setRowError(null);
137
+ setEditingPolicyId(policy.id);
138
+ setEditingPolicyName(policy.name);
139
+ setEditingPolicyDescription(policy.description ?? "");
140
+ }
141
+ async function onSavePolicy({ policyId }) {
142
+ setRowSavingId(policyId);
143
+ setRowError(null);
144
+ try {
145
+ await savePolicyMutation.mutate({ input: { policyId, name: editingPolicyName, description: editingPolicyDescription } });
146
+ setEditingPolicyId((current) => (current === policyId ? null : current));
147
+ }
148
+ catch (e) {
149
+ setRowError(describeApiError(e, t("failed to update policy")));
150
+ }
151
+ finally {
152
+ setRowSavingId((current) => (current === policyId ? null : current));
153
+ }
154
+ }
155
+ async function onDeletePolicy() {
156
+ if (!pendingPolicyDelete)
157
+ return;
158
+ const policy = pendingPolicyDelete;
159
+ await runRowDelete(policy.id, (id) => deletePolicyMutation.mutate({ input: id }), setRowSavingId, setRowError, () => setPendingPolicyDelete((current) => (current?.id === policy.id ? null : current)), (e) => describeApiError(e, t("failed to delete policy")));
160
+ }
161
+ async function loadPermissions(policyId) {
162
+ const generation = ++permissionsGenerationRef.current;
163
+ setPermissionsLoading(true);
164
+ try {
165
+ const { policyPermissions } = await port.listPolicyPermissions({ policyId: policyId });
166
+ if (permissionsGenerationRef.current !== generation)
167
+ return;
168
+ setPermissionRows(policyPermissions);
169
+ }
170
+ catch (e) {
171
+ if (permissionsGenerationRef.current !== generation)
172
+ return;
173
+ setPermissionRows([]);
174
+ setRowError(describeApiError(e, t("failed to load permissions")));
175
+ }
176
+ finally {
177
+ if (permissionsGenerationRef.current !== generation)
178
+ return;
179
+ setPermissionsLoading(false);
180
+ }
181
+ }
182
+ function togglePermissionForm({ policyId }) {
183
+ setRowError(null);
184
+ setPermissionInput("");
185
+ setResourceTypeInput("");
186
+ const closing = permissionPolicyIdRef.current === policyId;
187
+ permissionPolicyIdRef.current = closing ? null : policyId;
188
+ setPermissionPolicyId(permissionPolicyIdRef.current);
189
+ setPermissionRows([]);
190
+ if (!closing)
191
+ void loadPermissions(policyId);
192
+ }
193
+ async function onRemovePermission({ policyId, policyPermissionId }) {
194
+ setRemovingPermissionId(policyPermissionId);
195
+ setRowError(null);
196
+ try {
197
+ await removePermissionMutation.mutate({ input: { policyId, policyPermissionId } });
198
+ if (permissionPolicyIdRef.current === policyId)
199
+ await loadPermissions(policyId);
200
+ }
201
+ catch (e) {
202
+ setRowError(describeApiError(e, t("failed to remove permission")));
203
+ }
204
+ finally {
205
+ setRemovingPermissionId((current) => (current === policyPermissionId ? null : current));
206
+ }
207
+ }
208
+ async function onConfirmRemovePermission() {
209
+ if (!pendingPermissionRemove)
210
+ return;
211
+ const target = pendingPermissionRemove;
212
+ try {
213
+ await onRemovePermission({ policyId: target.policyId, policyPermissionId: target.row.id });
214
+ }
215
+ finally {
216
+ setPendingPermissionRemove((current) => (current?.row.id === target.row.id ? null : current));
217
+ }
218
+ }
219
+ async function onWritePermission({ policyId }) {
220
+ if (!permissionInput)
221
+ return;
222
+ const generationAtStart = permissionsGenerationRef.current;
223
+ setRowSavingId(policyId);
224
+ setRowError(null);
225
+ try {
226
+ await writePermissionMutation.mutate({ input: { policyId, permission: permissionInput, resourceType: resourceTypeInput || undefined } });
227
+ if (permissionsGenerationRef.current === generationAtStart) {
228
+ setPermissionInput("");
229
+ setResourceTypeInput("");
230
+ }
231
+ if (permissionPolicyIdRef.current === policyId)
232
+ await loadPermissions(policyId);
233
+ }
234
+ catch (e) {
235
+ setRowError(describeApiError(e, t("failed to add permission")));
236
+ }
237
+ finally {
238
+ setRowSavingId((current) => (current === policyId ? null : current));
239
+ }
240
+ }
241
+ const roleSaving = createRoleMutation.status === "pending";
242
+ const roleError = createRoleMutation.error ? describeApiError(createRoleMutation.error, t("failed to create role")) : null;
243
+ const policySaving = createPolicyMutation.status === "pending";
244
+ const policyError = createPolicyMutation.error
245
+ ? describeApiError(createPolicyMutation.error, t("failed to create policy"))
246
+ : null;
247
+ return {
248
+ roles,
249
+ policies,
250
+ error,
251
+ rowError,
252
+ roleName,
253
+ setRoleName,
254
+ roleSaving,
255
+ roleError,
256
+ onCreateRole,
257
+ policyName,
258
+ setPolicyName,
259
+ policyDescription,
260
+ setPolicyDescription,
261
+ policySaving,
262
+ policyError,
263
+ onCreatePolicy,
264
+ editingRoleId,
265
+ setEditingRoleId,
266
+ editingRoleName,
267
+ setEditingRoleName,
268
+ startEditRole,
269
+ onSaveRole,
270
+ editingPolicyId,
271
+ setEditingPolicyId,
272
+ editingPolicyName,
273
+ setEditingPolicyName,
274
+ editingPolicyDescription,
275
+ setEditingPolicyDescription,
276
+ startEditPolicy,
277
+ onSavePolicy,
278
+ rowSavingId,
279
+ permissionPolicyId,
280
+ permissionInput,
281
+ setPermissionInput,
282
+ resourceTypeInput,
283
+ setResourceTypeInput,
284
+ togglePermissionForm,
285
+ onWritePermission,
286
+ permissionRows,
287
+ permissionsLoading,
288
+ removingPermissionId,
289
+ onRemovePermission,
290
+ pendingPermissionRemove,
291
+ setPendingPermissionRemove,
292
+ onConfirmRemovePermission,
293
+ pendingRoleDelete,
294
+ setPendingRoleDelete,
295
+ onDeleteRole,
296
+ pendingPolicyDelete,
297
+ setPendingPolicyDelete,
298
+ onDeletePolicy,
299
+ t: boundT,
300
+ translate,
301
+ };
302
+ }
303
+ //# sourceMappingURL=use-roles.hooks.js.map
@@ -0,0 +1,35 @@
1
+ import type { AdminRole, AdminPolicy } from "../models.js";
2
+ import type { Translate } from "@jini-ai/ui/panel-kit";
3
+ import type { RowMenuItem } from "@jini-ai/admin/react";
4
+ import type { QueryKey } from "@jini-ai/ui/panel-kit";
5
+ export declare const KEYS: {
6
+ list: QueryKey;
7
+ };
8
+ export declare function describeApiError({ error, fallback, translate }: {
9
+ error: unknown;
10
+ fallback: string;
11
+ translate: Translate;
12
+ }): string;
13
+ export interface RoleRowMenuHandlers {
14
+ onRename: (role: AdminRole) => void;
15
+ onDelete: (role: AdminRole) => void;
16
+ }
17
+ export declare function roleMenuItems({ role, handlers, translate }: {
18
+ role: AdminRole;
19
+ handlers: RoleRowMenuHandlers;
20
+ translate: Translate;
21
+ }): RowMenuItem[];
22
+ export interface PolicyRowMenuHandlers {
23
+ onRename: (policy: AdminPolicy) => void;
24
+ onTogglePermissionForm: (required: {
25
+ policyId: string;
26
+ }) => void;
27
+ onDelete: (policy: AdminPolicy) => void;
28
+ }
29
+ export declare function policyMenuItems({ policy, permissionPolicyId, handlers, translate }: {
30
+ policy: AdminPolicy;
31
+ permissionPolicyId: string | null;
32
+ handlers: PolicyRowMenuHandlers;
33
+ translate: Translate;
34
+ }): RowMenuItem[];
35
+ //# sourceMappingURL=rules.d.ts.map
@@ -0,0 +1,31 @@
1
+ import { describeIdentityError } from "../errors.js";
2
+ export const KEYS = {
3
+ list: ["roles-and-policies"],
4
+ };
5
+ const STATIC_ERROR_MESSAGES = {
6
+ FORBIDDEN: "You do not have permission to do that.",
7
+ RESOURCE_CONFLICT: "It is still in use — remove that assignment/attachment first.",
8
+ PERMISSION_UNKNOWN: "That permission is not recognized.",
9
+ GRANT_EXCEEDS_ISSUER: "You cannot grant a permission you do not hold.",
10
+ };
11
+ export function describeApiError({ error, fallback, translate }) {
12
+ return describeIdentityError({ error, fallback, translate }, { messages: STATIC_ERROR_MESSAGES });
13
+ }
14
+ export function roleMenuItems({ role, handlers, translate }) {
15
+ return [
16
+ { key: "rename", label: translate("Rename"), onSelect: () => handlers.onRename(role) },
17
+ { key: "delete", label: translate("Delete"), destructive: true, onSelect: () => handlers.onDelete(role) },
18
+ ];
19
+ }
20
+ export function policyMenuItems({ policy, permissionPolicyId, handlers, translate }) {
21
+ return [
22
+ { key: "rename", label: translate("Rename"), onSelect: () => handlers.onRename(policy) },
23
+ {
24
+ key: "permission",
25
+ label: permissionPolicyId === policy.id ? translate("Close") : translate("Add permission"),
26
+ onSelect: () => handlers.onTogglePermissionForm({ policyId: policy.id }),
27
+ },
28
+ { key: "delete", label: translate("Delete"), destructive: true, onSelect: () => handlers.onDelete(policy) },
29
+ ];
30
+ }
31
+ //# sourceMappingURL=rules.js.map
@@ -0,0 +1,27 @@
1
+ import { type Translate } from "@jini-ai/ui/panel-kit";
2
+ export declare function rolesDescriptionParts({ translate }: {
3
+ translate: Translate;
4
+ }): {
5
+ prefix: string;
6
+ suffix: string;
7
+ linkLabel: string;
8
+ };
9
+ export declare function roleDeleteBodyParts({ translate }: {
10
+ translate: Translate;
11
+ }): {
12
+ prefix: string;
13
+ suffix: string;
14
+ };
15
+ export declare function policyDeleteBodyParts({ translate }: {
16
+ translate: Translate;
17
+ }): {
18
+ prefix: string;
19
+ suffix: string;
20
+ };
21
+ export declare function permissionRemoveBodyParts({ translate }: {
22
+ translate: Translate;
23
+ }): {
24
+ prefix: string;
25
+ suffix: string;
26
+ };
27
+ //# sourceMappingURL=text.d.ts.map
@@ -0,0 +1,13 @@
1
+ import { splitOnPlaceholders } from "@jini-ai/ui/panel-kit";
2
+ export function rolesDescriptionParts({ translate }) {
3
+ const [prefix = "", suffix = ""] = splitOnPlaceholders({ template: translate("Roles and policies grant access to operator users. Assign a role or policy to a specific user from the {users} screen."), tokens: ["{users}"] });
4
+ return { prefix, suffix, linkLabel: translate("Users") };
5
+ }
6
+ function nameParts(translate, template) {
7
+ const [prefix = "", suffix = ""] = splitOnPlaceholders({ template: translate(template), tokens: ["{name}"] });
8
+ return { prefix, suffix };
9
+ }
10
+ export function roleDeleteBodyParts({ translate }) { return nameParts(translate, 'Delete role "{name}"?'); }
11
+ export function policyDeleteBodyParts({ translate }) { return nameParts(translate, 'Delete policy "{name}"?'); }
12
+ export function permissionRemoveBodyParts({ translate }) { return nameParts(translate, 'Remove "{name}" from this policy? Anyone with this policy loses it.'); }
13
+ //# sourceMappingURL=text.js.map