@rebasepro/admin 0.2.3 → 0.2.5

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 (225) hide show
  1. package/dist/{CollectionEditorDialog-CmGXXSY9.js → CollectionEditorDialog-Cn8-tGyL.js} +89 -79
  2. package/dist/CollectionEditorDialog-Cn8-tGyL.js.map +1 -0
  3. package/dist/{CollectionsStudioView-DcLHT5bU.js → CollectionsStudioView-C-Ts1rZt.js} +5 -4
  4. package/dist/{CollectionsStudioView-DcLHT5bU.js.map → CollectionsStudioView-C-Ts1rZt.js.map} +1 -1
  5. package/dist/{ExportCollectionAction-BfN34eWX.js → ExportCollectionAction-BRdKM3DF.js} +4 -3
  6. package/dist/ExportCollectionAction-BRdKM3DF.js.map +1 -0
  7. package/dist/{ImportCollectionAction-SZrInjhx.js → ImportCollectionAction-U-v7lGxO.js} +3 -2
  8. package/dist/{ImportCollectionAction-SZrInjhx.js.map → ImportCollectionAction-U-v7lGxO.js.map} +1 -1
  9. package/dist/{PropertyEditView-Cvryrb3B.js → PropertyEditView-BDNYkfNf.js} +128 -121
  10. package/dist/PropertyEditView-BDNYkfNf.js.map +1 -0
  11. package/dist/collection_editor/ConfigControllerProvider.d.ts +0 -5
  12. package/dist/collection_editor/index.d.ts +0 -1
  13. package/dist/collection_editor/types/collection_editor_controller.d.ts +0 -2
  14. package/dist/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +3 -3
  15. package/dist/collection_editor_ui.js +3 -3
  16. package/dist/components/ArrayContainer.d.ts +2 -2
  17. package/dist/components/DefaultAppBar.d.ts +18 -1
  18. package/dist/components/DefaultDrawer.d.ts +51 -3
  19. package/dist/components/EntityCollectionTable/fields/TableStorageUpload.d.ts +2 -2
  20. package/dist/components/EntityCollectionTable/internal/EntityTableCell.d.ts +2 -2
  21. package/dist/components/EntityCollectionTable/table_bindings.d.ts +4 -3
  22. package/dist/components/EntityCollectionView/hooks/useKanbanDragAndDrop.d.ts +4 -3
  23. package/dist/components/EntityEditView.d.ts +2 -1
  24. package/dist/components/HomePage/HomePageDnD.d.ts +3 -3
  25. package/dist/components/PropertyCollectionView.d.ts +1 -1
  26. package/dist/components/PropertyIdCopyTooltip.d.ts +1 -1
  27. package/dist/components/RebaseRouteDefs.d.ts +1 -1
  28. package/dist/components/SelectableTable/SelectionStore.d.ts +4 -1
  29. package/dist/components/SelectableTable/filters/BooleanFilterField.d.ts +2 -2
  30. package/dist/components/SelectableTable/filters/DateTimeFilterField.d.ts +2 -2
  31. package/dist/components/SelectableTable/filters/ReferenceFilterField.d.ts +2 -2
  32. package/dist/components/SelectableTable/filters/StringNumberFilterField.d.ts +2 -2
  33. package/dist/components/admin/index.d.ts +1 -3
  34. package/dist/components/app/Drawer.d.ts +8 -1
  35. package/dist/data_export/export/export.d.ts +3 -3
  36. package/dist/editor/components/editor-bubble.d.ts +5 -1
  37. package/dist/editor/components/image-bubble.d.ts +5 -1
  38. package/dist/editor/components/index.d.ts +3 -3
  39. package/dist/editor/components/table-bubble.d.ts +5 -1
  40. package/dist/editor/nodeViews/ReactNodeView.d.ts +4 -1
  41. package/dist/editor/useProseMirror.d.ts +2 -2
  42. package/dist/editor/utils/remove_classes.d.ts +1 -1
  43. package/dist/editor.js +15 -14
  44. package/dist/editor.js.map +1 -1
  45. package/dist/form/EntityForm.d.ts +2 -2
  46. package/dist/form/components/StorageUploadProgress.d.ts +2 -2
  47. package/dist/form/field_bindings/MultiSelectFieldBinding.d.ts +1 -1
  48. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +1 -1
  49. package/dist/form/validation.d.ts +3 -3
  50. package/dist/hooks/navigation/useBuildNavigationStateController.d.ts +1 -1
  51. package/dist/hooks/navigation/useResolvedCollections.d.ts +6 -0
  52. package/dist/hooks/navigation/useResolvedViews.d.ts +3 -7
  53. package/dist/{index-DjduZG1T.js → index-DHaOV-7A.js} +3 -3
  54. package/dist/index-DHaOV-7A.js.map +1 -0
  55. package/dist/{index-MKPc70-v.js → index-DJSL_SCr.js} +3 -3
  56. package/dist/index-DJSL_SCr.js.map +1 -0
  57. package/dist/{index-PLIQXpTt.js → index-XMII4H3d.js} +3 -2
  58. package/dist/{index-PLIQXpTt.js.map → index-XMII4H3d.js.map} +1 -1
  59. package/dist/index.d.ts +1 -3
  60. package/dist/index.js +2688 -452
  61. package/dist/index.js.map +1 -1
  62. package/dist/{markdown-z2Ir7Cgo.js → markdown-DD2JDU1X.js} +2 -2
  63. package/dist/markdown-DD2JDU1X.js.map +1 -0
  64. package/dist/preview/components/UrlComponentPreview.d.ts +1 -0
  65. package/dist/types/components/EntityFormActionsProps.d.ts +1 -1
  66. package/dist/types/components/EntityFormProps.d.ts +2 -2
  67. package/dist/types/fields.d.ts +1 -1
  68. package/dist/{util-DbWax_sV.js → util-0GYaJqL_.js} +1505 -2043
  69. package/dist/util-0GYaJqL_.js.map +1 -0
  70. package/package.json +8 -8
  71. package/src/collection_editor/ConfigControllerProvider.tsx +3 -13
  72. package/src/collection_editor/index.ts +1 -3
  73. package/src/collection_editor/pgColumnToProperty.ts +19 -2
  74. package/src/collection_editor/types/collection_editor_controller.tsx +0 -3
  75. package/src/collection_editor/ui/EditorCollectionAction.tsx +1 -6
  76. package/src/collection_editor/ui/EditorCollectionActionStart.tsx +1 -6
  77. package/src/collection_editor/ui/EditorEntityAction.tsx +1 -6
  78. package/src/collection_editor/ui/HomePageEditorCollectionAction.tsx +7 -14
  79. package/src/collection_editor/ui/NewCollectionCard.tsx +1 -5
  80. package/src/collection_editor/ui/PropertyAddColumnComponent.tsx +3 -8
  81. package/src/collection_editor/ui/collection_editor/CollectionJsonImportDialog.tsx +8 -12
  82. package/src/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.tsx +21 -21
  83. package/src/collection_editor/ui/collection_editor/CollectionRLSTab.tsx +4 -4
  84. package/src/collection_editor/ui/collection_editor/EnumForm.tsx +1 -1
  85. package/src/collection_editor/ui/collection_editor/properties/BlockPropertyField.tsx +3 -3
  86. package/src/collection_editor/ui/collection_editor/properties/CommonPropertyFields.tsx +3 -3
  87. package/src/collection_editor/ui/collection_editor/properties/DateTimePropertyField.tsx +8 -8
  88. package/src/collection_editor/ui/collection_editor/properties/EnumPropertyField.tsx +5 -5
  89. package/src/collection_editor/ui/collection_editor/properties/MapPropertyField.tsx +2 -2
  90. package/src/collection_editor/ui/collection_editor/properties/MarkdownPropertyField.tsx +5 -5
  91. package/src/collection_editor/ui/collection_editor/properties/NumberPropertyField.tsx +5 -5
  92. package/src/collection_editor/ui/collection_editor/properties/ReferencePropertyField.tsx +2 -2
  93. package/src/collection_editor/ui/collection_editor/properties/RepeatPropertyField.tsx +2 -2
  94. package/src/collection_editor/ui/collection_editor/properties/StoragePropertyField.tsx +8 -8
  95. package/src/collection_editor/ui/collection_editor/properties/StringPropertyField.tsx +5 -5
  96. package/src/collection_editor/ui/collection_editor/properties/UrlPropertyField.tsx +3 -2
  97. package/src/collection_editor/ui/collection_editor/properties/VectorPropertyField.tsx +2 -2
  98. package/src/collection_editor/ui/collection_editor/properties/validation/ArrayPropertyValidation.tsx +2 -2
  99. package/src/collection_editor/ui/collection_editor/properties/validation/GeneralPropertyValidation.tsx +1 -1
  100. package/src/collection_editor/ui/collection_editor/properties/validation/NumberPropertyValidation.tsx +4 -7
  101. package/src/collection_editor/ui/collection_editor/properties/validation/StringPropertyValidation.tsx +4 -4
  102. package/src/components/ArrayContainer.tsx +3 -3
  103. package/src/components/DefaultAppBar.tsx +52 -31
  104. package/src/components/DefaultDrawer.tsx +280 -67
  105. package/src/components/DrawerNavigationItem.tsx +1 -1
  106. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +6 -5
  107. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +9 -7
  108. package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +5 -5
  109. package/src/components/EntityCollectionTable/fields/VirtualTableNumberInput.tsx +12 -9
  110. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +2 -2
  111. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +1 -1
  112. package/src/components/EntityCollectionTable/table_bindings.tsx +5 -4
  113. package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +4 -4
  114. package/src/components/EntityCollectionView/EntityCollectionListView.tsx +7 -0
  115. package/src/components/EntityCollectionView/EntityCollectionView.tsx +10 -5
  116. package/src/components/EntityCollectionView/hooks/useCollectionInlineEditor.ts +1 -1
  117. package/src/components/EntityCollectionView/hooks/useKanbanDragAndDrop.ts +7 -6
  118. package/src/components/EntityDetailView.tsx +46 -24
  119. package/src/components/EntityEditView.tsx +51 -28
  120. package/src/components/EntityEditViewFormActions.tsx +4 -4
  121. package/src/components/EntityPreview.tsx +9 -4
  122. package/src/components/HomePage/HomePageDnD.tsx +3 -2
  123. package/src/components/PropertyCollectionView.tsx +1 -1
  124. package/src/components/PropertyIdCopyTooltip.tsx +1 -1
  125. package/src/components/RebaseLayout.tsx +5 -1
  126. package/src/components/RebaseNavigation.tsx +2 -2
  127. package/src/components/RebaseRouteDefs.tsx +6 -11
  128. package/src/components/RebaseShell.tsx +16 -13
  129. package/src/components/SearchIconsView.tsx +1 -8
  130. package/src/components/SelectableTable/SelectableTable.tsx +8 -11
  131. package/src/components/SelectableTable/SelectionStore.ts +1 -1
  132. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +3 -3
  133. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +3 -3
  134. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +5 -5
  135. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +3 -3
  136. package/src/components/SideEntityProvider.tsx +2 -1
  137. package/src/components/admin/index.ts +1 -3
  138. package/src/components/app/Drawer.tsx +9 -1
  139. package/src/components/app/Scaffold.tsx +5 -1
  140. package/src/components/index.ts +1 -3
  141. package/src/data_export/export/export.ts +17 -17
  142. package/src/data_import/components/DataNewPropertiesMapping.tsx +1 -1
  143. package/src/editor/components/editor-bubble.tsx +32 -9
  144. package/src/editor/components/image-bubble.tsx +27 -11
  145. package/src/editor/components/index.ts +3 -3
  146. package/src/editor/components/table-bubble.tsx +79 -17
  147. package/src/editor/extensions/HighlightDecorationExtension.ts +3 -2
  148. package/src/editor/nodeViews/ReactNodeView.tsx +1 -1
  149. package/src/editor/nodeViews/TaskItemComponent.tsx +9 -8
  150. package/src/editor/schema.ts +135 -59
  151. package/src/editor/selectors/link-selector.tsx +8 -5
  152. package/src/editor/useProseMirror.ts +2 -2
  153. package/src/editor/utils/remove_classes.ts +6 -5
  154. package/src/form/EntityForm.tsx +15 -15
  155. package/src/form/EntityFormActions.tsx +2 -2
  156. package/src/form/PropertyFieldBinding.tsx +64 -64
  157. package/src/form/components/FieldHelperText.tsx +4 -4
  158. package/src/form/components/StorageUploadProgress.tsx +2 -2
  159. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +1 -1
  160. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +1 -1
  161. package/src/form/field_bindings/BlockFieldBinding.tsx +54 -53
  162. package/src/form/field_bindings/KeyValueFieldBinding.tsx +290 -289
  163. package/src/form/field_bindings/MapFieldBinding.tsx +2 -2
  164. package/src/form/field_bindings/MultiSelectFieldBinding.tsx +2 -2
  165. package/src/form/field_bindings/MultipleRelationFieldBinding.tsx +1 -1
  166. package/src/form/field_bindings/ReferenceAsStringFieldBinding.tsx +1 -1
  167. package/src/form/field_bindings/ReferenceFieldBinding.tsx +8 -6
  168. package/src/form/field_bindings/RelationFieldBinding.tsx +4 -4
  169. package/src/form/field_bindings/RepeatFieldBinding.tsx +1 -1
  170. package/src/form/field_bindings/SelectFieldBinding.tsx +1 -1
  171. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +84 -84
  172. package/src/form/field_bindings/SwitchFieldBinding.tsx +16 -16
  173. package/src/form/field_bindings/TextFieldBinding.tsx +77 -73
  174. package/src/form/field_bindings/UserSelectFieldBinding.tsx +17 -17
  175. package/src/form/validation.ts +43 -43
  176. package/src/hooks/navigation/useBuildNavigationStateController.tsx +4 -7
  177. package/src/hooks/navigation/useResolvedCollections.ts +27 -7
  178. package/src/hooks/navigation/useResolvedViews.tsx +8 -70
  179. package/src/index.ts +4 -3
  180. package/src/preview/PropertyPreview.tsx +2 -2
  181. package/src/preview/components/ImagePreview.tsx +2 -1
  182. package/src/preview/components/UrlComponentPreview.tsx +11 -2
  183. package/src/preview/components/UserPreview.tsx +1 -1
  184. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +2 -2
  185. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +4 -4
  186. package/src/preview/property_previews/ArrayOfRelationsPreview.tsx +3 -3
  187. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +3 -3
  188. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +3 -2
  189. package/src/preview/property_previews/ArrayOneOfPreview.tsx +6 -8
  190. package/src/preview/property_previews/ArrayPropertyEnumPreview.tsx +1 -1
  191. package/src/preview/property_previews/ArrayPropertyPreview.tsx +3 -3
  192. package/src/preview/property_previews/MapPropertyPreview.tsx +4 -3
  193. package/src/preview/property_previews/NumberPropertyPreview.tsx +5 -3
  194. package/src/preview/property_previews/StringPropertyPreview.tsx +10 -8
  195. package/src/types/components/EntityFormActionsProps.tsx +1 -1
  196. package/src/types/components/EntityFormProps.tsx +2 -2
  197. package/src/types/fields.tsx +2 -2
  198. package/src/util/previews.ts +9 -1
  199. package/dist/CollectionEditorDialog-CmGXXSY9.js.map +0 -1
  200. package/dist/ContentHomePage-C7vFqKSe.js +0 -1784
  201. package/dist/ContentHomePage-C7vFqKSe.js.map +0 -1
  202. package/dist/ExportCollectionAction-BfN34eWX.js.map +0 -1
  203. package/dist/PropertyEditView-Cvryrb3B.js.map +0 -1
  204. package/dist/RoleChip-QtUFXeTp.js +0 -67
  205. package/dist/RoleChip-QtUFXeTp.js.map +0 -1
  206. package/dist/RolesView-BCb7qwWs.js +0 -437
  207. package/dist/RolesView-BCb7qwWs.js.map +0 -1
  208. package/dist/UsersView-Cex24r8H.js +0 -408
  209. package/dist/UsersView-Cex24r8H.js.map +0 -1
  210. package/dist/collection_editor/types/config_permissions.d.ts +0 -19
  211. package/dist/components/admin/RoleChip.d.ts +0 -4
  212. package/dist/components/admin/RolesFilterSelect.d.ts +0 -2
  213. package/dist/components/admin/RolesView.d.ts +0 -4
  214. package/dist/components/admin/UserRolesSelectField.d.ts +0 -2
  215. package/dist/components/admin/UsersView.d.ts +0 -4
  216. package/dist/index-DjduZG1T.js.map +0 -1
  217. package/dist/index-MKPc70-v.js.map +0 -1
  218. package/dist/markdown-z2Ir7Cgo.js.map +0 -1
  219. package/dist/util-DbWax_sV.js.map +0 -1
  220. package/src/collection_editor/types/config_permissions.ts +0 -20
  221. package/src/components/admin/RoleChip.tsx +0 -23
  222. package/src/components/admin/RolesFilterSelect.tsx +0 -45
  223. package/src/components/admin/RolesView.tsx +0 -465
  224. package/src/components/admin/UserRolesSelectField.tsx +0 -50
  225. package/src/components/admin/UsersView.tsx +0 -687
@@ -1,20 +0,0 @@
1
- import { EntityCollection } from "@rebasepro/types";
2
-
3
- export type CollectionEditorPermissionsBuilder<USER = any, EC extends EntityCollection = EntityCollection> = (params: { user: USER | null, collection?: EC }) => CollectionEditorPermissions;
4
-
5
- export type CollectionEditorPermissions = {
6
- /**
7
- * Is the user allowed to create new collections.
8
- */
9
- createCollections: boolean;
10
-
11
- /**
12
- * Is the user allowed to modify this collection
13
- */
14
- editCollections: boolean;
15
-
16
- /**
17
- * Is the user allowed to delete this collection
18
- */
19
- deleteCollections: boolean;
20
- }
@@ -1,23 +0,0 @@
1
- import React from "react";
2
- import { Chip, ChipColorScheme } from "@rebasepro/ui";
3
- import { Role } from "@rebasepro/types";
4
- import { getColorSchemeForSeed, getColorSchemeForKey } from "@rebasepro/ui";
5
-
6
- export function RoleChip({ role }: { role: Role }) {
7
- let colorScheme: ChipColorScheme;
8
- if (role.isAdmin) {
9
- colorScheme = getColorSchemeForKey("blue");
10
- } else if (role.id === "editor") {
11
- colorScheme = getColorSchemeForKey("yellow");
12
- } else if (role.id === "viewer") {
13
- colorScheme = getColorSchemeForKey("gray");
14
- } else {
15
- colorScheme = getColorSchemeForSeed(role.id);
16
- }
17
-
18
- return (
19
- <Chip colorScheme={colorScheme} key={role.id}>
20
- {role.name}
21
- </Chip>
22
- );
23
- }
@@ -1,45 +0,0 @@
1
- import React from "react";
2
- import { CollectionActionsProps } from "@rebasepro/types";
3
- import { Select, SelectItem } from "@rebasepro/ui";
4
- import { useTranslation, useInternalUserManagementController } from "@rebasepro/core";
5
-
6
- export function RolesFilterSelect({
7
- tableController
8
- }: CollectionActionsProps<any>) {
9
- const { t } = useTranslation();
10
- const userManagement = useInternalUserManagementController();
11
- const roles = userManagement?.roles || [];
12
-
13
- const currentFilterValue = (tableController.filterValues?.roles?.[1] as string) || "";
14
-
15
- const handleRoleChange = (newRole: string) => {
16
- const filterVal = newRole === "" ? undefined : newRole;
17
- if (filterVal) {
18
- tableController.setFilterValues?.({
19
- ...tableController.filterValues,
20
- roles: ["array-contains", filterVal]
21
- });
22
- } else {
23
- const nextFilters = { ...tableController.filterValues };
24
- delete nextFilters.roles;
25
- tableController.setFilterValues?.(nextFilters);
26
- }
27
- };
28
-
29
- if (!roles || roles.length === 0) return null;
30
-
31
- return (
32
- <Select
33
- value={currentFilterValue || "__all__"}
34
- onValueChange={(v) => handleRoleChange(v === "__all__" ? "" : v)}
35
- placeholder={t("all_roles") || "All Roles"}
36
- size="small"
37
- className="w-48"
38
- >
39
- <SelectItem value="__all__">{t("all_roles") || "All Roles"}</SelectItem>
40
- {roles.map(role => (
41
- <SelectItem key={role.id} value={role.id}>{role.name}</SelectItem>
42
- ))}
43
- </Select>
44
- );
45
- }
@@ -1,465 +0,0 @@
1
-
2
- import React, { useState } from "react";
3
- import { useCollectionRegistryController } from "../../index";
4
- import { useSnackbarController, useTranslation } from "@rebasepro/core";
5
- import { getDataSourceCapabilities, Role, SecurityRule, UserManagementDelegate } from "@rebasepro/types";
6
- import { useBreadcrumbsController } from "../../index";
7
- import {
8
- Button,
9
- CenteredView,
10
- Checkbox,
11
- Chip,
12
- CircularProgress,
13
- Container,
14
- defaultBorderMixin,
15
- Dialog,
16
- DialogActions,
17
- DialogContent,
18
- DialogTitle,
19
- IconButton,
20
- iconSize,
21
- Label,
22
- LoadingButton,
23
- Paper,
24
- PlusIcon,
25
- Table,
26
- TableBody,
27
- TableCell,
28
- TableHeader,
29
- TableRow,
30
- TextField,
31
- Tooltip,
32
- Trash2Icon,
33
- Typography
34
- } from "@rebasepro/ui";
35
- import { RoleChip } from "./RoleChip";
36
- import { ConfirmationDialog } from "@rebasepro/core";
37
-
38
- // ============================================
39
- // RolesView Component
40
- // ============================================
41
- export function RolesView({ userManagement }: { userManagement: UserManagementDelegate }) {
42
- const { roles, saveRole, deleteRole, loading, allowDefaultRolesCreation, rolesError } = userManagement;
43
- const snackbarController = useSnackbarController();
44
- const { t } = useTranslation();
45
- const breadcrumbs = useBreadcrumbsController();
46
-
47
- React.useEffect(() => {
48
- breadcrumbs.set({
49
- breadcrumbs: [{ title: t("roles"),
50
- url: "/roles" }]
51
- });
52
-
53
- }, []);
54
-
55
- const [dialogOpen, setDialogOpen] = useState(false);
56
- const [selectedRole, setSelectedRole] = useState<Role | undefined>();
57
- const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false);
58
- const [roleToDelete, setRoleToDelete] = useState<Role | undefined>();
59
- const [deleteInProgress, setDeleteInProgress] = useState(false);
60
-
61
- const handleAddRole = () => {
62
- setSelectedRole(undefined);
63
- setDialogOpen(true);
64
- };
65
-
66
- const handleEditRole = (role: Role) => {
67
- setSelectedRole(role);
68
- setDialogOpen(true);
69
- };
70
-
71
- const handleClose = () => {
72
- setDialogOpen(false);
73
- setSelectedRole(undefined);
74
- };
75
-
76
- const handleDelete = async () => {
77
- if (!roleToDelete || !deleteRole) return;
78
- setDeleteInProgress(true);
79
- try {
80
- await deleteRole(roleToDelete);
81
- snackbarController.open({ type: "success",
82
- message: t("role_deleted_successfully") });
83
- setDeleteConfirmOpen(false);
84
- setRoleToDelete(undefined);
85
- } catch (error: unknown) {
86
- snackbarController.open({ type: "error",
87
- message: error instanceof Error ? error.message : t("error_deleting_role") });
88
- } finally {
89
- setDeleteInProgress(false);
90
- }
91
- };
92
-
93
- const createDefaultRoles = async () => {
94
- if (!saveRole) return;
95
- const defaultRoles: Role[] = [
96
- { id: "admin",
97
- name: "Admin",
98
- isAdmin: true },
99
- { id: "editor",
100
- name: "Editor",
101
- isAdmin: false },
102
- { id: "viewer",
103
- name: "Viewer",
104
- isAdmin: false }
105
- ];
106
- try {
107
- for (const role of defaultRoles) {
108
- await saveRole(role);
109
- }
110
- snackbarController.open({
111
- type: "success",
112
- message: t("saved_correctly")
113
- });
114
- } catch (error: unknown) {
115
- snackbarController.open({
116
- type: "error",
117
- message: error instanceof Error ? error.message : t("error_saving_role")
118
- });
119
- }
120
- };
121
-
122
- if (loading) {
123
- return <CenteredView><CircularProgress/></CenteredView>;
124
- }
125
-
126
- return (
127
- <Container className="w-full flex flex-col py-4 gap-4" maxWidth={"6xl"}>
128
- <div className="flex items-center mt-12 mb-4 gap-4">
129
- <Typography gutterBottom variant="h4" className="grow mb-0" component="h4">
130
- {t("roles")}
131
- </Typography>
132
- <Button startIcon={<PlusIcon/>} onClick={handleAddRole} disabled={!saveRole}>
133
- {t("add_role")}
134
- </Button>
135
- </div>
136
-
137
- <div className="w-full overflow-auto">
138
- <Table className="w-full">
139
- <TableHeader>
140
- <TableCell header>{t("role")}</TableCell>
141
- <TableCell header className="items-center">{t("is_admin")}</TableCell>
142
- <TableCell header className="w-24 text-right">{t("actions")}</TableCell>
143
- </TableHeader>
144
- <TableBody>
145
- {roles && roles.map((role: Role) => {
146
-
147
- return (
148
- <TableRow key={role.id} onClick={() => saveRole && handleEditRole(role)}>
149
- <TableCell>
150
- <RoleChip role={role}/>
151
- </TableCell>
152
- <TableCell className="items-center">
153
- <Checkbox checked={role.isAdmin ?? false} disabled/>
154
- </TableCell>
155
- <TableCell className="text-right whitespace-nowrap">
156
- <div className="flex justify-end items-center gap-1">
157
- {!role.isAdmin && deleteRole && (
158
- <Tooltip asChild title={t("delete_this_role")}>
159
- <IconButton
160
- size="small"
161
- onClick={(e) => {
162
- e.stopPropagation();
163
- setRoleToDelete(role);
164
- setDeleteConfirmOpen(true);
165
- }}>
166
- <Trash2Icon size={iconSize.small}/>
167
- </IconButton>
168
- </Tooltip>
169
- )}
170
- </div>
171
- </TableCell>
172
- </TableRow>
173
- );
174
- })}
175
-
176
- {(!roles || roles.length === 0) && (
177
- <TableRow>
178
- <TableCell colspan={3}>
179
- <CenteredView className="flex flex-col gap-4 my-8 items-center">
180
- <Typography variant="label">
181
- {rolesError
182
- ? t("no_permission_to_view_roles")
183
- : t("no_roles_yet")}
184
- </Typography>
185
- {rolesError && (
186
- <Typography variant="caption" color="secondary">
187
- {t("no_permission_description")}
188
- </Typography>
189
- )}
190
- {!rolesError && allowDefaultRolesCreation && saveRole && (
191
- <Button onClick={createDefaultRoles}>
192
- {t("create_default_roles")}
193
- </Button>
194
- )}
195
- </CenteredView>
196
- </TableCell>
197
- </TableRow>
198
- )}
199
- </TableBody>
200
- </Table>
201
- </div>
202
-
203
- {/* Role Edit Dialog */}
204
- {saveRole && (
205
- <RoleDetailsForm
206
- key={selectedRole?.id ?? "new"}
207
- open={dialogOpen}
208
- role={selectedRole}
209
- saveRole={saveRole}
210
- handleClose={handleClose}
211
- />
212
- )}
213
-
214
- {/* Delete Confirmation */}
215
- <ConfirmationDialog
216
- open={deleteConfirmOpen}
217
- loading={deleteInProgress}
218
- onAccept={handleDelete}
219
- onCancel={() => { setDeleteConfirmOpen(false); setRoleToDelete(undefined); }}
220
- title={<>{t("delete_confirmation_title")}</>}
221
- body={<>{t("delete_role_confirmation")}</>}
222
- />
223
- </Container>
224
- );
225
- }
226
-
227
- // ============================================
228
- // RoleDetailsForm Component
229
- // ============================================
230
- function RoleDetailsForm({
231
- open,
232
- role: roleProp,
233
- saveRole,
234
- handleClose
235
- }: {
236
- open: boolean;
237
- role?: Role;
238
- saveRole: (role: Role) => Promise<void>;
239
- handleClose: () => void;
240
- }) {
241
- const snackbarController = useSnackbarController();
242
- const { t } = useTranslation();
243
- const isNewRole = !roleProp;
244
-
245
- const [roleId, setRoleId] = useState(roleProp?.id || "");
246
- const [roleName, setRoleName] = useState(roleProp?.name || "");
247
- const [isAdmin, setIsAdmin] = useState(roleProp?.isAdmin ?? false);
248
-
249
- const [isSubmitting, setIsSubmitting] = useState(false);
250
- const [errors, setErrors] = useState<{ id?: string; name?: string }>({});
251
- const [submitCount, setSubmitCount] = useState(0);
252
-
253
- const validate = () => {
254
- const newErrors: typeof errors = {};
255
- if (!roleId) newErrors.id = "Required";
256
- if (!roleName) newErrors.name = "Required";
257
- setErrors(newErrors);
258
- return Object.keys(newErrors).length === 0;
259
- };
260
-
261
- const handleSubmit = async (e: React.FormEvent) => {
262
- e.preventDefault();
263
- setSubmitCount(c => c + 1);
264
-
265
- if (!validate()) return;
266
-
267
- setIsSubmitting(true);
268
- try {
269
- await saveRole({
270
- id: roleId,
271
- name: roleName,
272
- isAdmin
273
- });
274
- handleClose();
275
- } catch (error: unknown) {
276
- snackbarController.open({ type: "error",
277
- message: error instanceof Error ? error.message : "Failed to save role" });
278
- } finally {
279
- setIsSubmitting(false);
280
- }
281
- };
282
-
283
- return (
284
- <Dialog open={open} onOpenChange={(open) => !open ? handleClose() : undefined} maxWidth="4xl">
285
- <form onSubmit={handleSubmit} autoComplete="off" noValidate
286
- style={{ display: "flex",
287
- flexDirection: "column",
288
- position: "relative",
289
- height: "100%" }}>
290
-
291
- <DialogTitle variant="h4" gutterBottom={false}>
292
- {t("role")}
293
- </DialogTitle>
294
-
295
- <DialogContent className="h-full grow overflow-y-auto">
296
- <div className="grid grid-cols-12 gap-4">
297
- <div className="col-span-12 sm:col-span-4">
298
- <TextField
299
- name="id"
300
- required
301
- error={submitCount > 0 && Boolean(errors.id)}
302
- value={roleId}
303
- onChange={(e) => setRoleId(e.target.value)}
304
- label={t("role_id")}
305
- disabled={!isNewRole}
306
- />
307
- {submitCount > 0 && errors.id && (
308
- <Typography variant="caption" color="error">{errors.id}</Typography>
309
- )}
310
- </div>
311
-
312
- <div className="col-span-12 sm:col-span-4">
313
- <TextField
314
- name="name"
315
- required
316
- error={submitCount > 0 && Boolean(errors.name)}
317
- value={roleName}
318
- onChange={(e) => setRoleName(e.target.value)}
319
- label={t("role_name")}
320
- />
321
- {submitCount > 0 && errors.name && (
322
- <Typography variant="caption" color="error">{errors.name}</Typography>
323
- )}
324
- </div>
325
-
326
- <div className="col-span-12 sm:col-span-4 flex items-start pt-2">
327
- <Label className="flex items-center gap-2 cursor-pointer mt-3">
328
- <Checkbox
329
- checked={isAdmin}
330
- onCheckedChange={(checked) => setIsAdmin(Boolean(checked))}
331
- />
332
- <Typography variant="body2" className="font-medium">{t("is_admin")}</Typography>
333
- </Label>
334
- </div>
335
-
336
- <div className="col-span-12">
337
- <CollectionPermissionsMatrix roleId={roleId} isAdmin={isAdmin}/>
338
- </div>
339
- </div>
340
- </DialogContent>
341
-
342
- <DialogActions>
343
- <Button variant="text" onClick={handleClose}>
344
- {t("cancel")}
345
- </Button>
346
- <LoadingButton
347
- variant="filled"
348
- type="submit"
349
- disabled={isSubmitting}
350
- loading={isSubmitting}
351
- >
352
- {isNewRole ? t("create_role") : t("update")}
353
- </LoadingButton>
354
- </DialogActions>
355
- </form>
356
- </Dialog>
357
- );
358
- }
359
-
360
- // ============================================
361
- // CollectionPermissionsMatrix
362
- // ============================================
363
- const CRUD_OPS = [
364
- { op: "select" as const,
365
- label: "read" },
366
- { op: "insert" as const,
367
- label: "create" },
368
- { op: "update" as const,
369
- label: "edit" },
370
- { op: "delete" as const,
371
- label: "delete" }
372
- ];
373
-
374
- function hasRoleAccess(
375
- rules: SecurityRule[] | undefined,
376
- roleId: string,
377
- op: "select" | "insert" | "update" | "delete"
378
- ): boolean {
379
- if (!rules || rules.length === 0) return true;
380
- const applicable = rules.filter(r =>
381
- r.operation === op || r.operation === "all" ||
382
- r.operations?.includes(op) || r.operations?.includes("all")
383
- );
384
- if (applicable.length === 0) return false;
385
- const forRole = applicable.filter(r =>
386
- !r.roles || r.roles.length === 0 || r.roles.includes(roleId) || r.roles.includes("public")
387
- );
388
- if (forRole.length === 0) return false;
389
- for (const r of forRole) {
390
- if ((r.mode ?? "permissive") === "restrictive") return false;
391
- }
392
- return forRole.some(r => (r.mode ?? "permissive") === "permissive");
393
- }
394
-
395
- function PermCell({ granted }: { granted: boolean }) {
396
- return (
397
- <span className={granted
398
- ? "text-green-500 dark:text-green-400 font-bold"
399
- : "text-surface-300 dark:text-surface-600"}
400
- >
401
- {granted ? "✓" : "✗"}
402
- </span>
403
- );
404
- }
405
-
406
- function CollectionPermissionsMatrix({ roleId, isAdmin }: { roleId: string; isAdmin: boolean }) {
407
- const { collections } = useCollectionRegistryController();
408
- const { t } = useTranslation();
409
-
410
- if (!collections || collections.length === 0) {
411
- return (
412
- <div className="mt-4">
413
- <Typography variant="label" className="text-surface-400">{t("no_collections_configured")}</Typography>
414
- </div>
415
- );
416
- }
417
-
418
- const topLevel = collections;
419
-
420
- return (
421
- <div className="mt-4">
422
- <Typography variant="label" className="mb-2 block text-surface-500 dark:text-surface-400 uppercase tracking-wide text-xs">
423
- {t("collection_permissions")}
424
- </Typography>
425
- <div className={`rounded-lg overflow-hidden border w-full ${defaultBorderMixin}`}>
426
- <Table className="w-full">
427
- <TableHeader>
428
- <TableCell header>{t("collection")}</TableCell>
429
- {CRUD_OPS.map(({ op, label }) => (
430
- <TableCell key={op} header align="center" className="w-20">{t(label)}</TableCell>
431
- ))}
432
- </TableHeader>
433
- <TableBody>
434
- {topLevel.map((collection) => {
435
- const capabilities = getDataSourceCapabilities(collection.driver);
436
- const rules = capabilities.supportsRLS && 'securityRules' in collection ? collection.securityRules : undefined;
437
- const noRules = !rules || rules.length === 0;
438
- return (
439
- <TableRow key={collection.slug}>
440
- <TableCell>
441
- <div className="flex items-center gap-1.5">
442
- <span className="font-medium">{collection.name}</span>
443
- {noRules && !isAdmin && (
444
- <Tooltip title={t("no_security_rules_defined")}>
445
- <Chip size="smallest" colorScheme="gray">{t("no_rules")}</Chip>
446
- </Tooltip>
447
- )}
448
- </div>
449
- <span className="text-xs text-surface-400 font-mono">{collection.slug}</span>
450
- </TableCell>
451
- {CRUD_OPS.map(({ op }) => (
452
- <TableCell key={op} align="center" className="w-20">
453
- <PermCell granted={isAdmin || hasRoleAccess(rules, roleId, op)}/>
454
- </TableCell>
455
- ))}
456
- </TableRow>
457
- );
458
- })}
459
- </TableBody>
460
- </Table>
461
- </div>
462
- </div>
463
- );
464
- }
465
-
@@ -1,50 +0,0 @@
1
- import React from "react";
2
- import { FieldProps } from "../../types/fields";
3
- import { MultiSelect, MultiSelectItem } from "@rebasepro/ui";
4
- import { useTranslation, useInternalUserManagementController } from "@rebasepro/core";
5
- import { RoleChip } from "./RoleChip";
6
-
7
- export function UserRolesSelectField({
8
- propertyKey,
9
- value,
10
- setValue,
11
- disabled
12
- }: FieldProps) {
13
- const { t } = useTranslation();
14
- const userManagement = useInternalUserManagementController();
15
- const roles = userManagement?.roles || [];
16
-
17
- const selectedRoleIds = (value || []).map((r: any) => {
18
- if (typeof r === "object" && r !== null) {
19
- return r.id;
20
- }
21
- return r;
22
- });
23
-
24
- const handleValueChange = (val: string[]) => {
25
- const references = val.map(id => ({
26
- id,
27
- path: "roles",
28
- __type: "relation"
29
- }));
30
- setValue(references);
31
- };
32
-
33
- return (
34
- <div className="col-span-12">
35
- <MultiSelect
36
- className="w-full"
37
- label={t("roles") || "Roles"}
38
- value={selectedRoleIds}
39
- onValueChange={handleValueChange}
40
- disabled={disabled}
41
- >
42
- {roles.map(role => (
43
- <MultiSelectItem key={role.id} value={role.id}>
44
- <RoleChip role={role}/>
45
- </MultiSelectItem>
46
- ))}
47
- </MultiSelect>
48
- </div>
49
- );
50
- }