@rebasepro/admin 0.12.1-canary.gf5f1d39 → 0.13.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.
- package/README.md +1 -1
- package/dist/{CollectionEditorDialog-Dpc75wIZ.js → CollectionEditorDialog-CjXkWZ64.js} +75 -62
- package/dist/{CollectionEditorDialog-Dpc75wIZ.js.map → CollectionEditorDialog-CjXkWZ64.js.map} +1 -1
- package/dist/{PropertyEditView-DH3XZC2x.js → PropertyEditView-W8I3YV89.js} +36 -16
- package/dist/{PropertyEditView-DH3XZC2x.js.map → PropertyEditView-W8I3YV89.js.map} +1 -1
- package/dist/{RouterCollectionsStudioView-BZLq4MGp.js → RouterCollectionsStudioView-BsLTNoqX.js} +5 -5
- package/dist/{RouterCollectionsStudioView-BZLq4MGp.js.map → RouterCollectionsStudioView-BsLTNoqX.js.map} +1 -1
- package/dist/collection_editor/serializable_types.d.ts +4 -1
- package/dist/collection_editor/ui/collection_editor/CollectionRelationsTab.d.ts +1 -0
- package/dist/collection_editor/useLocalCollectionsConfigController.d.ts +8 -0
- package/dist/collection_editor_ui.js +5 -5
- package/dist/collection_editor_ui.js.map +1 -1
- package/dist/components/CollectionTableBinding/column_utils.d.ts +17 -0
- package/dist/components/CollectionViewBinding/CollectionViewStartActions.d.ts +7 -2
- package/dist/components/CollectionViewBinding/SortButton.d.ts +24 -0
- package/dist/components/CollectionViewBinding/SplitListCloseButton.d.ts +10 -0
- package/dist/components/CollectionViewBinding/SplitViewContext.d.ts +23 -0
- package/dist/components/CollectionViewBinding/hooks/useKanbanDragAndDrop.d.ts +26 -0
- package/dist/components/DetailViewBinding.d.ts +5 -0
- package/dist/components/EditFormActions.d.ts +12 -1
- package/dist/components/EditViewBinding.d.ts +6 -1
- package/dist/components/EntityIdentityBar.d.ts +53 -0
- package/dist/components/EntityInspector.d.ts +35 -0
- package/dist/components/EntityPreviewNesting.d.ts +25 -0
- package/dist/components/EntityViewBinding.d.ts +9 -0
- package/dist/components/InlineEntityPreview.d.ts +47 -0
- package/dist/components/history/EntityHistoryView.d.ts +4 -1
- package/dist/components/index.d.ts +2 -0
- package/dist/editor.js +18 -10
- package/dist/editor.js.map +1 -1
- package/dist/{export-BzIpUdSK.js → export-J79rMoNj.js} +2 -2
- package/dist/{export-BzIpUdSK.js.map → export-J79rMoNj.js.map} +1 -1
- package/dist/form/EntityForm.d.ts +1 -1
- package/dist/form/EntityFormActions.d.ts +11 -1
- package/dist/form/PropertyFieldBinding.d.ts +1 -1
- package/dist/form/components/FieldBlock.d.ts +30 -0
- package/dist/form/components/FormRail.d.ts +18 -0
- package/dist/form/components/FormSections.d.ts +16 -0
- package/dist/form/components/index.d.ts +3 -2
- package/dist/form/components/useRailVisible.d.ts +24 -0
- package/dist/form/field_bindings/BinaryFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/DateTimeFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/GeopointFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/MarkdownEditorFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/MultiSelectFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/ReadOnlyFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/SelectFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/SwitchFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/TextFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/UserSelectFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/VectorFieldBinding.d.ts +1 -1
- package/dist/{history-g9688IaK.js → history-D7L_JlLO.js} +35 -33
- package/dist/history-D7L_JlLO.js.map +1 -0
- package/dist/hooks/navigation/utils.d.ts +16 -0
- package/dist/hooks/useBuildSidePanel.d.ts +14 -0
- package/dist/hooks/useEntityDisplayTitle.d.ts +18 -0
- package/dist/hooks/useHistory.d.ts +7 -0
- package/dist/hooks/useRecordActions.d.ts +17 -0
- package/dist/{import-BjUG-cIY.js → import-BvYl--U4.js} +2 -2
- package/dist/{import-BjUG-cIY.js.map → import-BvYl--U4.js.map} +1 -1
- package/dist/index.js +106 -35
- package/dist/index.js.map +1 -1
- package/dist/markdown-CklalUUk.js.map +1 -1
- package/dist/preview/components/InlineEntityListPreview.d.ts +15 -0
- package/dist/preview/index.d.ts +1 -0
- package/dist/preview/property_previews/ArrayOfReferencesPreview.d.ts +1 -1
- package/dist/preview/property_previews/ArrayOfRelationsPreview.d.ts +1 -1
- package/dist/types/components/EntityFormActionsProps.d.ts +0 -1
- package/dist/types/components/EntityFormProps.d.ts +0 -5
- package/dist/types/fields.d.ts +24 -0
- package/dist/{util-B5fJm1FA.js → util-GiwPgxnL.js} +2106 -1117
- package/dist/util-GiwPgxnL.js.map +1 -0
- package/package.json +32 -34
- package/src/collection_editor/ConfigControllerProvider.tsx +1 -1
- package/src/collection_editor/serializable_types.ts +4 -3
- package/src/collection_editor/serializable_utils.ts +51 -17
- package/src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx +65 -22
- package/src/collection_editor/ui/collection_editor/CollectionRLSTab.tsx +38 -30
- package/src/collection_editor/ui/collection_editor/CollectionRelationsTab.tsx +3 -1
- package/src/collection_editor/ui/collection_editor/RouterCollectionStudioView.tsx +1 -1
- package/src/collection_editor/ui/collection_editor/RouterCollectionsStudioView.tsx +1 -1
- package/src/collection_editor/ui/collection_editor/properties/RelationPropertyField.tsx +16 -0
- package/src/collection_editor/useLocalCollectionsConfigController.tsx +127 -15
- package/src/collection_editor/validateCollectionJson.ts +3 -3
- package/src/components/AdminModeSyncer.tsx +1 -1
- package/src/components/CollectionTableBinding/PropertyTableCell.tsx +10 -2
- package/src/components/CollectionTableBinding/column_utils.tsx +59 -2
- package/src/components/CollectionTableBinding/table_bindings.tsx +2 -1
- package/src/components/CollectionViewBinding/CollectionBoardViewBinding.tsx +23 -16
- package/src/components/CollectionViewBinding/CollectionViewActions.tsx +7 -1
- package/src/components/CollectionViewBinding/CollectionViewBinding.tsx +9 -2
- package/src/components/CollectionViewBinding/CollectionViewStartActions.tsx +47 -12
- package/src/components/CollectionViewBinding/SortButton.tsx +189 -0
- package/src/components/CollectionViewBinding/SplitListCloseButton.tsx +33 -0
- package/src/components/CollectionViewBinding/SplitListView.tsx +18 -3
- package/src/components/CollectionViewBinding/SplitViewContext.tsx +34 -0
- package/src/components/CollectionViewBinding/hooks/useKanbanDragAndDrop.ts +48 -9
- package/src/components/CollectionViewBinding/useBoardDataController.tsx +80 -25
- package/src/components/CollectionViewBinding/usePreviewSlots.ts +18 -6
- package/src/components/DefaultAppBar.tsx +1 -1
- package/src/components/DefaultDrawer.tsx +1 -1
- package/src/components/DetailViewBinding.tsx +112 -148
- package/src/components/DrawerNavigationItem.tsx +1 -1
- package/src/components/EditFormActions.tsx +54 -129
- package/src/components/EditViewBinding.tsx +202 -99
- package/src/components/EntityIdentityBar.tsx +288 -0
- package/src/components/EntityInspector.tsx +137 -0
- package/src/components/EntityPreviewBinding.tsx +6 -2
- package/src/components/EntityPreviewNesting.tsx +50 -0
- package/src/components/EntityViewBinding.tsx +35 -32
- package/src/components/HomePage/FavouritesView.tsx +1 -1
- package/src/components/HomePage/NavigationCardBinding.tsx +1 -1
- package/src/components/HomePage/SmallNavigationCard.tsx +1 -1
- package/src/components/InlineEntityPreview.tsx +149 -0
- package/src/components/RebaseLayout.tsx +1 -1
- package/src/components/RebaseNavigation.tsx +45 -5
- package/src/components/RebaseRouteDefs.tsx +1 -1
- package/src/components/SelectableTable/SelectableTable.tsx +2 -2
- package/src/components/SidePanelBinding.tsx +19 -13
- package/src/components/UserSelector.tsx +12 -6
- package/src/components/common/default_entity_actions.tsx +4 -3
- package/src/components/history/EntityHistoryEntry.tsx +28 -7
- package/src/components/history/EntityHistoryView.tsx +29 -24
- package/src/components/history/LastEditedByIndicator.tsx +4 -3
- package/src/components/index.ts +2 -0
- package/src/data_import/utils/get_import_inference_type.ts +6 -0
- package/src/form/EntityForm.tsx +267 -179
- package/src/form/EntityFormActions.tsx +50 -99
- package/src/form/EntityFormBinding.tsx +4 -2
- package/src/form/PropertyFieldBinding.tsx +4 -0
- package/src/form/components/FieldBlock.tsx +119 -0
- package/src/form/components/FormRail.tsx +125 -0
- package/src/form/components/FormSections.tsx +118 -0
- package/src/form/components/index.tsx +3 -2
- package/src/form/components/useRailVisible.tsx +46 -0
- package/src/form/field_bindings/BinaryFieldBinding.tsx +3 -2
- package/src/form/field_bindings/DateTimeFieldBinding.tsx +3 -2
- package/src/form/field_bindings/GeopointFieldBinding.tsx +3 -2
- package/src/form/field_bindings/MapFieldBinding.tsx +1 -2
- package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +3 -2
- package/src/form/field_bindings/MultiSelectFieldBinding.tsx +2 -1
- package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +2 -1
- package/src/form/field_bindings/ReferenceFieldBinding.tsx +2 -1
- package/src/form/field_bindings/RelationFieldBinding.tsx +6 -4
- package/src/form/field_bindings/RepeatFieldBinding.tsx +4 -1
- package/src/form/field_bindings/SelectFieldBinding.tsx +3 -2
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +31 -8
- package/src/form/field_bindings/SwitchFieldBinding.tsx +7 -3
- package/src/form/field_bindings/TextFieldBinding.tsx +18 -16
- package/src/form/field_bindings/UserSelectFieldBinding.tsx +3 -2
- package/src/form/field_bindings/VectorFieldBinding.tsx +2 -1
- package/src/hooks/navigation/useBuildUrlController.tsx +1 -1
- package/src/hooks/navigation/useTopLevelNavigation.ts +18 -7
- package/src/hooks/navigation/utils.ts +20 -0
- package/src/hooks/useBuildSideDialogsController.tsx +2 -2
- package/src/hooks/useBuildSidePanel.tsx +22 -61
- package/src/hooks/useEntityDisplayTitle.tsx +60 -0
- package/src/hooks/useHistory.ts +20 -10
- package/src/hooks/useRecordActions.tsx +69 -0
- package/src/hooks/useResolvedUsers.ts +10 -5
- package/src/preview/PropertyPreview.tsx +48 -22
- package/src/preview/components/InlineEntityListPreview.tsx +42 -0
- package/src/preview/components/ReferencePreview.tsx +34 -14
- package/src/preview/components/RelationPreview.tsx +34 -14
- package/src/preview/index.ts +1 -0
- package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +24 -1
- package/src/preview/property_previews/ArrayOfRelationsPreview.tsx +25 -1
- package/src/routes/RebaseRoute.tsx +2 -2
- package/src/types/components/EntityFormActionsProps.tsx +0 -1
- package/src/types/components/EntityFormProps.tsx +0 -6
- package/src/types/fields.tsx +27 -0
- package/dist/form/components/FormEntry.d.ts +0 -6
- package/dist/form/components/FormLayout.d.ts +0 -5
- package/dist/history-g9688IaK.js.map +0 -1
- package/dist/util-B5fJm1FA.js.map +0 -1
- package/src/form/components/FormEntry.tsx +0 -22
- package/src/form/components/FormLayout.tsx +0 -16
|
@@ -8,6 +8,9 @@ import { PluginProviderStack, resolveComponentRef, useComponentOverride, Collect
|
|
|
8
8
|
|
|
9
9
|
import { CollectionViewBinding } from "./CollectionViewBinding/CollectionViewBinding";
|
|
10
10
|
import { EntityViewBinding } from "./EntityViewBinding";
|
|
11
|
+
import { EntityIdentityBar } from "./EntityIdentityBar";
|
|
12
|
+
import { SplitListCloseButton } from "./CollectionViewBinding/SplitListCloseButton";
|
|
13
|
+
import { EntityInspector, InspectorTab } from "./EntityInspector";
|
|
11
14
|
import { CircularProgressCenter, iconSize } from "@rebasepro/ui";
|
|
12
15
|
import {
|
|
13
16
|
Alert,
|
|
@@ -41,13 +44,11 @@ import {
|
|
|
41
44
|
} from "@rebasepro/app";
|
|
42
45
|
import { useUrlController } from "../hooks/navigation/contexts/UrlContext";
|
|
43
46
|
import { useCollectionRegistryController } from "../hooks/navigation/contexts/CollectionRegistryContext";
|
|
44
|
-
import { useNavigate } from "react-router
|
|
47
|
+
import { useNavigate } from "react-router";
|
|
45
48
|
import { getValueInPath } from "@rebasepro/utils";
|
|
46
49
|
import { getEntityTitlePropertyKeyForEntity, isUserSelectProperty, resolveTitleToString } from "../util/previews";
|
|
47
50
|
import { getUserLabel, useResolvedUser } from "../hooks/useResolvedUsers";
|
|
48
|
-
import { JsonPreviewBinding } from "../components/JsonPreviewBinding";
|
|
49
51
|
|
|
50
|
-
const EntityHistoryView = lazy(() => import("../components/history").then(m => ({ default: m.EntityHistoryView })));
|
|
51
52
|
|
|
52
53
|
import { MAIN_TAB_VALUE, JSON_TAB_VALUE, HISTORY_TAB_VALUE } from "../util/view_constants";
|
|
53
54
|
|
|
@@ -76,6 +77,11 @@ export interface DetailViewBindingProps<M extends Record<string, unknown> = Reco
|
|
|
76
77
|
onEditClick?: () => void;
|
|
77
78
|
layout?: "side_panel" | "full_screen" | "split" | "dialog";
|
|
78
79
|
barActions?: (params: BarActionsParams) => React.ReactNode;
|
|
80
|
+
/**
|
|
81
|
+
* Controls the owning panel puts at the identity bar's leading edge, ahead
|
|
82
|
+
* of the breadcrumb — the side panel's close button.
|
|
83
|
+
*/
|
|
84
|
+
barActionsStart?: React.ReactNode;
|
|
79
85
|
}
|
|
80
86
|
|
|
81
87
|
export function DetailViewBinding<M extends Record<string, unknown>>({
|
|
@@ -134,7 +140,8 @@ function DetailViewBindingInner<M extends Record<string, unknown>>({
|
|
|
134
140
|
entity,
|
|
135
141
|
dataLoading,
|
|
136
142
|
layout = "full_screen",
|
|
137
|
-
barActions
|
|
143
|
+
barActions,
|
|
144
|
+
barActionsStart
|
|
138
145
|
}: DetailViewBindingProps<M> & {
|
|
139
146
|
entity?: Entity<M>,
|
|
140
147
|
dataLoading: boolean,
|
|
@@ -189,7 +196,18 @@ entityId }
|
|
|
189
196
|
const customViewsCount = customViews?.length ?? 0;
|
|
190
197
|
const includeJsonView = collection.includeJsonView === undefined ? true : collection.includeJsonView;
|
|
191
198
|
const includeHistoryView = Boolean(collection.history);
|
|
192
|
-
|
|
199
|
+
// Same split as the edit view: the strip is for destinations, the inspector
|
|
200
|
+
// for the developer tools that used to sit in front of them.
|
|
201
|
+
const hasAdditionalViews = customViewsCount > 0 || subcollectionsCount > 0;
|
|
202
|
+
|
|
203
|
+
const [inspectorTab, setInspectorTab] = useState<InspectorTab | null>(null);
|
|
204
|
+
|
|
205
|
+
const legacyInspectorTab: InspectorTab | undefined = selectedTab === JSON_TAB_VALUE
|
|
206
|
+
? "json"
|
|
207
|
+
: selectedTab === HISTORY_TAB_VALUE ? "history" : undefined;
|
|
208
|
+
useEffect(() => {
|
|
209
|
+
if (legacyInspectorTab) setInspectorTab(legacyInspectorTab);
|
|
210
|
+
}, [legacyInspectorTab]);
|
|
193
211
|
|
|
194
212
|
const {
|
|
195
213
|
resolvedEntityViews
|
|
@@ -198,13 +216,11 @@ entityId }
|
|
|
198
216
|
const validTabValues = useMemo(() => {
|
|
199
217
|
const set = new Set<string>([
|
|
200
218
|
MAIN_TAB_VALUE,
|
|
201
|
-
...(includeJsonView ? [JSON_TAB_VALUE] : []),
|
|
202
|
-
...(includeHistoryView ? [HISTORY_TAB_VALUE] : []),
|
|
203
219
|
...resolvedEntityViews.map(v => v.key),
|
|
204
220
|
...subcollections.map(s => s.slug)
|
|
205
221
|
]);
|
|
206
222
|
return set;
|
|
207
|
-
}, [
|
|
223
|
+
}, [resolvedEntityViews, subcollections]);
|
|
208
224
|
|
|
209
225
|
const activeTab = validTabValues.has(selectedTab) ? selectedTab : MAIN_TAB_VALUE;
|
|
210
226
|
|
|
@@ -321,35 +337,6 @@ entityId }
|
|
|
321
337
|
|
|
322
338
|
const globalLoading = dataLoading && !usedEntity;
|
|
323
339
|
|
|
324
|
-
// JSON view
|
|
325
|
-
const jsonTabMounted = mountedTabsRef.current.has(JSON_TAB_VALUE);
|
|
326
|
-
const jsonView = (activeTab === JSON_TAB_VALUE || jsonTabMounted) ? <div
|
|
327
|
-
className={cls("relative flex-1 h-full overflow-auto w-full",
|
|
328
|
-
{ "hidden": activeTab !== JSON_TAB_VALUE })}
|
|
329
|
-
key={"json_view"}
|
|
330
|
-
role="tabpanel">
|
|
331
|
-
<ErrorBoundary>
|
|
332
|
-
<JsonPreviewBinding values={usedEntity?.values ?? {}} />
|
|
333
|
-
</ErrorBoundary>
|
|
334
|
-
</div> : null;
|
|
335
|
-
|
|
336
|
-
// History view
|
|
337
|
-
const historyView = includeHistoryView && activeTab === HISTORY_TAB_VALUE ? <div
|
|
338
|
-
className={"relative flex-1 h-full overflow-auto w-full"}
|
|
339
|
-
key={"history_view"}
|
|
340
|
-
role="tabpanel">
|
|
341
|
-
<ErrorBoundary>
|
|
342
|
-
<Suspense fallback={<CircularProgressCenter />}>
|
|
343
|
-
<EntityHistoryView
|
|
344
|
-
collection={collection}
|
|
345
|
-
entity={usedEntity}
|
|
346
|
-
formContext={readOnlyFormContext as FormContext<Record<string, unknown>>}
|
|
347
|
-
modifiedValues={usedEntity?.values}
|
|
348
|
-
/>
|
|
349
|
-
</Suspense>
|
|
350
|
-
</ErrorBoundary>
|
|
351
|
-
</div> : null;
|
|
352
|
-
|
|
353
340
|
// Subcollection views
|
|
354
341
|
const subCollectionsViews = childViews && childViews.map(({ collection: subcollection }) => {
|
|
355
342
|
const subcollectionId = subcollection.slug;
|
|
@@ -490,7 +477,9 @@ entityId }
|
|
|
490
477
|
|
|
491
478
|
const shouldShowTopBar = Boolean(barActions) || hasAdditionalViews || layout === "side_panel" || layout === "dialog" || Boolean(backToCollectionButton);
|
|
492
479
|
|
|
493
|
-
const fullScreenButton = !barActions &&
|
|
480
|
+
const fullScreenButton = !barActions && // Not in split: the list panel beside it carries the close control,
|
|
481
|
+
// and an expand button there competes with it.
|
|
482
|
+
(layout === "side_panel" || layout === "dialog") && entityId ? (
|
|
494
483
|
<Tooltip title={"Open full screen"}>
|
|
495
484
|
<IconButton
|
|
496
485
|
size="small"
|
|
@@ -516,130 +505,105 @@ entityId }
|
|
|
516
505
|
</Button>
|
|
517
506
|
) : null;
|
|
518
507
|
|
|
519
|
-
// Main content view
|
|
508
|
+
// Main content view. The title, the `path/id` chip and the empty band under
|
|
509
|
+
// them have moved into the identity bar, and the `w-80 2xl:w-96` rail that
|
|
510
|
+
// held a single Edit button is gone — the bar holds it now.
|
|
520
511
|
const mainView = <div
|
|
521
512
|
className={cls(
|
|
522
513
|
"flex-1 flex flex-row w-full overflow-y-auto justify-center",
|
|
523
514
|
!mainViewVisible ? "hidden" : ""
|
|
524
515
|
)}>
|
|
525
|
-
<div
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
"
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
)}>
|
|
533
|
-
{/* Title and entity path */}
|
|
534
|
-
<div className={"w-full flex flex-col items-start my-4 lg:my-6"}>
|
|
535
|
-
<div className="flex items-center justify-between w-full">
|
|
536
|
-
<Typography
|
|
537
|
-
className={cls("my-4 grow line-clamp-1", collection.hideIdFromForm ? "mb-6" : "")}
|
|
538
|
-
variant={"h4"}>
|
|
539
|
-
{title}
|
|
540
|
-
</Typography>
|
|
541
|
-
{editButton}
|
|
542
|
-
</div>
|
|
543
|
-
|
|
544
|
-
<Alert color={"base"} outerClassName={"w-full"} size={"small"}>
|
|
545
|
-
<code
|
|
546
|
-
className={"text-xs select-all text-text-secondary dark:text-text-secondary-dark"}>
|
|
547
|
-
{usedEntity?.path ?? path}/{entityId}
|
|
548
|
-
</code>
|
|
549
|
-
</Alert>
|
|
550
|
-
</div>
|
|
551
|
-
|
|
552
|
-
{/* Property detail display */}
|
|
553
|
-
<div className="mt-12 flex flex-col gap-8">
|
|
554
|
-
{propertyDetailView()}
|
|
555
|
-
</div>
|
|
556
|
-
|
|
557
|
-
<div className="h-16" />
|
|
558
|
-
</div>
|
|
559
|
-
|
|
560
|
-
{/* Side action bar for large screens */}
|
|
561
|
-
{canEdit && onEditClick && layout === "full_screen" && <div
|
|
562
|
-
className={cls(
|
|
563
|
-
"overflow-auto h-full hidden @6xl:flex flex-col gap-2 w-80 2xl:w-96 px-4 py-16 sticky top-0 border-l",
|
|
564
|
-
defaultBorderMixin
|
|
565
|
-
)}>
|
|
566
|
-
<Button
|
|
567
|
-
fullWidth={true}
|
|
568
|
-
variant="filled"
|
|
569
|
-
color="primary"
|
|
570
|
-
startIcon={<PencilIcon size={iconSize.small} />}
|
|
571
|
-
onClick={onEditClick}>
|
|
572
|
-
{t("edit_entity")}
|
|
573
|
-
</Button>
|
|
574
|
-
</div>}
|
|
516
|
+
<div className={cls(
|
|
517
|
+
"w-full max-w-3xl 2xl:max-w-4xl flex flex-col",
|
|
518
|
+
layout === "dialog"
|
|
519
|
+
? "pt-5 pb-12 px-6 sm:px-8"
|
|
520
|
+
: "pt-6 pb-16 px-5 sm:px-8"
|
|
521
|
+
)}>
|
|
522
|
+
{propertyDetailView()}
|
|
575
523
|
</div>
|
|
576
524
|
</div>;
|
|
577
525
|
|
|
578
526
|
let result = <div className="relative flex flex-col h-full w-full bg-white dark:bg-surface-800">
|
|
579
527
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
{
|
|
584
|
-
|
|
585
|
-
{
|
|
586
|
-
|
|
587
|
-
{
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
528
|
+
<EntityIdentityBar
|
|
529
|
+
collection={collection as AdminCollection}
|
|
530
|
+
title={title}
|
|
531
|
+
entityId={entityId}
|
|
532
|
+
status={"existing"}
|
|
533
|
+
dirty={false}
|
|
534
|
+
saving={false}
|
|
535
|
+
onInspect={includeJsonView ? () => setInspectorTab("json") : undefined}
|
|
536
|
+
onViewHistory={includeHistoryView ? () => setInspectorTab("history") : undefined}
|
|
537
|
+
leading={<>
|
|
538
|
+
{barActionsStart}
|
|
539
|
+
{/* Split view: closing the list is opening this record
|
|
540
|
+
full screen, and the control for it belongs at this
|
|
541
|
+
bar's leading edge. */}
|
|
542
|
+
{layout === "split" && <SplitListCloseButton/>}
|
|
543
|
+
</>}
|
|
544
|
+
trailing={<>
|
|
545
|
+
{editButton}
|
|
546
|
+
{pluginActionsTop}
|
|
547
|
+
{backToCollectionButton}
|
|
548
|
+
{fullScreenButton}
|
|
549
|
+
{barActions?.({
|
|
550
|
+
path,
|
|
551
|
+
entityId,
|
|
552
|
+
values: usedEntity?.values ?? {},
|
|
553
|
+
status: "existing"
|
|
554
|
+
})}
|
|
555
|
+
</>}
|
|
556
|
+
/>
|
|
557
|
+
|
|
558
|
+
{hasAdditionalViews && <div className={cls(
|
|
559
|
+
"h-10 shrink-0 flex items-stretch border-b px-2 min-w-0",
|
|
560
|
+
defaultBorderMixin
|
|
561
|
+
)}>
|
|
562
|
+
<Tabs
|
|
563
|
+
className={"!w-full"}
|
|
564
|
+
innerClassName={"h-full"}
|
|
565
|
+
variant={"boxy"}
|
|
566
|
+
value={activeTab}
|
|
567
|
+
onValueChange={(value) => {
|
|
568
|
+
onSideTabClick(value);
|
|
569
|
+
}}>
|
|
570
|
+
|
|
571
|
+
<Tab value={MAIN_TAB_VALUE}>
|
|
572
|
+
<span className="flex items-center gap-1.5">
|
|
573
|
+
{getIcon(collection.icon, undefined, undefined, "smallest")}
|
|
574
|
+
{collection.singularName ?? collection.name}
|
|
575
|
+
</span>
|
|
576
|
+
</Tab>
|
|
627
577
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
</div>}
|
|
578
|
+
{customViewTabsStart}
|
|
579
|
+
{customViewTabsEnd}
|
|
580
|
+
{subcollectionTabs}
|
|
581
|
+
</Tabs>
|
|
633
582
|
</div>}
|
|
634
583
|
|
|
635
|
-
{
|
|
636
|
-
|
|
637
|
-
|
|
584
|
+
{/* See EditViewBinding: the inspector docks beside the record rather
|
|
585
|
+
than over it, so the record stays readable and scrollable. */}
|
|
586
|
+
<div className={"flex-1 min-h-0 flex"}>
|
|
587
|
+
|
|
588
|
+
<div className={"flex-1 min-w-0 flex flex-col"}>
|
|
589
|
+
{globalLoading
|
|
590
|
+
? <DetailViewSkeleton collection={collection} />
|
|
591
|
+
: mainView}
|
|
638
592
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
593
|
+
{customViewsView}
|
|
594
|
+
{subCollectionsViews}
|
|
595
|
+
</div>
|
|
596
|
+
|
|
597
|
+
<EntityInspector
|
|
598
|
+
tab={inspectorTab}
|
|
599
|
+
onTabChange={setInspectorTab}
|
|
600
|
+
onClose={() => setInspectorTab(null)}
|
|
601
|
+
collection={collection as AdminCollection}
|
|
602
|
+
entity={usedEntity as Entity<Record<string, unknown>> | undefined}
|
|
603
|
+
formContext={readOnlyFormContext as FormContext<Record<string, unknown>> | undefined}
|
|
604
|
+
values={usedEntity?.values}
|
|
605
|
+
includeHistory={includeHistoryView}/>
|
|
606
|
+
</div>
|
|
643
607
|
|
|
644
608
|
</div>;
|
|
645
609
|
|
|
@@ -24,11 +24,21 @@ import { getIcon } from "@rebasepro/app";
|
|
|
24
24
|
import { useAdminContext } from "../hooks/useAdminContext";
|
|
25
25
|
import { useChildViewSource } from "../hooks/useChildViewSource";
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* The entity form's footer.
|
|
29
|
+
*
|
|
30
|
+
* It used to render in two shapes: this footer, and a `w-80 2xl:w-96` sticky
|
|
31
|
+
* side rail carrying the same Save and Discard above several hundred pixels of
|
|
32
|
+
* nothing. The rail is gone, and Save/Discard have moved to the identity bar
|
|
33
|
+
* where they stay visible while the form scrolls — so with
|
|
34
|
+
* `showDefaultActions={false}` this renders only what the bar cannot host:
|
|
35
|
+
* record actions (copy, delete, custom), plugin actions, the saving error, and
|
|
36
|
+
* the side-panel-only "save and close".
|
|
37
|
+
*/
|
|
27
38
|
export function EditFormActions({
|
|
28
39
|
collection,
|
|
29
40
|
path,
|
|
30
41
|
entity,
|
|
31
|
-
layout,
|
|
32
42
|
savingError,
|
|
33
43
|
formex,
|
|
34
44
|
disabled,
|
|
@@ -69,10 +79,11 @@ export function EditFormActions({
|
|
|
69
79
|
return actions;
|
|
70
80
|
}, [canCreate, canDelete, collection, path, customizationController.entityActions?.length, entity, collection.disableDefaultActions, isLinkedChildView]);
|
|
71
81
|
|
|
72
|
-
|
|
82
|
+
// Record actions stay in the footer whether or not the bar carries Save;
|
|
83
|
+
// they are things you do *to* the record, not ways to leave the form.
|
|
84
|
+
const formActions = entityActions.filter(a => a.includeInForm === undefined || a.includeInForm);
|
|
73
85
|
|
|
74
|
-
|
|
75
|
-
const bottomActions = buildBottomActions({
|
|
86
|
+
return buildBottomActions({
|
|
76
87
|
savingError,
|
|
77
88
|
entity,
|
|
78
89
|
formActions,
|
|
@@ -88,36 +99,8 @@ export function EditFormActions({
|
|
|
88
99
|
formContext,
|
|
89
100
|
formex,
|
|
90
101
|
t,
|
|
91
|
-
|
|
102
|
+
showDefaultActions
|
|
92
103
|
});
|
|
93
|
-
|
|
94
|
-
const sideActions = buildSideActions({
|
|
95
|
-
savingError,
|
|
96
|
-
entity,
|
|
97
|
-
formActions,
|
|
98
|
-
collection,
|
|
99
|
-
context,
|
|
100
|
-
sidePanelController,
|
|
101
|
-
sideDialogContext,
|
|
102
|
-
disabled,
|
|
103
|
-
status,
|
|
104
|
-
pluginActions,
|
|
105
|
-
openEntityMode,
|
|
106
|
-
navigateBack,
|
|
107
|
-
formContext,
|
|
108
|
-
formex,
|
|
109
|
-
t,
|
|
110
|
-
className: layout === "responsive" ? "hidden @6xl:flex" : undefined
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
if (layout === "responsive") {
|
|
114
|
-
return <>
|
|
115
|
-
{bottomActions}
|
|
116
|
-
{sideActions}
|
|
117
|
-
</>;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return layout === "bottom" ? bottomActions : sideActions;
|
|
121
104
|
}
|
|
122
105
|
|
|
123
106
|
type ActionsViewProps<M extends Record<string, unknown>> = {
|
|
@@ -136,6 +119,7 @@ type ActionsViewProps<M extends Record<string, unknown>> = {
|
|
|
136
119
|
formContext: FormContext,
|
|
137
120
|
formex: FormexController<Record<string, unknown>>;
|
|
138
121
|
t: (key: string, vars?: Record<string, string>) => string;
|
|
122
|
+
showDefaultActions: boolean;
|
|
139
123
|
className?: string;
|
|
140
124
|
};
|
|
141
125
|
|
|
@@ -155,14 +139,28 @@ function buildBottomActions<M extends Record<string, unknown>>({
|
|
|
155
139
|
formContext,
|
|
156
140
|
formex,
|
|
157
141
|
t,
|
|
142
|
+
showDefaultActions,
|
|
158
143
|
className
|
|
159
144
|
}: ActionsViewProps<M>) {
|
|
160
145
|
|
|
161
146
|
const hasErrors = Object.keys(formex.errors).length > 0 && formex.submitCount > 0;
|
|
147
|
+
// "Save and close" only means something where there is something to close.
|
|
162
148
|
const canClose = openEntityMode === "side_panel" || openEntityMode === "dialog";
|
|
149
|
+
const showBackToDetail = collection.defaultEntityAction === "view" && status === "existing";
|
|
150
|
+
|
|
151
|
+
// When the container carries the actions — the entity view's identity bar
|
|
152
|
+
// does — this renders nothing at all. A full-width bar holding a copy icon
|
|
153
|
+
// and a delete icon is the same waste as the side rail it replaced: the
|
|
154
|
+
// record actions moved into the bar's overflow menu, and Save, Discard and
|
|
155
|
+
// "save and close" are buttons up there too.
|
|
156
|
+
const hasContent = showDefaultActions || Boolean(savingError);
|
|
157
|
+
|
|
158
|
+
if (!hasContent) return null;
|
|
159
|
+
|
|
163
160
|
return <DialogActions
|
|
164
161
|
className={className}
|
|
165
|
-
|
|
162
|
+
// In normal flow at the foot of the form column, not overlaying it.
|
|
163
|
+
position={"sticky"}>
|
|
166
164
|
{savingError &&
|
|
167
165
|
<div className="text-right">
|
|
168
166
|
<Typography color={"error"}>{savingError.message}</Typography>
|
|
@@ -202,13 +200,8 @@ function buildBottomActions<M extends Record<string, unknown>>({
|
|
|
202
200
|
<ErrorTooltip title={"This form has errors"}>
|
|
203
201
|
<AlertCircleIcon className="ml-4 text-red-500" size={iconSize.smallest}/>
|
|
204
202
|
</ErrorTooltip> : null}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
disabled={disabled || formex.isSubmitting}
|
|
208
|
-
type="reset">
|
|
209
|
-
{status === "existing" ? t("discard") : t("clear")}
|
|
210
|
-
</Button>
|
|
211
|
-
{collection.defaultEntityAction === "view" && status === "existing" && (
|
|
203
|
+
|
|
204
|
+
{showBackToDetail && (
|
|
212
205
|
<Button variant="text"
|
|
213
206
|
color="primary"
|
|
214
207
|
disabled={disabled}
|
|
@@ -216,19 +209,29 @@ function buildBottomActions<M extends Record<string, unknown>>({
|
|
|
216
209
|
{t("back_to_detail") ?? "Back to details"}
|
|
217
210
|
</Button>
|
|
218
211
|
)}
|
|
219
|
-
|
|
220
|
-
|
|
212
|
+
|
|
213
|
+
{showDefaultActions && <>
|
|
214
|
+
<Button variant="text"
|
|
221
215
|
color="primary"
|
|
222
|
-
type="submit"
|
|
223
216
|
disabled={disabled || formex.isSubmitting}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
}}>
|
|
227
|
-
{status === "existing" && t("save")}
|
|
228
|
-
{status === "copy" && t("create_copy")}
|
|
229
|
-
{status === "new" && t("create")}
|
|
217
|
+
type="reset">
|
|
218
|
+
{status === "existing" ? t("discard") : t("clear")}
|
|
230
219
|
</Button>
|
|
231
|
-
|
|
220
|
+
<Tooltip title={hasErrors ? (t("fix_errors_before_saving") ?? "Fix highlighted errors before saving") : undefined}>
|
|
221
|
+
<Button variant={canClose ? "text" : "filled"}
|
|
222
|
+
color="primary"
|
|
223
|
+
type="submit"
|
|
224
|
+
disabled={disabled || formex.isSubmitting}
|
|
225
|
+
onClick={() => {
|
|
226
|
+
sideDialogContext.setPendingClose(false);
|
|
227
|
+
}}>
|
|
228
|
+
{status === "existing" && t("save")}
|
|
229
|
+
{status === "copy" && t("create_copy")}
|
|
230
|
+
{status === "new" && t("create")}
|
|
231
|
+
</Button>
|
|
232
|
+
</Tooltip>
|
|
233
|
+
</>}
|
|
234
|
+
|
|
232
235
|
{canClose && <LoadingButton variant="filled"
|
|
233
236
|
color="primary"
|
|
234
237
|
type="submit"
|
|
@@ -244,84 +247,6 @@ function buildBottomActions<M extends Record<string, unknown>>({
|
|
|
244
247
|
</DialogActions>;
|
|
245
248
|
}
|
|
246
249
|
|
|
247
|
-
function buildSideActions<M extends Record<string, unknown>>({
|
|
248
|
-
savingError,
|
|
249
|
-
entity,
|
|
250
|
-
formActions,
|
|
251
|
-
collection,
|
|
252
|
-
context,
|
|
253
|
-
sidePanelController,
|
|
254
|
-
disabled,
|
|
255
|
-
status,
|
|
256
|
-
sideDialogContext,
|
|
257
|
-
pluginActions,
|
|
258
|
-
openEntityMode,
|
|
259
|
-
navigateBack,
|
|
260
|
-
formContext,
|
|
261
|
-
formex,
|
|
262
|
-
t,
|
|
263
|
-
className
|
|
264
|
-
}: ActionsViewProps<M>) {
|
|
265
|
-
|
|
266
|
-
const hasErrors = Object.keys(formex.errors).length > 0 && formex.submitCount > 0;
|
|
267
|
-
return <div
|
|
268
|
-
className={cls("overflow-auto h-full flex flex-col gap-2 w-80 2xl:w-96 px-4 py-16 sticky top-0 border-l", defaultBorderMixin, className)}>
|
|
269
|
-
<Tooltip title={hasErrors ? (t("fix_errors_before_saving") ?? "Fix highlighted errors before saving") : undefined}>
|
|
270
|
-
<LoadingButton fullWidth={true}
|
|
271
|
-
variant="filled"
|
|
272
|
-
color="primary"
|
|
273
|
-
type="submit"
|
|
274
|
-
loading={formex.isSubmitting}
|
|
275
|
-
startIcon={hasErrors ? <AlertCircleIcon/> : undefined}
|
|
276
|
-
disabled={disabled || formex.isSubmitting}
|
|
277
|
-
onClick={() => {
|
|
278
|
-
sideDialogContext.setPendingClose?.(false);
|
|
279
|
-
}}>
|
|
280
|
-
{status === "existing" && t("save")}
|
|
281
|
-
{status === "copy" && t("create_copy")}
|
|
282
|
-
{status === "new" && t("create")}
|
|
283
|
-
</LoadingButton>
|
|
284
|
-
</Tooltip>
|
|
285
|
-
|
|
286
|
-
<Button fullWidth={true} variant="text" disabled={disabled || formex.isSubmitting} type="reset">
|
|
287
|
-
{status === "existing" ? t("discard") : t("clear")}
|
|
288
|
-
</Button>
|
|
289
|
-
{collection.defaultEntityAction === "view" && status === "existing" && (
|
|
290
|
-
<Button fullWidth={true} variant="text" disabled={disabled} onClick={navigateBack}>
|
|
291
|
-
{t("back_to_detail") ?? "Back to details"}
|
|
292
|
-
</Button>
|
|
293
|
-
)}
|
|
294
|
-
|
|
295
|
-
{pluginActions}
|
|
296
|
-
|
|
297
|
-
{formActions.length > 0 && <div className="flex flex-row flex-wrap mt-2">
|
|
298
|
-
{formActions.map((action, index) => {
|
|
299
|
-
const props = {
|
|
300
|
-
view: "form",
|
|
301
|
-
entity,
|
|
302
|
-
path: getCollectionDataPath(collection),
|
|
303
|
-
collection: collection,
|
|
304
|
-
context,
|
|
305
|
-
sidePanelController,
|
|
306
|
-
openEntityMode,
|
|
307
|
-
navigateBack,
|
|
308
|
-
formContext
|
|
309
|
-
} satisfies EntityActionClickProps<Record<string, unknown>>;
|
|
310
|
-
const isEnabled = !action.isEnabled || action.isEnabled(props);
|
|
311
|
-
return (
|
|
312
|
-
<EntityActionButton key={action.key ?? action.name ?? index} action={action} enabled={isEnabled} props={props}/>
|
|
313
|
-
);
|
|
314
|
-
})}
|
|
315
|
-
</div>}
|
|
316
|
-
|
|
317
|
-
{savingError &&
|
|
318
|
-
<div className="text-right">
|
|
319
|
-
<Typography color={"error"}>{savingError.message}</Typography>
|
|
320
|
-
</div>
|
|
321
|
-
}
|
|
322
|
-
</div>;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
250
|
function EntityActionButton({
|
|
326
251
|
action,
|
|
327
252
|
enabled,
|