@rebasepro/cms 0.20.0 → 0.21.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/dist/{CollectionEditorDialog-DQjLtp1W.js → CollectionEditorDialog-C-A_NCKB.js} +15 -14
- package/dist/CollectionEditorDialog-C-A_NCKB.js.map +1 -0
- package/dist/JsonPreviewBinding-v0w3H0fp.js +35 -0
- package/dist/JsonPreviewBinding-v0w3H0fp.js.map +1 -0
- package/dist/{PropertyEditView-BMCCD2OI.js → PropertyEditView-Dv7496fx.js} +2 -57
- package/dist/{PropertyEditView-BMCCD2OI.js.map → PropertyEditView-Dv7496fx.js.map} +1 -1
- package/dist/{RouterCollectionsStudioView-DwsbIAqr.js → RouterCollectionsStudioView-DuDFEYuL.js} +4 -4
- package/dist/{RouterCollectionsStudioView-DwsbIAqr.js.map → RouterCollectionsStudioView-DuDFEYuL.js.map} +1 -1
- package/dist/collection_editor/ui/collection_editor/templates/blog_template.d.ts +126 -2
- package/dist/collection_editor/ui/collection_editor/templates/pages_template.d.ts +201 -2
- package/dist/collection_editor/ui/collection_editor/templates/products_template.d.ts +92 -2
- package/dist/collection_editor/ui/collection_editor/templates/users_template.d.ts +43 -2
- package/dist/collection_editor_ui.js +4 -4
- package/dist/components/CollectionViewBinding/CollectionViewStartActions.d.ts +6 -2
- package/dist/components/CollectionViewBinding/EntityCardBinding.d.ts +11 -1
- package/dist/components/DeleteEntityDialog.d.ts +11 -3
- package/dist/data_export/export/ExportCollectionAction.d.ts +1 -1
- package/dist/data_export/export/fetch_export_data.d.ts +10 -16
- package/dist/editor/editor.d.ts +1 -6
- package/dist/editor.js +1 -1
- package/dist/editor.js.map +1 -1
- package/dist/{export-DJoGYb89.js → export-DtSmLT6u.js} +54 -42
- package/dist/export-DtSmLT6u.js.map +1 -0
- package/dist/form/EntityForm.d.ts +1 -1
- package/dist/{history-BBpsdTrJ.js → history-C6kUDQ3f.js} +2 -2
- package/dist/{history-BBpsdTrJ.js.map → history-C6kUDQ3f.js.map} +1 -1
- package/dist/{import-C4VQ0rwO.js → import-BciQBH5t.js} +2 -2
- package/dist/{import-C4VQ0rwO.js.map → import-BciQBH5t.js.map} +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +12 -12
- package/dist/index.js.map +1 -1
- package/dist/selection/SelectionMenu.d.ts +27 -0
- package/dist/selection/index.d.ts +2 -0
- package/dist/selection/resolve_selection.d.ts +62 -0
- package/dist/types/components/EntityFormProps.d.ts +13 -0
- package/dist/util/entity_pages.d.ts +36 -0
- package/dist/util/map_with_concurrency.d.ts +16 -0
- package/dist/{util-4oPxPkbp.js → util-h6jhiiBE.js} +674 -195
- package/dist/util-h6jhiiBE.js.map +1 -0
- package/package.json +9 -9
- package/dist/CollectionEditorDialog-DQjLtp1W.js.map +0 -1
- package/dist/export-DJoGYb89.js.map +0 -1
- package/dist/util-4oPxPkbp.js.map +0 -1
package/dist/{RouterCollectionsStudioView-DwsbIAqr.js → RouterCollectionsStudioView-DuDFEYuL.js}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import {
|
|
3
|
-
import { t as CollectionEditor } from "./CollectionEditorDialog-
|
|
4
|
-
import { s as AIModifiedPathsProvider } from "./PropertyEditView-
|
|
2
|
+
import { Sn as useUrlController } from "./util-h6jhiiBE.js";
|
|
3
|
+
import { t as CollectionEditor } from "./CollectionEditorDialog-C-A_NCKB.js";
|
|
4
|
+
import { s as AIModifiedPathsProvider } from "./PropertyEditView-Dv7496fx.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";
|
|
@@ -185,4 +185,4 @@ function RouterCollectionsStudioView(props) {
|
|
|
185
185
|
//#endregion
|
|
186
186
|
export { CollectionStudioView as i, RouterCollectionsStudioView_exports as n, CollectionsStudioView as r, RouterCollectionsStudioView as t };
|
|
187
187
|
|
|
188
|
-
//# sourceMappingURL=RouterCollectionsStudioView-
|
|
188
|
+
//# sourceMappingURL=RouterCollectionsStudioView-DuDFEYuL.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RouterCollectionsStudioView-DwsbIAqr.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/cms-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-sheet\">\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/cms-types\";\nimport { readStoredString, writeStoredString } from \"@rebasepro/utils\";\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 // Checked, not just parsed: `parseFloat` answers NaN for anything it cannot\n // read, and a NaN pane size lays the sidebar out to nothing — with the bad\n // value still in storage on reload. `SplitListView.getSavedPanelSize` is the\n // same read, done this way.\n const [sidebarSize, setSidebarSize] = useState(() => {\n const saved = readStoredString(\"rebase_collections_editor_sidebar_size\");\n const parsed = saved === null ? NaN : parseFloat(saved);\n return Number.isFinite(parsed) && parsed > 0 && parsed < 100 ? parsed : 25;\n });\n\n useEffect(() => {\n writeStoredString(\"rebase_collections_editor_sidebar_size\", sidebarSize.toString());\n }, [sidebarSize]);\n\n return (\n <div className=\"flex h-full w-full bg-surface-sheet 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-sheet border-r\", defaultBorderMixin)}>\n <div className={cls(\"flex items-center justify-between px-3 py-2 border-b 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-surface-hover 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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"}
|
|
1
|
+
{"version":3,"file":"RouterCollectionsStudioView-DuDFEYuL.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/cms-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-sheet\">\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/cms-types\";\nimport { readStoredString, writeStoredString } from \"@rebasepro/utils\";\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 // Checked, not just parsed: `parseFloat` answers NaN for anything it cannot\n // read, and a NaN pane size lays the sidebar out to nothing — with the bad\n // value still in storage on reload. `SplitListView.getSavedPanelSize` is the\n // same read, done this way.\n const [sidebarSize, setSidebarSize] = useState(() => {\n const saved = readStoredString(\"rebase_collections_editor_sidebar_size\");\n const parsed = saved === null ? NaN : parseFloat(saved);\n return Number.isFinite(parsed) && parsed > 0 && parsed < 100 ? parsed : 25;\n });\n\n useEffect(() => {\n writeStoredString(\"rebase_collections_editor_sidebar_size\", sidebarSize.toString());\n }, [sidebarSize]);\n\n return (\n <div className=\"flex h-full w-full bg-surface-sheet 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-sheet border-r\", defaultBorderMixin)}>\n <div className={cls(\"flex items-center justify-between px-3 py-2 border-b 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-surface-hover 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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"}
|
|
@@ -1,2 +1,126 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export declare const blogCollectionTemplate: {
|
|
2
|
+
slug: string;
|
|
3
|
+
table: string;
|
|
4
|
+
name: string;
|
|
5
|
+
singularName: string;
|
|
6
|
+
icon: string;
|
|
7
|
+
description: string;
|
|
8
|
+
defaultSize: "l";
|
|
9
|
+
properties: {
|
|
10
|
+
name: {
|
|
11
|
+
name: string;
|
|
12
|
+
validation: {
|
|
13
|
+
required: true;
|
|
14
|
+
};
|
|
15
|
+
type: "string";
|
|
16
|
+
};
|
|
17
|
+
header_image: {
|
|
18
|
+
name: string;
|
|
19
|
+
type: "string";
|
|
20
|
+
storage: {
|
|
21
|
+
storagePath: string;
|
|
22
|
+
acceptedFiles: string[];
|
|
23
|
+
metadata: {
|
|
24
|
+
cacheControl: string;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
content: {
|
|
29
|
+
name: string;
|
|
30
|
+
description: string;
|
|
31
|
+
validation: {
|
|
32
|
+
required: true;
|
|
33
|
+
};
|
|
34
|
+
type: "array";
|
|
35
|
+
oneOf: {
|
|
36
|
+
typeField: string;
|
|
37
|
+
valueField: string;
|
|
38
|
+
properties: {
|
|
39
|
+
text: {
|
|
40
|
+
type: "string";
|
|
41
|
+
name: string;
|
|
42
|
+
admin: {
|
|
43
|
+
markdown: true;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
quote: {
|
|
47
|
+
type: "string";
|
|
48
|
+
name: string;
|
|
49
|
+
admin: {
|
|
50
|
+
multiline: true;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
images: {
|
|
54
|
+
name: string;
|
|
55
|
+
type: "array";
|
|
56
|
+
of: {
|
|
57
|
+
type: "string";
|
|
58
|
+
storage: {
|
|
59
|
+
storagePath: string;
|
|
60
|
+
acceptedFiles: string[];
|
|
61
|
+
metadata: {
|
|
62
|
+
cacheControl: string;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
description: string;
|
|
67
|
+
};
|
|
68
|
+
products: {
|
|
69
|
+
name: string;
|
|
70
|
+
type: "array";
|
|
71
|
+
of: {
|
|
72
|
+
type: "reference";
|
|
73
|
+
path: string;
|
|
74
|
+
admin: {
|
|
75
|
+
previewProperties: string[];
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
propertiesOrder: string[];
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
created_on: {
|
|
84
|
+
name: string;
|
|
85
|
+
type: "date";
|
|
86
|
+
autoValue: "on_create";
|
|
87
|
+
};
|
|
88
|
+
status: {
|
|
89
|
+
name: string;
|
|
90
|
+
validation: {
|
|
91
|
+
required: true;
|
|
92
|
+
};
|
|
93
|
+
type: "string";
|
|
94
|
+
enum: {
|
|
95
|
+
published: {
|
|
96
|
+
id: string;
|
|
97
|
+
label: string;
|
|
98
|
+
};
|
|
99
|
+
draft: string;
|
|
100
|
+
};
|
|
101
|
+
defaultValue: string;
|
|
102
|
+
};
|
|
103
|
+
publish_date: {
|
|
104
|
+
name: string;
|
|
105
|
+
type: "date";
|
|
106
|
+
admin: {
|
|
107
|
+
clearable: true;
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
reviewed: {
|
|
111
|
+
name: string;
|
|
112
|
+
type: "boolean";
|
|
113
|
+
};
|
|
114
|
+
tags: {
|
|
115
|
+
name: string;
|
|
116
|
+
description: string;
|
|
117
|
+
type: "array";
|
|
118
|
+
of: {
|
|
119
|
+
type: "string";
|
|
120
|
+
admin: {
|
|
121
|
+
previewAsTag: true;
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
};
|
|
@@ -1,2 +1,201 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export declare const pagesCollectionTemplate: {
|
|
2
|
+
slug: string;
|
|
3
|
+
table: string;
|
|
4
|
+
name: string;
|
|
5
|
+
singularName: string;
|
|
6
|
+
icon: string;
|
|
7
|
+
description: string;
|
|
8
|
+
properties: {
|
|
9
|
+
title: {
|
|
10
|
+
type: "string";
|
|
11
|
+
name: string;
|
|
12
|
+
validation: {
|
|
13
|
+
required: true;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
slug: {
|
|
17
|
+
type: "string";
|
|
18
|
+
name: string;
|
|
19
|
+
validation: {
|
|
20
|
+
required: true;
|
|
21
|
+
unique: true;
|
|
22
|
+
matches: string;
|
|
23
|
+
matchesMessage: string;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
hero_section: {
|
|
27
|
+
type: "map";
|
|
28
|
+
name: string;
|
|
29
|
+
properties: {
|
|
30
|
+
headline: {
|
|
31
|
+
type: "string";
|
|
32
|
+
name: string;
|
|
33
|
+
validation: {
|
|
34
|
+
required: true;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
subhead: {
|
|
38
|
+
type: "string";
|
|
39
|
+
name: string;
|
|
40
|
+
};
|
|
41
|
+
background_image: {
|
|
42
|
+
type: "string";
|
|
43
|
+
name: string;
|
|
44
|
+
storage: {
|
|
45
|
+
storagePath: string;
|
|
46
|
+
acceptedFiles: string[];
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
call_to_action: {
|
|
50
|
+
type: "string";
|
|
51
|
+
name: string;
|
|
52
|
+
};
|
|
53
|
+
call_to_action_link: {
|
|
54
|
+
type: "string";
|
|
55
|
+
name: string;
|
|
56
|
+
url: true;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
content: {
|
|
61
|
+
type: "array";
|
|
62
|
+
name: string;
|
|
63
|
+
oneOf: {
|
|
64
|
+
properties: {
|
|
65
|
+
section: {
|
|
66
|
+
type: "map";
|
|
67
|
+
name: string;
|
|
68
|
+
properties: {
|
|
69
|
+
title: {
|
|
70
|
+
type: "string";
|
|
71
|
+
name: string;
|
|
72
|
+
validation: {
|
|
73
|
+
required: true;
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
content: {
|
|
77
|
+
type: "string";
|
|
78
|
+
name: string;
|
|
79
|
+
admin: {
|
|
80
|
+
markdown: true;
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
image: {
|
|
84
|
+
type: "string";
|
|
85
|
+
name: string;
|
|
86
|
+
storage: {
|
|
87
|
+
storagePath: string;
|
|
88
|
+
acceptedFiles: string[];
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
link: {
|
|
92
|
+
type: "string";
|
|
93
|
+
name: string;
|
|
94
|
+
url: true;
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
image: {
|
|
99
|
+
type: "string";
|
|
100
|
+
name: string;
|
|
101
|
+
storage: {
|
|
102
|
+
storagePath: string;
|
|
103
|
+
acceptedFiles: string[];
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
slider: {
|
|
107
|
+
type: "array";
|
|
108
|
+
name: string;
|
|
109
|
+
of: {
|
|
110
|
+
type: "map";
|
|
111
|
+
properties: {
|
|
112
|
+
title: {
|
|
113
|
+
type: "string";
|
|
114
|
+
name: string;
|
|
115
|
+
validation: {
|
|
116
|
+
required: true;
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
image: {
|
|
120
|
+
type: "string";
|
|
121
|
+
storage: {
|
|
122
|
+
storagePath: string;
|
|
123
|
+
acceptedFiles: string[];
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
sidebar: {
|
|
133
|
+
type: "map";
|
|
134
|
+
name: string;
|
|
135
|
+
properties: {
|
|
136
|
+
title: {
|
|
137
|
+
type: "string";
|
|
138
|
+
name: string;
|
|
139
|
+
validation: {
|
|
140
|
+
required: false;
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
content: {
|
|
144
|
+
type: "string";
|
|
145
|
+
name: string;
|
|
146
|
+
admin: {
|
|
147
|
+
markdown: true;
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
seo_metadata: {
|
|
153
|
+
type: "map";
|
|
154
|
+
name: string;
|
|
155
|
+
properties: {
|
|
156
|
+
meta_title: {
|
|
157
|
+
type: "string";
|
|
158
|
+
name: string;
|
|
159
|
+
};
|
|
160
|
+
meta_description: {
|
|
161
|
+
type: "string";
|
|
162
|
+
name: string;
|
|
163
|
+
};
|
|
164
|
+
focus_keywords: {
|
|
165
|
+
type: "array";
|
|
166
|
+
name: string;
|
|
167
|
+
of: {
|
|
168
|
+
type: "string";
|
|
169
|
+
};
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
footer_override: {
|
|
174
|
+
type: "string";
|
|
175
|
+
name: string;
|
|
176
|
+
admin: {
|
|
177
|
+
markdown: true;
|
|
178
|
+
};
|
|
179
|
+
};
|
|
180
|
+
publish_date: {
|
|
181
|
+
type: "date";
|
|
182
|
+
name: string;
|
|
183
|
+
validation: {
|
|
184
|
+
required: true;
|
|
185
|
+
};
|
|
186
|
+
};
|
|
187
|
+
last_updated: {
|
|
188
|
+
type: "date";
|
|
189
|
+
name: string;
|
|
190
|
+
autoValue: "on_update";
|
|
191
|
+
};
|
|
192
|
+
is_published: {
|
|
193
|
+
type: "boolean";
|
|
194
|
+
name: string;
|
|
195
|
+
admin: {
|
|
196
|
+
columnWidth: number;
|
|
197
|
+
};
|
|
198
|
+
description: string;
|
|
199
|
+
};
|
|
200
|
+
};
|
|
201
|
+
};
|
|
@@ -1,2 +1,92 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export declare const productsCollectionTemplate: {
|
|
2
|
+
slug: string;
|
|
3
|
+
table: string;
|
|
4
|
+
name: string;
|
|
5
|
+
singularName: string;
|
|
6
|
+
icon: string;
|
|
7
|
+
description: string;
|
|
8
|
+
properties: {
|
|
9
|
+
name: {
|
|
10
|
+
type: "string";
|
|
11
|
+
name: string;
|
|
12
|
+
description: string;
|
|
13
|
+
validation: {
|
|
14
|
+
required: true;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
brand: {
|
|
18
|
+
type: "string";
|
|
19
|
+
name: string;
|
|
20
|
+
validation: {
|
|
21
|
+
required: true;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
description: {
|
|
25
|
+
type: "string";
|
|
26
|
+
name: string;
|
|
27
|
+
description: string;
|
|
28
|
+
admin: {
|
|
29
|
+
markdown: true;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
main_image: {
|
|
33
|
+
type: "string";
|
|
34
|
+
name: string;
|
|
35
|
+
storage: {
|
|
36
|
+
storagePath: string;
|
|
37
|
+
acceptedFiles: string[];
|
|
38
|
+
};
|
|
39
|
+
description: string;
|
|
40
|
+
};
|
|
41
|
+
available: {
|
|
42
|
+
type: "boolean";
|
|
43
|
+
name: string;
|
|
44
|
+
admin: {
|
|
45
|
+
columnWidth: number;
|
|
46
|
+
};
|
|
47
|
+
description: string;
|
|
48
|
+
};
|
|
49
|
+
price: {
|
|
50
|
+
type: "number";
|
|
51
|
+
name: string;
|
|
52
|
+
validation: {
|
|
53
|
+
requiredMessage: string;
|
|
54
|
+
min: number;
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
images: {
|
|
58
|
+
type: "array";
|
|
59
|
+
name: string;
|
|
60
|
+
admin: {
|
|
61
|
+
hideFromCollection: true;
|
|
62
|
+
};
|
|
63
|
+
of: {
|
|
64
|
+
type: "string";
|
|
65
|
+
storage: {
|
|
66
|
+
storagePath: string;
|
|
67
|
+
acceptedFiles: string[];
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
related_products: {
|
|
72
|
+
type: "array";
|
|
73
|
+
name: string;
|
|
74
|
+
description: string;
|
|
75
|
+
of: {
|
|
76
|
+
type: "reference";
|
|
77
|
+
path: string;
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
metadata: {
|
|
81
|
+
name: string;
|
|
82
|
+
description: string;
|
|
83
|
+
type: "map";
|
|
84
|
+
keyValue: true;
|
|
85
|
+
};
|
|
86
|
+
added_on: {
|
|
87
|
+
type: "date";
|
|
88
|
+
name: string;
|
|
89
|
+
autoValue: "on_create";
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
};
|
|
@@ -1,2 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export declare const usersCollectionTemplate: {
|
|
2
|
+
slug: string;
|
|
3
|
+
table: string;
|
|
4
|
+
name: string;
|
|
5
|
+
singularName: string;
|
|
6
|
+
description: string;
|
|
7
|
+
icon: string;
|
|
8
|
+
properties: {
|
|
9
|
+
displayName: {
|
|
10
|
+
name: string;
|
|
11
|
+
type: "string";
|
|
12
|
+
};
|
|
13
|
+
email: {
|
|
14
|
+
name: string;
|
|
15
|
+
type: "string";
|
|
16
|
+
email: true;
|
|
17
|
+
};
|
|
18
|
+
emailVerified: {
|
|
19
|
+
name: string;
|
|
20
|
+
type: "boolean";
|
|
21
|
+
};
|
|
22
|
+
phone: {
|
|
23
|
+
name: string;
|
|
24
|
+
type: "string";
|
|
25
|
+
};
|
|
26
|
+
favourite_products: {
|
|
27
|
+
name: string;
|
|
28
|
+
type: "array";
|
|
29
|
+
of: {
|
|
30
|
+
type: "reference";
|
|
31
|
+
path: string;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
photoURL: {
|
|
35
|
+
name: string;
|
|
36
|
+
type: "string";
|
|
37
|
+
url: true;
|
|
38
|
+
admin: {
|
|
39
|
+
urlPreview: "image";
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as CollectionEditorDialog } from "./CollectionEditorDialog-
|
|
3
|
-
import { n as PropertyForm, r as PropertyFormDialog } from "./PropertyEditView-
|
|
4
|
-
import { i as CollectionStudioView, r as CollectionsStudioView, t as RouterCollectionsStudioView } from "./RouterCollectionsStudioView-
|
|
1
|
+
import { Sn as useUrlController } from "./util-h6jhiiBE.js";
|
|
2
|
+
import { n as CollectionEditorDialog } from "./CollectionEditorDialog-C-A_NCKB.js";
|
|
3
|
+
import { n as PropertyForm, r as PropertyFormDialog } from "./PropertyEditView-Dv7496fx.js";
|
|
4
|
+
import { i as CollectionStudioView, r as CollectionsStudioView, t as RouterCollectionsStudioView } from "./RouterCollectionsStudioView-DuDFEYuL.js";
|
|
5
5
|
import { t as SchemaChangeDialog } from "./SchemaChangeDialog-BeP0A4MJ.js";
|
|
6
6
|
import "react";
|
|
7
7
|
import { useSnackbarController } from "@rebasepro/app";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Properties } from "@rebasepro/types";
|
|
2
2
|
import React from "react";
|
|
3
|
-
import { EntityTableController, SelectionController, AdminCollection, ViewMode } from "@rebasepro/cms-types";
|
|
3
|
+
import { EntityTableController, SelectionController, SelectionQuery, AdminCollection, ViewMode } from "@rebasepro/cms-types";
|
|
4
4
|
export type CollectionViewStartActionsProps<M extends Record<string, unknown>> = {
|
|
5
5
|
collection: AdminCollection<M>;
|
|
6
6
|
path: string;
|
|
@@ -27,7 +27,11 @@ export type CollectionViewStartActionsProps<M extends Record<string, unknown>> =
|
|
|
27
27
|
* offered — see `sortButton`.
|
|
28
28
|
*/
|
|
29
29
|
viewMode?: ViewMode;
|
|
30
|
+
/** Whether rows can be selected at all in this mount. */
|
|
31
|
+
selectionEnabled?: boolean;
|
|
32
|
+
/** The view's live query — what the menu's "all matching" item stands for. */
|
|
33
|
+
selectionQuery?: SelectionQuery<M>;
|
|
30
34
|
compact?: boolean;
|
|
31
35
|
openNewDocument: (defaultValues?: Record<string, unknown>) => void;
|
|
32
36
|
};
|
|
33
|
-
export declare function CollectionViewStartActions<M extends Record<string, unknown>>({ collection, relativePath, parentCollectionSlugs, parentEntityIds, path, selectionController, tableController, collectionEntitiesCount, entitiesCount, resolvedProperties, viewMode, compact, openNewDocument }: CollectionViewStartActionsProps<M>): React.JSX.Element;
|
|
37
|
+
export declare function CollectionViewStartActions<M extends Record<string, unknown>>({ collection, relativePath, parentCollectionSlugs, parentEntityIds, path, selectionController, tableController, collectionEntitiesCount, entitiesCount, resolvedProperties, viewMode, selectionEnabled, selectionQuery, compact, openNewDocument }: CollectionViewStartActionsProps<M>): React.JSX.Element;
|
|
@@ -6,7 +6,17 @@ export type EntityCardBindingProps<M extends Record<string, unknown> = Record<st
|
|
|
6
6
|
searchString?: string;
|
|
7
7
|
entity: Entity<M>;
|
|
8
8
|
collection: AdminCollection<M>;
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* The card was clicked.
|
|
11
|
+
*
|
|
12
|
+
* Carries the originating event as well as the entity, because the grid's
|
|
13
|
+
* own handler needs it: `CardView` hands `renderCard` an
|
|
14
|
+
* `(e: React.MouseEvent) => void` that reads `e.metaKey` / `e.ctrlKey` and
|
|
15
|
+
* calls `e.preventDefault()`. That handler used to be passed here through
|
|
16
|
+
* `onClick as any` and then invoked with the *entity*, so its modifier
|
|
17
|
+
* branch read `entity.metaKey` — always undefined — and never ran.
|
|
18
|
+
*/
|
|
19
|
+
onClick?: (entity: Entity<M>, event?: React.MouseEvent) => void;
|
|
10
20
|
selected?: boolean;
|
|
11
21
|
highlighted?: boolean;
|
|
12
22
|
onSelectionChange?: (entity: Entity<M>, selected: boolean) => void;
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { Entity } from "@rebasepro/types";
|
|
2
2
|
import React from "react";
|
|
3
|
-
import type { AdminCollection } from "@rebasepro/cms-types";
|
|
3
|
+
import type { AdminCollection, EntitySelection } from "@rebasepro/cms-types";
|
|
4
4
|
export interface DeleteEntityDialogProps<M extends Record<string, unknown>> {
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* What to delete: one row, or a whole selection.
|
|
7
|
+
*
|
|
8
|
+
* A selection may be a *query* — every row matching a filter, most of them
|
|
9
|
+
* never read. That is why this is not an `Entity[]`: the rows do not exist
|
|
10
|
+
* until {@link resolveSelection} reads them, and it only does that once the
|
|
11
|
+
* user has confirmed.
|
|
12
|
+
*/
|
|
13
|
+
target?: Entity<M> | EntitySelection<M>;
|
|
6
14
|
path: string;
|
|
7
15
|
collection: AdminCollection<M>;
|
|
8
16
|
open: boolean;
|
|
@@ -18,4 +26,4 @@ export interface DeleteEntityDialogProps<M extends Record<string, unknown>> {
|
|
|
18
26
|
*/
|
|
19
27
|
variant?: "delete" | "unlink";
|
|
20
28
|
}
|
|
21
|
-
export declare function DeleteEntityDialog<M extends Record<string, unknown>>({
|
|
29
|
+
export declare function DeleteEntityDialog<M extends Record<string, unknown>>({ target, collection, onClose, open, onEntityDelete, onMultipleEntitiesDelete, path, variant }: DeleteEntityDialogProps<M>): React.JSX.Element;
|