@rebasepro/admin 0.3.0 → 0.5.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 (106) hide show
  1. package/README.md +135 -0
  2. package/dist/{CollectionEditorDialog-D0VqpLPO.js → CollectionEditorDialog-C8E440oK.js} +22 -5
  3. package/dist/CollectionEditorDialog-C8E440oK.js.map +1 -0
  4. package/dist/{CollectionsStudioView-Bc3Rxxc2.js → CollectionsStudioView-Brr_b06v.js} +4 -4
  5. package/dist/{CollectionsStudioView-Bc3Rxxc2.js.map → CollectionsStudioView-Brr_b06v.js.map} +1 -1
  6. package/dist/{ExportCollectionAction-Ckc-09BQ.js → ExportCollectionAction-D3TTYXrq.js} +35 -27
  7. package/dist/ExportCollectionAction-D3TTYXrq.js.map +1 -0
  8. package/dist/{ImportCollectionAction-BqjIrC3Z.js → ImportCollectionAction-Dn7lya6E.js} +2 -2
  9. package/dist/{ImportCollectionAction-BqjIrC3Z.js.map → ImportCollectionAction-Dn7lya6E.js.map} +1 -1
  10. package/dist/{PropertyEditView-CvRSV-A2.js → PropertyEditView-ChBleIbN.js} +4 -4
  11. package/dist/PropertyEditView-ChBleIbN.js.map +1 -0
  12. package/dist/collection_editor/ui/collection_editor/PropertyEditView.d.ts +1 -0
  13. package/dist/collection_editor/ui/collection_editor/templates/blog_template.d.ts +1 -1
  14. package/dist/collection_editor/ui/collection_editor/templates/pages_template.d.ts +1 -1
  15. package/dist/collection_editor/ui/collection_editor/templates/products_template.d.ts +1 -1
  16. package/dist/collection_editor/ui/collection_editor/templates/users_template.d.ts +1 -1
  17. package/dist/collection_editor_ui.js +3 -3
  18. package/dist/components/CollectionPanel.d.ts +83 -0
  19. package/dist/components/EntityDetailView.d.ts +0 -3
  20. package/dist/components/EntityEditView.d.ts +2 -3
  21. package/dist/components/RebaseRouteDefs.d.ts +1 -1
  22. package/dist/components/SelectableTable/SelectableTable.d.ts +2 -2
  23. package/dist/components/SelectableTable/SelectableTableContext.d.ts +1 -1
  24. package/dist/components/SelectableTable/SelectionStore.d.ts +3 -3
  25. package/dist/components/admin/index.d.ts +1 -3
  26. package/dist/components/index.d.ts +1 -0
  27. package/dist/editor.js +15 -5
  28. package/dist/editor.js.map +1 -1
  29. package/dist/hooks/navigation/useBuildNavigationStateController.d.ts +1 -1
  30. package/dist/hooks/navigation/useResolvedViews.d.ts +2 -5
  31. package/dist/{index-BCcLwgfe.js → index-D3S9x_RP.js} +2 -2
  32. package/dist/{index-BCcLwgfe.js.map → index-D3S9x_RP.js.map} +1 -1
  33. package/dist/{index-DY2k5TtG.js → index-D9RNzm01.js} +3 -3
  34. package/dist/index-D9RNzm01.js.map +1 -0
  35. package/dist/{index-UQOMHwt1.js → index-DrrT332R.js} +3 -3
  36. package/dist/index-DrrT332R.js.map +1 -0
  37. package/dist/index.d.ts +2 -4
  38. package/dist/index.js +228 -295
  39. package/dist/index.js.map +1 -1
  40. package/dist/util/entity_view_constants.d.ts +6 -0
  41. package/dist/util/resolutions.d.ts +1 -2
  42. package/dist/{util-ZM9gQuCv.js → util-COYYD8zr.js} +473 -880
  43. package/dist/util-COYYD8zr.js.map +1 -0
  44. package/package.json +9 -10
  45. package/src/collection_editor/pgColumnToProperty.ts +19 -2
  46. package/src/collection_editor/ui/collection_editor/CollectionRelationsTab.tsx +2 -2
  47. package/src/collection_editor/ui/collection_editor/PropertyEditView.tsx +2 -1
  48. package/src/collection_editor/ui/collection_editor/PropertyFieldPreview.tsx +2 -2
  49. package/src/collection_editor/ui/collection_editor/properties/conditions/ConditionsEditor.tsx +2 -1
  50. package/src/collection_editor/ui/collection_editor/properties/conditions/EnumConditionsEditor.tsx +1 -1
  51. package/src/collection_editor/ui/collection_editor/templates/blog_template.ts +1 -1
  52. package/src/collection_editor/ui/collection_editor/templates/pages_template.ts +1 -1
  53. package/src/collection_editor/ui/collection_editor/templates/products_template.ts +1 -1
  54. package/src/collection_editor/ui/collection_editor/templates/users_template.ts +1 -1
  55. package/src/collection_editor/validateCollectionJson.ts +12 -12
  56. package/src/components/CollectionPanel.tsx +155 -0
  57. package/src/components/DefaultDrawer.tsx +2 -2
  58. package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +5 -2
  59. package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +64 -34
  60. package/src/components/EntityCollectionView/EntityCollectionListView.tsx +8 -1
  61. package/src/components/EntityCollectionView/EntityCollectionView.tsx +4 -1
  62. package/src/components/EntityCollectionView/hooks/useCollectionInlineEditor.ts +1 -0
  63. package/src/components/EntityCollectionView/useEntityPreviewSlots.ts +68 -18
  64. package/src/components/EntityDetailView.tsx +32 -36
  65. package/src/components/EntityEditView.tsx +101 -50
  66. package/src/components/EntityEditViewFormActions.tsx +4 -4
  67. package/src/components/EntitySidePanel.tsx +50 -14
  68. package/src/components/PropertyCollectionView.tsx +1 -0
  69. package/src/components/RebaseRouteDefs.tsx +4 -6
  70. package/src/components/SelectableTable/SelectableTable.tsx +24 -22
  71. package/src/components/SelectableTable/SelectableTableContext.tsx +2 -1
  72. package/src/components/SelectableTable/SelectionStore.ts +4 -4
  73. package/src/components/admin/index.ts +1 -3
  74. package/src/components/index.ts +3 -3
  75. package/src/data_export/export/BasicExportAction.tsx +11 -9
  76. package/src/data_export/export/ExportCollectionAction.tsx +15 -13
  77. package/src/editor/editor.tsx +20 -4
  78. package/src/form/EntityForm.tsx +3 -3
  79. package/src/form/PropertyFieldBinding.tsx +1 -1
  80. package/src/form/field_bindings/KeyValueFieldBinding.tsx +1 -1
  81. package/src/form/field_bindings/MapFieldBinding.tsx +3 -45
  82. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +3 -1
  83. package/src/hooks/navigation/useBuildNavigationStateController.tsx +2 -3
  84. package/src/hooks/navigation/useResolvedCollections.ts +2 -10
  85. package/src/hooks/navigation/useResolvedViews.tsx +6 -48
  86. package/src/hooks/useBuildSideEntityController.tsx +20 -3
  87. package/src/index.ts +6 -5
  88. package/src/util/entity_view_constants.ts +6 -0
  89. package/src/util/previews.ts +9 -1
  90. package/src/util/resolutions.ts +2 -6
  91. package/dist/CollectionEditorDialog-D0VqpLPO.js.map +0 -1
  92. package/dist/ExportCollectionAction-Ckc-09BQ.js.map +0 -1
  93. package/dist/PropertyEditView-CvRSV-A2.js.map +0 -1
  94. package/dist/components/admin/RoleChip.d.ts +0 -4
  95. package/dist/components/admin/RolesFilterSelect.d.ts +0 -2
  96. package/dist/components/admin/RolesView.d.ts +0 -4
  97. package/dist/components/admin/UserRolesSelectField.d.ts +0 -2
  98. package/dist/components/admin/UsersView.d.ts +0 -4
  99. package/dist/index-DY2k5TtG.js.map +0 -1
  100. package/dist/index-UQOMHwt1.js.map +0 -1
  101. package/dist/util-ZM9gQuCv.js.map +0 -1
  102. package/src/components/admin/RoleChip.tsx +0 -23
  103. package/src/components/admin/RolesFilterSelect.tsx +0 -45
  104. package/src/components/admin/RolesView.tsx +0 -470
  105. package/src/components/admin/UserRolesSelectField.tsx +0 -50
  106. package/src/components/admin/UsersView.tsx +0 -693
@@ -1,6 +1,6 @@
1
1
 
2
- import type { AppView, AppViewsBuilder, EffectiveRoleController, EntityCollection, RebasePlugin } from "@rebasepro/types";
3
- import React, { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from "react";
2
+ import type { AppView, AppViewsBuilder, EffectiveRoleController, RebasePlugin } from "@rebasepro/types";
3
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
4
 
5
5
  /**
6
6
  * Compare two view arrays by their slug identity.
@@ -17,14 +17,10 @@ function viewSlugsEqual(a: AppView[] | undefined, b: AppView[] | undefined): boo
17
17
  return true;
18
18
  }
19
19
 
20
- import { AuthController, RebaseData, User } from "@rebasepro/types";
21
- import { UserManagementDelegate } from "@rebasepro/types";
20
+ import type { AuthController, RebaseData, User } from "@rebasepro/types";
22
21
 
23
22
  import { resolveAppViews } from "./useNavigationResolution";
24
23
 
25
-
26
- import { RolesView } from "../../components/admin/RolesView";
27
-
28
24
  export type UseResolvedViewsProps<USER extends User> = {
29
25
  authController: AuthController<USER>;
30
26
  views?: AppView[] | AppViewsBuilder;
@@ -33,7 +29,6 @@ export type UseResolvedViewsProps<USER extends User> = {
33
29
  plugins?: RebasePlugin[];
34
30
  adminMode?: "content" | "studio" | "settings";
35
31
  effectiveRoleController?: EffectiveRoleController;
36
- userManagement?: UserManagementDelegate<USER>;
37
32
  };
38
33
 
39
34
  export type UseResolvedViewsResult = {
@@ -46,8 +41,7 @@ export type UseResolvedViewsResult = {
46
41
 
47
42
  /**
48
43
  * Hook that resolves view and admin view props (which may be async builders or arrays)
49
- * into concrete AppView[]. Also injects the Roles admin view when userManagement
50
- * is provided with roles.
44
+ * into concrete AppView[].
51
45
  *
52
46
  * Uses refs for potentially-unstable dependencies (driver, authController,
53
47
  * plugins) to avoid re-triggering effects when their object identity changes.
@@ -63,8 +57,7 @@ export function useResolvedViews<USER extends User>(
63
57
  data,
64
58
  plugins,
65
59
  adminMode = "content",
66
- effectiveRoleController,
67
- userManagement
60
+ effectiveRoleController
68
61
  } = props;
69
62
 
70
63
  const [loading, setLoading] = useState(true);
@@ -110,32 +103,6 @@ export function useResolvedViews<USER extends User>(
110
103
  const resolvedAuthControllerRef = useRef(resolvedAuthController);
111
104
  resolvedAuthControllerRef.current = resolvedAuthController;
112
105
 
113
- // Memoize JSX element for injected Roles admin view to ensure stable reference.
114
- const hasRoles = !!userManagement?.roles;
115
- const rolesViewElement = useMemo(() =>
116
- hasRoles ? <RolesView /> : null,
117
- [hasRoles]
118
- );
119
-
120
- const injectedAdminViews: AppView[] = useMemo(() => {
121
- const views: AppView[] = [];
122
- const isUserAdmin = userManagement?.isAdmin !== false;
123
- if (userManagement && isUserAdmin && userManagement.roles && rolesViewElement) {
124
- views.push({
125
- slug: "roles",
126
- name: "Roles",
127
- icon: "Shield",
128
- view: rolesViewElement,
129
- group: "Settings"
130
- });
131
- }
132
- return views;
133
- }, [userManagement, rolesViewElement]);
134
-
135
- // Store injectedAdminViews in a ref for effect access
136
- const injectedAdminViewsRef = useRef(injectedAdminViews);
137
- injectedAdminViewsRef.current = injectedAdminViews;
138
-
139
106
  const initialLoading = resolvedAuthController.initialLoading;
140
107
  const user = resolvedAuthController.user;
141
108
 
@@ -146,20 +113,11 @@ export function useResolvedViews<USER extends User>(
146
113
 
147
114
  (async () => {
148
115
  try {
149
- const [newViews, newAdminViewsProp] = await Promise.all([
116
+ const [newViews, newAdminViews] = await Promise.all([
150
117
  resolveAppViews(viewsProp, resolvedAuthControllerRef.current, dataRef.current, pluginsRef.current),
151
118
  resolveAppViews(adminViewsProp, resolvedAuthControllerRef.current, dataRef.current)
152
119
  ]);
153
120
 
154
- // Generic dedup: developer-provided admin views override any injected ones with the same slug.
155
- // No hardcoded slug checks — works for any slug generically.
156
- const customSlugs = new Set(newAdminViewsProp.flatMap(v => Array.isArray(v.slug) ? v.slug : [v.slug]));
157
- const finalInjected = injectedAdminViewsRef.current.filter(v => {
158
- const slugs = Array.isArray(v.slug) ? v.slug : [v.slug];
159
- return slugs.every(s => !customSlugs.has(s));
160
- });
161
- const newAdminViews = [...newAdminViewsProp, ...finalInjected];
162
-
163
121
  // Compare views by slug identity rather than deepEqual.
164
122
  // Views contain React elements (JSX) whose internal properties
165
123
  // change on every render, making deepEqual unreliable.
@@ -26,7 +26,7 @@ export function getEntityViewWidth(props: EntitySidePanelProps<any>, small: bool
26
26
  selectedSecondaryForm
27
27
  } = resolvedSelectedEntityView(props.collection?.entityViews, customizationController, props.selectedTab);
28
28
 
29
- const shouldUseSmallLayout = !props.selectedTab || props.selectedTab === JSON_TAB_VALUE || props.selectedTab === HISTORY_TAB_VALUE || Boolean(selectedSecondaryForm);
29
+ const shouldUseSmallLayout = !props.selectedTab || props.selectedTab === "edit" || props.selectedTab === JSON_TAB_VALUE || props.selectedTab === HISTORY_TAB_VALUE || Boolean(selectedSecondaryForm);
30
30
 
31
31
  let resolvedWidth: string | undefined;
32
32
  if (props.width) {
@@ -187,8 +187,8 @@ width: newWidth };
187
187
 
188
188
  sideDialogsController.open(
189
189
  propsToSidePanel({
190
- selectedTab: defaultSelectedView,
191
- ...props
190
+ ...props,
191
+ selectedTab: props.selectedTab ?? defaultSelectedView,
192
192
  },
193
193
  urlController.buildUrlCollectionPath,
194
194
  urlController.resolveDatabasePathsFrom,
@@ -241,6 +241,7 @@ export function buildSidePanelsFromUrl(path: string, collections: EntityCollecti
241
241
  path: navigationEntry.slug,
242
242
  entityId: navigationEntry.entityId,
243
243
  copy: false,
244
+ collection: navigationEntry.parentCollection,
244
245
  width: navigationEntry.parentCollection?.sideDialogWidth
245
246
  };
246
247
  } else if (navigationEntry.type === "custom_view") {
@@ -257,6 +258,22 @@ export function buildSidePanelsFromUrl(path: string, collections: EntityCollecti
257
258
 
258
259
  }
259
260
 
261
+ // When the URL doesn't contain a tab segment but the collection has a
262
+ // defaultSelectedView, resolve it so the panel opens with the correct
263
+ // width and the URL is updated on the next replace() cycle.
264
+ if (sidePanel && !sidePanel.selectedTab && sidePanel.collection) {
265
+ const defaultView = resolveDefaultSelectedView(
266
+ sidePanel.collection.defaultSelectedView,
267
+ {
268
+ status: sidePanel.copy ? "copy" : (sidePanel.entityId ? "existing" : "new"),
269
+ entityId: sidePanel.entityId
270
+ }
271
+ );
272
+ if (defaultView) {
273
+ sidePanel.selectedTab = defaultView;
274
+ }
275
+ }
276
+
260
277
  if (newFlag) {
261
278
  sidePanel = {
262
279
  path: lastCollectionPath,
package/src/index.ts CHANGED
@@ -45,7 +45,7 @@ export {
45
45
  DefaultDrawer,
46
46
  DrawerFooterActions,
47
47
  AdminModeSyncer,
48
- // ContentHomePage, UsersView, RolesView are lazy-loaded — not re-exported here
48
+ // ContentHomePage is lazy-loaded — not re-exported here
49
49
  RebaseCMS,
50
50
  RebaseShell,
51
51
  RebaseAuthGate,
@@ -53,12 +53,14 @@ export {
53
53
  RebaseLayout,
54
54
  RebaseRouteDefs,
55
55
  SideDialogs,
56
- useApp
56
+ useApp,
57
+ CollectionPanel
57
58
  } from "./components";
58
59
  export type {
59
60
  EntityViewProps,
60
61
  EntitySelectionProps,
61
- SelectableTableProps
62
+ SelectableTableProps,
63
+ CollectionPanelProps
62
64
  } from "./components";
63
65
 
64
66
  export * from "./hooks";
@@ -97,7 +99,6 @@ export * from "./data_export";
97
99
  // Collection editor — moved from @rebasepro/studio (CMS-dependent visual schema editor)
98
100
  export * from "./collection_editor";
99
101
 
100
- export { RolesFilterSelect } from "./components/admin/RolesFilterSelect";
101
- export { UserRolesSelectField } from "./components/admin/UserRolesSelectField";
102
+
102
103
  export { CreationResultDialog } from "./components/admin/CreationResultDialog";
103
104
 
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Shared tab value constants used by EntityEditView and EntityDetailView.
3
+ */
4
+ export const MAIN_TAB_VALUE = "__main_##Q$SC^#S6";
5
+ export const JSON_TAB_VALUE = "__json";
6
+ export const HISTORY_TAB_VALUE = "__rebase_history";
@@ -3,6 +3,11 @@ import { AuthController } from "@rebasepro/types";
3
3
  import { isPropertyBuilder } from "@rebasepro/common";
4
4
  import { isReferenceProperty, isRelationProperty } from "./property_utils";
5
5
 
6
+ function isHiddenProperty(property: Property | undefined): boolean {
7
+ if (!property) return false;
8
+ return Boolean(property.ui?.hideFromCollection);
9
+ }
10
+
6
11
  export function getEntityPreviewKeys(
7
12
  authController: AuthController,
8
13
  targetCollection: EntityCollection<any>,
@@ -26,7 +31,7 @@ export function getEntityPreviewKeys(
26
31
  })
27
32
  .filter(key => {
28
33
  const property = targetCollection.properties[key];
29
- return property && !isPropertyBuilder(property) && !isReferenceProperty(property) && !isRelationProperty(property);
34
+ return property && !isPropertyBuilder(property) && !isReferenceProperty(property) && !isRelationProperty(property) && !isHiddenProperty(property);
30
35
  }).slice(0, limit);
31
36
  }
32
37
  }
@@ -43,6 +48,9 @@ export function getEntityTitlePropertyKey<M extends Record<string, unknown>>(col
43
48
  const property = collection.properties[key];
44
49
  if (property && !isPropertyBuilder(property)) {
45
50
  const prop = property as Property;
51
+ if (isHiddenProperty(prop)) {
52
+ continue;
53
+ }
46
54
  if (prop.type === "string" && !prop.ui?.multiline && !prop.ui?.markdown && !prop.storage && !prop.isId) {
47
55
  if (!firstStringCandidate) {
48
56
  firstStringCandidate = key;
@@ -1,10 +1,7 @@
1
1
  import { HistoryIcon } from "@rebasepro/ui";
2
- import React, { lazy } from "react";
3
- import type { EntityCustomView, EntityCollection } from "@rebasepro/types";
4
- import type { CustomizationController, EntityAction } from "@rebasepro/types";
2
+ import React from "react";
3
+ import type { CustomizationController, EntityAction, EntityCustomView } from "@rebasepro/types";
5
4
 
6
- // Lazy-load: only resolved when HistoryIcon tab is visited
7
- const EntityHistoryView = lazy(() => import("../components/history").then(m => ({ default: m.EntityHistoryView })));
8
5
  /**
9
6
  * Built-in entity views that are resolved by token name.
10
7
  * These are always available without needing to be registered
@@ -15,7 +12,6 @@ const BUILTIN_ENTITY_VIEWS: Record<string, EntityCustomView> = {
15
12
  key: "__rebase_history",
16
13
  name: "History",
17
14
  tabComponent: React.createElement(HistoryIcon, { size: 20 }),
18
- Builder: EntityHistoryView,
19
15
  position: "end"
20
16
  }
21
17
  };