@rebasepro/admin 0.16.0 → 0.16.1-canary.g2d1aec8

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 (167) hide show
  1. package/dist/{CollectionEditorDialog-D2Vf4C3-.js → CollectionEditorDialog-Cec5jU6R.js} +7 -3
  2. package/dist/{CollectionEditorDialog-D2Vf4C3-.js.map → CollectionEditorDialog-Cec5jU6R.js.map} +1 -1
  3. package/dist/{PropertyEditView-D3NBsK9_.js → PropertyEditView-BuSPZwnQ.js} +2 -2
  4. package/dist/{PropertyEditView-D3NBsK9_.js.map → PropertyEditView-BuSPZwnQ.js.map} +1 -1
  5. package/dist/{RouterCollectionsStudioView-hPB54l3Q.js → RouterCollectionsStudioView-BiNFpEii.js} +4 -4
  6. package/dist/{RouterCollectionsStudioView-hPB54l3Q.js.map → RouterCollectionsStudioView-BiNFpEii.js.map} +1 -1
  7. package/dist/SchemaChangeDialog-WKIbzS6P.js +327 -0
  8. package/dist/SchemaChangeDialog-WKIbzS6P.js.map +1 -0
  9. package/dist/collection_editor/ConfigControllerProvider.d.ts +4 -4
  10. package/dist/collection_editor/_cms_internals.d.ts +23 -23
  11. package/dist/collection_editor/api/index.d.ts +1 -1
  12. package/dist/collection_editor/extensibility_types.d.ts +1 -1
  13. package/dist/collection_editor/index.d.ts +21 -21
  14. package/dist/collection_editor/liveSchemaClient.d.ts +170 -0
  15. package/dist/collection_editor/serializable_utils.d.ts +1 -1
  16. package/dist/collection_editor/types/collection_editor_controller.d.ts +1 -1
  17. package/dist/collection_editor/types/config_controller.d.ts +11 -0
  18. package/dist/collection_editor/ui/collection_editor/AICollectionGeneratorPopover.d.ts +1 -1
  19. package/dist/collection_editor/ui/collection_editor/AIModifiedPathsContext.d.ts +1 -1
  20. package/dist/collection_editor/ui/collection_editor/CollectionEditorDialog.d.ts +4 -4
  21. package/dist/collection_editor/ui/collection_editor/CollectionEditorWelcomeView.d.ts +1 -1
  22. package/dist/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +2 -2
  23. package/dist/collection_editor/ui/collection_editor/CollectionStudioView.d.ts +1 -1
  24. package/dist/collection_editor/ui/collection_editor/CollectionsStudioView.d.ts +2 -2
  25. package/dist/collection_editor/ui/collection_editor/GeneralSettingsForm.d.ts +1 -1
  26. package/dist/collection_editor/ui/collection_editor/PropertyEditView.d.ts +2 -2
  27. package/dist/collection_editor/ui/collection_editor/RouterCollectionStudioView.d.ts +1 -1
  28. package/dist/collection_editor/ui/collection_editor/RouterCollectionsStudioView.d.ts +1 -1
  29. package/dist/collection_editor/ui/collection_editor/SchemaChangeDialog.d.ts +66 -0
  30. package/dist/collection_editor/ui/collection_editor/SubcollectionsEditTab.d.ts +2 -2
  31. package/dist/collection_editor/ui/collection_editor/import/CollectionEditorImportDataPreview.d.ts +1 -1
  32. package/dist/collection_editor/ui/collection_editor/import/CollectionEditorImportMapping.d.ts +1 -1
  33. package/dist/collection_editor/ui/collection_editor/import/clean_import_data.d.ts +1 -1
  34. package/dist/collection_editor/ui/collection_editor/properties/conditions/index.d.ts +6 -6
  35. package/dist/collection_editor/useCollectionEditorController.d.ts +1 -1
  36. package/dist/collection_editor/useCollectionsConfigController.d.ts +1 -1
  37. package/dist/collection_editor/useJsonCollectionsConfigController.d.ts +2 -2
  38. package/dist/collection_editor/useLiveSchemaEditing.d.ts +71 -0
  39. package/dist/collection_editor/useLocalCollectionsConfigController.d.ts +1 -1
  40. package/dist/collection_editor_ui.d.ts +12 -12
  41. package/dist/collection_editor_ui.js +4 -4
  42. package/dist/components/CollectionTableBinding/CollectionTableBinding.d.ts +1 -1
  43. package/dist/components/CollectionTableBinding/PropertyTableCell.d.ts +1 -1
  44. package/dist/components/CollectionTableBinding/fields/TableStorageUpload.d.ts +1 -1
  45. package/dist/components/CollectionTableBinding/index.d.ts +5 -5
  46. package/dist/components/CollectionTableBinding/internal/popup_field/PopupFormField.d.ts +1 -1
  47. package/dist/components/CollectionViewBinding/SlotValue.d.ts +2 -2
  48. package/dist/components/CollectionViewBinding/hooks/useKanbanDragAndDrop.d.ts +1 -1
  49. package/dist/components/EditFormActions.d.ts +1 -1
  50. package/dist/components/EditViewBinding.d.ts +3 -3
  51. package/dist/components/EntityInspector.d.ts +1 -1
  52. package/dist/components/EntityPreviewBinding.d.ts +1 -1
  53. package/dist/components/EntityViewBinding.d.ts +1 -1
  54. package/dist/components/HomePage/index.d.ts +4 -4
  55. package/dist/components/PropertyCollectionView.d.ts +1 -1
  56. package/dist/components/ReferenceWidget.d.ts +1 -1
  57. package/dist/components/admin/index.d.ts +1 -1
  58. package/dist/components/app/AppBar.d.ts +1 -1
  59. package/dist/components/app/index.d.ts +4 -4
  60. package/dist/components/common/index.d.ts +1 -1
  61. package/dist/components/field_configs.d.ts +1 -1
  62. package/dist/components/history/EntityHistoryEntry.d.ts +2 -2
  63. package/dist/components/history/index.d.ts +5 -5
  64. package/dist/components/index.d.ts +45 -45
  65. package/dist/data_export/export/index.d.ts +4 -4
  66. package/dist/data_export/index.d.ts +1 -1
  67. package/dist/data_import/components/DataNewPropertiesMapping.d.ts +1 -1
  68. package/dist/data_import/components/ImportSaveInProgress.d.ts +1 -1
  69. package/dist/data_import/components/index.d.ts +4 -4
  70. package/dist/data_import/hooks/index.d.ts +1 -1
  71. package/dist/data_import/hooks/useImportConfig.d.ts +1 -1
  72. package/dist/data_import/import/ImportCollectionAction.d.ts +1 -1
  73. package/dist/data_import/import/index.d.ts +1 -1
  74. package/dist/data_import/index.d.ts +5 -5
  75. package/dist/data_import/types/index.d.ts +1 -1
  76. package/dist/data_import/utils/file_to_json.d.ts +1 -1
  77. package/dist/data_import/utils/index.d.ts +5 -5
  78. package/dist/editor/components/SlashCommandMenu.d.ts +2 -2
  79. package/dist/editor/components/index.d.ts +5 -5
  80. package/dist/editor/editor.d.ts +2 -2
  81. package/dist/editor/index.d.ts +2 -2
  82. package/dist/editor/nodeViews/ImageComponent.d.ts +1 -1
  83. package/dist/editor/nodeViews/TaskItemComponent.d.ts +1 -1
  84. package/dist/editor/types.d.ts +1 -1
  85. package/dist/{export-oauWlxuu.js → export-BItpoIu0.js} +2 -2
  86. package/dist/{export-oauWlxuu.js.map → export-BItpoIu0.js.map} +1 -1
  87. package/dist/form/EntityForm.d.ts +1 -1
  88. package/dist/form/EntityFormActions.d.ts +1 -1
  89. package/dist/form/EntityFormBinding.d.ts +1 -1
  90. package/dist/form/PropertyFieldBinding.d.ts +1 -1
  91. package/dist/form/components/StorageItemPreview.d.ts +1 -1
  92. package/dist/form/components/index.d.ts +6 -6
  93. package/dist/form/field_bindings/ArrayCustomShapedFieldBinding.d.ts +1 -1
  94. package/dist/form/field_bindings/ArrayOfReferencesFieldBinding.d.ts +1 -1
  95. package/dist/form/field_bindings/BinaryFieldBinding.d.ts +1 -1
  96. package/dist/form/field_bindings/BlockFieldBinding.d.ts +1 -1
  97. package/dist/form/field_bindings/DateTimeFieldBinding.d.ts +1 -1
  98. package/dist/form/field_bindings/GeopointFieldBinding.d.ts +1 -1
  99. package/dist/form/field_bindings/KeyValueFieldBinding.d.ts +1 -1
  100. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  101. package/dist/form/field_bindings/MarkdownEditorFieldBinding.d.ts +2 -2
  102. package/dist/form/field_bindings/MultiSelectFieldBinding.d.ts +1 -1
  103. package/dist/form/field_bindings/MultipleRelationFieldBinding.d.ts +1 -1
  104. package/dist/form/field_bindings/ReadOnlyFieldBinding.d.ts +1 -1
  105. package/dist/form/field_bindings/ReferenceFieldBinding.d.ts +1 -1
  106. package/dist/form/field_bindings/RelationFieldBinding.d.ts +1 -1
  107. package/dist/form/field_bindings/RepeatFieldBinding.d.ts +1 -1
  108. package/dist/form/field_bindings/SelectFieldBinding.d.ts +1 -1
  109. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +1 -1
  110. package/dist/form/field_bindings/SwitchFieldBinding.d.ts +1 -1
  111. package/dist/form/field_bindings/TextFieldBinding.d.ts +1 -1
  112. package/dist/form/field_bindings/UserSelectFieldBinding.d.ts +1 -1
  113. package/dist/form/field_bindings/VectorFieldBinding.d.ts +1 -1
  114. package/dist/form/index.d.ts +24 -24
  115. package/dist/{history-C2cqc0bw.js → history-C7WF14VR.js} +2 -2
  116. package/dist/{history-C2cqc0bw.js.map → history-C7WF14VR.js.map} +1 -1
  117. package/dist/hooks/index.d.ts +16 -16
  118. package/dist/hooks/navigation/contexts/index.d.ts +3 -3
  119. package/dist/hooks/useBuildSideDialogsController.d.ts +1 -1
  120. package/dist/hooks/useSelectionDialog.d.ts +1 -1
  121. package/dist/{import-Bxv5JPm-.js → import-CZgNAlcd.js} +2 -2
  122. package/dist/{import-Bxv5JPm-.js.map → import-CZgNAlcd.js.map} +1 -1
  123. package/dist/index.d.ts +17 -15
  124. package/dist/index.js +238 -21
  125. package/dist/index.js.map +1 -1
  126. package/dist/preview/PropertyPreview.d.ts +1 -1
  127. package/dist/preview/components/ArrayEnumPreview.d.ts +1 -1
  128. package/dist/preview/components/BooleanPreview.d.ts +1 -1
  129. package/dist/preview/components/ImagePreview.d.ts +1 -1
  130. package/dist/preview/components/ReferencePreview.d.ts +1 -1
  131. package/dist/preview/components/RelationPreview.d.ts +1 -1
  132. package/dist/preview/components/StorageThumbnail.d.ts +1 -1
  133. package/dist/preview/components/UrlComponentPreview.d.ts +2 -2
  134. package/dist/preview/components/UserPreview.d.ts +1 -1
  135. package/dist/preview/index.d.ts +24 -24
  136. package/dist/preview/property_previews/ArrayOfMapsPreview.d.ts +1 -1
  137. package/dist/preview/property_previews/ArrayOfReferencesPreview.d.ts +1 -1
  138. package/dist/preview/property_previews/ArrayOfRelationsPreview.d.ts +1 -1
  139. package/dist/preview/property_previews/ArrayOfStorageComponentsPreview.d.ts +1 -1
  140. package/dist/preview/property_previews/ArrayOfStringsPreview.d.ts +1 -1
  141. package/dist/preview/property_previews/ArrayOneOfPreview.d.ts +1 -1
  142. package/dist/preview/property_previews/ArrayPropertyEnumPreview.d.ts +1 -1
  143. package/dist/preview/property_previews/ArrayPropertyPreview.d.ts +1 -1
  144. package/dist/preview/property_previews/MapPropertyPreview.d.ts +1 -1
  145. package/dist/preview/property_previews/NumberPropertyPreview.d.ts +1 -1
  146. package/dist/preview/property_previews/SkeletonPropertyComponent.d.ts +1 -1
  147. package/dist/preview/property_previews/StringPropertyPreview.d.ts +1 -1
  148. package/dist/preview/util.d.ts +1 -1
  149. package/dist/routes/index.d.ts +2 -2
  150. package/dist/types/components/EntityFormActionsProps.d.ts +2 -2
  151. package/dist/types/components/EntityFormProps.d.ts +3 -3
  152. package/dist/types/components/index.d.ts +3 -3
  153. package/dist/types/fields.d.ts +1 -1
  154. package/dist/types/index.d.ts +2 -2
  155. package/dist/util/index.d.ts +5 -5
  156. package/dist/{util-C4qsI1QV.js → util-wrBH4QSB.js} +130 -7
  157. package/dist/util-wrBH4QSB.js.map +1 -0
  158. package/package.json +10 -10
  159. package/src/collection_editor/ConfigControllerProvider.tsx +5 -0
  160. package/src/collection_editor/liveSchemaClient.ts +272 -0
  161. package/src/collection_editor/types/config_controller.tsx +11 -0
  162. package/src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx +10 -0
  163. package/src/collection_editor/ui/collection_editor/SchemaChangeDialog.tsx +368 -0
  164. package/src/collection_editor/useLiveSchemaEditing.tsx +285 -0
  165. package/src/collection_editor/useLocalCollectionsConfigController.tsx +109 -10
  166. package/src/index.ts +6 -0
  167. package/dist/util-C4qsI1QV.js.map +0 -1
@@ -5,6 +5,7 @@ import { getSubcollections } from "@rebasepro/common";
5
5
  import React, { useEffect, useMemo, useRef, useState } from "react";
6
6
  import type { AdminCollection } from "@rebasepro/admin-types";
7
7
  import { DEFAULT_API_PATH } from "@rebasepro/app";
8
+ import { useLiveSchemaEditing } from "./useLiveSchemaEditing";
8
9
 
9
10
  /**
10
11
  * What the backend said about its schema editor, and how sure we are.
@@ -172,6 +173,47 @@ export function useLocalCollectionsConfigController(
172
173
  // eslint-disable-next-line react-hooks/exhaustive-deps
173
174
  }, [editorUrl, forcedReadOnly, authKey]);
174
175
 
176
+ // ── Live schema editing ───────────────────────────────────────────
177
+ // The same edit, against a backend that can also change the database and
178
+ // commit the result. When it is available, a save is planned and shown
179
+ // before anything happens; when it is not, this is inert and writes go
180
+ // straight to the source-only editor exactly as before.
181
+ const liveSchema = useLiveSchemaEditing({
182
+ baseUrl: `${String(clientBaseUrl).replace(/\/$/, "")}${clientApiPath}/admin/schema`,
183
+ getAuthToken: resolveToken,
184
+ authKey,
185
+ // The fallback the dialog offers when a change cannot be applied —
186
+ // removing a property, most often, which the ensure path has no way to
187
+ // carry out. Writing the source and leaving the database alone is what
188
+ // the editor did before any of this existed.
189
+ writeSourceOnly: async ({ collectionId, collection }) => {
190
+ await request("/collection/save", { collectionId, collectionData: collection });
191
+ }
192
+ });
193
+
194
+ /**
195
+ * Perform a write, through the live editor when there is one.
196
+ *
197
+ * `sourceOnly` is the write this controller has always done. It stays the
198
+ * whole behaviour on a backend that cannot edit its schema — a bundle
199
+ * deployment, a non-Postgres driver, a version too old to be asked — so
200
+ * nothing about the editor depends on the feature being there.
201
+ */
202
+ const write = async (
203
+ collectionId: string,
204
+ collection: Record<string, unknown>,
205
+ sourceOnly: () => Promise<void>
206
+ ): Promise<void> => {
207
+ // `ready()`, not `status` — the rendered status is undefined for one
208
+ // round trip after mount, so reading it here would send a save issued
209
+ // in that window down the source-only path with no confirmation, while
210
+ // the same save a second later would open a dialog. One round trip is
211
+ // cheap; behaviour that depends on how fast somebody clicked is not.
212
+ const available = await liveSchema.ready();
213
+ if (!available.enabled) return sourceOnly();
214
+ await liveSchema.reviewChange({ collectionId, collection });
215
+ };
216
+
175
217
  const readOnly = forcedReadOnly
176
218
  ?? (availability.state === "known" ? !availability.enabled : buildModeGuess());
177
219
 
@@ -179,24 +221,42 @@ export function useLocalCollectionsConfigController(
179
221
  ? availability.reason
180
222
  : "Collections can only be edited against a backend running the schema editor, which is off in production.";
181
223
 
224
+ const findCollection = (id: string): AdminCollection | undefined =>
225
+ parsedCollections.find(c => (c as AdminCollection & { id?: string }).id === id || c.slug === id);
226
+
227
+ /**
228
+ * The whole collection as it should end up.
229
+ *
230
+ * Live editing computes the proposed state by replacing one collection in
231
+ * the set, so it needs all of it: handed a patch, it would read every
232
+ * property the patch does not mention as a removal and refuse the change.
233
+ * A collection this does not recognise is a new one, and the patch is the
234
+ * whole of it.
235
+ */
236
+ const wholeCollection = (id: string, patch: Record<string, unknown>): Record<string, unknown> => {
237
+ const current = findCollection(id) as Record<string, unknown> | undefined;
238
+ return current ? { ...current, ...patch } : patch;
239
+ };
240
+
182
241
  return useMemo(() => ({
183
242
  loading: false,
184
243
  readOnly,
185
244
  readOnlyReason,
186
245
  collections: parsedCollections,
246
+ dialog: liveSchema.dialog,
187
247
  getCollection: (id: string) => {
188
- const found = parsedCollections.find(c => (c as AdminCollection & { id?: string }).id === id || c.slug === id);
248
+ const found = findCollection(id);
189
249
  if (found) return found;
190
250
  throw Error(`Collection ${id} not found in local mode`);
191
251
  },
192
252
 
193
253
  saveCollection: async ({ id, collectionData }: SaveCollectionParams) => {
194
- await request("/collection/save", { collectionId: id,
195
- collectionData });
254
+ await write(id, collectionData as unknown as Record<string, unknown>, () =>
255
+ request("/collection/save", { collectionId: id, collectionData }));
196
256
  },
197
257
  updateCollection: async ({ id, collectionData }: UpdateCollectionParams) => {
198
- await request("/collection/save", { collectionId: id,
199
- collectionData });
258
+ await write(id, wholeCollection(id, collectionData as Record<string, unknown>), () =>
259
+ request("/collection/save", { collectionId: id, collectionData }));
200
260
  },
201
261
  deleteCollection: async ({ id }: DeleteCollectionParams) => {
202
262
  await request("/collection/delete", { collectionId: id });
@@ -207,14 +267,30 @@ collectionData });
207
267
  // mention — `securityRules` first, which then falls back to the
208
268
  // directory default and widens who can read the collection.
209
269
  saveProperty: async ({ path, propertyKey, property, newPropertiesOrder }: SavePropertyParams) => {
210
- await request("/property/save", { collectionId: path,
270
+ // Assembled into the whole collection before it is planned. This is
271
+ // the write that most often *is* a schema change — adding a field
272
+ // to a collection is adding a column — and the one whose payload
273
+ // says least about it on its own.
274
+ const current = findCollection(path) as Record<string, unknown> | undefined;
275
+ const properties = {
276
+ ...(current?.properties as Record<string, unknown> | undefined ?? {}),
277
+ [propertyKey]: property
278
+ };
279
+ const proposed = wholeCollection(path, {
280
+ properties,
281
+ ...(newPropertiesOrder ? { propertiesOrder: newPropertiesOrder } : {})
282
+ });
283
+
284
+ await write(path, proposed, async () => {
285
+ await request("/property/save", { collectionId: path,
211
286
  propertyKey,
212
287
  propertyConfig: property });
213
- if (newPropertiesOrder) {
214
- await request("/collection/save", { collectionId: path,
288
+ if (newPropertiesOrder) {
289
+ await request("/collection/save", { collectionId: path,
215
290
  collectionData: { propertiesOrder: newPropertiesOrder },
216
291
  partial: true });
217
- }
292
+ }
293
+ });
218
294
  },
219
295
  deleteProperty: async ({ path, propertyKey, newPropertiesOrder }: DeletePropertyParams) => {
220
296
  await request("/property/delete", { collectionId: path,
@@ -238,5 +314,28 @@ partial: true });
238
314
 
239
315
  navigationEntries: [],
240
316
  saveNavigationEntries: async () => { }
241
- }), [clientOrUrl, parsedCollections, readOnly, readOnlyReason, options?.getAuthToken]);
317
+ // `liveSchema.dialog` and `liveSchema.status` both change as the flow
318
+ // runs — a plan arrives, a dialog opens — and a controller memoised
319
+ // without them would keep handing back a closed dialog and a stale
320
+ // answer about whether the backend can edit its schema at all.
321
+ //
322
+ // `write`, `request`, `findCollection` and `wholeCollection` are
323
+ // rebuilt on every render, so listing them would defeat the memo
324
+ // entirely. Each is already covered *transitively* by what is listed:
325
+ // `request` closes over `editorUrl` and a ref, and `editorUrl` derives
326
+ // from `clientOrUrl`; `findCollection` and `wholeCollection` close over
327
+ // `parsedCollections`; `write` closes over `liveSchema.status` and
328
+ // `liveSchema.reviewChange`, and the latter is a `useCallback` keyed on
329
+ // a client built from `clientOrUrl`. Every input that can change is in
330
+ // the array under the name it actually varies with.
331
+ // eslint-disable-next-line react-hooks/exhaustive-deps
332
+ }), [
333
+ clientOrUrl,
334
+ parsedCollections,
335
+ readOnly,
336
+ readOnlyReason,
337
+ options?.getAuthToken,
338
+ liveSchema.dialog,
339
+ liveSchema.status
340
+ ]);
242
341
  }
package/src/index.ts CHANGED
@@ -112,6 +112,12 @@ export * from "./data_export";
112
112
 
113
113
  // Collection editor — moved from @rebasepro/studio (admin-dependent visual schema editor)
114
114
  export * from "./collection_editor";
115
+ export * from "./collection_editor/liveSchemaClient";
116
+ export * from "./collection_editor/useLiveSchemaEditing";
117
+ // `SchemaChangeDialog` is deliberately absent, like `CollectionEditorDialog`
118
+ // and `PropertyFormDialog` beside it: re-exporting it from the barrel puts it
119
+ // back in the eager bundle and undoes the `lazyChunk` in `useLiveSchemaEditing`.
120
+ // Import it by path if you need the component itself.
115
121
 
116
122
 
117
123
  export { CreationResultDialog } from "./components/admin/CreationResultDialog";