@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
package/dist/{RouterCollectionsStudioView-BZLq4MGp.js → RouterCollectionsStudioView-BsLTNoqX.js}
RENAMED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import { in as useUrlController } from "./util-
|
|
3
|
-
import { s as AIModifiedPathsProvider } from "./PropertyEditView-
|
|
4
|
-
import { t as CollectionEditor } from "./CollectionEditorDialog-
|
|
2
|
+
import { in as useUrlController } from "./util-GiwPgxnL.js";
|
|
3
|
+
import { s as AIModifiedPathsProvider } from "./PropertyEditView-W8I3YV89.js";
|
|
4
|
+
import { t as CollectionEditor } from "./CollectionEditorDialog-CjXkWZ64.js";
|
|
5
5
|
import { useEffect, useState } from "react";
|
|
6
6
|
import { Button, IconButton, PlusIcon, ResizablePanels, Tooltip, Typography, cls, defaultBorderMixin, iconSize } from "@rebasepro/ui";
|
|
7
7
|
import { IconForView, UnsavedChangesDialog, useUnsavedChangesDialog } from "@rebasepro/app";
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
-
import { useLocation, useNavigate } from "react-router
|
|
9
|
+
import { useLocation, useNavigate } from "react-router";
|
|
10
10
|
//#region src/collection_editor/ui/collection_editor/CollectionStudioView.tsx
|
|
11
11
|
function CollectionStudioView({ collectionId, onSave, onCancel, ...props }) {
|
|
12
12
|
const [formDirty, setFormDirty] = useState(false);
|
|
@@ -189,4 +189,4 @@ function RouterCollectionsStudioView(props) {
|
|
|
189
189
|
//#endregion
|
|
190
190
|
export { CollectionStudioView as i, RouterCollectionsStudioView_exports as n, CollectionsStudioView as r, RouterCollectionsStudioView as t };
|
|
191
191
|
|
|
192
|
-
//# sourceMappingURL=RouterCollectionsStudioView-
|
|
192
|
+
//# sourceMappingURL=RouterCollectionsStudioView-BsLTNoqX.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RouterCollectionsStudioView-BZLq4MGp.js","names":[],"sources":["../src/collection_editor/ui/collection_editor/CollectionStudioView.tsx","../src/collection_editor/ui/collection_editor/CollectionsStudioView.tsx","../src/collection_editor/ui/collection_editor/RouterCollectionsStudioView.tsx"],"sourcesContent":["\nimport { useUnsavedChangesDialog, UnsavedChangesDialog } from \"@rebasepro/app\";\nimport * as React from \"react\";\nimport { useState } from \"react\";\nimport { Button, PlusIcon, Typography } from \"@rebasepro/ui\";\nimport { CollectionEditorDialogProps } from \"./CollectionEditorDialog\";\nimport { AIModifiedPathsProvider } from \"./AIModifiedPathsContext\";\nimport { CollectionEditor } from \"./CollectionEditorDialog\";\nimport type { AdminCollection } from \"@rebasepro/admin-types\";\n\nexport type CollectionStudioViewProps = Omit<CollectionEditorDialogProps, \"open\" | \"isNewCollection\" | \"editedCollectionId\" | \"handleClose\" | \"handleCancel\"> & {\n collectionId?: string | \"new\";\n\n /**\n * Called after a successful save.\n * Receives the saved collection (or undefined if dismissed without saving).\n * When not provided, save completes silently.\n */\n onSave?: (collection?: AdminCollection) => void;\n\n /**\n * Called when the user cancels editing.\n * When not provided, cancel is a no-op.\n */\n onCancel?: () => void;\n};\n\nexport function CollectionStudioView({ collectionId, onSave, onCancel, ...props }: CollectionStudioViewProps) {\n\n // Form state from the editor\n const [formDirty, setFormDirty] = useState<boolean>(false);\n const [cancelRequested, setCancelRequested] = useState<boolean>(false);\n\n const { dialogProps, triggerDialog } = useUnsavedChangesDialog(\n formDirty,\n () => setFormDirty(false)\n );\n\n const activeCollectionId = collectionId;\n\n const handleCancelClick = () => {\n if (!formDirty) {\n onCancel?.();\n } else {\n setCancelRequested(true);\n triggerDialog();\n }\n };\n\n return (\n <div className=\"flex-grow flex flex-col h-full w-full bg-surface-50 dark:bg-surface-800\">\n <AIModifiedPathsProvider>\n {activeCollectionId ? (\n <CollectionEditor\n key={activeCollectionId}\n {...props}\n fullScreen={true}\n open={true}\n isNewCollection={activeCollectionId === \"new\"}\n editedCollectionId={activeCollectionId !== \"new\" ? activeCollectionId : undefined}\n handleCancel={handleCancelClick}\n handleClose={(savedCollection) => {\n setFormDirty(false);\n if (savedCollection) {\n setTimeout(() => {\n onSave?.(savedCollection);\n }, 0);\n }\n }}\n setFormDirty={setFormDirty}\n />\n ) : (\n <div className=\"flex-grow flex flex-col items-center justify-center h-full gap-4\">\n <Typography variant=\"label\">\n Select a collection or create a new one\n </Typography>\n <Button\n disabled={props.configController?.readOnly}\n onClick={() => onSave?.()}\n >\n <PlusIcon/>\n Add new collection\n </Button>\n </div>\n )}\n\n <UnsavedChangesDialog\n {...dialogProps}\n handleOk={() => {\n dialogProps.handleOk();\n if (cancelRequested) {\n onCancel?.();\n setCancelRequested(false);\n }\n }}\n handleCancel={() => {\n dialogProps.handleCancel();\n setCancelRequested(false);\n }}\n />\n </AIModifiedPathsProvider>\n </div>\n );\n}\n","\nimport { IconForView } from \"@rebasepro/app\";\nimport React, { useState, useEffect } from \"react\";\nimport {\n Button,\n cls,\n defaultBorderMixin,\n IconButton,\n iconSize,\n PlusIcon,\n ResizablePanels,\n Tooltip,\n Typography\n} from \"@rebasepro/ui\";\n\nimport { CollectionsConfigController } from \"../../types/config_controller\";\nimport { CollectionStudioView } from \"./CollectionStudioView\";\nimport type { CollectionEditorExtensionProps } from \"../../extensibility_types\";\nimport type { AdminCollection } from \"@rebasepro/admin-types\";\n\nexport interface CollectionsStudioViewProps extends CollectionEditorExtensionProps {\n configController: CollectionsConfigController;\n\n /**\n * Collections to show in the sidebar.\n * When provided, overrides the collections from `configController`.\n * Use this to control exactly which collections the editor displays.\n */\n collections?: AdminCollection[];\n\n /**\n * Controlled active collection ID.\n * When provided together with `onActiveCollectionChange`,\n * navigation is fully external — no internal state is used.\n */\n activeCollectionId?: string;\n\n /**\n * Called when the user clicks a collection, \"new\", or navigates.\n * When provided, the component is fully controlled (no internal state).\n * When not provided, the component manages selection via internal state.\n *\n * Pass `\"new\"` to create a new collection. Pass `undefined` to deselect.\n */\n onActiveCollectionChange?: (collectionId: string | undefined) => void;\n}\n\nexport function CollectionsStudioView({\n configController,\n collections: collectionsProp,\n activeCollectionId: controlledActiveId,\n onActiveCollectionChange,\n propertyTypePresets,\n hiddenPropertyTypes,\n renderExtraPropertyFields,\n renderExtraCollectionFields,\n visibleTabs,\n standalone,\n}: CollectionsStudioViewProps) {\n\n // ── Navigation state ────────────────────────────────────────────────\n // If onActiveCollectionChange is provided, the component is controlled.\n // Otherwise, use internal state.\n const [internalActiveId, setInternalActiveId] = useState<string | undefined>(undefined);\n const isControlled = onActiveCollectionChange !== undefined;\n const activeCollectionId = isControlled ? controlledActiveId : internalActiveId;\n\n const setActiveCollectionId = (id: string | undefined) => {\n if (isControlled) {\n onActiveCollectionChange?.(id);\n } else {\n setInternalActiveId(id);\n }\n };\n\n // ── Collections list ────────────────────────────────────────────────\n const collections = collectionsProp ?? configController.collections ?? [];\n\n // ── Sidebar sizing ──────────────────────────────────────────────────\n const [sidebarSize, setSidebarSize] = useState(() => {\n try {\n const saved = localStorage.getItem(\"rebase_collections_editor_sidebar_size\");\n return saved !== null ? parseFloat(saved) : 25;\n } catch (e) {\n return 25;\n }\n });\n\n useEffect(() => {\n try {\n localStorage.setItem(\"rebase_collections_editor_sidebar_size\", sidebarSize.toString());\n } catch (e) {\n // ignore local storage error\n }\n }, [sidebarSize]);\n\n return (\n <div className=\"flex h-full w-full bg-surface-50 dark:bg-surface-800 overflow-hidden text-text-primary dark:text-text-primary-dark\">\n <ResizablePanels\n orientation=\"horizontal\"\n panelSizePercent={sidebarSize}\n onPanelSizeChange={setSidebarSize}\n minPanelSizePx={220}\n firstPanel={\n <div className={cls(\"flex flex-col h-full w-full bg-surface-50 dark:bg-surface-800 border-r\", defaultBorderMixin)}>\n <div className={cls(\"flex items-center justify-between px-3 py-2 border-b bg-surface-50 dark:bg-surface-900 min-h-[48px]\", defaultBorderMixin)}>\n <Typography variant=\"caption\" className=\"font-semibold text-[11px] uppercase tracking-wider text-surface-400 dark:text-surface-400\">\n Collections\n </Typography>\n <Tooltip title={configController.readOnly ? configController.readOnlyReason || \"Read only\" : \"Add collection\"}>\n <div>\n <IconButton\n size=\"small\"\n disabled={configController.readOnly}\n onClick={() => setActiveCollectionId(\"new\")}\n className={activeCollectionId === \"new\" ? \"text-primary dark:text-primary-dark\" : \"text-text-secondary dark:text-text-secondary-dark\"}\n >\n <PlusIcon size={iconSize.smallest}/>\n </IconButton>\n </div>\n </Tooltip>\n </div>\n\n <div className=\"flex-grow overflow-y-auto w-full no-scrollbar p-2 space-y-0.5\">\n {collections.length === 0 && (\n <div className=\"p-4 text-center\">\n <Typography variant=\"caption\" className=\"text-text-disabled dark:text-text-disabled-dark italic\">\n No collections yet.\n </Typography>\n </div>\n )}\n {collections.map((collection) => {\n const collectionKey = collection.slug;\n const isSelected = activeCollectionId === collectionKey;\n return (\n <div\n key={collectionKey}\n onClick={() => setActiveCollectionId(collectionKey)}\n className={cls(\n \"flex items-center gap-2.5 px-3 h-[30px] cursor-pointer rounded-lg text-[13px] font-medium transition-colors\",\n isSelected\n ? \"bg-primary/8 text-primary dark:bg-primary/10 dark:text-primary-light font-semibold\"\n : \"hover:bg-primary/5 dark:hover:bg-primary/5 text-surface-700 dark:text-surface-300 hover:text-surface-900 dark:hover:text-white\"\n )}\n >\n <IconForView collectionOrView={collection} size={\"smallest\"} className={cls(\n isSelected\n ? \"text-primary dark:text-primary-light\"\n : \"text-surface-500 dark:text-text-secondary-dark\"\n )}/>\n <span className=\"truncate flex-1\">\n {collection.name || collection.slug}\n </span>\n </div>\n );\n })}\n </div>\n </div>\n }\n secondPanel={\n <div className=\"flex-grow flex flex-col min-w-0 h-full w-full\">\n {/* We use key to force unmount when switching collections, preventing stale state */}\n {activeCollectionId ? (\n <CollectionStudioView\n key={activeCollectionId}\n configController={configController}\n collectionId={activeCollectionId}\n onSave={(savedCollection) => {\n // After creating a new collection, switch to it\n if (activeCollectionId === \"new\" && savedCollection?.slug) {\n setActiveCollectionId(savedCollection.slug);\n }\n }}\n onCancel={() => setActiveCollectionId(undefined)}\n propertyTypePresets={propertyTypePresets}\n hiddenPropertyTypes={hiddenPropertyTypes}\n renderExtraPropertyFields={renderExtraPropertyFields}\n renderExtraCollectionFields={renderExtraCollectionFields}\n visibleTabs={visibleTabs}\n standalone={standalone}\n />\n ) : (\n <div className=\"flex flex-col items-center justify-center h-full gap-4\">\n <Typography variant=\"label\">\n Select a collection or create a new one to start editing\n </Typography>\n <Button\n disabled={configController.readOnly}\n onClick={() => setActiveCollectionId(\"new\")}\n >\n <PlusIcon/>\n Add new collection\n </Button>\n </div>\n )}\n </div>\n }\n />\n </div>\n );\n}\n","/**\n * Router-aware wrapper around CollectionsStudioView.\n *\n * This component provides the react-router-based navigation behavior\n * that Rebase Studio expects: the active collection is derived from the\n * URL, and clicking a collection navigates via react-router.\n *\n * External consumers should use `CollectionsStudioView` directly\n * (which has no react-router dependency).\n */\nimport React from \"react\";\nimport { useLocation, useNavigate } from \"react-router-dom\";\nimport { useUrlController } from \"../../_cms_internals\";\nimport { CollectionsStudioView, CollectionsStudioViewProps } from \"./CollectionsStudioView\";\n\nexport type RouterCollectionsStudioViewProps = Omit<CollectionsStudioViewProps, \"activeCollectionId\" | \"onActiveCollectionChange\">;\n\nexport function RouterCollectionsStudioView(props: RouterCollectionsStudioViewProps) {\n const navigate = useNavigate();\n const urlController = useUrlController();\n const location = useLocation();\n\n // Determine the active collection from the URL segment after \"schema/\"\n const basePath = urlController.buildAppUrlPath(\"schema\");\n const relativePath = location.pathname.replace(basePath, \"\").replace(/^\\//, \"\");\n const activeCollectionId = relativePath.split(\"/\")[0] || undefined;\n\n return (\n <CollectionsStudioView\n {...props}\n activeCollectionId={activeCollectionId}\n onActiveCollectionChange={(id) => {\n if (id) {\n navigate(urlController.buildAppUrlPath(`schema/${id}`));\n } else {\n navigate(urlController.buildAppUrlPath(\"schema\"));\n }\n }}\n />\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RouterCollectionsStudioView-BsLTNoqX.js","names":[],"sources":["../src/collection_editor/ui/collection_editor/CollectionStudioView.tsx","../src/collection_editor/ui/collection_editor/CollectionsStudioView.tsx","../src/collection_editor/ui/collection_editor/RouterCollectionsStudioView.tsx"],"sourcesContent":["\nimport { useUnsavedChangesDialog, UnsavedChangesDialog } from \"@rebasepro/app\";\nimport * as React from \"react\";\nimport { useState } from \"react\";\nimport { Button, PlusIcon, Typography } from \"@rebasepro/ui\";\nimport { CollectionEditorDialogProps } from \"./CollectionEditorDialog\";\nimport { AIModifiedPathsProvider } from \"./AIModifiedPathsContext\";\nimport { CollectionEditor } from \"./CollectionEditorDialog\";\nimport type { AdminCollection } from \"@rebasepro/admin-types\";\n\nexport type CollectionStudioViewProps = Omit<CollectionEditorDialogProps, \"open\" | \"isNewCollection\" | \"editedCollectionId\" | \"handleClose\" | \"handleCancel\"> & {\n collectionId?: string | \"new\";\n\n /**\n * Called after a successful save.\n * Receives the saved collection (or undefined if dismissed without saving).\n * When not provided, save completes silently.\n */\n onSave?: (collection?: AdminCollection) => void;\n\n /**\n * Called when the user cancels editing.\n * When not provided, cancel is a no-op.\n */\n onCancel?: () => void;\n};\n\nexport function CollectionStudioView({ collectionId, onSave, onCancel, ...props }: CollectionStudioViewProps) {\n\n // Form state from the editor\n const [formDirty, setFormDirty] = useState<boolean>(false);\n const [cancelRequested, setCancelRequested] = useState<boolean>(false);\n\n const { dialogProps, triggerDialog } = useUnsavedChangesDialog(\n formDirty,\n () => setFormDirty(false)\n );\n\n const activeCollectionId = collectionId;\n\n const handleCancelClick = () => {\n if (!formDirty) {\n onCancel?.();\n } else {\n setCancelRequested(true);\n triggerDialog();\n }\n };\n\n return (\n <div className=\"flex-grow flex flex-col h-full w-full bg-surface-50 dark:bg-surface-800\">\n <AIModifiedPathsProvider>\n {activeCollectionId ? (\n <CollectionEditor\n key={activeCollectionId}\n {...props}\n fullScreen={true}\n open={true}\n isNewCollection={activeCollectionId === \"new\"}\n editedCollectionId={activeCollectionId !== \"new\" ? activeCollectionId : undefined}\n handleCancel={handleCancelClick}\n handleClose={(savedCollection) => {\n setFormDirty(false);\n if (savedCollection) {\n setTimeout(() => {\n onSave?.(savedCollection);\n }, 0);\n }\n }}\n setFormDirty={setFormDirty}\n />\n ) : (\n <div className=\"flex-grow flex flex-col items-center justify-center h-full gap-4\">\n <Typography variant=\"label\">\n Select a collection or create a new one\n </Typography>\n <Button\n disabled={props.configController?.readOnly}\n onClick={() => onSave?.()}\n >\n <PlusIcon/>\n Add new collection\n </Button>\n </div>\n )}\n\n <UnsavedChangesDialog\n {...dialogProps}\n handleOk={() => {\n dialogProps.handleOk();\n if (cancelRequested) {\n onCancel?.();\n setCancelRequested(false);\n }\n }}\n handleCancel={() => {\n dialogProps.handleCancel();\n setCancelRequested(false);\n }}\n />\n </AIModifiedPathsProvider>\n </div>\n );\n}\n","\nimport { IconForView } from \"@rebasepro/app\";\nimport React, { useState, useEffect } from \"react\";\nimport {\n Button,\n cls,\n defaultBorderMixin,\n IconButton,\n iconSize,\n PlusIcon,\n ResizablePanels,\n Tooltip,\n Typography\n} from \"@rebasepro/ui\";\n\nimport { CollectionsConfigController } from \"../../types/config_controller\";\nimport { CollectionStudioView } from \"./CollectionStudioView\";\nimport type { CollectionEditorExtensionProps } from \"../../extensibility_types\";\nimport type { AdminCollection } from \"@rebasepro/admin-types\";\n\nexport interface CollectionsStudioViewProps extends CollectionEditorExtensionProps {\n configController: CollectionsConfigController;\n\n /**\n * Collections to show in the sidebar.\n * When provided, overrides the collections from `configController`.\n * Use this to control exactly which collections the editor displays.\n */\n collections?: AdminCollection[];\n\n /**\n * Controlled active collection ID.\n * When provided together with `onActiveCollectionChange`,\n * navigation is fully external — no internal state is used.\n */\n activeCollectionId?: string;\n\n /**\n * Called when the user clicks a collection, \"new\", or navigates.\n * When provided, the component is fully controlled (no internal state).\n * When not provided, the component manages selection via internal state.\n *\n * Pass `\"new\"` to create a new collection. Pass `undefined` to deselect.\n */\n onActiveCollectionChange?: (collectionId: string | undefined) => void;\n}\n\nexport function CollectionsStudioView({\n configController,\n collections: collectionsProp,\n activeCollectionId: controlledActiveId,\n onActiveCollectionChange,\n propertyTypePresets,\n hiddenPropertyTypes,\n renderExtraPropertyFields,\n renderExtraCollectionFields,\n visibleTabs,\n standalone,\n}: CollectionsStudioViewProps) {\n\n // ── Navigation state ────────────────────────────────────────────────\n // If onActiveCollectionChange is provided, the component is controlled.\n // Otherwise, use internal state.\n const [internalActiveId, setInternalActiveId] = useState<string | undefined>(undefined);\n const isControlled = onActiveCollectionChange !== undefined;\n const activeCollectionId = isControlled ? controlledActiveId : internalActiveId;\n\n const setActiveCollectionId = (id: string | undefined) => {\n if (isControlled) {\n onActiveCollectionChange?.(id);\n } else {\n setInternalActiveId(id);\n }\n };\n\n // ── Collections list ────────────────────────────────────────────────\n const collections = collectionsProp ?? configController.collections ?? [];\n\n // ── Sidebar sizing ──────────────────────────────────────────────────\n const [sidebarSize, setSidebarSize] = useState(() => {\n try {\n const saved = localStorage.getItem(\"rebase_collections_editor_sidebar_size\");\n return saved !== null ? parseFloat(saved) : 25;\n } catch (e) {\n return 25;\n }\n });\n\n useEffect(() => {\n try {\n localStorage.setItem(\"rebase_collections_editor_sidebar_size\", sidebarSize.toString());\n } catch (e) {\n // ignore local storage error\n }\n }, [sidebarSize]);\n\n return (\n <div className=\"flex h-full w-full bg-surface-50 dark:bg-surface-800 overflow-hidden text-text-primary dark:text-text-primary-dark\">\n <ResizablePanels\n orientation=\"horizontal\"\n panelSizePercent={sidebarSize}\n onPanelSizeChange={setSidebarSize}\n minPanelSizePx={220}\n firstPanel={\n <div className={cls(\"flex flex-col h-full w-full bg-surface-50 dark:bg-surface-800 border-r\", defaultBorderMixin)}>\n <div className={cls(\"flex items-center justify-between px-3 py-2 border-b bg-surface-50 dark:bg-surface-900 min-h-[48px]\", defaultBorderMixin)}>\n <Typography variant=\"caption\" className=\"font-semibold text-[11px] uppercase tracking-wider text-surface-400 dark:text-surface-400\">\n Collections\n </Typography>\n <Tooltip title={configController.readOnly ? configController.readOnlyReason || \"Read only\" : \"Add collection\"}>\n <div>\n <IconButton\n size=\"small\"\n disabled={configController.readOnly}\n onClick={() => setActiveCollectionId(\"new\")}\n className={activeCollectionId === \"new\" ? \"text-primary dark:text-primary-dark\" : \"text-text-secondary dark:text-text-secondary-dark\"}\n >\n <PlusIcon size={iconSize.smallest}/>\n </IconButton>\n </div>\n </Tooltip>\n </div>\n\n <div className=\"flex-grow overflow-y-auto w-full no-scrollbar p-2 space-y-0.5\">\n {collections.length === 0 && (\n <div className=\"p-4 text-center\">\n <Typography variant=\"caption\" className=\"text-text-disabled dark:text-text-disabled-dark italic\">\n No collections yet.\n </Typography>\n </div>\n )}\n {collections.map((collection) => {\n const collectionKey = collection.slug;\n const isSelected = activeCollectionId === collectionKey;\n return (\n <div\n key={collectionKey}\n onClick={() => setActiveCollectionId(collectionKey)}\n className={cls(\n \"flex items-center gap-2.5 px-3 h-[30px] cursor-pointer rounded-lg text-[13px] font-medium transition-colors\",\n isSelected\n ? \"bg-primary/8 text-primary dark:bg-primary/10 dark:text-primary-light font-semibold\"\n : \"hover:bg-primary/5 dark:hover:bg-primary/5 text-surface-700 dark:text-surface-300 hover:text-surface-900 dark:hover:text-white\"\n )}\n >\n <IconForView collectionOrView={collection} size={\"smallest\"} className={cls(\n isSelected\n ? \"text-primary dark:text-primary-light\"\n : \"text-surface-500 dark:text-text-secondary-dark\"\n )}/>\n <span className=\"truncate flex-1\">\n {collection.name || collection.slug}\n </span>\n </div>\n );\n })}\n </div>\n </div>\n }\n secondPanel={\n <div className=\"flex-grow flex flex-col min-w-0 h-full w-full\">\n {/* We use key to force unmount when switching collections, preventing stale state */}\n {activeCollectionId ? (\n <CollectionStudioView\n key={activeCollectionId}\n configController={configController}\n collectionId={activeCollectionId}\n onSave={(savedCollection) => {\n // After creating a new collection, switch to it\n if (activeCollectionId === \"new\" && savedCollection?.slug) {\n setActiveCollectionId(savedCollection.slug);\n }\n }}\n onCancel={() => setActiveCollectionId(undefined)}\n propertyTypePresets={propertyTypePresets}\n hiddenPropertyTypes={hiddenPropertyTypes}\n renderExtraPropertyFields={renderExtraPropertyFields}\n renderExtraCollectionFields={renderExtraCollectionFields}\n visibleTabs={visibleTabs}\n standalone={standalone}\n />\n ) : (\n <div className=\"flex flex-col items-center justify-center h-full gap-4\">\n <Typography variant=\"label\">\n Select a collection or create a new one to start editing\n </Typography>\n <Button\n disabled={configController.readOnly}\n onClick={() => setActiveCollectionId(\"new\")}\n >\n <PlusIcon/>\n Add new collection\n </Button>\n </div>\n )}\n </div>\n }\n />\n </div>\n );\n}\n","/**\n * Router-aware wrapper around CollectionsStudioView.\n *\n * This component provides the react-router-based navigation behavior\n * that Rebase Studio expects: the active collection is derived from the\n * URL, and clicking a collection navigates via react-router.\n *\n * External consumers should use `CollectionsStudioView` directly\n * (which has no react-router dependency).\n */\nimport React from \"react\";\nimport { useLocation, useNavigate } from \"react-router\";\nimport { useUrlController } from \"../../_cms_internals\";\nimport { CollectionsStudioView, CollectionsStudioViewProps } from \"./CollectionsStudioView\";\n\nexport type RouterCollectionsStudioViewProps = Omit<CollectionsStudioViewProps, \"activeCollectionId\" | \"onActiveCollectionChange\">;\n\nexport function RouterCollectionsStudioView(props: RouterCollectionsStudioViewProps) {\n const navigate = useNavigate();\n const urlController = useUrlController();\n const location = useLocation();\n\n // Determine the active collection from the URL segment after \"schema/\"\n const basePath = urlController.buildAppUrlPath(\"schema\");\n const relativePath = location.pathname.replace(basePath, \"\").replace(/^\\//, \"\");\n const activeCollectionId = relativePath.split(\"/\")[0] || undefined;\n\n return (\n <CollectionsStudioView\n {...props}\n activeCollectionId={activeCollectionId}\n onActiveCollectionChange={(id) => {\n if (id) {\n navigate(urlController.buildAppUrlPath(`schema/${id}`));\n } else {\n navigate(urlController.buildAppUrlPath(\"schema\"));\n }\n }}\n />\n );\n}\n"],"mappings":"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"}
|
|
@@ -21,7 +21,8 @@ export interface SerializableAdminBaseOptions {
|
|
|
21
21
|
hideFromCollection?: boolean;
|
|
22
22
|
readOnly?: boolean;
|
|
23
23
|
disabled?: boolean | SerializablePropertyDisabledConfig;
|
|
24
|
-
|
|
24
|
+
span?: 1 | 2 | 3 | 4;
|
|
25
|
+
/** Opaque props handed to a custom `Field` / `Preview`. Round-tripped as-is. */
|
|
25
26
|
customProps?: unknown;
|
|
26
27
|
/** Narrows the filter operators offered for this property. Plain data. */
|
|
27
28
|
filterOperators?: readonly WhereFilterOp[];
|
|
@@ -245,6 +246,7 @@ export type SerializableRelation = {
|
|
|
245
246
|
target?: string;
|
|
246
247
|
relationName?: string;
|
|
247
248
|
foreignKeyOnTarget?: string;
|
|
249
|
+
sourceKey?: string;
|
|
248
250
|
onUpdate?: OnAction;
|
|
249
251
|
onDelete?: OnAction;
|
|
250
252
|
} | {
|
|
@@ -252,6 +254,7 @@ export type SerializableRelation = {
|
|
|
252
254
|
target?: string;
|
|
253
255
|
relationName?: string;
|
|
254
256
|
foreignKeyOnTarget?: string;
|
|
257
|
+
sourceKey?: string;
|
|
255
258
|
onUpdate?: OnAction;
|
|
256
259
|
onDelete?: OnAction;
|
|
257
260
|
} | {
|
|
@@ -3,4 +3,12 @@ import type { AdminCollection } from "@rebasepro/admin-types";
|
|
|
3
3
|
export declare function useLocalCollectionsConfigController(clientOrUrl: any, baseCollections?: AdminCollection[], options?: {
|
|
4
4
|
readOnly?: boolean;
|
|
5
5
|
getAuthToken?: () => Promise<string | null>;
|
|
6
|
+
/**
|
|
7
|
+
* Identity of the signed-in user, if any.
|
|
8
|
+
*
|
|
9
|
+
* Only used to re-ask the backend when it changes: whether the editor
|
|
10
|
+
* will accept a write depends on who is asking, and the answer to an
|
|
11
|
+
* anonymous probe does not survive a sign-in.
|
|
12
|
+
*/
|
|
13
|
+
authKey?: string | null;
|
|
6
14
|
}): CollectionsConfigController;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { in as useUrlController } from "./util-
|
|
2
|
-
import { n as PropertyForm, r as PropertyFormDialog } from "./PropertyEditView-
|
|
3
|
-
import { n as CollectionEditorDialog } from "./CollectionEditorDialog-
|
|
4
|
-
import { i as CollectionStudioView, r as CollectionsStudioView, t as RouterCollectionsStudioView } from "./RouterCollectionsStudioView-
|
|
1
|
+
import { in as useUrlController } from "./util-GiwPgxnL.js";
|
|
2
|
+
import { n as PropertyForm, r as PropertyFormDialog } from "./PropertyEditView-W8I3YV89.js";
|
|
3
|
+
import { n as CollectionEditorDialog } from "./CollectionEditorDialog-CjXkWZ64.js";
|
|
4
|
+
import { i as CollectionStudioView, r as CollectionsStudioView, t as RouterCollectionsStudioView } from "./RouterCollectionsStudioView-BsLTNoqX.js";
|
|
5
5
|
import "react";
|
|
6
6
|
import { useSnackbarController } from "@rebasepro/app";
|
|
7
7
|
import { jsx } from "react/jsx-runtime";
|
|
8
|
-
import { useNavigate } from "react-router
|
|
8
|
+
import { useNavigate } from "react-router";
|
|
9
9
|
//#region src/collection_editor/ui/collection_editor/RouterCollectionStudioView.tsx
|
|
10
10
|
function RouterCollectionStudioView(props) {
|
|
11
11
|
const navigate = useNavigate();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collection_editor_ui.js","names":[],"sources":["../src/collection_editor/ui/collection_editor/RouterCollectionStudioView.tsx"],"sourcesContent":["/**\n * Router-aware wrapper around CollectionStudioView.\n *\n * This component provides the react-router-based navigation behavior\n * that Rebase Studio expects: cancel navigates to the root path,\n * save navigates to the saved collection's slug, and a snackbar\n * toast is shown on success.\n *\n * External consumers should use `CollectionStudioView` directly\n * (which has no react-router dependency).\n */\nimport React from \"react\";\nimport { useNavigate } from \"react-router
|
|
1
|
+
{"version":3,"file":"collection_editor_ui.js","names":[],"sources":["../src/collection_editor/ui/collection_editor/RouterCollectionStudioView.tsx"],"sourcesContent":["/**\n * Router-aware wrapper around CollectionStudioView.\n *\n * This component provides the react-router-based navigation behavior\n * that Rebase Studio expects: cancel navigates to the root path,\n * save navigates to the saved collection's slug, and a snackbar\n * toast is shown on success.\n *\n * External consumers should use `CollectionStudioView` directly\n * (which has no react-router dependency).\n */\nimport React from \"react\";\nimport { useNavigate } from \"react-router\";\nimport { useUrlController } from \"../../_cms_internals\";\nimport { useSnackbarController } from \"@rebasepro/app\";\nimport { CollectionStudioView, CollectionStudioViewProps } from \"./CollectionStudioView\";\n\nexport type RouterCollectionStudioViewProps = Omit<CollectionStudioViewProps, \"onSave\" | \"onCancel\">;\n\nexport function RouterCollectionStudioView(props: RouterCollectionStudioViewProps) {\n const navigate = useNavigate();\n const urlController = useUrlController();\n const snackbarController = useSnackbarController();\n\n return (\n <CollectionStudioView\n {...props}\n onCancel={() => {\n navigate(urlController.buildAppUrlPath(\"/\"));\n }}\n onSave={(savedCollection) => {\n if (savedCollection) {\n snackbarController.open({\n type: \"success\",\n message: `Collection ${savedCollection.name || savedCollection.slug} saved`\n });\n if (props.collectionId === \"new\") {\n navigate(urlController.buildAppUrlPath(`s/schema/${savedCollection.slug}`));\n }\n }\n }}\n />\n );\n}\n"],"mappings":";;;;;;;;;AAmBA,SAAgB,2BAA2B,OAAwC;CAC/E,MAAM,WAAW,YAAY;CAC7B,MAAM,gBAAgB,iBAAiB;CACvC,MAAM,qBAAqB,sBAAsB;CAEjD,OACI,oBAAC,sBAAD;EACI,GAAI;EACJ,gBAAgB;GACZ,SAAS,cAAc,gBAAgB,GAAG,CAAC;EAC/C;EACA,SAAS,oBAAoB;GACzB,IAAI,iBAAiB;IACjB,mBAAmB,KAAK;KACpB,MAAM;KACN,SAAS,cAAc,gBAAgB,QAAQ,gBAAgB,KAAK;IACxE,CAAC;IACD,IAAI,MAAM,iBAAiB,OACvB,SAAS,cAAc,gBAAgB,YAAY,gBAAgB,MAAM,CAAC;GAElF;EACJ;CACH,CAAA;AAET"}
|
|
@@ -20,3 +20,20 @@ export interface PropertiesToColumnsParams<M extends Record<string, unknown>> {
|
|
|
20
20
|
}>;
|
|
21
21
|
}
|
|
22
22
|
export declare function propertiesToColumns<M extends Record<string, unknown>>({ properties, sortable, fixedFilter, engine, AdditionalHeaderWidget }: PropertiesToColumnsParams<M>): VirtualTableColumn[];
|
|
23
|
+
export type SortablePropertyOption = {
|
|
24
|
+
key: string;
|
|
25
|
+
title: string;
|
|
26
|
+
property: Property;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* The properties a sort can be applied to, as keys and titles.
|
|
30
|
+
*
|
|
31
|
+
* Only the table renders headers, so the list, card and split views had no way
|
|
32
|
+
* to order anything — the controller has carried `sortBy` all along, with no
|
|
33
|
+
* control bound to it outside the table. This is the same walk
|
|
34
|
+
* `propertiesToColumns` makes, under the same keys and the same
|
|
35
|
+
* `sortableProperty` authority, so a sort picked from the toolbar means exactly
|
|
36
|
+
* what clicking the header would have meant, and the two cannot drift into
|
|
37
|
+
* offering different columns.
|
|
38
|
+
*/
|
|
39
|
+
export declare function getSortablePropertyOptions(properties: Properties): SortablePropertyOption[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Properties } from "@rebasepro/types";
|
|
2
2
|
import React from "react";
|
|
3
|
-
import { EntityTableController, SelectionController, AdminCollection } from "@rebasepro/admin-types";
|
|
3
|
+
import { EntityTableController, SelectionController, AdminCollection, ViewMode } from "@rebasepro/admin-types";
|
|
4
4
|
export type CollectionViewStartActionsProps<M extends Record<string, unknown>> = {
|
|
5
5
|
collection: AdminCollection<M>;
|
|
6
6
|
path: string;
|
|
@@ -14,7 +14,12 @@ export type CollectionViewStartActionsProps<M extends Record<string, unknown>> =
|
|
|
14
14
|
* Resolved properties from the collection for the filters dialog
|
|
15
15
|
*/
|
|
16
16
|
resolvedProperties?: Properties;
|
|
17
|
+
/**
|
|
18
|
+
* Which view is being displayed. Decides whether the sort control is
|
|
19
|
+
* offered — see `sortButton`.
|
|
20
|
+
*/
|
|
21
|
+
viewMode?: ViewMode;
|
|
17
22
|
compact?: boolean;
|
|
18
23
|
openNewDocument: (defaultValues?: Record<string, unknown>) => void;
|
|
19
24
|
};
|
|
20
|
-
export declare function CollectionViewStartActions<M extends Record<string, unknown>>({ collection, relativePath, parentCollectionSlugs, parentEntityIds, path, selectionController, tableController, collectionEntitiesCount, resolvedProperties, compact, openNewDocument }: CollectionViewStartActionsProps<M>): React.JSX.Element;
|
|
25
|
+
export declare function CollectionViewStartActions<M extends Record<string, unknown>>({ collection, relativePath, parentCollectionSlugs, parentEntityIds, path, selectionController, tableController, collectionEntitiesCount, resolvedProperties, viewMode, compact, openNewDocument }: CollectionViewStartActionsProps<M>): React.JSX.Element;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Properties } from "@rebasepro/types";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { EntityTableController } from "@rebasepro/admin-types";
|
|
4
|
+
export type SortButtonProps<M extends Record<string, unknown>> = {
|
|
5
|
+
tableController: EntityTableController<M>;
|
|
6
|
+
/**
|
|
7
|
+
* Resolved properties of the collection. The sortable ones among them are
|
|
8
|
+
* the options offered.
|
|
9
|
+
*/
|
|
10
|
+
properties: Properties;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Toolbar control that orders the collection by one property.
|
|
14
|
+
*
|
|
15
|
+
* The table orders by clicking a column header, which leaves every other view
|
|
16
|
+
* mode — list, cards, and either of them inside a split view — with no way to
|
|
17
|
+
* order at all, even though the controller has always carried `sortBy` and the
|
|
18
|
+
* query has always honoured it. This binds a control to it.
|
|
19
|
+
*
|
|
20
|
+
* Clicking the active property flips its direction, so ascending → descending
|
|
21
|
+
* is one click rather than a trip through a direction selector; clicking a
|
|
22
|
+
* different one starts it ascending. The popover stays open through both.
|
|
23
|
+
*/
|
|
24
|
+
export declare function SortButton<M extends Record<string, unknown>>({ tableController, properties }: SortButtonProps<M>): React.JSX.Element | null;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Closes the list of a split view, leaving the open record on its own.
|
|
4
|
+
*
|
|
5
|
+
* It leads the record's own app bar, where the breadcrumb starts — this is the
|
|
6
|
+
* entity pane's old "Open full screen" button, moved to that edge and wearing an
|
|
7
|
+
* X: closing the list and opening the record full screen are the same thing, so
|
|
8
|
+
* there is one control and one route (`#full`) rather than two.
|
|
9
|
+
*/
|
|
10
|
+
export declare function SplitListCloseButton(): React.JSX.Element | null;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* The enclosing master-detail split view, exposed to the list panel so it can
|
|
4
|
+
* carry the control that closes it.
|
|
5
|
+
*/
|
|
6
|
+
export type SplitViewController = {
|
|
7
|
+
/** Whether a record is open in the detail pane. */
|
|
8
|
+
detailOpen: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Close the list and leave the open record on its own, full screen. This is
|
|
11
|
+
* the existing full-screen entity route (`#full`), not a second mechanism.
|
|
12
|
+
*/
|
|
13
|
+
openFullScreen: () => void;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* The enclosing split view, or `undefined` when the component is not rendered
|
|
17
|
+
* inside one (a side panel, a dialog, a full-screen route).
|
|
18
|
+
*/
|
|
19
|
+
export declare function useSplitView(): SplitViewController | undefined;
|
|
20
|
+
export declare function SplitViewProvider({ value, children }: {
|
|
21
|
+
value: SplitViewController;
|
|
22
|
+
children: React.ReactNode;
|
|
23
|
+
}): React.JSX.Element;
|
|
@@ -2,6 +2,32 @@ import { RebaseData, Entity } from "@rebasepro/types";
|
|
|
2
2
|
import { RebaseContext, AnalyticsController, AdminCollection } from "@rebasepro/admin-types";
|
|
3
3
|
import { BoardItem } from "@rebasepro/ui";
|
|
4
4
|
import { BoardDataController } from "../useBoardDataController";
|
|
5
|
+
/**
|
|
6
|
+
* The digits a board order key is built from: base36, lower case only.
|
|
7
|
+
*
|
|
8
|
+
* The library's default alphabet is base62, and its keys only sort correctly
|
|
9
|
+
* under byte ordering. The column is sorted by the *database*, and Postgres'
|
|
10
|
+
* default collation is not byte ordering — under `en_US.UTF-8`, `"aa"` sorts
|
|
11
|
+
* before `"aC"`, so as soon as a board had been dragged around enough to reach
|
|
12
|
+
* the upper-case digits its order stopped matching the keys. One case has no
|
|
13
|
+
* such ambiguity: digits before letters is true of every collation in use.
|
|
14
|
+
*
|
|
15
|
+
* A key written with the old alphabet no longer validates, which is what makes
|
|
16
|
+
* the board offer to initialise the column — one click, and the order is
|
|
17
|
+
* rewritten in a form the database can sort.
|
|
18
|
+
*/
|
|
19
|
+
export declare const ORDER_KEY_DIGITS = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
20
|
+
/**
|
|
21
|
+
* Whether a stored order value is a key `fractional-indexing` can interpolate
|
|
22
|
+
* against.
|
|
23
|
+
*
|
|
24
|
+
* Anything else — a plain `"12"` from a seed or a migration, an empty string —
|
|
25
|
+
* makes `generateKeyBetween` throw, and the fallback below then hands out the
|
|
26
|
+
* same first key to every card, so each drag lands at the bottom of the column
|
|
27
|
+
* on top of the last one that did. Asking the library itself is the only
|
|
28
|
+
* definition of "valid" worth trusting.
|
|
29
|
+
*/
|
|
30
|
+
export declare function isValidOrderKey(value: unknown): value is string;
|
|
5
31
|
export interface UseKanbanDragAndDropParams<M extends Record<string, unknown>> {
|
|
6
32
|
collection: AdminCollection<M>;
|
|
7
33
|
fullPath: string;
|
|
@@ -24,5 +24,10 @@ export interface DetailViewBindingProps<M extends Record<string, unknown> = Reco
|
|
|
24
24
|
onEditClick?: () => void;
|
|
25
25
|
layout?: "side_panel" | "full_screen" | "split" | "dialog";
|
|
26
26
|
barActions?: (params: BarActionsParams) => React.ReactNode;
|
|
27
|
+
/**
|
|
28
|
+
* Controls the owning panel puts at the identity bar's leading edge, ahead
|
|
29
|
+
* of the breadcrumb — the side panel's close button.
|
|
30
|
+
*/
|
|
31
|
+
barActionsStart?: React.ReactNode;
|
|
27
32
|
}
|
|
28
33
|
export declare function DetailViewBinding<M extends Record<string, unknown>>({ entityId, ...props }: DetailViewBindingProps<M>): React.JSX.Element;
|
|
@@ -1,3 +1,14 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import type { EntityFormActionsProps } from "../types/components/EntityFormActionsProps";
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* The entity form's footer.
|
|
5
|
+
*
|
|
6
|
+
* It used to render in two shapes: this footer, and a `w-80 2xl:w-96` sticky
|
|
7
|
+
* side rail carrying the same Save and Discard above several hundred pixels of
|
|
8
|
+
* nothing. The rail is gone, and Save/Discard have moved to the identity bar
|
|
9
|
+
* where they stay visible while the form scrolls — so with
|
|
10
|
+
* `showDefaultActions={false}` this renders only what the bar cannot host:
|
|
11
|
+
* record actions (copy, delete, custom), plugin actions, the saving error, and
|
|
12
|
+
* the side-panel-only "save and close".
|
|
13
|
+
*/
|
|
14
|
+
export declare function EditFormActions({ collection, path, entity, savingError, formex, disabled, status, pluginActions, openEntityMode, showDefaultActions, navigateBack, formContext }: EntityFormActionsProps): React.JSX.Element | null;
|
|
@@ -35,6 +35,11 @@ export interface EditViewBindingProps<M extends Record<string, unknown> = Record
|
|
|
35
35
|
navigateBack?: () => void;
|
|
36
36
|
layout?: "side_panel" | "full_screen" | "split" | "dialog";
|
|
37
37
|
barActions?: (params: BarActionsParams) => React.ReactNode;
|
|
38
|
+
/**
|
|
39
|
+
* Controls the owning panel puts at the identity bar's leading edge, ahead
|
|
40
|
+
* of the breadcrumb — the side panel's close button.
|
|
41
|
+
*/
|
|
42
|
+
barActionsStart?: React.ReactNode;
|
|
38
43
|
formProps?: Partial<EntityFormBindingProps<M>>;
|
|
39
44
|
/**
|
|
40
45
|
* Pre-populate the form with these values when creating a new entity.
|
|
@@ -48,7 +53,7 @@ export interface EditViewBindingProps<M extends Record<string, unknown> = Record
|
|
|
48
53
|
* a record is opened.
|
|
49
54
|
*/
|
|
50
55
|
export declare function EditViewBinding<M extends Record<string, unknown>>({ entityId, ...props }: EditViewBindingProps<M>): React.JSX.Element;
|
|
51
|
-
export declare function EditViewBindingInner<M extends Record<string, unknown>>({ path, entityId, selectedTab: selectedTabProp, collection, parentCollectionSlugs, parentEntityIds, onValuesModified, onSaved, onTabChange, navigateBack, entity, initialDirtyValues, dataLoading, layout, barActions, status, setStatus, formProps, canEdit }: EditViewBindingProps<M> & {
|
|
56
|
+
export declare function EditViewBindingInner<M extends Record<string, unknown>>({ path, entityId, selectedTab: selectedTabProp, collection, parentCollectionSlugs, parentEntityIds, onValuesModified, onSaved, onTabChange, navigateBack, entity, initialDirtyValues, dataLoading, layout, barActions, barActionsStart, status, setStatus, formProps, canEdit }: EditViewBindingProps<M> & {
|
|
52
57
|
entity?: Entity<M>;
|
|
53
58
|
initialDirtyValues?: Partial<M>;
|
|
54
59
|
dataLoading: boolean;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { AdminCollection } from "@rebasepro/admin-types";
|
|
2
|
+
import type { EntityStatus } from "@rebasepro/types";
|
|
3
|
+
import React from "react";
|
|
4
|
+
export interface EntityIdentityBarProps {
|
|
5
|
+
/** Plural collection name, shown as the breadcrumb ahead of the title. */
|
|
6
|
+
collection: AdminCollection;
|
|
7
|
+
/** Resolved record title, already guarded against showing a field default. */
|
|
8
|
+
title: string;
|
|
9
|
+
entityId?: string | number;
|
|
10
|
+
status: EntityStatus;
|
|
11
|
+
dirty: boolean;
|
|
12
|
+
saving: boolean;
|
|
13
|
+
/** Undefined hides the Save button — read-only views, or a custom form. */
|
|
14
|
+
onSave?: () => void;
|
|
15
|
+
onDiscard?: () => void;
|
|
16
|
+
saveDisabled?: boolean;
|
|
17
|
+
hasErrors?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Save and dismiss, for the side panel and the dialog where the dominant
|
|
20
|
+
* action is "done with this record" rather than "keep editing".
|
|
21
|
+
*/
|
|
22
|
+
onSaveAndClose?: () => void;
|
|
23
|
+
onBack?: () => void;
|
|
24
|
+
onInspect?: () => void;
|
|
25
|
+
/** Opens the inspector straight on its history tab. */
|
|
26
|
+
onViewHistory?: () => void;
|
|
27
|
+
/**
|
|
28
|
+
* Actions performed *on* the record — copy, delete, whatever the collection
|
|
29
|
+
* adds — as menu items under the overflow button. They live here rather
|
|
30
|
+
* than in a footer, which is what let the footer go away entirely.
|
|
31
|
+
*/
|
|
32
|
+
recordActions?: React.ReactNode;
|
|
33
|
+
/** Plugin-contributed actions, rendered inline before Save. */
|
|
34
|
+
pluginActions?: React.ReactNode;
|
|
35
|
+
/** Close / full-screen buttons supplied by the panel that owns this view. */
|
|
36
|
+
trailing?: React.ReactNode;
|
|
37
|
+
/**
|
|
38
|
+
* Controls the owning panel puts at the bar's leading edge, ahead of the
|
|
39
|
+
* breadcrumb — where the side panel's close button lives.
|
|
40
|
+
*/
|
|
41
|
+
leading?: React.ReactNode;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The persistent header of an entity view: who this record is, and what you can
|
|
45
|
+
* do to it.
|
|
46
|
+
*
|
|
47
|
+
* The title and the id used to live inside the scrolling form, above 72px of
|
|
48
|
+
* empty space — 219px of chrome that carried nothing and scrolled away the
|
|
49
|
+
* moment you touched the wheel, leaving no indication of which record you were
|
|
50
|
+
* editing. They live here instead, and the left half of a bar that was
|
|
51
|
+
* previously empty now does the work.
|
|
52
|
+
*/
|
|
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;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { AdminCollection } from "@rebasepro/admin-types";
|
|
2
|
+
import type { Entity } from "@rebasepro/types";
|
|
3
|
+
import type { FormContext } from "../types/fields";
|
|
4
|
+
import React from "react";
|
|
5
|
+
export type InspectorTab = "json" | "history";
|
|
6
|
+
export interface EntityInspectorProps {
|
|
7
|
+
/** The open tab, or null when the panel is closed. */
|
|
8
|
+
tab: InspectorTab | null;
|
|
9
|
+
onTabChange: (tab: InspectorTab) => void;
|
|
10
|
+
onClose: () => void;
|
|
11
|
+
collection: AdminCollection;
|
|
12
|
+
entity?: Entity<Record<string, unknown>>;
|
|
13
|
+
formContext?: FormContext<Record<string, unknown>>;
|
|
14
|
+
values?: Record<string, unknown>;
|
|
15
|
+
/** History is only offered when the collection records it. */
|
|
16
|
+
includeHistory: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Bumped once per save by the view that owns the form. The panel stays open
|
|
19
|
+
* across a save — the bar's Save button sits above it — so without this the
|
|
20
|
+
* history list would still be the one fetched when the panel opened.
|
|
21
|
+
*/
|
|
22
|
+
refreshToken?: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Raw values and revision history, as an inspector rather than as tabs.
|
|
26
|
+
*
|
|
27
|
+
* These were the first two entries in the entity tab strip — two icon-only tabs
|
|
28
|
+
* with no label and no tooltip, sitting *before* the record you opened the page
|
|
29
|
+
* to edit. They are developer tools, not places the record lives, so they belong
|
|
30
|
+
* behind one affordance in the bar; a content editor should never meet `<>`.
|
|
31
|
+
*
|
|
32
|
+
* The panel sits below the identity bar and beside the record deliberately: you
|
|
33
|
+
* keep seeing which record you are inspecting, and keep being able to edit it.
|
|
34
|
+
*/
|
|
35
|
+
export declare function EntityInspector({ tab, onTabChange, onClose, collection, entity, formContext, values, includeHistory, refreshToken }: EntityInspectorProps): React.JSX.Element | null;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Current entity preview nesting depth. 0 means "not inside another preview".
|
|
4
|
+
*/
|
|
5
|
+
export declare function useEntityPreviewDepth(): number;
|
|
6
|
+
/**
|
|
7
|
+
* True when the preview being rendered lives inside another entity preview,
|
|
8
|
+
* and should therefore render its compact variant.
|
|
9
|
+
*/
|
|
10
|
+
export declare function useIsNestedEntityPreview(): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Marks its children as being rendered inside an entity preview, so any
|
|
13
|
+
* reference or relation below collapses to a chip.
|
|
14
|
+
*/
|
|
15
|
+
export declare function NestedEntityPreviewBoundary({ children }: {
|
|
16
|
+
children: React.ReactNode;
|
|
17
|
+
}): React.JSX.Element;
|
|
18
|
+
/**
|
|
19
|
+
* Resets the nesting depth back to 0. Used by surfaces that open a fresh
|
|
20
|
+
* rendering context for an entity — a side panel, a dialog — from within a
|
|
21
|
+
* preview, where the children are no longer visually nested.
|
|
22
|
+
*/
|
|
23
|
+
export declare function RootEntityPreviewBoundary({ children }: {
|
|
24
|
+
children: React.ReactNode;
|
|
25
|
+
}): React.JSX.Element;
|
|
@@ -10,4 +10,13 @@ export interface EntityViewBindingProps<M extends Record<string, unknown>> {
|
|
|
10
10
|
path: string;
|
|
11
11
|
className?: string;
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* The read-only rendering of a record's values.
|
|
15
|
+
*
|
|
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.
|
|
21
|
+
*/
|
|
13
22
|
export declare function EntityViewBinding<M extends Record<string, unknown>>({ entity, collection, path, className }: EntityViewBindingProps<M>): React.JSX.Element;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Entity } from "@rebasepro/types";
|
|
3
|
+
import type { AdminCollection } from "@rebasepro/admin-types";
|
|
4
|
+
export type InlineEntityPreviewProps = {
|
|
5
|
+
entity: Entity<any>;
|
|
6
|
+
collection?: AdminCollection;
|
|
7
|
+
/** Overrides the resolved title. */
|
|
8
|
+
label?: string;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
/** When set, takes over the click. Otherwise the row opens the side panel. */
|
|
11
|
+
onClick?: (e: React.SyntheticEvent) => void;
|
|
12
|
+
/** Set to false to render text only, with no click target. */
|
|
13
|
+
includeEntityLink?: boolean;
|
|
14
|
+
/** Icon size in px. Defaults to a hair under the surrounding text. */
|
|
15
|
+
iconSize?: number;
|
|
16
|
+
className?: string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* An entity rendered as one line of text: a small link glyph that marks it as
|
|
20
|
+
* pointing elsewhere, then the target's title in whatever typography surrounds
|
|
21
|
+
* it.
|
|
22
|
+
*
|
|
23
|
+
* This is what a reference or relation renders as when it is *not* the subject
|
|
24
|
+
* of its slot — nested inside another entity preview, or filling a title slot.
|
|
25
|
+
* The card treatment (image, id, preview properties, side-panel button) only
|
|
26
|
+
* makes sense at the top level; repeating it one level down produces a bordered
|
|
27
|
+
* box inside a bordered box, each with its own action buttons.
|
|
28
|
+
*
|
|
29
|
+
* @group Preview components
|
|
30
|
+
*/
|
|
31
|
+
export declare function InlineEntityPreview({ entity, collection: collectionProp, label, disabled, onClick, includeEntityLink, iconSize, className }: InlineEntityPreviewProps): React.JSX.Element;
|
|
32
|
+
/**
|
|
33
|
+
* Placeholder shown while the target of an inline reference is being fetched.
|
|
34
|
+
*/
|
|
35
|
+
export declare function InlineEntityPreviewSkeleton({ className }: {
|
|
36
|
+
className?: string;
|
|
37
|
+
}): React.JSX.Element;
|
|
38
|
+
/**
|
|
39
|
+
* Shown when the target of an inline reference cannot be resolved — a deleted
|
|
40
|
+
* row, or a collection that is not registered. Keeps the line readable instead
|
|
41
|
+
* of dropping an error box into the middle of a card.
|
|
42
|
+
*/
|
|
43
|
+
export declare function InlineEntityPreviewMissing({ label, tooltip, className }: {
|
|
44
|
+
label: string;
|
|
45
|
+
tooltip?: string;
|
|
46
|
+
className?: string;
|
|
47
|
+
}): React.JSX.Element;
|
|
@@ -3,4 +3,7 @@ import type { EntityCustomViewParams } from "@rebasepro/admin-types";
|
|
|
3
3
|
* Entity history tab view. Shows a paginated list of entity revisions
|
|
4
4
|
* fetched from the backend API. Supports infinite scroll and revert.
|
|
5
5
|
*/
|
|
6
|
-
export declare function EntityHistoryView<M extends Record<string, unknown>>({ entity, collection, formContext }: EntityCustomViewParams<M>
|
|
6
|
+
export declare function EntityHistoryView<M extends Record<string, unknown>>({ entity, collection, formContext, refreshToken }: EntityCustomViewParams<M> & {
|
|
7
|
+
/** Bumped once per save, so the list picks up the revision it just made. */
|
|
8
|
+
refreshToken?: number;
|
|
9
|
+
}): import("react").JSX.Element;
|
|
@@ -19,6 +19,8 @@ export * from "./ReferenceWidget";
|
|
|
19
19
|
export * from "./SearchIconsView";
|
|
20
20
|
export * from "./FieldCaption";
|
|
21
21
|
export * from "./EntityPreviewBinding";
|
|
22
|
+
export * from "./EntityPreviewNesting";
|
|
23
|
+
export * from "./InlineEntityPreview";
|
|
22
24
|
export * from "./common";
|
|
23
25
|
export * from "./field_configs";
|
|
24
26
|
export * from "./SidePanelProvider";
|