@rebasepro/cms-types 0.17.0-canary.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 (78) hide show
  1. package/LICENSE +21 -0
  2. package/dist/admin_collection.d.ts +650 -0
  3. package/dist/augment.d.ts +81 -0
  4. package/dist/collections.d.ts +282 -0
  5. package/dist/controllers/analytics_controller.d.ts +7 -0
  6. package/dist/controllers/auth.d.ts +111 -0
  7. package/dist/controllers/customization_controller.d.ts +69 -0
  8. package/dist/controllers/dialogs_controller.d.ts +36 -0
  9. package/dist/controllers/index.d.ts +10 -0
  10. package/dist/controllers/local_config_persistence.d.ts +20 -0
  11. package/dist/controllers/navigation.d.ts +248 -0
  12. package/dist/controllers/registry.d.ts +96 -0
  13. package/dist/controllers/side_dialogs_controller.d.ts +67 -0
  14. package/dist/controllers/side_panel_controller.d.ts +97 -0
  15. package/dist/controllers/snackbar.d.ts +45 -0
  16. package/dist/index.d.ts +18 -0
  17. package/dist/index.es.js +154 -0
  18. package/dist/index.es.js.map +1 -0
  19. package/dist/react_component_ref.d.ts +43 -0
  20. package/dist/rebase_context.d.ts +68 -0
  21. package/dist/types/breadcrumbs.d.ts +15 -0
  22. package/dist/types/builders.d.ts +15 -0
  23. package/dist/types/collection_views.d.ts +105 -0
  24. package/dist/types/component_overrides.d.ts +196 -0
  25. package/dist/types/entity_actions.d.ts +112 -0
  26. package/dist/types/entity_display.d.ts +148 -0
  27. package/dist/types/entity_link_builder.d.ts +7 -0
  28. package/dist/types/entity_views.d.ts +115 -0
  29. package/dist/types/export_import.d.ts +21 -0
  30. package/dist/types/form_layout.d.ts +126 -0
  31. package/dist/types/formex.d.ts +40 -0
  32. package/dist/types/index.d.ts +18 -0
  33. package/dist/types/locales.d.ts +4 -0
  34. package/dist/types/modify_collections.d.ts +5 -0
  35. package/dist/types/plugins.d.ts +277 -0
  36. package/dist/types/property_config.d.ts +74 -0
  37. package/dist/types/property_options.d.ts +255 -0
  38. package/dist/types/slots.d.ts +279 -0
  39. package/dist/types/translations.d.ts +989 -0
  40. package/dist/types/user_management_delegate.d.ts +22 -0
  41. package/package.json +103 -0
  42. package/src/admin_collection.ts +775 -0
  43. package/src/augment.ts +79 -0
  44. package/src/collections.ts +312 -0
  45. package/src/controllers/analytics_controller.tsx +57 -0
  46. package/src/controllers/auth.ts +122 -0
  47. package/src/controllers/customization_controller.tsx +81 -0
  48. package/src/controllers/dialogs_controller.tsx +37 -0
  49. package/src/controllers/index.ts +10 -0
  50. package/src/controllers/local_config_persistence.tsx +22 -0
  51. package/src/controllers/navigation.ts +288 -0
  52. package/src/controllers/registry.ts +114 -0
  53. package/src/controllers/side_dialogs_controller.tsx +82 -0
  54. package/src/controllers/side_panel_controller.tsx +112 -0
  55. package/src/controllers/snackbar.ts +51 -0
  56. package/src/index.ts +20 -0
  57. package/src/react_component_ref.ts +52 -0
  58. package/src/rebase_context.ts +81 -0
  59. package/src/types/breadcrumbs.ts +16 -0
  60. package/src/types/builders.ts +18 -0
  61. package/src/types/collection_views.tsx +125 -0
  62. package/src/types/component_overrides.ts +244 -0
  63. package/src/types/entity_actions.tsx +134 -0
  64. package/src/types/entity_display.ts +182 -0
  65. package/src/types/entity_link_builder.ts +8 -0
  66. package/src/types/entity_views.tsx +135 -0
  67. package/src/types/export_import.ts +26 -0
  68. package/src/types/form_layout.ts +137 -0
  69. package/src/types/formex.ts +45 -0
  70. package/src/types/index.ts +18 -0
  71. package/src/types/locales.ts +81 -0
  72. package/src/types/modify_collections.tsx +6 -0
  73. package/src/types/plugins.tsx +346 -0
  74. package/src/types/property_config.tsx +97 -0
  75. package/src/types/property_options.ts +300 -0
  76. package/src/types/slots.tsx +334 -0
  77. package/src/types/translations.ts +1104 -0
  78. package/src/types/user_management_delegate.ts +23 -0
@@ -0,0 +1,52 @@
1
+ import type React from "react";
2
+ import type { ComponentLike, ComponentRef, LazyComponentRef } from "@rebasepro/types";
3
+
4
+ /**
5
+ * `ComponentRef`, narrowed to real React types.
6
+ *
7
+ * Core's {@link ComponentRef} describes a component structurally
8
+ * ({@link ComponentLike}) so that `properties.ts` — and therefore the whole
9
+ * property model the backend reads — can live without React. The trade is that
10
+ * the return type is `unknown`, so a function returning something React cannot
11
+ * render type-checks there.
12
+ *
13
+ * Use this type wherever React genuinely exists: authoring a collection's admin
14
+ * options, and inside the admin packages. Assignments flow into core unchanged,
15
+ * because every member of this union is a member of that one.
16
+ */
17
+ export type ReactComponentRef<P = any> =
18
+ | string
19
+ | LazyComponentRef<P>
20
+ | (() => Promise<{ default: React.ComponentType<P> }>)
21
+ | React.ComponentType<P>;
22
+
23
+ /**
24
+ * The `ComponentLike` contract, as a signature the compiler has to keep true.
25
+ *
26
+ * The split rests on one claim: **every form a React component takes is
27
+ * assignable to `ComponentLike`** — function components, class components,
28
+ * `memo`, `forwardRef`. If that stopped holding, core's `ComponentRef` would
29
+ * quietly begin rejecting real components, and the failure would surface far away
30
+ * in whichever collection file happened to use the broken form.
31
+ *
32
+ * So the claim is not left to a test that someone has to run. This function's
33
+ * parameter and return types state it, and `pnpm typecheck` enforces it on every
34
+ * commit. It is also useful on its own: an explicit widening at the point where
35
+ * an authored component enters a collection config.
36
+ *
37
+ * @example
38
+ * import { MyField } from "./MyField";
39
+ * admin: { Field: asComponentRef(MyField) }
40
+ */
41
+ export function asComponentRef<P>(component: React.ComponentType<P>): ComponentRef<P> {
42
+ return component;
43
+ }
44
+
45
+ /**
46
+ * The same contract in the other direction: a `ComponentLike` is only renderable
47
+ * once narrowed, and this is the single sanctioned place that narrowing is
48
+ * spelled out. `resolveComponentRef` in `@rebasepro/app` does the runtime half.
49
+ */
50
+ export function asReactComponent<P>(component: ComponentLike<P>): React.ComponentType<P> {
51
+ return component as React.ComponentType<P>;
52
+ }
@@ -0,0 +1,81 @@
1
+ import type { AnalyticsController } from "./controllers/analytics_controller";
2
+ import type { AuthController } from "./controllers/auth";
3
+ import type { UserConfigurationPersistence } from "./controllers/local_config_persistence";
4
+ import type { DatabaseAdmin } from "@rebasepro/types";
5
+ import type { RebaseCallContext } from "@rebasepro/types";
6
+ import type { User } from "@rebasepro/types";
7
+
8
+ /**
9
+ * Context that includes the internal controllers and contexts used by the app.
10
+ * Some controllers and context included in this context can be accessed
11
+ * directly from their respective hooks.
12
+ * @group Hooks and utilities
13
+ * @see useRebaseContext
14
+ */
15
+ export type RebaseContext<USER extends User = User, AuthControllerType extends AuthController<USER> = AuthController<USER>> = RebaseCallContext<USER> & {
16
+
17
+ authController: AuthControllerType;
18
+
19
+ /**
20
+ * Controller mapping strings to collections
21
+ */
22
+ collectionRegistryController?: import("@rebasepro/types").CollectionRegistryController;
23
+
24
+ /**
25
+ * Controller for navigation state
26
+ */
27
+ navigationStateController?: import("./controllers/navigation").NavigationStateController;
28
+
29
+ /**
30
+ * Controller for side dialogs (side sheets)
31
+ */
32
+ sideDialogsController?: import("./controllers/side_dialogs_controller").SideDialogsController;
33
+
34
+ /**
35
+ * Controller to open the side panel displaying entity forms
36
+ */
37
+ sidePanelController?: import("./controllers/side_panel_controller").SidePanelController;
38
+
39
+ /**
40
+ * Controller resolving URLs in the admin
41
+ */
42
+ urlController?: import("./controllers/navigation").UrlController;
43
+
44
+ /**
45
+ * Controller to handle simple confirmation and alert dialogs
46
+ */
47
+ dialogsController?: import("./controllers/dialogs_controller").DialogsController;
48
+
49
+ /**
50
+ * Controller for admin customization
51
+ */
52
+ customizationController?: import("./controllers/customization_controller").CustomizationController;
53
+
54
+ /**
55
+ * Controller for effective role
56
+ */
57
+ effectiveRoleController?: { effectiveRole: string | null, setEffectiveRole: (role: string | null) => void };
58
+
59
+ /**
60
+ * Use this controller to access data stored in the browser for the user
61
+ */
62
+ userConfigPersistence?: UserConfigurationPersistence;
63
+
64
+ /**
65
+ * Callback to send analytics events
66
+ */
67
+ analyticsController?: AnalyticsController;
68
+
69
+
70
+ /**
71
+ * Administrative database operations (SQL, schema discovery).
72
+ * Only available in developer/admin contexts.
73
+ */
74
+ databaseAdmin?: DatabaseAdmin;
75
+
76
+ /**
77
+ * Controller for snackbars
78
+ */
79
+ snackbarController?: import("./controllers/snackbar").SnackbarController;
80
+
81
+ };
@@ -0,0 +1,16 @@
1
+ export interface BreadcrumbEntry {
2
+ title: string;
3
+ url: string;
4
+ /**
5
+ * Stable identifier for this entry (e.g., collection path). Lets the
6
+ * provider tell a rebuilt-but-unchanged trail from a real navigation.
7
+ */
8
+ id?: string;
9
+ }
10
+
11
+ export interface BreadcrumbsController {
12
+ breadcrumbs: BreadcrumbEntry[];
13
+ set: (props: {
14
+ breadcrumbs: BreadcrumbEntry[];
15
+ }) => void;
16
+ }
@@ -0,0 +1,18 @@
1
+ import type { AuthController } from "../controllers/auth";
2
+ import type { RebaseData } from "@rebasepro/types";
3
+ import type { User } from "@rebasepro/types";
4
+
5
+ import type { AppView } from "../controllers/navigation";
6
+ import type { AdminCollection } from "@rebasepro/cms-types";
7
+
8
+ export type CollectionConfigsBuilder<EC extends AdminCollection = AdminCollection> = (params: {
9
+ user: User | null,
10
+ authController: AuthController,
11
+ data: RebaseData
12
+ }) => EC[] | Promise<EC[]>;
13
+
14
+ export type AppViewsBuilder = (params: {
15
+ user: User | null,
16
+ authController: AuthController,
17
+ data: RebaseData
18
+ }) => AppView[] | Promise<AppView[]>;
@@ -0,0 +1,125 @@
1
+ import React from "react";
2
+ import type { Entity, ComponentRef } from "@rebasepro/types";
3
+ import type { AdminCollection } from "@rebasepro/cms-types";
4
+
5
+ import type { CollectionSize, EntityTableController, SelectionController, ViewMode } from "../collections";
6
+
7
+ /**
8
+ * A custom rendering of *one* collection's rows, selectable from the same view
9
+ * switcher as list / table / cards / kanban.
10
+ *
11
+ * This is the middle scope of custom UI. The other two already exist and this
12
+ * is not a substitute for either:
13
+ *
14
+ * - one record → `entityViews` (the entity tab strip)
15
+ * - one collection's rows, rendered differently → **this**
16
+ * - a workflow spanning several collections → `AppView` (`views={[…]}`)
17
+ *
18
+ * A view mode is another rendering of the *same query*. The `Builder` is handed
19
+ * the live {@link EntityTableController}, so it inherits the collection's
20
+ * filters, search string, sort, pagination, role checks and entity side panel
21
+ * for free — which is the whole reason to declare one instead of an `AppView`.
22
+ *
23
+ * If your component ignores `tableController` and fetches tables of its own, it
24
+ * wants to be an `AppView`: the toolbar above it — search box, filters, the
25
+ * record count — would be describing a query the view does not render.
26
+ *
27
+ * @group Models
28
+ */
29
+ export type CollectionCustomView<M extends Record<string, unknown> = Record<string, unknown>> = {
30
+ /**
31
+ * Identifies this view. It is what `defaultViewMode` and `enabledViews`
32
+ * name, and what the `__view` URL param carries, so it must not collide
33
+ * with a built-in mode ("list", "table", "cards", "kanban").
34
+ *
35
+ * Treat it as frozen once shipped: users have it persisted in their saved
36
+ * collection config and in bookmarked URLs.
37
+ */
38
+ key: string;
39
+
40
+ /** Label shown in the view switcher. */
41
+ name: string;
42
+
43
+ /**
44
+ * Icon shown beside the name, as a `lucide-react` icon name (e.g. `"Map"`)
45
+ * or a rendered node. A name is what the collection editor can store.
46
+ */
47
+ icon?: string | React.ReactNode;
48
+
49
+ /**
50
+ * The component that renders the rows.
51
+ */
52
+ Builder: ComponentRef<CollectionCustomViewParams<M>>;
53
+
54
+ /**
55
+ * How clicking a record should present it, overriding what
56
+ * `resolveOpenEntityMode` would otherwise derive from the view mode.
57
+ * Defaults to `"side_panel"`, which is what the board uses: a custom view
58
+ * usually owns its whole surface and should keep it.
59
+ */
60
+ openEntityMode?: "side_panel" | "full_screen" | "split" | "dialog";
61
+
62
+ /**
63
+ * Whether the size selector applies to this view. Off by default — most
64
+ * custom views have no notion of row height.
65
+ */
66
+ sizeable?: boolean;
67
+ };
68
+
69
+ /**
70
+ * What a {@link CollectionCustomView}'s `Builder` receives.
71
+ *
72
+ * This is the same set the built-in view bindings are given, so a custom view
73
+ * starts from parity with them.
74
+ *
75
+ * @group Models
76
+ */
77
+ export interface CollectionCustomViewParams<M extends Record<string, unknown> = Record<string, unknown>> {
78
+ /** The collection being rendered, fully resolved. */
79
+ collection: AdminCollection<M>;
80
+
81
+ /**
82
+ * The live query: rows, loading state, pagination, and the filter / sort /
83
+ * search state shared with the toolbar. Read rows from here rather than
84
+ * fetching — that is what keeps the toolbar honest.
85
+ */
86
+ tableController: EntityTableController<M>;
87
+
88
+ /** Full path of the collection, e.g. `users/1234/addresses`. */
89
+ path: string;
90
+
91
+ /** Parent path segments, when this is a subcollection. */
92
+ parentCollectionSlugs?: string[];
93
+ parentEntityIds?: string[];
94
+
95
+ /**
96
+ * Open a record. Routes through the collection's resolved
97
+ * `openEntityMode`, so the side panel, split view and full-screen form all
98
+ * work without the view knowing which one it got.
99
+ */
100
+ onEntityClick?: (entity: Entity<M>) => void;
101
+
102
+ /** Create a record. Undefined when the user may not create. */
103
+ onNewClick?: () => void;
104
+
105
+ /** Whether the current user may create records in this collection. */
106
+ canCreate?: boolean;
107
+
108
+ selectionController?: SelectionController<M>;
109
+ selectionEnabled?: boolean;
110
+
111
+ /** Records to draw as highlighted, e.g. the one open in the side panel. */
112
+ highlightedEntities?: Entity<M>[];
113
+
114
+ /** Records deleted in this session, for optimistic removal. */
115
+ deletedEntities?: Entity<M>[];
116
+
117
+ /** The shared empty state, so a custom view matches the built-ins. */
118
+ emptyComponent?: React.ReactNode;
119
+
120
+ /** Set when the view declared `sizeable`. */
121
+ size?: CollectionSize;
122
+
123
+ /** The mode this view was resolved to, for views that render several. */
124
+ viewMode?: ViewMode;
125
+ }
@@ -0,0 +1,244 @@
1
+ import type React from "react";
2
+ import type { Property } from "@rebasepro/types";
3
+ import type { WhereFilterOp } from "@rebasepro/types";
4
+
5
+ // ── Scoped component name unions ──────────────────────────────────────
6
+
7
+ /**
8
+ * Components that can only be overridden at the **app level** via the
9
+ * `components` prop on `<Rebase>`.
10
+ *
11
+ * These are shell-level / global components that exist outside of any
12
+ * specific collection context.
13
+ *
14
+ * @group Component Overrides
15
+ */
16
+ export type AppComponentName =
17
+ // ── Shell / Layout ──
18
+ | "Shell.AppBar"
19
+ | "Shell.Drawer"
20
+ | "Shell.DrawerNavigationItem"
21
+ | "Shell.DrawerNavigationGroup"
22
+
23
+ // ── Home Page ──
24
+ | "HomePage"
25
+ | "HomePage.CollectionCard"
26
+
27
+ // ── Auth ──
28
+ | "Auth.LoginView";
29
+
30
+ /**
31
+ * Components that can be overridden at the **collection level**
32
+ * (on an individual collection definition) or at the **app level**
33
+ * (as a default for all collections).
34
+ *
35
+ * When set at the app level, these act as defaults. When set on a
36
+ * specific collection, they override the app-level default for that
37
+ * collection only.
38
+ *
39
+ * @group Component Overrides
40
+ */
41
+ export type CollectionComponentName =
42
+ // ── Collection View ──
43
+ | "Collection.View"
44
+ | "Collection.Table"
45
+ | "Collection.Card"
46
+ | "Collection.EmptyState"
47
+ | "Collection.Actions"
48
+ | "Collection.FilterField"
49
+
50
+ // ── Entity / Form ──
51
+ | "Entity.Form"
52
+ | "EditView.FormActions"
53
+ | "DetailView"
54
+ | "Entity.SidePanel"
55
+ | "EntityPreview"
56
+ | "Entity.MissingReference";
57
+
58
+ /**
59
+ * All overridable component names across all scopes.
60
+ * @group Component Overrides
61
+ */
62
+ export type OverridableComponentName = AppComponentName | CollectionComponentName;
63
+
64
+ /**
65
+ * Props received by a filter field component — whether it is a built-in
66
+ * per-type field, a property-level replacement (`property.ui.Filter`), or a
67
+ * `"Collection.FilterField"` override.
68
+ *
69
+ * The `operators` list is **already resolved**: it is the intersection of the
70
+ * engine's {@link DataSourceCapabilities.filterOperators}, the property-type
71
+ * defaults, and any `property.ui.filterOperators` narrowing. A custom field
72
+ * should only offer operators from this list — anything else may throw at
73
+ * query time on engines that cannot execute it.
74
+ *
75
+ * @example
76
+ * ```tsx
77
+ * function MyStatusFilter({ value, setValue, operators }: FilterFieldBindingProps) {
78
+ * return (
79
+ * <select
80
+ * value={value?.[1] as string ?? ""}
81
+ * onChange={e => setValue(e.target.value ? ["==", e.target.value] : undefined)}>
82
+ * <option value="">Any</option>
83
+ * <option value="active">Active</option>
84
+ * <option value="archived">Archived</option>
85
+ * </select>
86
+ * );
87
+ * }
88
+ * ```
89
+ *
90
+ * @group Component Overrides
91
+ */
92
+ export interface FilterFieldBindingProps {
93
+ /** Key of the property being filtered (the column id). */
94
+ propertyKey: string;
95
+
96
+ /**
97
+ * The resolved property. For array properties this is the **item**
98
+ * property (`property.of`), with `isArray` set to true.
99
+ */
100
+ property: Property;
101
+
102
+ /** True when the underlying property is an array of `property`. */
103
+ isArray: boolean;
104
+
105
+ /**
106
+ * Operators this field may offer, already narrowed by engine
107
+ * capabilities, property-type defaults, and `property.ui.filterOperators`.
108
+ */
109
+ operators: readonly WhereFilterOp[];
110
+
111
+ /** Current filter condition for this property, if any. */
112
+ value?: [WhereFilterOp, unknown];
113
+
114
+ /** Set (or clear, with `undefined`) the filter condition. */
115
+ setValue: (value?: [WhereFilterOp, unknown]) => void;
116
+
117
+ /** Display title for the field (usually the property name). */
118
+ title?: string;
119
+
120
+ /**
121
+ * Coordination flags used by fields that open their own dialogs
122
+ * (e.g. the reference picker hides the parent filters dialog).
123
+ */
124
+ hidden?: boolean;
125
+ setHidden?: (hidden: boolean) => void;
126
+ }
127
+
128
+ // ── Override entry ────────────────────────────────────────────────────
129
+
130
+ /**
131
+ * A single component override entry.
132
+ *
133
+ * - **Eject mode** (default): Your component fully replaces the built-in one.
134
+ * It receives the same props as the original.
135
+ *
136
+ * - **Wrap mode** (`wrap: true`): Your component wraps the original. The
137
+ * built-in component is passed as `OriginalComponent` in props, so you can
138
+ * render it inside your custom layout/logic.
139
+ *
140
+ * @example
141
+ * ```tsx
142
+ * // Eject — full replacement
143
+ * { Component: MyCustomAppBar }
144
+ *
145
+ * // Wrap — augment the original
146
+ * {
147
+ * Component: ({ OriginalComponent, ...props }) => (
148
+ * <div>
149
+ * <MyBanner />
150
+ * <OriginalComponent {...props} />
151
+ * </div>
152
+ * ),
153
+ * wrap: true
154
+ * }
155
+ * ```
156
+ *
157
+ * @group Component Overrides
158
+ */
159
+ export interface ComponentOverride<P = Record<string, unknown>> {
160
+ /**
161
+ * The replacement component. Receives the same props as the built-in
162
+ * component it replaces.
163
+ *
164
+ * When `wrap` is true, an additional `OriginalComponent` prop is injected
165
+ * containing the default component, allowing you to render it within
166
+ * your custom wrapper.
167
+ */
168
+ Component: React.ComponentType<P>;
169
+
170
+ /**
171
+ * When true, the original default component is injected as the
172
+ * `OriginalComponent` prop into your Component, enabling the
173
+ * wrapping pattern (similar to Docusaurus's `--wrap` swizzle mode).
174
+ *
175
+ * When false or omitted, your component fully replaces the default
176
+ * (similar to Docusaurus's `--eject` swizzle mode).
177
+ *
178
+ * @default false
179
+ */
180
+ wrap?: boolean;
181
+ }
182
+
183
+ // ── Override maps by scope ────────────────────────────────────────────
184
+
185
+ /**
186
+ * Collection-scoped overrides. Only collection-level components
187
+ * can be overridden here.
188
+ *
189
+ * Set on a collection's `components` field to customize
190
+ * components for that specific collection.
191
+ *
192
+ * @example
193
+ * ```tsx
194
+ * const productsCollection = {
195
+ * name: "Products",
196
+ * slug: "products",
197
+ * components: {
198
+ * "Entity.Form": { Component: ProductForm },
199
+ * "Collection.EmptyState": { Component: ProductsEmptyState },
200
+ * "Collection.Card": { Component: ProductCard },
201
+ * }
202
+ * };
203
+ * ```
204
+ *
205
+ * @group Component Overrides
206
+ */
207
+ export type CollectionComponentOverrideMap = {
208
+ [K in CollectionComponentName]?: ComponentOverride;
209
+ };
210
+
211
+ /**
212
+ * App-level overrides. Includes both app-only components (Shell, HomePage, Auth)
213
+ * and collection-level components (as defaults for all collections).
214
+ *
215
+ * Pass this to the `components` prop on `<Rebase>`.
216
+ *
217
+ * Collection-level components set here act as **defaults** — they apply to all
218
+ * collections unless a specific collection overrides them in its own
219
+ * `components`.
220
+ *
221
+ * @example
222
+ * ```tsx
223
+ * <Rebase
224
+ * client={client}
225
+ * components={{
226
+ * // App-level: only available here
227
+ * "Shell.AppBar": { Component: MyAppBar },
228
+ * "HomePage": { Component: MyDashboard },
229
+ *
230
+ * // Collection defaults: apply to ALL collections
231
+ * "EditView.FormActions": {
232
+ * Component: MyFormActions,
233
+ * wrap: true
234
+ * },
235
+ * "Collection.EmptyState": { Component: MyEmptyState },
236
+ * }}
237
+ * />
238
+ * ```
239
+ *
240
+ * @group Component Overrides
241
+ */
242
+ export type ComponentOverrideMap = {
243
+ [K in OverridableComponentName]?: ComponentOverride;
244
+ };
@@ -0,0 +1,134 @@
1
+ import React from "react";
2
+ import type { Entity } from "@rebasepro/types";
3
+
4
+ import type { SelectionController } from "../collections";
5
+ import type { FormContext } from "./entity_views";
6
+ import type { User } from "@rebasepro/types";
7
+ import type { RebaseContext } from "../rebase_context";
8
+ import type { SidePanelController } from "../controllers/side_panel_controller";
9
+ import type { AdminCollection } from "@rebasepro/cms-types";
10
+
11
+ /**
12
+ * A entity action is a custom action that can be performed on a entity.
13
+ * They are displayed in the entity view and in the collection view.
14
+ */
15
+ export interface EntityAction<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {
16
+ /**
17
+ * Title of the action
18
+ */
19
+ name: string;
20
+
21
+ /**
22
+ * Key of the action. You only need to provide this if you want to
23
+ * override the default actions, or if you are not passing the action
24
+ * directly to the `entityActions` prop of a collection.
25
+ * You can define your actions at the app level, in which case you
26
+ * must provide a key.
27
+ * The default actions are:
28
+ * - edit
29
+ * - delete
30
+ * - copy
31
+ */
32
+ key?: string;
33
+
34
+ /**
35
+ * Icon of the action: a Lucide icon name (`"FileBarChart"`) or an element.
36
+ *
37
+ * The name form is what lets a collection declare one from the config package,
38
+ * which is plain `.ts` with no React dependency — an element would drag the
39
+ * whole UI layer into a backend that only loads the collection for its schema.
40
+ * It also matches how every other icon in a collection is written
41
+ * (`admin.icon`, `entityViews[].icon`), which were already strings while this
42
+ * one alone was not.
43
+ */
44
+ icon?: React.ReactElement | string;
45
+
46
+ /**
47
+ * Callback when the action is clicked
48
+ * @param props
49
+ */
50
+ onClick(props: EntityActionClickProps<M, USER>): Promise<void> | void;
51
+
52
+ /**
53
+ * Optional callback in case you want to disable the action
54
+ * @param props
55
+ */
56
+ isEnabled?(props: EntityActionClickProps<M, USER>): boolean;
57
+
58
+ /**
59
+ * When true, this action is rendered inline on each row in the list view.
60
+ * By default, entity actions only appear in the table view and entity form.
61
+ * Use this for actions that should be easily accessible regardless of view mode.
62
+ */
63
+ showActionsInListView?: boolean;
64
+
65
+ /**
66
+ * Show this action collapsed in the menu of the collection view.
67
+ * Defaults to true
68
+ * If false, the action will be shown in the menu
69
+ */
70
+ collapsed?: boolean;
71
+
72
+ /**
73
+ * Show this action in the form, defaults to true
74
+ */
75
+ includeInForm?: boolean;
76
+
77
+ }
78
+
79
+ export type EntityActionClickProps<M extends Record<string, unknown>, USER extends User = User> = {
80
+ entity?: Entity<M>;
81
+ context?: RebaseContext<USER>;
82
+
83
+ path?: string;
84
+ collection?: AdminCollection<M>;
85
+
86
+ /**
87
+ * Optional form context, present if the action is being called from a form.
88
+ * This allows you to access the form state and methods, including modifying the form values.
89
+ */
90
+ formContext?: FormContext;
91
+
92
+ /**
93
+ * Present if this actions is being called from a side dialog only
94
+ */
95
+ sidePanelController?: SidePanelController;
96
+
97
+ /**
98
+ * Is the action being called from the collection view or from the entity form view?
99
+ */
100
+ view: "collection" | "form";
101
+
102
+ /**
103
+ * If the action is rendered in the form, is it open in a side panel or full screen?
104
+ */
105
+ openEntityMode?: "side_panel" | "full_screen" | "split" | "dialog";
106
+
107
+ /**
108
+ * Optional selection controller, present if the action is being called from a collection view
109
+ */
110
+ selectionController?: SelectionController;
111
+
112
+ /**
113
+ * Optional highlight function to highlight the entity in the collection view
114
+ * @param entity
115
+ */
116
+ highlightEntity?: (entity: Entity<Record<string, unknown>>) => void;
117
+
118
+ /**
119
+ * Optional unhighlight function to remove the highlight from the entity in the collection view
120
+ * @param entity
121
+ */
122
+ unhighlightEntity?: (entity: Entity<Record<string, unknown>>) => void;
123
+
124
+ /**
125
+ * Optional function to navigate back (e.g. when deleting a entity or navigating from a form)
126
+ */
127
+ navigateBack?: () => void;
128
+
129
+ /**
130
+ * Callback to be called when the collection changes, e.g. after a entity is deleted or created.
131
+ */
132
+ onCollectionChange?: () => void;
133
+
134
+ };