@rebasepro/admin 0.13.0 → 0.13.1-canary.g18cfeb7

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 (143) hide show
  1. package/dist/{CollectionEditorDialog-CjXkWZ64.js → CollectionEditorDialog-CUFXevVg.js} +3 -3
  2. package/dist/{CollectionEditorDialog-CjXkWZ64.js.map → CollectionEditorDialog-CUFXevVg.js.map} +1 -1
  3. package/dist/{PropertyEditView-W8I3YV89.js → PropertyEditView-DDUC7giL.js} +2 -2
  4. package/dist/{PropertyEditView-W8I3YV89.js.map → PropertyEditView-DDUC7giL.js.map} +1 -1
  5. package/dist/{RouterCollectionsStudioView-BsLTNoqX.js → RouterCollectionsStudioView-vzS848Gf.js} +9 -13
  6. package/dist/RouterCollectionsStudioView-vzS848Gf.js.map +1 -0
  7. package/dist/collection_editor/serializable_types.d.ts +1 -0
  8. package/dist/collection_editor_ui.js +4 -4
  9. package/dist/components/AdditionalFieldValue.d.ts +25 -0
  10. package/dist/components/CollectionViewBinding/CollectionViewBinding.d.ts +16 -0
  11. package/dist/components/CollectionViewBinding/SlotValue.d.ts +63 -0
  12. package/dist/components/CollectionViewBinding/SplitListCloseButton.d.ts +17 -4
  13. package/dist/components/CollectionViewBinding/SplitListShowButton.d.ts +12 -0
  14. package/dist/components/CollectionViewBinding/usePreviewSlots.d.ts +55 -5
  15. package/dist/components/DetailViewBinding.d.ts +15 -0
  16. package/dist/components/DrawerNavigationGroup.d.ts +9 -6
  17. package/dist/components/DrawerNavigationItem.d.ts +16 -6
  18. package/dist/components/EditViewBinding.d.ts +30 -1
  19. package/dist/components/EntityDisplayHeader.d.ts +53 -0
  20. package/dist/components/EntityIdentityBar.d.ts +43 -1
  21. package/dist/components/EntityViewBinding.d.ts +60 -6
  22. package/dist/components/RebaseLayout.d.ts +1 -1
  23. package/dist/components/RebaseShell.d.ts +1 -1
  24. package/dist/components/RelationSelector.d.ts +8 -1
  25. package/dist/components/UserSelector.d.ts +8 -1
  26. package/dist/components/app/Scaffold.d.ts +9 -3
  27. package/dist/components/index.d.ts +2 -0
  28. package/dist/{export-J79rMoNj.js → export-5bl2EoSs.js} +2 -2
  29. package/dist/{export-J79rMoNj.js.map → export-5bl2EoSs.js.map} +1 -1
  30. package/dist/form/components/FieldBlock.d.ts +58 -4
  31. package/dist/form/components/FormRail.d.ts +13 -0
  32. package/dist/form/components/FormSections.d.ts +15 -1
  33. package/dist/form/components/useRailVisible.d.ts +5 -4
  34. package/dist/form/form_utils.d.ts +38 -1
  35. package/dist/{history-D7L_JlLO.js → history-BuKKAhoY.js} +4 -4
  36. package/dist/{history-D7L_JlLO.js.map → history-BuKKAhoY.js.map} +1 -1
  37. package/dist/hooks/useEntityDisplay.d.ts +102 -0
  38. package/dist/hooks/useEntityDisplayTitle.d.ts +18 -9
  39. package/dist/{import-BvYl--U4.js → import-BhdWs34H.js} +3 -3
  40. package/dist/{import-BvYl--U4.js.map → import-BhdWs34H.js.map} +1 -1
  41. package/dist/index.d.ts +2 -2
  42. package/dist/index.js +152 -57
  43. package/dist/index.js.map +1 -1
  44. package/dist/preview/compact_text.d.ts +23 -0
  45. package/dist/preview/components/BooleanPreview.d.ts +3 -1
  46. package/dist/preview/property_previews/ArrayOfStringsPreview.d.ts +1 -1
  47. package/dist/preview/property_previews/ArrayOneOfPreview.d.ts +1 -1
  48. package/dist/preview/property_previews/ArrayPropertyPreview.d.ts +1 -1
  49. package/dist/preview/property_previews/MapPropertyPreview.d.ts +1 -1
  50. package/dist/preview/property_previews/StringPropertyPreview.d.ts +1 -1
  51. package/dist/routes/RebaseRoute.d.ts +1 -1
  52. package/dist/types/components/PropertyPreviewProps.d.ts +19 -0
  53. package/dist/util/number_format.d.ts +14 -0
  54. package/dist/util/previews.d.ts +9 -2
  55. package/dist/{util-GiwPgxnL.js → util-DNG7iK0w.js} +3756 -2300
  56. package/dist/util-DNG7iK0w.js.map +1 -0
  57. package/package.json +9 -9
  58. package/src/collection_editor/serializable_types.ts +1 -0
  59. package/src/collection_editor/ui/collection_editor/CollectionsStudioView.tsx +9 -11
  60. package/src/components/AdditionalFieldValue.tsx +68 -0
  61. package/src/components/CollectionTableBinding/CollectionTableBinding.tsx +7 -8
  62. package/src/components/CollectionTableBinding/PropertyTableCell.tsx +2 -2
  63. package/src/components/CollectionTableBinding/column_utils.tsx +15 -6
  64. package/src/components/CollectionTableBinding/internal/popup_field/PopupFormField.tsx +2 -2
  65. package/src/components/CollectionViewBinding/BoardCardBinding.tsx +26 -27
  66. package/src/components/CollectionViewBinding/CollectionListViewBinding.tsx +723 -348
  67. package/src/components/CollectionViewBinding/CollectionViewActions.tsx +1 -1
  68. package/src/components/CollectionViewBinding/CollectionViewBinding.tsx +38 -8
  69. package/src/components/CollectionViewBinding/EntityCardBinding.tsx +23 -36
  70. package/src/components/CollectionViewBinding/SlotValue.tsx +156 -0
  71. package/src/components/CollectionViewBinding/SplitListCloseButton.tsx +23 -7
  72. package/src/components/CollectionViewBinding/SplitListShowButton.tsx +28 -0
  73. package/src/components/CollectionViewBinding/SplitListView.tsx +33 -2
  74. package/src/components/CollectionViewBinding/useBoardDataController.tsx +12 -3
  75. package/src/components/CollectionViewBinding/usePreviewSlots.ts +183 -64
  76. package/src/components/CollectionViewBinding/utils.ts +7 -4
  77. package/src/components/DefaultDrawer.tsx +19 -23
  78. package/src/components/DetailViewBinding.tsx +93 -56
  79. package/src/components/DrawerNavigationGroup.tsx +16 -39
  80. package/src/components/DrawerNavigationItem.tsx +44 -16
  81. package/src/components/EditViewBinding.tsx +215 -42
  82. package/src/components/EntityDisplayHeader.tsx +170 -0
  83. package/src/components/EntityIdentityBar.tsx +163 -23
  84. package/src/components/EntityInspector.tsx +24 -6
  85. package/src/components/EntityPreviewBinding.tsx +58 -18
  86. package/src/components/EntityViewBinding.tsx +342 -41
  87. package/src/components/InlineEntityPreview.tsx +10 -10
  88. package/src/components/RebaseLayout.tsx +2 -2
  89. package/src/components/RebaseShell.tsx +2 -2
  90. package/src/components/ReferenceTable/SelectionTableBinding.tsx +4 -2
  91. package/src/components/RelationSelector.tsx +15 -4
  92. package/src/components/SideDialogs.tsx +15 -3
  93. package/src/components/SidePanelBinding.tsx +122 -66
  94. package/src/components/UserSelector.tsx +15 -4
  95. package/src/components/app/Scaffold.tsx +112 -10
  96. package/src/components/history/LastEditedByIndicator.tsx +7 -12
  97. package/src/components/index.ts +3 -0
  98. package/src/data_import/utils/data.ts +9 -1
  99. package/src/form/EntityForm.tsx +64 -52
  100. package/src/form/EntityFormBinding.tsx +24 -11
  101. package/src/form/PropertyFieldBinding.tsx +2 -2
  102. package/src/form/components/FieldBlock.tsx +80 -10
  103. package/src/form/components/FormRail.tsx +19 -2
  104. package/src/form/components/FormSections.tsx +32 -5
  105. package/src/form/components/StorageUploadProgress.tsx +9 -3
  106. package/src/form/components/useRailVisible.tsx +5 -4
  107. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +2 -2
  108. package/src/form/field_bindings/BinaryFieldBinding.tsx +10 -5
  109. package/src/form/field_bindings/BlockFieldBinding.tsx +3 -3
  110. package/src/form/field_bindings/GeopointFieldBinding.tsx +23 -16
  111. package/src/form/field_bindings/MapFieldBinding.tsx +2 -2
  112. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +13 -7
  113. package/src/form/field_bindings/MultiSelectFieldBinding.tsx +7 -1
  114. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +7 -1
  115. package/src/form/field_bindings/ReferenceFieldBinding.tsx +1 -1
  116. package/src/form/field_bindings/RelationFieldBinding.tsx +5 -2
  117. package/src/form/field_bindings/RepeatFieldBinding.tsx +3 -3
  118. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +2 -2
  119. package/src/form/field_bindings/UserSelectFieldBinding.tsx +4 -1
  120. package/src/form/field_bindings/VectorFieldBinding.tsx +6 -4
  121. package/src/form/form_utils.ts +78 -0
  122. package/src/hooks/navigation/useBuildCollectionRegistryController.tsx +29 -5
  123. package/src/hooks/useEntityDisplay.tsx +262 -0
  124. package/src/hooks/useEntityDisplayTitle.tsx +27 -38
  125. package/src/index.ts +9 -1
  126. package/src/preview/PropertyPreview.tsx +25 -5
  127. package/src/preview/compact_text.ts +68 -0
  128. package/src/preview/components/BooleanPreview.tsx +5 -2
  129. package/src/preview/components/StorageThumbnail.tsx +5 -2
  130. package/src/preview/property_previews/ArrayOfRelationsPreview.tsx +6 -3
  131. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +26 -1
  132. package/src/preview/property_previews/ArrayOneOfPreview.tsx +10 -1
  133. package/src/preview/property_previews/ArrayPropertyPreview.tsx +10 -1
  134. package/src/preview/property_previews/MapPropertyPreview.tsx +52 -1
  135. package/src/preview/property_previews/NumberPropertyPreview.tsx +9 -1
  136. package/src/preview/property_previews/StringPropertyPreview.tsx +8 -5
  137. package/src/routes/RebaseRoute.tsx +62 -4
  138. package/src/types/components/PropertyPreviewProps.tsx +21 -0
  139. package/src/util/number_format.ts +46 -0
  140. package/src/util/previews.ts +8 -55
  141. package/src/util/property_utils.tsx +6 -1
  142. package/dist/RouterCollectionsStudioView-BsLTNoqX.js.map +0 -1
  143. package/dist/util-GiwPgxnL.js.map +0 -1
@@ -4,6 +4,15 @@ import React from "react";
4
4
  export interface EntityIdentityBarProps {
5
5
  /** Plural collection name, shown as the breadcrumb ahead of the title. */
6
6
  collection: AdminCollection;
7
+ /**
8
+ * Where the breadcrumb points. Without it the collection name is inert text
9
+ * that still reads as a breadcrumb — worse than no breadcrumb at all, and
10
+ * the only way back once a layout drops its back arrow.
11
+ *
12
+ * Left unset by the overlays (side panel, dialog), where the collection is
13
+ * already underneath and navigating would dismiss the record instead.
14
+ */
15
+ collectionUrl?: string;
7
16
  /** Resolved record title, already guarded against showing a field default. */
8
17
  title: string;
9
18
  entityId?: string | number;
@@ -20,10 +29,43 @@ export interface EntityIdentityBarProps {
20
29
  * action is "done with this record" rather than "keep editing".
21
30
  */
22
31
  onSaveAndClose?: () => void;
32
+ /**
33
+ * Where {@link onSaveAndClose} is offered.
34
+ *
35
+ * `"button"` — its own filled button, and Save demotes to text. For the
36
+ * overlays, where you opened the record to do one thing to it and closing is
37
+ * the dominant intent.
38
+ *
39
+ * `"menu"` — a `▾` welded to the Save button. For the split, where the list
40
+ * is right there and `j`/`k` walk from record to record: there, saving and
41
+ * *staying* is the common case, so it keeps the filled button and dismissing
42
+ * is one step further in. The gesture still exists, so muscle memory carried
43
+ * over from the side panel finds it.
44
+ */
45
+ saveAndClosePlacement?: "button" | "menu";
46
+ /**
47
+ * Dismiss this record, from the ✕ at the bar's trailing edge.
48
+ *
49
+ * Fenced off from Save by a separator: it is chrome, not the last item in
50
+ * the action row. The panel that supplies it decides what dismissing means —
51
+ * in the split it is a navigation, which the layout's unsaved-changes
52
+ * blocker already guards, so the ✕ cannot drop an edit without asking.
53
+ */
54
+ onClose?: () => void;
23
55
  onBack?: () => void;
24
56
  onInspect?: () => void;
25
57
  /** Opens the inspector straight on its history tab. */
26
58
  onViewHistory?: () => void;
59
+ /**
60
+ * Where this record appears on the live site, from `entityLinkBuilder`.
61
+ *
62
+ * Here rather than above the record, where it used to be a single unlabelled
63
+ * icon alone on its own right-aligned row — the only thing between the bar
64
+ * and the first field, and the only control in the view that did not say
65
+ * what it was. It is a thing you do *to* a record, so it belongs with the
66
+ * others.
67
+ */
68
+ externalLink?: string;
27
69
  /**
28
70
  * Actions performed *on* the record — copy, delete, whatever the collection
29
71
  * adds — as menu items under the overflow button. They live here rather
@@ -50,4 +92,4 @@ export interface EntityIdentityBarProps {
50
92
  * editing. They live here instead, and the left half of a bar that was
51
93
  * previously empty now does the work.
52
94
  */
53
- export declare function EntityIdentityBar({ collection, title, entityId, status, dirty, saving, onSave, onDiscard, saveDisabled, hasErrors, onSaveAndClose, onBack, onInspect, onViewHistory, recordActions, pluginActions, trailing, leading }: EntityIdentityBarProps): React.JSX.Element;
95
+ export declare function EntityIdentityBar({ collection, collectionUrl, title, entityId, status, dirty, saving, onSave, onDiscard, saveDisabled, hasErrors, onSaveAndClose, saveAndClosePlacement, onClose, onBack, onInspect, onViewHistory, externalLink, recordActions, pluginActions, trailing, leading }: EntityIdentityBarProps): React.JSX.Element;
@@ -1,6 +1,30 @@
1
1
  import type { AdminCollection } from "@rebasepro/admin-types";
2
+ import type { FormContext } from "../types/fields";
2
3
  import React from "react";
3
4
  import { Entity } from "@rebasepro/types";
5
+ /**
6
+ * The fields the read-only view lays out, in render order.
7
+ *
8
+ * The same set the form uses, minus two groups. Both are dropped *before* the
9
+ * layout resolves rather than skipped while rendering, because the resolver has
10
+ * by then given each one a place on the grid — skipping later leaves that place
11
+ * as a hole.
12
+ *
13
+ * - The `additionalFields` when there is no form context to hand them: those
14
+ * entries are arbitrary components, not values, and one rendered against no
15
+ * context is nothing at all.
16
+ * - `headerKeys` — the properties {@link EntityDisplayHeader} has already
17
+ * rendered as the record's picture, subtitle, state and labels. Leaving one in
18
+ * prints its value twice on one screen.
19
+ *
20
+ * The record's **title property is not among them**, deliberately. It names the
21
+ * page in the identity bar, but a heading and a labelled field are different
22
+ * things: `Order #` is a column with a name and a description that someone opens
23
+ * the record to read, and dropping it because its text also appears in the
24
+ * breadcrumb removes a value from the record on the grounds that it is legible
25
+ * somewhere else. See {@link HEADER_DISPLAY_ROLES}.
26
+ */
27
+ export declare function readOnlyFieldKeys(collection: AdminCollection, hasFormContext: boolean, headerKeys?: ReadonlySet<string>): string[];
4
28
  /**
5
29
  * @group Components
6
30
  */
@@ -9,14 +33,44 @@ export interface EntityViewBindingProps<M extends Record<string, unknown>> {
9
33
  collection: AdminCollection<M>;
10
34
  path: string;
11
35
  className?: string;
36
+ /**
37
+ * Lay the record out as a page: a centred, scrolling column with the
38
+ * metadata rail beside it, exactly as the form does. Off for the inline
39
+ * uses — the delete dialog renders the record inside a box it already owns.
40
+ */
41
+ asPage?: boolean;
42
+ /** Padding preset, matching the form's. Only read when `asPage`. */
43
+ openEntityMode?: "side_panel" | "full_screen" | "split" | "dialog";
44
+ /**
45
+ * Needed only to render `additionalFields`, which are arbitrary components
46
+ * that take a form context. Without one those entries are left out rather
47
+ * than rendered against a fake context.
48
+ */
49
+ formContext?: FormContext<M>;
12
50
  }
13
51
  /**
14
52
  * The read-only rendering of a record's values.
15
53
  *
16
- * This used to prepend a synthetic `Id` row of its own. Between that row, the
17
- * collection's own id property, and the `path/id` chip above it, the same UUID
18
- * appeared three times and in the ~340px split pane each copy wrapped over
19
- * four lines, so most of the first screen was one id repeated. The id is now a
20
- * copyable chip in the identity bar, once.
54
+ * This is the same layout as {@link EntityForm}: the sections, the grid spans,
55
+ * the labels and the rail all come from the one resolver, so the record does
56
+ * not rearrange itself when you press Edit. Only the controls differ each
57
+ * field renders its {@link PropertyPreview} instead of an input.
58
+ *
59
+ * It used to be a flat two-column table of every value in the record: no
60
+ * grouping, no widths, a label column sized for short names and a value column
61
+ * that wrapped emails over two lines while the pane beside it stayed empty. A
62
+ * boolean and a markdown body were given the same room.
63
+ *
64
+ * The synthetic `Id` row it used to prepend is gone with the same reasoning the
65
+ * form applies: between that row, the collection's own id property and the
66
+ * `path/id` chip above them, one UUID appeared three times. The id is a
67
+ * copyable chip in the identity bar, and the rail's record block, once each.
68
+ *
69
+ * The labels are the form's labels, icon and all: a field is the same field
70
+ * whether or not you are editing it. What `mode: "read"` drops is the per-field
71
+ * *description*, which is input help rather than part of the label — and what it
72
+ * adds is room. A control is a bordered box that separates itself from the next
73
+ * one; a value is bare text, so the rows and sections are opened up rather than
74
+ * inheriting spacing sized for inputs.
21
75
  */
22
- export declare function EntityViewBinding<M extends Record<string, unknown>>({ entity, collection, path, className }: EntityViewBindingProps<M>): React.JSX.Element;
76
+ export declare function EntityViewBinding<M extends Record<string, unknown>>({ entity, collection, className, asPage, openEntityMode, formContext }: EntityViewBindingProps<M>): React.JSX.Element;
@@ -7,7 +7,7 @@ export interface RebaseLayoutProps {
7
7
  appBar?: React.ReactNode;
8
8
  /** Custom Drawer to override the default. */
9
9
  drawer?: React.ReactNode;
10
- /** Expand the drawer while the pointer is over it. Not a load-time default — that is `defaultDrawerOpen`. */
10
+ /** Expand the drawer while the pointer is over it. On by default; pass `false` to opt out. Not a load-time default — that is `defaultDrawerOpen`. */
11
11
  autoOpenDrawer?: boolean;
12
12
  /** Start with the drawer expanded instead of collapsed to icons. Ignored on small layouts. */
13
13
  defaultDrawerOpen?: boolean;
@@ -4,7 +4,7 @@ export interface RebaseShellProps {
4
4
  /** Top bar. Only rendered if provided — pass `<AppBar/>` for the default one. */
5
5
  appBar?: React.ReactNode;
6
6
  drawer?: React.ReactNode;
7
- /** Expand the drawer while the pointer is over it. Not a load-time default — that is `defaultDrawerOpen`. */
7
+ /** Expand the drawer while the pointer is over it. On by default; pass `false` to opt out. Not a load-time default — that is `defaultDrawerOpen`. */
8
8
  autoOpenDrawer?: boolean;
9
9
  /** Start with the drawer expanded instead of collapsed to icons. Ignored on small layouts. */
10
10
  defaultDrawerOpen?: boolean;
@@ -15,7 +15,14 @@ export interface RelationSelectorProps {
15
15
  /** Callback returning selected EntityRelation(s) */
16
16
  onValueChange?: (updatedValue: EntityRelation | EntityRelation[] | undefined) => void;
17
17
  placeholder?: React.ReactNode;
18
- size?: "small" | "medium";
18
+ /**
19
+ * `large` is the form's size and is on the shared 28/32/40/48 control
20
+ * scale, so a relation picker lines up with the text field beside it.
21
+ *
22
+ * `small` and `medium` predate that scale (42 and 56) and are kept as they
23
+ * are because the table cells and the filter row are built around them.
24
+ */
25
+ size?: "small" | "medium" | "large";
19
26
  useChips?: boolean;
20
27
  disabled?: boolean;
21
28
  error?: boolean;
@@ -6,7 +6,14 @@ export interface UserSelectorProps {
6
6
  value?: string | null;
7
7
  onValueChange?: (userId: string | null) => void;
8
8
  placeholder?: React.ReactNode;
9
- size?: "small" | "medium";
9
+ /**
10
+ * `large` is the form's size and is on the shared 28/32/40/48 control
11
+ * scale, so a user picker lines up with the text field beside it.
12
+ *
13
+ * `small` and `medium` predate that scale (42 and 56) and are kept as they
14
+ * are because the table cells and the filter row are built around them.
15
+ */
16
+ size?: "small" | "medium" | "large";
10
17
  disabled?: boolean;
11
18
  invisible?: boolean;
12
19
  clearable?: boolean;
@@ -1,19 +1,25 @@
1
1
  import React from "react";
2
2
  export declare const DRAWER_WIDTH = 280;
3
+ /**
4
+ * Namespaced by base path: two admins served from one origin are two different
5
+ * navigations, and a single key would have them overwrite each other's drawer.
6
+ */
7
+ export declare function drawerOpenStorageKey(basePath: string | undefined): string;
3
8
  /**
4
9
  * @group Core
5
10
  */
6
11
  export interface ScaffoldProps {
7
12
  /**
8
- * Open the drawer on hover
13
+ * Expand the collapsed drawer while the pointer is over it. On by default —
14
+ * pass `false` to keep the rail a rail until the user clicks the toggle.
9
15
  */
10
16
  autoOpenDrawer?: boolean;
11
17
  /**
12
18
  * Start with the drawer expanded rather than collapsed to icons.
13
19
  *
14
20
  * Distinct from {@link autoOpenDrawer}, which is a hover behaviour: this one
15
- * only seeds the initial state, so the user's own toggle still wins for the
16
- * rest of the session.
21
+ * only seeds the very first visit. Once the user toggles the drawer, that
22
+ * choice is stored in `localStorage` and wins over this prop on every load.
17
23
  *
18
24
  * Ignored on small layouts, where an expanded drawer covers the content it is
19
25
  * meant to navigate.
@@ -1,5 +1,7 @@
1
1
  export type { EntityViewBindingProps } from "./EntityViewBinding";
2
2
  export { EntityViewBinding } from "./EntityViewBinding";
3
+ export type { EntityDisplayHeaderProps } from "./EntityDisplayHeader";
4
+ export { EntityDisplayHeader, HEADER_DISPLAY_ROLES } from "./EntityDisplayHeader";
3
5
  export * from "./DetailViewBinding";
4
6
  export type { SelectionProps } from "./ReferenceTable/SelectionTableBinding";
5
7
  export { SelectionTableBinding } from "./ReferenceTable/SelectionTableBinding";
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { nn as useAdminContext } from "./util-GiwPgxnL.js";
2
+ import { nn as useAdminContext } from "./util-DNG7iK0w.js";
3
3
  import React, { useCallback } from "react";
4
4
  import { Alert, BooleanSwitchWithLabel, Button, CircularProgress, Dialog, DialogActions, DialogContent, DialogTitle, DownloadIcon, IconButton, Label, RadioGroup, RadioGroupItem, Tooltip, iconSize } from "@rebasepro/ui";
5
5
  import { getDefaultValuesFor } from "@rebasepro/common";
@@ -515,4 +515,4 @@ var export_exports = /* @__PURE__ */ __exportAll({
515
515
  //#endregion
516
516
  export { downloadDataAsCsv as a, getEntityJsonExportableData as c, downloadBlob as i, ExportCollectionAction as n, downloadEntitiesExport as o, BasicExportAction as r, getEntityCSVExportableData as s, export_exports as t };
517
517
 
518
- //# sourceMappingURL=export-J79rMoNj.js.map
518
+ //# sourceMappingURL=export-5bl2EoSs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"export-J79rMoNj.js","names":[],"sources":["../src/data_export/export/export.ts","../src/data_export/export/BasicExportAction.tsx","../src/data_export/export/ExportCollectionAction.tsx","../src/data_export/export/index.ts"],"sourcesContent":["import { Entity, EntityReference, Properties, Property } from \"@rebasepro/types\";\nimport { type ArrayValuesCount, getArrayValuesCount, getValueInPath } from \"@rebasepro/utils\";\n\ninterface Header {\n key: string;\n label: string;\n}\n\nexport interface DownloadEntitiesExportParams<M extends Record<string, unknown>> {\n data: Entity<M>[];\n additionalData: Record<string, unknown>[] | undefined;\n properties: Properties;\n propertiesOrder: string[] | undefined;\n name: string;\n flattenArrays: boolean;\n additionalHeaders: string[] | undefined;\n exportType: \"csv\" | \"json\";\n dateExportType: \"timestamp\" | \"string\";\n}\n\nexport function downloadEntitiesExport<M extends Record<string, unknown>>({\n data,\n additionalData,\n properties,\n propertiesOrder,\n name,\n flattenArrays,\n additionalHeaders,\n exportType,\n dateExportType\n}: DownloadEntitiesExportParams<M>\n) {\n\n console.debug(\"Downloading export\", {\n dataLength: data.length,\n properties,\n exportType,\n dateExportType\n });\n\n if (exportType === \"csv\") {\n const arrayValuesCount = flattenArrays ? getArrayValuesCount(data.map(d => d.values)) : {};\n const headers = getExportHeaders(properties, propertiesOrder, additionalHeaders, arrayValuesCount);\n const exportableData = getEntityCSVExportableData(data, additionalData, properties, headers, dateExportType);\n const headersData = entryToCSVRow(headers.map(h => h.label));\n const csvData = exportableData.map(entry => entryToCSVRow(entry));\n downloadBlob([headersData, ...csvData], `${name}.csv`, \"text/csv\");\n } else {\n const exportableData = getEntityJsonExportableData(data, additionalData, properties, dateExportType);\n const json = JSON.stringify(exportableData, null, 2);\n downloadBlob([json], `${name}.json`, \"application/json\");\n }\n}\n\nexport function getEntityCSVExportableData(data: Entity<Record<string, unknown>>[],\n additionalData: Record<string, unknown>[] | undefined,\n properties: Properties,\n headers: Header[],\n dateExportType: \"timestamp\" | \"string\"\n) {\n\n const mergedData: Record<string, unknown>[] = data.map(e => ({\n id: e.id,\n ...processValuesForExport(e.values, properties, \"csv\", dateExportType)\n }));\n\n if (additionalData) {\n additionalData.forEach((additional, index) => {\n mergedData[index] = { ...mergedData[index],\n...additional };\n });\n }\n\n return mergedData && mergedData.map((entry) => {\n return headers.map((header) => getValueInPath(entry, header.key));\n });\n}\n\nexport function getEntityJsonExportableData(data: Entity<Record<string, unknown>>[],\n additionalData: Record<string, unknown>[] | undefined,\n properties: Properties,\n dateExportType: \"timestamp\" | \"string\"\n) {\n\n const mergedData: Record<string, unknown>[] = data.map(e => ({\n id: e.id,\n ...processValuesForExport(e.values, properties, \"json\", dateExportType)\n }));\n\n if (additionalData) {\n additionalData.forEach((additional, index) => {\n mergedData[index] = { ...mergedData[index],\n...additional };\n });\n }\n\n return mergedData;\n}\n\nfunction getExportHeaders<M extends Record<string, unknown>>(properties: Properties,\n propertiesOrder: string[] | undefined,\n additionalHeaders: string[] | undefined,\n arrayValuesCount?: ArrayValuesCount): Header[] {\n\n const headers: Header[] = [\n {\n label: \"id\",\n key: \"id\"\n },\n ...(propertiesOrder ?? Object.keys(properties))\n .flatMap((childKey) => {\n const property = properties[childKey];\n if (!property) {\n console.warn(\"Property not found\", childKey, properties);\n return [];\n }\n if (arrayValuesCount && arrayValuesCount[childKey] > 1) {\n return Array.from({ length: arrayValuesCount[childKey] },\n (_, i) => getHeaders(property as Property, `${childKey}[${i}]`, \"\"))\n .flat();\n } else {\n return getHeaders(property as Property, childKey, \"\");\n }\n })\n ];\n\n if (additionalHeaders) {\n headers.push(...additionalHeaders.map(h => ({\n label: h,\n key: h\n })));\n }\n\n return headers;\n}\n\n/**\n * Get headers for property. There could be more than one header per property\n * @param property\n * @param propertyKey\n * @param prefix\n */\nfunction getHeaders(property: Property, propertyKey: string, prefix = \"\"): Header[] {\n const currentKey = prefix ? `${prefix}.${propertyKey}` : propertyKey;\n if (property.type === \"map\" && property.properties) {\n return Object.entries(property.properties)\n .map(([childKey, p]) => getHeaders(p, childKey, currentKey))\n .flat();\n } else {\n return [{\n label: currentKey,\n key: currentKey\n }];\n }\n}\n\nfunction processValueForExport(inputValue: unknown,\n property: Property,\n exportType: \"csv\" | \"json\",\n dateExportType: \"timestamp\" | \"string\"\n): unknown {\n\n let value: unknown;\n if (property.type === \"map\" && property.properties) {\n value = processValuesForExport(inputValue as Record<string, unknown>, property.properties as Properties, exportType, dateExportType);\n } else if (property.type === \"array\") {\n if (property.of && Array.isArray(inputValue)) {\n if (Array.isArray(property.of)) {\n value = property.of.map((p, i) => processValueForExport(inputValue[i], p, exportType, dateExportType));\n } else if (property.of.type === \"map\") {\n value = exportType === \"csv\"\n ? inputValue.map((e) => JSON.stringify(e))\n : inputValue.map((e) => processValueForExport(e, property.of as Property, exportType, dateExportType));\n ;\n } else {\n value = inputValue.map((e) => processValueForExport(e, property.of as Property, exportType, dateExportType));\n }\n } else {\n value = inputValue;\n }\n } else if (property.type === \"reference\" && inputValue && typeof inputValue === \"object\" && \"isEntityReference\" in inputValue && typeof (inputValue as EntityReference).isEntityReference === \"function\" && (inputValue as EntityReference).isEntityReference()) {\n const ref = inputValue ? inputValue as EntityReference : undefined;\n value = ref ? ref.fullPath : null;\n } else if (property.type === \"date\" && inputValue instanceof Date) {\n value = inputValue ? (dateExportType === \"timestamp\" ? inputValue.getTime() : inputValue.toISOString()) : null;\n } else {\n value = inputValue;\n }\n\n return value;\n}\n\nfunction processValuesForExport<M extends Record<string, unknown>>\n (inputValues: Record<string, unknown>,\n properties: Properties,\n exportType: \"csv\" | \"json\",\n dateExportType: \"timestamp\" | \"string\"\n ): Record<string, unknown> {\n const updatedValues = Object.entries(properties)\n .map(([key, property]) => {\n const inputValue = inputValues && (inputValues)[key];\n const updatedValue = processValueForExport(inputValue, property as Property, exportType, dateExportType);\n if (updatedValue === undefined) return {};\n return ({ [key]: updatedValue });\n })\n .reduce((a, b) => ({ ...a,\n...b }), {}) as Record<string, unknown>;\n return { ...inputValues,\n...updatedValues };\n}\n\nfunction entryToCSVRow(entry: unknown[]) {\n return entry\n .map((v: unknown) => {\n if (v === null || v === undefined) return \"\";\n if (Array.isArray(v))\n return \"\\\"\" + JSON.stringify(v).replaceAll(\"\\\"\", \"\\\"\\\"\") + \"\\\"\";\n const s = String(v);\n return \"\\\"\" + s.replaceAll(\"\\\"\", \"\\\"\\\"\") + \"\\\"\";\n })\n .join(\",\") + \"\\r\\n\";\n}\n\nexport function downloadBlob(content: BlobPart[], filename: string, contentType: string) {\n const blob = new Blob(content, { type: contentType });\n const url = URL.createObjectURL(blob);\n const pom = document.createElement(\"a\");\n pom.href = url;\n pom.setAttribute(\"download\", filename);\n pom.click();\n}\n\nexport function downloadDataAsCsv(data: object[], name: string) {\n if (data.length === 0) return;\n\n const headers = Object.keys(data[0]);\n const csvContent = [\n headers.join(\",\"),\n ...data.map(row => headers.map(header => {\n const value = (row as Record<string, unknown>)[header];\n if (value === null || value === undefined) return \"\";\n if (Array.isArray(value)) return `\"${JSON.stringify(value).replace(/\"/g, '\"\"')}\"`;\n return `\"${String(value).replace(/\"/g, '\"\"')}\"`;\n }).join(\",\"))\n ].join(\"\\r\\n\");\n\n downloadBlob([csvContent], `${name}.csv`, \"text/csv\");\n}\n","\nimport React, { useCallback } from \"react\";\n\nimport { useTranslation } from \"@rebasepro/app\";\nimport { Entity, Properties } from \"@rebasepro/types\";\nimport {\n BooleanSwitchWithLabel,\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n DownloadIcon,\n IconButton,\n Label,\n RadioGroup,\n RadioGroupItem,\n Tooltip,\n Typography\n} from \"@rebasepro/ui\";\nimport { downloadEntitiesExport } from \"./export\";\n\nexport type BasicExportActionProps = {\n data: Entity<any>[];\n properties: Properties;\n propertiesOrder?: string[];\n}\n\nexport function BasicExportAction({\n data,\n properties,\n propertiesOrder\n}: BasicExportActionProps) {\n\n const { t } = useTranslation();\n const dateRef = React.useRef<Date>(new Date());\n const [flattenArrays, setFlattenArrays] = React.useState<boolean>(true);\n const [exportType, setExportType] = React.useState<\"csv\" | \"json\">(\"csv\");\n const [dateExportType, setDateExportType] = React.useState<\"timestamp\" | \"string\">(\"string\");\n\n const [open, setOpen] = React.useState(false);\n\n const handleClickOpen = useCallback(() => {\n setOpen(true);\n }, [setOpen]);\n\n const handleClose = useCallback(() => {\n setOpen(false);\n }, [setOpen]);\n\n const onOkClicked = useCallback(() => {\n downloadEntitiesExport({\n data,\n additionalData: [],\n properties,\n propertiesOrder,\n name: \"export.csv\",\n flattenArrays,\n additionalHeaders: [],\n exportType,\n dateExportType\n });\n handleClose();\n }, []);\n\n return <>\n\n <Tooltip title={\"Export\"}\n asChild={true}>\n <IconButton\n size={\"small\"}\n color={\"primary\"} onClick={handleClickOpen}>\n <DownloadIcon\n size={\"small\"}/>\n </IconButton>\n </Tooltip>\n\n <Dialog\n open={open}\n onOpenChange={setOpen}\n maxWidth={\"xl\"}>\n\n <DialogTitle variant={\"h6\"}>{t(\"export_data\")}</DialogTitle>\n\n <DialogContent className={\"flex flex-col gap-4 my-4\"}>\n\n <div>{t(\"download_table_csv\")}</div>\n\n <div className={\"flex flex-row gap-4\"}>\n <div className={\"p-4 flex flex-col\"}>\n <RadioGroup value={exportType} onValueChange={(v) => setExportType(v as \"csv\" | \"json\")}>\n <div className=\"flex items-center gap-2\">\n <RadioGroupItem value=\"csv\" id=\"radio-csv\"/>\n <Label htmlFor=\"radio-csv\">{t(\"csv\")}</Label>\n </div>\n <div className=\"flex items-center gap-2\">\n <RadioGroupItem value=\"json\" id=\"radio-json\"/>\n <Label htmlFor=\"radio-json\">{t(\"json\")}</Label>\n </div>\n </RadioGroup>\n </div>\n\n <div className={\"p-4 flex flex-col\"}>\n <RadioGroup value={dateExportType} onValueChange={(v) => setDateExportType(v as \"timestamp\" | \"string\")}>\n <div className=\"flex items-center gap-2\">\n <RadioGroupItem value=\"timestamp\" id=\"radio-timestamp\"/>\n <Label htmlFor=\"radio-timestamp\">{t(\"dates_as_timestamps\")} ({dateRef.current.getTime()})</Label>\n </div>\n <div className=\"flex items-center gap-2\">\n <RadioGroupItem value=\"string\" id=\"radio-string\"/>\n <Label htmlFor=\"radio-string\">{t(\"dates_as_strings\")} ({dateRef.current.toISOString()})</Label>\n </div>\n </RadioGroup>\n </div>\n </div>\n\n <BooleanSwitchWithLabel\n size={\"small\"}\n disabled={exportType !== \"csv\"}\n value={flattenArrays}\n onValueChange={setFlattenArrays}\n label={t(\"flatten_arrays\")}/>\n\n </DialogContent>\n\n <DialogActions>\n\n <Button onClick={handleClose}\n variant={\"text\"}>\n {t(\"cancel\")}\n </Button>\n\n <Button onClick={onOkClicked}>\n {t(\"download\")}\n </Button>\n\n </DialogActions>\n\n </Dialog>\n\n </>;\n}\n","\nimport React, { useCallback } from \"react\";\n\nimport {\n useAuthController,\n useCustomizationController,\n useData,\n useTranslation\n} from \"@rebasepro/app\";\nimport { useAdminContext } from \"../../hooks\";\nimport { Entity, User } from \"@rebasepro/types\";\nimport { CollectionActionsProps, ExportConfig, RebaseContext, AdminCollection } from \"@rebasepro/admin-types\";\nimport { getDefaultValuesFor } from \"@rebasepro/common\";\nimport {\n Alert,\n BooleanSwitchWithLabel,\n Button,\n CircularProgress,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n DownloadIcon,\n IconButton,\n iconSize,\n Label,\n RadioGroup,\n RadioGroupItem,\n Tooltip\n} from \"@rebasepro/ui\";\nimport { downloadEntitiesExport } from \"./export\";\n\nconst DOCS_LIMIT = 500;\n\nexport function ExportCollectionAction<M extends Record<string, unknown>, USER extends User>({\n collection,\n path,\n collectionEntitiesCount,\n onAnalyticsEvent,\n exportAllowed,\n notAllowedView\n}: CollectionActionsProps<M, USER, AdminCollection<M>> & {\n exportAllowed?: (props: { collectionEntitiesCount: number, path: string, collection: AdminCollection }) => boolean;\n notAllowedView?: React.ReactNode;\n onAnalyticsEvent?: (event: string, params?: any) => void;\n}) {\n\n const { t } = useTranslation();\n\n const exportConfig = typeof collection.exportable === \"object\" ? collection.exportable : undefined;\n\n const dateRef = React.useRef<Date>(new Date());\n\n const [includeUndefinedValues, setIncludeUndefinedValues] = React.useState<boolean>(false);\n const [flattenArrays, setFlattenArrays] = React.useState<boolean>(true);\n const [exportType, setExportType] = React.useState<\"csv\" | \"json\">(\"csv\");\n const [dateExportType, setDateExportType] = React.useState<\"timestamp\" | \"string\">(\"string\");\n\n const context = useAdminContext<USER>();\n const dataClient = useData();\n\n const canExport = !exportAllowed || exportAllowed({\n collectionEntitiesCount: collectionEntitiesCount ?? 0,\n path,\n collection\n });\n\n const [dataLoading, setDataLoading] = React.useState<boolean>(false);\n const [dataLoadingError, setDataLoadingError] = React.useState<Error | undefined>();\n\n const [open, setOpen] = React.useState(false);\n\n const handleClickOpen = useCallback(() => {\n setOpen(true);\n }, [setOpen]);\n\n const handleClose = useCallback(() => {\n setOpen(false);\n }, [setOpen]);\n\n const fetchAdditionalFields = useCallback(async (entities: Entity<M>[]) => {\n\n const additionalExportFields = exportConfig?.additionalFields;\n const additionalFields = collection.additionalFields;\n\n const resolvedExportColumnsValues: Record<string, any>[] = additionalExportFields\n ? await Promise.all(entities.map(async (entity) => {\n return (await Promise.all(additionalExportFields.map(async (column) => {\n return {\n [column.key]: await column.builder({\n entity,\n context: context as RebaseContext\n })\n };\n }))).reduce((a, b) => ({ ...a,\n...b }), {});\n }))\n : [];\n\n const resolvedColumnsValues: Record<string, any>[] = additionalFields\n ? await Promise.all(entities.map(async (entity) => {\n return (await Promise.all(additionalFields\n .map(async (field) => {\n if (!field.value)\n return {};\n return {\n [field.key]: await field.value({\n entity,\n context: context as RebaseContext\n })\n };\n }))).reduce((a, b) => ({ ...a,\n...b }), {});\n }))\n : [];\n return [...resolvedExportColumnsValues, ...resolvedColumnsValues];\n }, [exportConfig?.additionalFields]);\n\n const doDownload = useCallback(async (collection: AdminCollection<M>,\n exportConfig: ExportConfig<any> | undefined) => {\n\n onAnalyticsEvent?.(\"export_collection\", {\n collection: collection.slug\n });\n setDataLoading(true);\n dataClient.collection(path).find({})\n .then(async (res) => {\n const data = res.data as Entity<M>[];\n setDataLoadingError(undefined);\n const additionalData = await fetchAdditionalFields(data);\n const additionalHeaders = [\n ...exportConfig?.additionalFields?.map(column => column.key) ?? [],\n ...collection.additionalFields?.map(field => field.key) ?? []\n ];\n\n const dataWithDefaults = includeUndefinedValues\n ? data.map(entity => {\n const defaultValues = getDefaultValuesFor(collection.properties);\n return {\n ...entity,\n values: { ...defaultValues,\n...entity.values }\n };\n })\n : data;\n downloadEntitiesExport({\n data: dataWithDefaults,\n additionalData,\n properties: collection.properties,\n propertiesOrder: collection.propertiesOrder,\n name: collection.name,\n flattenArrays,\n additionalHeaders,\n exportType,\n dateExportType\n });\n onAnalyticsEvent?.(\"export_collection_success\", {\n collection: collection.slug\n });\n })\n .catch((e) => {\n console.error(\"Error loading export data\", e);\n setDataLoadingError(e);\n })\n .finally(() => setDataLoading(false));\n\n }, [onAnalyticsEvent, dataClient, path, fetchAdditionalFields, includeUndefinedValues, flattenArrays, exportType, dateExportType]);\n\n const onOkClicked = useCallback(() => {\n doDownload(collection, exportConfig);\n handleClose();\n }, [doDownload, collection, exportConfig, handleClose]);\n\n return <>\n\n <Tooltip title={\"Export\"}\n asChild={true}>\n <IconButton\n size={\"small\"}\n color={\"primary\"}\n onClick={handleClickOpen}>\n <DownloadIcon size={iconSize.small}/>\n </IconButton>\n </Tooltip>\n\n <Dialog\n open={open}\n onOpenChange={setOpen}\n maxWidth={\"xl\"}>\n\n <DialogTitle variant={\"h6\"}>{t(\"export_data\")}</DialogTitle>\n\n <DialogContent className={\"flex flex-col gap-4 my-4\"}>\n\n <div>{t(\"download_table_csv\")}</div>\n\n {collectionEntitiesCount !== undefined && collectionEntitiesCount > DOCS_LIMIT &&\n <Alert color={\"warning\"}>\n <div>\n {t(\"large_number_of_documents\", { count: collectionEntitiesCount.toString() })}\n </div>\n </Alert>}\n\n <div className={\"flex flex-row gap-4\"}>\n <div className={\"p-4 flex flex-col\"}>\n <RadioGroup value={exportType} onValueChange={(v) => setExportType(v as \"csv\" | \"json\")}>\n <div className=\"flex items-center gap-2\">\n <RadioGroupItem value=\"csv\" id=\"radio-csv\"/>\n <Label htmlFor=\"radio-csv\">{t(\"csv\")}</Label>\n </div>\n <div className=\"flex items-center gap-2\">\n <RadioGroupItem value=\"json\" id=\"radio-json\"/>\n <Label htmlFor=\"radio-json\">{t(\"json\")}</Label>\n </div>\n </RadioGroup>\n </div>\n\n <div className={\"p-4 flex flex-col\"}>\n <RadioGroup value={dateExportType} onValueChange={(v) => setDateExportType(v as \"timestamp\" | \"string\")}>\n <div className=\"flex items-center gap-2\">\n <RadioGroupItem value=\"timestamp\" id=\"radio-timestamp\"/>\n <Label htmlFor=\"radio-timestamp\">{t(\"dates_as_timestamps\")} ({dateRef.current.getTime()})</Label>\n </div>\n <div className=\"flex items-center gap-2\">\n <RadioGroupItem value=\"string\" id=\"radio-string\"/>\n <Label htmlFor=\"radio-string\">{t(\"dates_as_strings\")} ({dateRef.current.toISOString()})</Label>\n </div>\n </RadioGroup>\n </div>\n </div>\n\n <BooleanSwitchWithLabel\n size={\"small\"}\n disabled={exportType !== \"csv\"}\n value={flattenArrays}\n onValueChange={setFlattenArrays}\n label={t(\"flatten_arrays\")}/>\n\n <BooleanSwitchWithLabel\n size={\"small\"}\n value={includeUndefinedValues}\n onValueChange={setIncludeUndefinedValues}\n label={t(\"include_undefined_values\")}/>\n\n {!canExport && notAllowedView}\n\n </DialogContent>\n\n <DialogActions>\n\n {dataLoading && <CircularProgress size={\"smallest\"}/>}\n\n <Button onClick={handleClose}\n variant={\"text\"}>\n {t(\"cancel\")}\n </Button>\n\n <Button onClick={onOkClicked}\n disabled={dataLoading || !canExport}>\n {t(\"download\")}\n </Button>\n\n </DialogActions>\n\n </Dialog>\n\n </>;\n}\n","export * from \"./export\";\nexport * from \"./BasicExportAction\";\nexport * from \"./ExportCollectionAction\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"export-5bl2EoSs.js","names":[],"sources":["../src/data_export/export/export.ts","../src/data_export/export/BasicExportAction.tsx","../src/data_export/export/ExportCollectionAction.tsx","../src/data_export/export/index.ts"],"sourcesContent":["import { Entity, EntityReference, Properties, Property } from \"@rebasepro/types\";\nimport { type ArrayValuesCount, getArrayValuesCount, getValueInPath } from \"@rebasepro/utils\";\n\ninterface Header {\n key: string;\n label: string;\n}\n\nexport interface DownloadEntitiesExportParams<M extends Record<string, unknown>> {\n data: Entity<M>[];\n additionalData: Record<string, unknown>[] | undefined;\n properties: Properties;\n propertiesOrder: string[] | undefined;\n name: string;\n flattenArrays: boolean;\n additionalHeaders: string[] | undefined;\n exportType: \"csv\" | \"json\";\n dateExportType: \"timestamp\" | \"string\";\n}\n\nexport function downloadEntitiesExport<M extends Record<string, unknown>>({\n data,\n additionalData,\n properties,\n propertiesOrder,\n name,\n flattenArrays,\n additionalHeaders,\n exportType,\n dateExportType\n}: DownloadEntitiesExportParams<M>\n) {\n\n console.debug(\"Downloading export\", {\n dataLength: data.length,\n properties,\n exportType,\n dateExportType\n });\n\n if (exportType === \"csv\") {\n const arrayValuesCount = flattenArrays ? getArrayValuesCount(data.map(d => d.values)) : {};\n const headers = getExportHeaders(properties, propertiesOrder, additionalHeaders, arrayValuesCount);\n const exportableData = getEntityCSVExportableData(data, additionalData, properties, headers, dateExportType);\n const headersData = entryToCSVRow(headers.map(h => h.label));\n const csvData = exportableData.map(entry => entryToCSVRow(entry));\n downloadBlob([headersData, ...csvData], `${name}.csv`, \"text/csv\");\n } else {\n const exportableData = getEntityJsonExportableData(data, additionalData, properties, dateExportType);\n const json = JSON.stringify(exportableData, null, 2);\n downloadBlob([json], `${name}.json`, \"application/json\");\n }\n}\n\nexport function getEntityCSVExportableData(data: Entity<Record<string, unknown>>[],\n additionalData: Record<string, unknown>[] | undefined,\n properties: Properties,\n headers: Header[],\n dateExportType: \"timestamp\" | \"string\"\n) {\n\n const mergedData: Record<string, unknown>[] = data.map(e => ({\n id: e.id,\n ...processValuesForExport(e.values, properties, \"csv\", dateExportType)\n }));\n\n if (additionalData) {\n additionalData.forEach((additional, index) => {\n mergedData[index] = { ...mergedData[index],\n...additional };\n });\n }\n\n return mergedData && mergedData.map((entry) => {\n return headers.map((header) => getValueInPath(entry, header.key));\n });\n}\n\nexport function getEntityJsonExportableData(data: Entity<Record<string, unknown>>[],\n additionalData: Record<string, unknown>[] | undefined,\n properties: Properties,\n dateExportType: \"timestamp\" | \"string\"\n) {\n\n const mergedData: Record<string, unknown>[] = data.map(e => ({\n id: e.id,\n ...processValuesForExport(e.values, properties, \"json\", dateExportType)\n }));\n\n if (additionalData) {\n additionalData.forEach((additional, index) => {\n mergedData[index] = { ...mergedData[index],\n...additional };\n });\n }\n\n return mergedData;\n}\n\nfunction getExportHeaders<M extends Record<string, unknown>>(properties: Properties,\n propertiesOrder: string[] | undefined,\n additionalHeaders: string[] | undefined,\n arrayValuesCount?: ArrayValuesCount): Header[] {\n\n const headers: Header[] = [\n {\n label: \"id\",\n key: \"id\"\n },\n ...(propertiesOrder ?? Object.keys(properties))\n .flatMap((childKey) => {\n const property = properties[childKey];\n if (!property) {\n console.warn(\"Property not found\", childKey, properties);\n return [];\n }\n if (arrayValuesCount && arrayValuesCount[childKey] > 1) {\n return Array.from({ length: arrayValuesCount[childKey] },\n (_, i) => getHeaders(property as Property, `${childKey}[${i}]`, \"\"))\n .flat();\n } else {\n return getHeaders(property as Property, childKey, \"\");\n }\n })\n ];\n\n if (additionalHeaders) {\n headers.push(...additionalHeaders.map(h => ({\n label: h,\n key: h\n })));\n }\n\n return headers;\n}\n\n/**\n * Get headers for property. There could be more than one header per property\n * @param property\n * @param propertyKey\n * @param prefix\n */\nfunction getHeaders(property: Property, propertyKey: string, prefix = \"\"): Header[] {\n const currentKey = prefix ? `${prefix}.${propertyKey}` : propertyKey;\n if (property.type === \"map\" && property.properties) {\n return Object.entries(property.properties)\n .map(([childKey, p]) => getHeaders(p, childKey, currentKey))\n .flat();\n } else {\n return [{\n label: currentKey,\n key: currentKey\n }];\n }\n}\n\nfunction processValueForExport(inputValue: unknown,\n property: Property,\n exportType: \"csv\" | \"json\",\n dateExportType: \"timestamp\" | \"string\"\n): unknown {\n\n let value: unknown;\n if (property.type === \"map\" && property.properties) {\n value = processValuesForExport(inputValue as Record<string, unknown>, property.properties as Properties, exportType, dateExportType);\n } else if (property.type === \"array\") {\n if (property.of && Array.isArray(inputValue)) {\n if (Array.isArray(property.of)) {\n value = property.of.map((p, i) => processValueForExport(inputValue[i], p, exportType, dateExportType));\n } else if (property.of.type === \"map\") {\n value = exportType === \"csv\"\n ? inputValue.map((e) => JSON.stringify(e))\n : inputValue.map((e) => processValueForExport(e, property.of as Property, exportType, dateExportType));\n ;\n } else {\n value = inputValue.map((e) => processValueForExport(e, property.of as Property, exportType, dateExportType));\n }\n } else {\n value = inputValue;\n }\n } else if (property.type === \"reference\" && inputValue && typeof inputValue === \"object\" && \"isEntityReference\" in inputValue && typeof (inputValue as EntityReference).isEntityReference === \"function\" && (inputValue as EntityReference).isEntityReference()) {\n const ref = inputValue ? inputValue as EntityReference : undefined;\n value = ref ? ref.fullPath : null;\n } else if (property.type === \"date\" && inputValue instanceof Date) {\n value = inputValue ? (dateExportType === \"timestamp\" ? inputValue.getTime() : inputValue.toISOString()) : null;\n } else {\n value = inputValue;\n }\n\n return value;\n}\n\nfunction processValuesForExport<M extends Record<string, unknown>>\n (inputValues: Record<string, unknown>,\n properties: Properties,\n exportType: \"csv\" | \"json\",\n dateExportType: \"timestamp\" | \"string\"\n ): Record<string, unknown> {\n const updatedValues = Object.entries(properties)\n .map(([key, property]) => {\n const inputValue = inputValues && (inputValues)[key];\n const updatedValue = processValueForExport(inputValue, property as Property, exportType, dateExportType);\n if (updatedValue === undefined) return {};\n return ({ [key]: updatedValue });\n })\n .reduce((a, b) => ({ ...a,\n...b }), {}) as Record<string, unknown>;\n return { ...inputValues,\n...updatedValues };\n}\n\nfunction entryToCSVRow(entry: unknown[]) {\n return entry\n .map((v: unknown) => {\n if (v === null || v === undefined) return \"\";\n if (Array.isArray(v))\n return \"\\\"\" + JSON.stringify(v).replaceAll(\"\\\"\", \"\\\"\\\"\") + \"\\\"\";\n const s = String(v);\n return \"\\\"\" + s.replaceAll(\"\\\"\", \"\\\"\\\"\") + \"\\\"\";\n })\n .join(\",\") + \"\\r\\n\";\n}\n\nexport function downloadBlob(content: BlobPart[], filename: string, contentType: string) {\n const blob = new Blob(content, { type: contentType });\n const url = URL.createObjectURL(blob);\n const pom = document.createElement(\"a\");\n pom.href = url;\n pom.setAttribute(\"download\", filename);\n pom.click();\n}\n\nexport function downloadDataAsCsv(data: object[], name: string) {\n if (data.length === 0) return;\n\n const headers = Object.keys(data[0]);\n const csvContent = [\n headers.join(\",\"),\n ...data.map(row => headers.map(header => {\n const value = (row as Record<string, unknown>)[header];\n if (value === null || value === undefined) return \"\";\n if (Array.isArray(value)) return `\"${JSON.stringify(value).replace(/\"/g, '\"\"')}\"`;\n return `\"${String(value).replace(/\"/g, '\"\"')}\"`;\n }).join(\",\"))\n ].join(\"\\r\\n\");\n\n downloadBlob([csvContent], `${name}.csv`, \"text/csv\");\n}\n","\nimport React, { useCallback } from \"react\";\n\nimport { useTranslation } from \"@rebasepro/app\";\nimport { Entity, Properties } from \"@rebasepro/types\";\nimport {\n BooleanSwitchWithLabel,\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n DownloadIcon,\n IconButton,\n Label,\n RadioGroup,\n RadioGroupItem,\n Tooltip,\n Typography\n} from \"@rebasepro/ui\";\nimport { downloadEntitiesExport } from \"./export\";\n\nexport type BasicExportActionProps = {\n data: Entity<any>[];\n properties: Properties;\n propertiesOrder?: string[];\n}\n\nexport function BasicExportAction({\n data,\n properties,\n propertiesOrder\n}: BasicExportActionProps) {\n\n const { t } = useTranslation();\n const dateRef = React.useRef<Date>(new Date());\n const [flattenArrays, setFlattenArrays] = React.useState<boolean>(true);\n const [exportType, setExportType] = React.useState<\"csv\" | \"json\">(\"csv\");\n const [dateExportType, setDateExportType] = React.useState<\"timestamp\" | \"string\">(\"string\");\n\n const [open, setOpen] = React.useState(false);\n\n const handleClickOpen = useCallback(() => {\n setOpen(true);\n }, [setOpen]);\n\n const handleClose = useCallback(() => {\n setOpen(false);\n }, [setOpen]);\n\n const onOkClicked = useCallback(() => {\n downloadEntitiesExport({\n data,\n additionalData: [],\n properties,\n propertiesOrder,\n name: \"export.csv\",\n flattenArrays,\n additionalHeaders: [],\n exportType,\n dateExportType\n });\n handleClose();\n }, []);\n\n return <>\n\n <Tooltip title={\"Export\"}\n asChild={true}>\n <IconButton\n size={\"small\"}\n color={\"primary\"} onClick={handleClickOpen}>\n <DownloadIcon\n size={\"small\"}/>\n </IconButton>\n </Tooltip>\n\n <Dialog\n open={open}\n onOpenChange={setOpen}\n maxWidth={\"xl\"}>\n\n <DialogTitle variant={\"h6\"}>{t(\"export_data\")}</DialogTitle>\n\n <DialogContent className={\"flex flex-col gap-4 my-4\"}>\n\n <div>{t(\"download_table_csv\")}</div>\n\n <div className={\"flex flex-row gap-4\"}>\n <div className={\"p-4 flex flex-col\"}>\n <RadioGroup value={exportType} onValueChange={(v) => setExportType(v as \"csv\" | \"json\")}>\n <div className=\"flex items-center gap-2\">\n <RadioGroupItem value=\"csv\" id=\"radio-csv\"/>\n <Label htmlFor=\"radio-csv\">{t(\"csv\")}</Label>\n </div>\n <div className=\"flex items-center gap-2\">\n <RadioGroupItem value=\"json\" id=\"radio-json\"/>\n <Label htmlFor=\"radio-json\">{t(\"json\")}</Label>\n </div>\n </RadioGroup>\n </div>\n\n <div className={\"p-4 flex flex-col\"}>\n <RadioGroup value={dateExportType} onValueChange={(v) => setDateExportType(v as \"timestamp\" | \"string\")}>\n <div className=\"flex items-center gap-2\">\n <RadioGroupItem value=\"timestamp\" id=\"radio-timestamp\"/>\n <Label htmlFor=\"radio-timestamp\">{t(\"dates_as_timestamps\")} ({dateRef.current.getTime()})</Label>\n </div>\n <div className=\"flex items-center gap-2\">\n <RadioGroupItem value=\"string\" id=\"radio-string\"/>\n <Label htmlFor=\"radio-string\">{t(\"dates_as_strings\")} ({dateRef.current.toISOString()})</Label>\n </div>\n </RadioGroup>\n </div>\n </div>\n\n <BooleanSwitchWithLabel\n size={\"small\"}\n disabled={exportType !== \"csv\"}\n value={flattenArrays}\n onValueChange={setFlattenArrays}\n label={t(\"flatten_arrays\")}/>\n\n </DialogContent>\n\n <DialogActions>\n\n <Button onClick={handleClose}\n variant={\"text\"}>\n {t(\"cancel\")}\n </Button>\n\n <Button onClick={onOkClicked}>\n {t(\"download\")}\n </Button>\n\n </DialogActions>\n\n </Dialog>\n\n </>;\n}\n","\nimport React, { useCallback } from \"react\";\n\nimport {\n useAuthController,\n useCustomizationController,\n useData,\n useTranslation\n} from \"@rebasepro/app\";\nimport { useAdminContext } from \"../../hooks\";\nimport { Entity, User } from \"@rebasepro/types\";\nimport { CollectionActionsProps, ExportConfig, RebaseContext, AdminCollection } from \"@rebasepro/admin-types\";\nimport { getDefaultValuesFor } from \"@rebasepro/common\";\nimport {\n Alert,\n BooleanSwitchWithLabel,\n Button,\n CircularProgress,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n DownloadIcon,\n IconButton,\n iconSize,\n Label,\n RadioGroup,\n RadioGroupItem,\n Tooltip\n} from \"@rebasepro/ui\";\nimport { downloadEntitiesExport } from \"./export\";\n\nconst DOCS_LIMIT = 500;\n\nexport function ExportCollectionAction<M extends Record<string, unknown>, USER extends User>({\n collection,\n path,\n collectionEntitiesCount,\n onAnalyticsEvent,\n exportAllowed,\n notAllowedView\n}: CollectionActionsProps<M, USER, AdminCollection<M>> & {\n exportAllowed?: (props: { collectionEntitiesCount: number, path: string, collection: AdminCollection }) => boolean;\n notAllowedView?: React.ReactNode;\n onAnalyticsEvent?: (event: string, params?: any) => void;\n}) {\n\n const { t } = useTranslation();\n\n const exportConfig = typeof collection.exportable === \"object\" ? collection.exportable : undefined;\n\n const dateRef = React.useRef<Date>(new Date());\n\n const [includeUndefinedValues, setIncludeUndefinedValues] = React.useState<boolean>(false);\n const [flattenArrays, setFlattenArrays] = React.useState<boolean>(true);\n const [exportType, setExportType] = React.useState<\"csv\" | \"json\">(\"csv\");\n const [dateExportType, setDateExportType] = React.useState<\"timestamp\" | \"string\">(\"string\");\n\n const context = useAdminContext<USER>();\n const dataClient = useData();\n\n const canExport = !exportAllowed || exportAllowed({\n collectionEntitiesCount: collectionEntitiesCount ?? 0,\n path,\n collection\n });\n\n const [dataLoading, setDataLoading] = React.useState<boolean>(false);\n const [dataLoadingError, setDataLoadingError] = React.useState<Error | undefined>();\n\n const [open, setOpen] = React.useState(false);\n\n const handleClickOpen = useCallback(() => {\n setOpen(true);\n }, [setOpen]);\n\n const handleClose = useCallback(() => {\n setOpen(false);\n }, [setOpen]);\n\n const fetchAdditionalFields = useCallback(async (entities: Entity<M>[]) => {\n\n const additionalExportFields = exportConfig?.additionalFields;\n const additionalFields = collection.additionalFields;\n\n const resolvedExportColumnsValues: Record<string, any>[] = additionalExportFields\n ? await Promise.all(entities.map(async (entity) => {\n return (await Promise.all(additionalExportFields.map(async (column) => {\n return {\n [column.key]: await column.builder({\n entity,\n context: context as RebaseContext\n })\n };\n }))).reduce((a, b) => ({ ...a,\n...b }), {});\n }))\n : [];\n\n const resolvedColumnsValues: Record<string, any>[] = additionalFields\n ? await Promise.all(entities.map(async (entity) => {\n return (await Promise.all(additionalFields\n .map(async (field) => {\n if (!field.value)\n return {};\n return {\n [field.key]: await field.value({\n entity,\n context: context as RebaseContext\n })\n };\n }))).reduce((a, b) => ({ ...a,\n...b }), {});\n }))\n : [];\n return [...resolvedExportColumnsValues, ...resolvedColumnsValues];\n }, [exportConfig?.additionalFields]);\n\n const doDownload = useCallback(async (collection: AdminCollection<M>,\n exportConfig: ExportConfig<any> | undefined) => {\n\n onAnalyticsEvent?.(\"export_collection\", {\n collection: collection.slug\n });\n setDataLoading(true);\n dataClient.collection(path).find({})\n .then(async (res) => {\n const data = res.data as Entity<M>[];\n setDataLoadingError(undefined);\n const additionalData = await fetchAdditionalFields(data);\n const additionalHeaders = [\n ...exportConfig?.additionalFields?.map(column => column.key) ?? [],\n ...collection.additionalFields?.map(field => field.key) ?? []\n ];\n\n const dataWithDefaults = includeUndefinedValues\n ? data.map(entity => {\n const defaultValues = getDefaultValuesFor(collection.properties);\n return {\n ...entity,\n values: { ...defaultValues,\n...entity.values }\n };\n })\n : data;\n downloadEntitiesExport({\n data: dataWithDefaults,\n additionalData,\n properties: collection.properties,\n propertiesOrder: collection.propertiesOrder,\n name: collection.name,\n flattenArrays,\n additionalHeaders,\n exportType,\n dateExportType\n });\n onAnalyticsEvent?.(\"export_collection_success\", {\n collection: collection.slug\n });\n })\n .catch((e) => {\n console.error(\"Error loading export data\", e);\n setDataLoadingError(e);\n })\n .finally(() => setDataLoading(false));\n\n }, [onAnalyticsEvent, dataClient, path, fetchAdditionalFields, includeUndefinedValues, flattenArrays, exportType, dateExportType]);\n\n const onOkClicked = useCallback(() => {\n doDownload(collection, exportConfig);\n handleClose();\n }, [doDownload, collection, exportConfig, handleClose]);\n\n return <>\n\n <Tooltip title={\"Export\"}\n asChild={true}>\n <IconButton\n size={\"small\"}\n color={\"primary\"}\n onClick={handleClickOpen}>\n <DownloadIcon size={iconSize.small}/>\n </IconButton>\n </Tooltip>\n\n <Dialog\n open={open}\n onOpenChange={setOpen}\n maxWidth={\"xl\"}>\n\n <DialogTitle variant={\"h6\"}>{t(\"export_data\")}</DialogTitle>\n\n <DialogContent className={\"flex flex-col gap-4 my-4\"}>\n\n <div>{t(\"download_table_csv\")}</div>\n\n {collectionEntitiesCount !== undefined && collectionEntitiesCount > DOCS_LIMIT &&\n <Alert color={\"warning\"}>\n <div>\n {t(\"large_number_of_documents\", { count: collectionEntitiesCount.toString() })}\n </div>\n </Alert>}\n\n <div className={\"flex flex-row gap-4\"}>\n <div className={\"p-4 flex flex-col\"}>\n <RadioGroup value={exportType} onValueChange={(v) => setExportType(v as \"csv\" | \"json\")}>\n <div className=\"flex items-center gap-2\">\n <RadioGroupItem value=\"csv\" id=\"radio-csv\"/>\n <Label htmlFor=\"radio-csv\">{t(\"csv\")}</Label>\n </div>\n <div className=\"flex items-center gap-2\">\n <RadioGroupItem value=\"json\" id=\"radio-json\"/>\n <Label htmlFor=\"radio-json\">{t(\"json\")}</Label>\n </div>\n </RadioGroup>\n </div>\n\n <div className={\"p-4 flex flex-col\"}>\n <RadioGroup value={dateExportType} onValueChange={(v) => setDateExportType(v as \"timestamp\" | \"string\")}>\n <div className=\"flex items-center gap-2\">\n <RadioGroupItem value=\"timestamp\" id=\"radio-timestamp\"/>\n <Label htmlFor=\"radio-timestamp\">{t(\"dates_as_timestamps\")} ({dateRef.current.getTime()})</Label>\n </div>\n <div className=\"flex items-center gap-2\">\n <RadioGroupItem value=\"string\" id=\"radio-string\"/>\n <Label htmlFor=\"radio-string\">{t(\"dates_as_strings\")} ({dateRef.current.toISOString()})</Label>\n </div>\n </RadioGroup>\n </div>\n </div>\n\n <BooleanSwitchWithLabel\n size={\"small\"}\n disabled={exportType !== \"csv\"}\n value={flattenArrays}\n onValueChange={setFlattenArrays}\n label={t(\"flatten_arrays\")}/>\n\n <BooleanSwitchWithLabel\n size={\"small\"}\n value={includeUndefinedValues}\n onValueChange={setIncludeUndefinedValues}\n label={t(\"include_undefined_values\")}/>\n\n {!canExport && notAllowedView}\n\n </DialogContent>\n\n <DialogActions>\n\n {dataLoading && <CircularProgress size={\"smallest\"}/>}\n\n <Button onClick={handleClose}\n variant={\"text\"}>\n {t(\"cancel\")}\n </Button>\n\n <Button onClick={onOkClicked}\n disabled={dataLoading || !canExport}>\n {t(\"download\")}\n </Button>\n\n </DialogActions>\n\n </Dialog>\n\n </>;\n}\n","export * from \"./export\";\nexport * from \"./BasicExportAction\";\nexport * from \"./ExportCollectionAction\";\n"],"mappings":"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"}
@@ -1,5 +1,21 @@
1
1
  import type { Property } from "@rebasepro/types";
2
+ import type { PropertySpan } from "@rebasepro/admin-types";
2
3
  import React from "react";
4
+ /**
5
+ * Grid placement for a span.
6
+ *
7
+ * Written out as literal class strings rather than composed, because Tailwind
8
+ * scans source text: a template literal would produce classes that exist at
9
+ * runtime and were never generated into the stylesheet.
10
+ *
11
+ * Below the column breakpoint every field takes the single available column, so
12
+ * the side panel, the dialog and mobile all get a plain stack.
13
+ *
14
+ * Lives here rather than in the form, because the read-only rendering of a
15
+ * record places its fields on the same grid — a record that changes shape when
16
+ * you press Edit is the bug this whole layout exists to avoid.
17
+ */
18
+ export declare function spanClass(span: PropertySpan): string;
3
19
  /**
4
20
  * Does this property's editor supply its own heading?
5
21
  *
@@ -13,18 +29,56 @@ import React from "react";
13
29
  * in step: the self-labelling types are exactly the ones that take a full row.
14
30
  */
15
31
  export declare function isSelfLabellingProperty(property: Property | undefined): boolean;
32
+ /**
33
+ * The type icon in a field label, in px.
34
+ *
35
+ * Matched to the label's 13px rather than taken from `iconSize.smallest` (16),
36
+ * which is sized for buttons. Exported so the surfaces that draw a label
37
+ * themselves — the additional-field cards, the rail — can stay in step.
38
+ */
39
+ export declare const LABEL_ICON_SIZE = 14;
16
40
  export interface FieldBlockProps {
17
41
  propertyKey: string;
18
42
  property?: Property;
19
43
  /** Rendered by the form rather than by the field, unless self-labelling. */
20
44
  showLabel: boolean;
45
+ /**
46
+ * Which of the two renderings this block frames.
47
+ *
48
+ * The **label is identical in both** — same size, same weight, same colour,
49
+ * same type icon, same required marker. A field is the same field whether or
50
+ * not you are editing it, and a record whose labels restyle themselves under
51
+ * Edit reads as two different screens.
52
+ *
53
+ * What `"read"` drops is the *description*, which is not part of the label:
54
+ * it is input help. "Sum of all line items before tax and shipping" under a
55
+ * number that is visibly a sum tells a reader nothing, and a line of it
56
+ * under every field is what a record has instead of room.
57
+ */
58
+ mode?: "edit" | "read";
59
+ /**
60
+ * Label text, when there is no property to take it from.
61
+ *
62
+ * For additional fields, which are columns a collection computes rather
63
+ * than stores. They go on the same grid as the properties and so have to
64
+ * carry the same label — drawing their own is how they ended up a size out
65
+ * and a couple of pixels off from the field beside them.
66
+ */
67
+ label?: string;
68
+ /** Type icon, when there is no property to derive one from. */
69
+ icon?: React.ReactNode;
21
70
  children: React.ReactNode;
22
71
  }
23
72
  /**
24
73
  * One field's worth of the form grid: label, control, description.
25
74
  *
26
- * The label carries a small type icon so a number reads differently from a
27
- * relation at a glance, and the description sits under the control where it
28
- * annotates what you just filled in.
75
+ * The same block frames the read-only rendering of a record, so a field sits in
76
+ * the same place, at the same width, under the same label whether or not you are
77
+ * editing it see {@link EntityViewBinding}.
78
+ *
79
+ * The label is one size down from the control it names (13px against the body's
80
+ * 14) with its icon matched to it at 14px. Labels are scaffolding: you read them
81
+ * to find the value, then read the value. Setting them at body size made a
82
+ * column of records scan as a column of field names with data attached.
29
83
  */
30
- export declare function FieldBlock({ propertyKey, property, showLabel, children }: FieldBlockProps): React.JSX.Element;
84
+ export declare function FieldBlock({ propertyKey, property, showLabel, mode, label, icon, children }: FieldBlockProps): React.JSX.Element;
@@ -16,3 +16,16 @@ export interface FormRailProps {
16
16
  * visible while you scroll.
17
17
  */
18
18
  export declare function FormRail({ fields, showRecordMeta, entity, renderField }: FormRailProps): React.JSX.Element | null;
19
+ /**
20
+ * The record's id and audit timestamps.
21
+ *
22
+ * Exported because the rail is not the only place it renders. The rail is shown
23
+ * only when it has been *measured* to fit, and every layout narrower than that —
24
+ * the split pane, the side panel, the dialog — folds its contents back into the
25
+ * column. The fields folded back but this block did not, so on three of the four
26
+ * layouts a record simply had no id on screen: the only copy of it was the
27
+ * truncated `e166a394…b422` chip in the identity bar.
28
+ */
29
+ export declare function RecordMeta({ entity }: {
30
+ entity: Entity<Record<string, unknown>>;
31
+ }): React.JSX.Element;
@@ -12,5 +12,19 @@ export interface FormSectionsProps {
12
12
  */
13
13
  errorKeys: ReadonlySet<string>;
14
14
  renderField: (field: ResolvedFormField) => React.ReactNode;
15
+ /**
16
+ * Which rendering this is. `"read"` opens the gaps up rather than closing
17
+ * them: a control is a bordered 40px box that separates itself from the next
18
+ * one, and a value is bare text that does not. The form can also afford
19
+ * tighter rows because a description usually sits between them; with that
20
+ * gone, the same numbers ran a record's values together into one block.
21
+ */
22
+ mode?: "edit" | "read";
23
+ /**
24
+ * Renders one field as a summary row, for a section that asked for
25
+ * `readVariant: "summary"`. Only the read view supplies it; without it such
26
+ * a section falls back to the grid rather than to nothing.
27
+ */
28
+ renderSummaryField?: (field: ResolvedFormField, index: number, total: number) => React.ReactNode;
15
29
  }
16
- export declare function FormSections({ sections, collapsed, onToggle, errorKeys, renderField }: FormSectionsProps): React.JSX.Element;
30
+ export declare function FormSections({ sections, collapsed, onToggle, errorKeys, renderField, mode, renderSummaryField }: FormSectionsProps): React.JSX.Element;
@@ -2,10 +2,11 @@ import React from "react";
2
2
  /**
3
3
  * Below this the form is a single column and the rail is not shown.
4
4
  *
5
- * Roughly the 288px rail plus a content column still wide enough to hold a
6
- * four-up row. Above it the rail is worth having even in the split view; below
7
- * it a narrow split pane, the side panel, the dialog, a phone its fields
8
- * fold back into the column.
5
+ * Roughly the 320px rail plus a content column still wide enough to hold a
6
+ * four-up row at the threshold that leaves ~680px, which is four columns of
7
+ * ~145px once the gutters are taken out. Above it the rail is worth having even
8
+ * in the split view; below it — a narrow split pane, the side panel, the dialog,
9
+ * a phone — its fields fold back into the column.
9
10
  */
10
11
  export declare const RAIL_MIN_WIDTH = 1000;
11
12
  /**