@rebasepro/admin 0.11.1-canary.gfd39654 → 0.12.1-canary.g009ed95
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 +2 -2
- package/dist/{CollectionEditorDialog-o7F_zbGY.js → CollectionEditorDialog-B-iVE9y3.js} +126 -317
- package/dist/CollectionEditorDialog-B-iVE9y3.js.map +1 -0
- package/dist/{PropertyEditView-DgB2b22q.js → PropertyEditView-DoLEH_bQ.js} +36 -16
- package/dist/{PropertyEditView-DgB2b22q.js.map → PropertyEditView-DoLEH_bQ.js.map} +1 -1
- package/dist/{RouterCollectionsStudioView-DaLRgPkj.js → RouterCollectionsStudioView-C3669Ezm.js} +5 -5
- package/dist/{RouterCollectionsStudioView-DaLRgPkj.js.map → RouterCollectionsStudioView-C3669Ezm.js.map} +1 -1
- package/dist/collection_editor/CollectionEditorDialogsContext.d.ts +1 -1
- package/dist/collection_editor/_cms_internals.d.ts +1 -1
- package/dist/collection_editor/extensibility_types.d.ts +1 -1
- package/dist/collection_editor/serializable_types.d.ts +44 -13
- package/dist/collection_editor/serializable_utils.d.ts +1 -1
- package/dist/collection_editor/ui/collection_editor/CollectionRLSTab.d.ts +1 -11
- 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/CollectionEditorDialogs.d.ts +2 -2
- package/dist/components/CollectionTableBinding/column_utils.d.ts +7 -1
- package/dist/components/CollectionViewBinding/CollectionListViewBinding.d.ts +2 -2
- 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/DefaultDrawer.d.ts +3 -3
- package/dist/components/DetailViewBinding.d.ts +5 -0
- package/dist/components/DrawerNavigationGroup.d.ts +8 -1
- package/dist/components/DrawerNavigationItem.d.ts +7 -1
- package/dist/components/EditFormActions.d.ts +12 -1
- package/dist/components/EditViewBinding.d.ts +7 -2
- package/dist/components/EntityIdentityBar.d.ts +53 -0
- package/dist/components/EntityInspector.d.ts +29 -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/RebaseAdmin.d.ts +1 -1
- package/dist/components/RebaseAuthGate.d.ts +1 -1
- package/dist/components/RebaseLayout.d.ts +5 -1
- package/dist/components/RebaseNavigation.d.ts +2 -2
- package/dist/components/RebaseRouteDefs.d.ts +1 -1
- package/dist/components/RebaseShell.d.ts +6 -1
- package/dist/components/RelationSelector.d.ts +14 -0
- package/dist/components/SelectableTable/filters/RelationFilterField.d.ts +27 -0
- package/dist/components/SelectableTable/filters/null_filter.d.ts +46 -0
- package/dist/components/SidePanelProvider.d.ts +2 -2
- package/dist/components/app/Scaffold.d.ts +11 -0
- package/dist/components/field_configs.d.ts +1 -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-BvqhjdEb.js → export-B8DIn-u8.js} +3 -3
- package/dist/export-B8DIn-u8.js.map +1 -0
- package/dist/form/EntityForm.d.ts +3 -3
- package/dist/form/EntityFormActions.d.ts +11 -1
- package/dist/form/EntityFormBinding.d.ts +5 -5
- 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-Dz20hH38.js → history-ClwDEtqN.js} +32 -31
- package/dist/history-ClwDEtqN.js.map +1 -0
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/navigation/utils.d.ts +16 -0
- package/dist/hooks/useAdminContext.d.ts +29 -0
- package/dist/hooks/useBuildSidePanel.d.ts +14 -0
- package/dist/hooks/useEntityDisplayTitle.d.ts +18 -0
- package/dist/hooks/useHistory.d.ts +7 -11
- package/dist/hooks/useRecordActions.d.ts +17 -0
- package/dist/{import-DINSB-Vu.js → import-Cwzf4RW5.js} +2 -2
- package/dist/{import-DINSB-Vu.js.map → import-Cwzf4RW5.js.map} +1 -1
- package/dist/index.js +159 -65
- 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 +1 -6
- package/dist/types/fields.d.ts +25 -1
- package/dist/{util-BhhfHY1M.js → util-DSh3HRzK.js} +2235 -1264
- package/dist/util-DSh3HRzK.js.map +1 -0
- package/package.json +32 -34
- package/src/collection_editor/CollectionEditorDialogsContext.tsx +1 -1
- package/src/collection_editor/ConfigControllerProvider.tsx +2 -2
- package/src/collection_editor/_cms_internals.ts +1 -1
- package/src/collection_editor/extensibility_types.ts +1 -1
- package/src/collection_editor/index.ts +2 -2
- package/src/collection_editor/serializable_types.ts +48 -16
- package/src/collection_editor/serializable_utils.ts +118 -75
- package/src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx +66 -23
- package/src/collection_editor/ui/collection_editor/CollectionRLSTab.tsx +102 -69
- package/src/collection_editor/ui/collection_editor/CollectionRelationsTab.tsx +3 -1
- package/src/collection_editor/ui/collection_editor/EntityActionsEditTab.tsx +1 -1
- package/src/collection_editor/ui/collection_editor/GetCodeDialog.tsx +1 -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/SubcollectionsEditTab.tsx +2 -2
- 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/CollectionEditorDialogs.tsx +2 -2
- package/src/components/CollectionTableBinding/CollectionRowActions.tsx +5 -4
- package/src/components/CollectionTableBinding/CollectionTableBinding.tsx +8 -2
- package/src/components/CollectionTableBinding/PropertyTableCell.tsx +10 -2
- package/src/components/CollectionTableBinding/column_utils.tsx +45 -7
- package/src/components/CollectionTableBinding/table_bindings.tsx +12 -11
- package/src/components/CollectionViewBinding/CollectionBoardViewBinding.tsx +23 -16
- package/src/components/CollectionViewBinding/CollectionListViewBinding.tsx +8 -7
- package/src/components/CollectionViewBinding/CollectionViewActions.tsx +9 -3
- package/src/components/CollectionViewBinding/CollectionViewBinding.tsx +10 -4
- package/src/components/CollectionViewBinding/CollectionViewStartActions.tsx +24 -13
- 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 +20 -9
- package/src/components/DeleteEntityDialog.tsx +2 -2
- package/src/components/DetailViewBinding.tsx +119 -142
- package/src/components/DrawerNavigationGroup.tsx +47 -4
- package/src/components/DrawerNavigationItem.tsx +20 -6
- package/src/components/EditFormActions.tsx +58 -132
- package/src/components/EditViewBinding.tsx +183 -94
- package/src/components/EntityIdentityBar.tsx +288 -0
- package/src/components/EntityInspector.tsx +132 -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/ContentHomePage.tsx +4 -4
- 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/RebaseAdmin.tsx +3 -3
- package/src/components/RebaseAuthGate.tsx +1 -1
- package/src/components/RebaseLayout.tsx +9 -3
- package/src/components/RebaseNavigation.tsx +54 -14
- package/src/components/RebaseRouteDefs.tsx +3 -3
- package/src/components/RebaseShell.tsx +10 -1
- package/src/components/RelationSelector.tsx +18 -3
- package/src/components/SelectableTable/SelectableTable.tsx +2 -2
- package/src/components/SelectableTable/filters/FilterFieldBinding.tsx +1 -1
- package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +36 -9
- package/src/components/SelectableTable/filters/RelationFilterField.tsx +93 -17
- package/src/components/SelectableTable/filters/null_filter.ts +63 -0
- package/src/components/SidePanelBinding.tsx +19 -13
- package/src/components/SidePanelProvider.tsx +2 -2
- package/src/components/UserSelector.tsx +12 -6
- package/src/components/app/Scaffold.tsx +16 -1
- package/src/components/common/default_entity_actions.tsx +4 -3
- package/src/components/history/EntityHistoryEntry.tsx +28 -7
- package/src/components/history/EntityHistoryView.tsx +20 -20
- package/src/components/history/LastEditedByIndicator.tsx +4 -3
- package/src/components/index.ts +2 -0
- package/src/data_export/export/ExportCollectionAction.tsx +2 -2
- package/src/data_import/utils/get_import_inference_type.ts +6 -0
- package/src/form/EntityForm.tsx +269 -181
- package/src/form/EntityFormActions.tsx +52 -100
- package/src/form/EntityFormBinding.tsx +11 -9
- 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/ArrayOfReferencesFieldBinding.tsx +3 -3
- 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/MultipleRelationFieldBinding.tsx +16 -5
- package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +2 -1
- package/src/form/field_bindings/ReferenceFieldBinding.tsx +5 -4
- package/src/form/field_bindings/RelationFieldBinding.tsx +23 -10
- package/src/form/field_bindings/RepeatFieldBinding.tsx +6 -3
- 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/index.ts +1 -1
- package/src/hooks/navigation/useBuildUrlController.tsx +1 -1
- package/src/hooks/navigation/useNavigationResolution.ts +10 -4
- package/src/hooks/navigation/useTopLevelNavigation.ts +18 -7
- package/src/hooks/navigation/utils.ts +20 -0
- package/src/hooks/{useCMSContext.tsx → useAdminContext.tsx} +10 -10
- 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 +14 -17
- package/src/hooks/useRecordActions.tsx +69 -0
- package/src/hooks/useResolvedNavigationFrom.tsx +2 -2
- package/src/hooks/useResolvedUsers.ts +10 -5
- package/src/index.ts +4 -4
- package/src/preview/PropertyPreview.tsx +52 -26
- package/src/preview/components/InlineEntityListPreview.tsx +42 -0
- package/src/preview/components/ReferencePreview.tsx +34 -14
- package/src/preview/components/RelationPreview.tsx +35 -15
- package/src/preview/index.ts +1 -0
- package/src/preview/property_previews/ArrayOfMapsPreview.tsx +1 -1
- package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +26 -3
- package/src/preview/property_previews/ArrayOfRelationsPreview.tsx +27 -3
- package/src/preview/property_previews/SkeletonPropertyComponent.tsx +2 -2
- package/src/routes/RebaseRoute.tsx +2 -2
- package/src/types/components/EntityFormActionsProps.tsx +0 -1
- package/src/types/components/EntityFormProps.tsx +2 -8
- package/src/types/fields.tsx +28 -1
- package/dist/CollectionEditorDialog-o7F_zbGY.js.map +0 -1
- package/dist/collection_editor/pgColumnToProperty.d.ts +0 -7
- package/dist/editor/extensions/Image/index.d.ts +0 -6
- package/dist/export-BvqhjdEb.js.map +0 -1
- package/dist/form/components/FormEntry.d.ts +0 -6
- package/dist/form/components/FormLayout.d.ts +0 -5
- package/dist/history-Dz20hH38.js.map +0 -1
- package/dist/hooks/useCMSContext.d.ts +0 -29
- package/dist/util-BhhfHY1M.js.map +0 -1
- package/src/collection_editor/pgColumnToProperty.ts +0 -291
- package/src/editor/extensions/Image/index.ts +0 -133
- package/src/form/components/FormEntry.tsx +0 -22
- package/src/form/components/FormLayout.tsx +0 -16
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ CMS frontend — content management views, forms, routing, visual schema editor,
|
|
|
8
8
|
pnpm add @rebasepro/admin
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
**Peer dependencies:** `react >= 19`, `react-dom >= 19
|
|
11
|
+
**Peer dependencies:** `react >= 19.2.7`, `react-dom >= 19.2.7`, `react-router ^8`
|
|
12
12
|
|
|
13
13
|
## What This Package Does
|
|
14
14
|
|
|
@@ -71,7 +71,7 @@ pnpm add @rebasepro/admin
|
|
|
71
71
|
| `useSelectionController` | Row selection state for tables |
|
|
72
72
|
| `useHistory` | Snapshot change history and version revert |
|
|
73
73
|
| `useBreadcrumbsController` | Breadcrumb navigation state |
|
|
74
|
-
| `
|
|
74
|
+
| `useAdminContext` | Access the admin-level context |
|
|
75
75
|
| `useResolvedNavigationFrom` | Resolve navigation tree from collection configs |
|
|
76
76
|
|
|
77
77
|
### Data Import/Export
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import { $t as CollectionTableBinding, A as getFieldId, Ct as convertDataToEntity, Dt as useImportConfig, Et as getInferenceType, Ft as FieldCaption,
|
|
3
|
-
import { a as updatePropertyFromWidget, c as useAIModifiedPaths, i as supportedFields, l as useSafeSnackbarController, n as PropertyForm, o as PropertyTree, r as PropertyFormDialog, s as AIModifiedPathsProvider } from "./PropertyEditView-
|
|
2
|
+
import { $t as CollectionTableBinding, A as getFieldId, Ct as convertDataToEntity, Dt as useImportConfig, Et as getInferenceType, Ft as FieldCaption, Ln as useCollectionRegistryController, Nt as PropertyConfigBadge, Ot as ImportSaveInProgress, Pt as SearchIconsView, St as DataNewPropertiesMapping, Zt as useSelectionController, _ as useCollectionsConfigController, i as namespaceToPropertiesOrderPath, in as useUrlController, k as getFieldConfig, kt as ImportFileUpload, l as validateCollectionJson, m as toSerializableCollectionConfig, n as getFullIdPath, o as CollectionGenerationApiError, on as useNavigationStateController, r as idToPropertiesPath, t as getFullId, vt as useCollectionEditorController, xt as ImportNewPropertyFieldPreview } from "./util-DSh3HRzK.js";
|
|
3
|
+
import { a as updatePropertyFromWidget, c as useAIModifiedPaths, i as supportedFields, l as useSafeSnackbarController, n as PropertyForm, o as PropertyTree, r as PropertyFormDialog, s as AIModifiedPathsProvider } from "./PropertyEditView-DoLEH_bQ.js";
|
|
4
4
|
import * as React$1 from "react";
|
|
5
5
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
6
6
|
import { Alert, AppWindow, ArrowLeftIcon, BooleanSwitchWithLabel, Button, Card, CheckIcon, Chip, CircularProgress, CircularProgressCenter, CodeIcon, ColumnsIcon, Container, CopyIcon, DebouncedTextField, Dialog, DialogActions, DialogContent, DialogTitle, ErrorBoundary, FileIcon, FileSearchIcon, FileTextIcon, IconButton, KanbanIcon, KeyIcon, LayoutGridIcon, ListIcon, LoadingButton, Menu, MultiSelect, MultiSelectItem, PanelLeftIcon, Paper, PlusIcon, Select, SelectItem, ShoppingCartIcon, SquareIcon, Tab, TableIcon, Tabs, TextField, ToggleButtonGroup, Tooltip, Trash2Icon, Typography, UserIcon, XIcon, cls, coolIconKeys, defaultBorderMixin, iconSize } from "@rebasepro/ui";
|
|
7
|
-
import {
|
|
7
|
+
import { buildCollectionFromTableMetadata, getGeneratedPolicyNames, getSubcollections, getTableName, isPropertyBuilder } from "@rebasepro/common";
|
|
8
8
|
import { AIIcon, ConfirmationDialog, ErrorView, IconForView, UnsavedChangesDialog, removeInitialAndTrailingSlashes, useAuthController, useCustomizationController, useLargeLayout, useRebaseContext, useUnsavedChangesDialog } from "@rebasepro/app";
|
|
9
9
|
import { Field, Formex, clone, getIn, useCreateFormex, useFormex } from "@rebasepro/forms";
|
|
10
10
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
-
import { camelCase, getPolicyNamesForRule,
|
|
11
|
+
import { camelCase, getPolicyNamesForRule, isEmptyObject, mergeDeep, prettifyIdentifier, randomString, removeUndefined, singular, slugify, toSnakeCase, unslugify } from "@rebasepro/utils";
|
|
12
12
|
import { getDataSourceCapabilities } from "@rebasepro/types";
|
|
13
13
|
import { z } from "zod";
|
|
14
14
|
import { buildEntityPropertiesFromData, buildPropertyFromData } from "@rebasepro/inference";
|
|
@@ -696,7 +696,7 @@ function GetCodeDialog({ collection, onOpenChange, open }) {
|
|
|
696
696
|
variant: "body2",
|
|
697
697
|
className: "my-4 mb-8",
|
|
698
698
|
children: [
|
|
699
|
-
"If you want to customise the collection in code, you can add this collection code to your
|
|
699
|
+
"If you want to customise the collection in code, you can add this collection code to your admin app configuration. More info in the ",
|
|
700
700
|
/* @__PURE__ */ jsx("a", {
|
|
701
701
|
rel: "noopener noreferrer",
|
|
702
702
|
href: "https://rebase.pro/docs/cloud/quickstart",
|
|
@@ -875,7 +875,8 @@ function CollectionPropertiesEditorForm({ showErrors, isNewCollection, propertyE
|
|
|
875
875
|
return currentPropertiesOrderRef.current[namespace] ?? getIn(values, namespaceToPropertiesOrderPath(namespace));
|
|
876
876
|
};
|
|
877
877
|
const updatePropertiesOrder = (newPropertiesOrder, namespace) => {
|
|
878
|
-
|
|
878
|
+
const propertiesOrderPath = namespaceToPropertiesOrderPath(namespace);
|
|
879
|
+
setFieldValue(propertiesOrderPath, newPropertiesOrder, false);
|
|
879
880
|
currentPropertiesOrderRef.current[namespace ?? ""] = newPropertiesOrder;
|
|
880
881
|
};
|
|
881
882
|
const deleteProperty = (propertyKey, namespace) => {
|
|
@@ -884,7 +885,10 @@ function CollectionPropertiesEditorForm({ showErrors, isNewCollection, propertyE
|
|
|
884
885
|
if (!fullId) throw Error("collection editor miss config");
|
|
885
886
|
setFieldValue(idToPropertiesPath(fullId), void 0, false);
|
|
886
887
|
const currentPropertiesOrder = getCurrentPropertiesOrder(namespace);
|
|
887
|
-
if (currentPropertiesOrder)
|
|
888
|
+
if (currentPropertiesOrder) {
|
|
889
|
+
const newPropertiesOrder = currentPropertiesOrder.filter((p) => p !== propertyKey);
|
|
890
|
+
updatePropertiesOrder(newPropertiesOrder, namespace);
|
|
891
|
+
}
|
|
888
892
|
setNewPropertyDialogOpen(false);
|
|
889
893
|
setSelectedPropertyIndex(void 0);
|
|
890
894
|
setSelectedPropertyKey(void 0);
|
|
@@ -1177,7 +1181,8 @@ function CollectionJsonImportDialog({ open, onClose, onImport }) {
|
|
|
1177
1181
|
setErrors([]);
|
|
1178
1182
|
return;
|
|
1179
1183
|
}
|
|
1180
|
-
|
|
1184
|
+
const result = validateCollectionJson(value);
|
|
1185
|
+
setErrors(result.errors);
|
|
1181
1186
|
}, []);
|
|
1182
1187
|
const handleImport = useCallback(() => {
|
|
1183
1188
|
const result = validateCollectionJson(jsonValue);
|
|
@@ -2077,7 +2082,8 @@ function CollectionEditorImportMapping({ importConfig, propertyConfigs }) {
|
|
|
2077
2082
|
return currentPropertiesOrderRef.current[namespace] ?? getIn(values, namespaceToPropertiesOrderPath(namespace));
|
|
2078
2083
|
};
|
|
2079
2084
|
const updatePropertiesOrder = (newPropertiesOrder, namespace) => {
|
|
2080
|
-
|
|
2085
|
+
const propertiesOrderPath = namespaceToPropertiesOrderPath(namespace);
|
|
2086
|
+
setFieldValue(propertiesOrderPath, newPropertiesOrder, false);
|
|
2081
2087
|
currentPropertiesOrderRef.current[namespace ?? ""] = newPropertiesOrder;
|
|
2082
2088
|
};
|
|
2083
2089
|
if (previousId && previousId !== id) {
|
|
@@ -2329,9 +2335,58 @@ function sanitizeSqlIdentifier(name) {
|
|
|
2329
2335
|
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) throw new Error(`Invalid SQL identifier: "${name}". Only letters, digits, and underscores are allowed.`);
|
|
2330
2336
|
return `"${name}"`;
|
|
2331
2337
|
}
|
|
2338
|
+
/**
|
|
2339
|
+
* `pg_policies` reports the operation and the permissive flag in upper case;
|
|
2340
|
+
* `SecurityRule` names them in lower case. These two used to be `.toLowerCase()`
|
|
2341
|
+
* assigned straight into a `SecurityRule`, which typechecks only against a
|
|
2342
|
+
* `string` field — and this file declared its own local `SecurityRule` with
|
|
2343
|
+
* `operation?: string`, so it did. Against the real type it does not: an
|
|
2344
|
+
* unrecognised `cmd` would have been written into the collection as a policy
|
|
2345
|
+
* operation that compiles to nothing.
|
|
2346
|
+
*/
|
|
2347
|
+
function toSecurityOperation(cmd) {
|
|
2348
|
+
switch (cmd) {
|
|
2349
|
+
case "SELECT": return "select";
|
|
2350
|
+
case "INSERT": return "insert";
|
|
2351
|
+
case "UPDATE": return "update";
|
|
2352
|
+
case "DELETE": return "delete";
|
|
2353
|
+
case "ALL": return "all";
|
|
2354
|
+
default: return;
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
function toSecurityMode(permissive) {
|
|
2358
|
+
if (!permissive) return void 0;
|
|
2359
|
+
return permissive === "RESTRICTIVE" ? "restrictive" : "permissive";
|
|
2360
|
+
}
|
|
2361
|
+
/**
|
|
2362
|
+
* Build a {@link SecurityRule} from a `pg_policies` row.
|
|
2363
|
+
*
|
|
2364
|
+
* `SecurityRule` is a discriminated union and this is the part the local shadow
|
|
2365
|
+
* type flattened away: a raw-SQL rule *requires* `using`, so a policy with only
|
|
2366
|
+
* a `WITH CHECK` clause — every INSERT-only policy — is not one. It is a
|
|
2367
|
+
* roles-only rule carrying the check. Assembling the object field-by-field
|
|
2368
|
+
* against `operation?: string` accepted all of these and told the compiler
|
|
2369
|
+
* nothing.
|
|
2370
|
+
*/
|
|
2371
|
+
function toSecurityRule(policy) {
|
|
2372
|
+
const base = {
|
|
2373
|
+
name: policy.policyname ?? "",
|
|
2374
|
+
operation: toSecurityOperation(policy.cmd),
|
|
2375
|
+
mode: toSecurityMode(policy.permissive),
|
|
2376
|
+
roles: policy.roles ? [...policy.roles] : void 0
|
|
2377
|
+
};
|
|
2378
|
+
if (policy.qual) return {
|
|
2379
|
+
...base,
|
|
2380
|
+
using: policy.qual,
|
|
2381
|
+
withCheck: policy.with_check || void 0
|
|
2382
|
+
};
|
|
2383
|
+
return base;
|
|
2384
|
+
}
|
|
2332
2385
|
function CollectionRLSTab() {
|
|
2333
2386
|
const { values, setFieldValue } = useFormex();
|
|
2334
2387
|
const [editingPolicy, setEditingPolicy] = useState(null);
|
|
2388
|
+
const { readOnly, readOnlyReason } = useCollectionsConfigController();
|
|
2389
|
+
const readOnlyTitle = readOnlyReason || "This backend does not accept collection edits.";
|
|
2335
2390
|
const rules = values.securityRules || [];
|
|
2336
2391
|
const { databaseAdmin } = useRebaseContext();
|
|
2337
2392
|
const [dbPolicies, setDbPolicies] = useState([]);
|
|
@@ -2353,7 +2408,7 @@ function CollectionRLSTab() {
|
|
|
2353
2408
|
if (Array.isArray(res)) return res;
|
|
2354
2409
|
return [];
|
|
2355
2410
|
};
|
|
2356
|
-
|
|
2411
|
+
const policies = extractRows(result).map((p) => {
|
|
2357
2412
|
let parsedRoles = [];
|
|
2358
2413
|
const r = p.roles || p.ROLES;
|
|
2359
2414
|
if (Array.isArray(r)) parsedRoles = r;
|
|
@@ -2367,7 +2422,8 @@ function CollectionRLSTab() {
|
|
|
2367
2422
|
qual: p.qual || p.QUAL || null,
|
|
2368
2423
|
with_check: p.with_check || p.WITH_CHECK || null
|
|
2369
2424
|
};
|
|
2370
|
-
})
|
|
2425
|
+
});
|
|
2426
|
+
setDbPolicies(policies);
|
|
2371
2427
|
} catch (e) {
|
|
2372
2428
|
console.error("Failed to fetch DB policies", e);
|
|
2373
2429
|
} finally {
|
|
@@ -2414,37 +2470,13 @@ function CollectionRLSTab() {
|
|
|
2414
2470
|
};
|
|
2415
2471
|
}, [databaseAdmin]);
|
|
2416
2472
|
const tableName = values.id || values.table || values.alias;
|
|
2417
|
-
/**
|
|
2418
|
-
* Every policy name `rebase db push` would write for this collection.
|
|
2419
|
-
*
|
|
2420
|
-
* Two things make this more than `rules.map(r => r.name)`:
|
|
2421
|
-
* - a rule without an explicit `name` becomes `<table>_<op>_<hash>`, so
|
|
2422
|
-
* comparing `rule.name` to `policyname` never matches for it;
|
|
2423
|
-
* - the generator also injects the safe-by-default baseline
|
|
2424
|
-
* (`<table>_default_admin_*`), which is in no collection's `securityRules`.
|
|
2425
|
-
*
|
|
2426
|
-
* Missing either made Rebase's own policies look hand-written, and offered to
|
|
2427
|
-
* import them back into the codebase that produced them.
|
|
2428
|
-
*/
|
|
2429
2473
|
const generatedPolicyNames = useMemo(() => {
|
|
2430
2474
|
if (!tableName) return /* @__PURE__ */ new Set();
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
}, [
|
|
2434
|
-
rules,
|
|
2435
|
-
tableName,
|
|
2436
|
-
values
|
|
2437
|
-
]);
|
|
2475
|
+
return getGeneratedPolicyNames(values);
|
|
2476
|
+
}, [tableName, values]);
|
|
2438
2477
|
const unmappedPolicies = dbPolicies.filter((dp) => !generatedPolicyNames.has(dp.policyname));
|
|
2439
2478
|
const handleSave = async (newPolicy) => {
|
|
2440
|
-
const rule =
|
|
2441
|
-
name: newPolicy.policyname ?? "",
|
|
2442
|
-
operation: newPolicy.cmd?.toLowerCase(),
|
|
2443
|
-
mode: newPolicy.permissive?.toLowerCase(),
|
|
2444
|
-
using: newPolicy.qual || void 0,
|
|
2445
|
-
withCheck: newPolicy.with_check || void 0,
|
|
2446
|
-
roles: newPolicy.roles
|
|
2447
|
-
};
|
|
2479
|
+
const rule = toSecurityRule(newPolicy);
|
|
2448
2480
|
let newRules;
|
|
2449
2481
|
if (editingPolicy === "new") newRules = [...rules, rule];
|
|
2450
2482
|
else newRules = rules.map((r) => r.name === editingPolicy.policyname ? rule : r);
|
|
@@ -2464,11 +2496,15 @@ function CollectionRLSTab() {
|
|
|
2464
2496
|
children: [/* @__PURE__ */ jsx(Typography, {
|
|
2465
2497
|
variant: "h5",
|
|
2466
2498
|
children: "Row Level Security"
|
|
2467
|
-
}), /* @__PURE__ */ jsx(
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2499
|
+
}), /* @__PURE__ */ jsx(Tooltip, {
|
|
2500
|
+
title: readOnly ? readOnlyTitle : void 0,
|
|
2501
|
+
children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, {
|
|
2502
|
+
variant: "filled",
|
|
2503
|
+
color: "neutral",
|
|
2504
|
+
disabled: readOnly,
|
|
2505
|
+
onClick: () => setEditingPolicy("new"),
|
|
2506
|
+
children: "CREATE POLICY"
|
|
2507
|
+
}) })
|
|
2472
2508
|
})]
|
|
2473
2509
|
}),
|
|
2474
2510
|
rules.length === 0 ? /* @__PURE__ */ jsx("div", {
|
|
@@ -2510,18 +2546,20 @@ function CollectionRLSTab() {
|
|
|
2510
2546
|
children: [/* @__PURE__ */ jsx(Button, {
|
|
2511
2547
|
size: "small",
|
|
2512
2548
|
variant: "text",
|
|
2549
|
+
disabled: readOnly,
|
|
2513
2550
|
onClick: () => setEditingPolicy({
|
|
2514
|
-
policyname: rule.name,
|
|
2551
|
+
policyname: rule.name ?? "",
|
|
2515
2552
|
tablename: values.id || values.table || values.alias || "your_table",
|
|
2516
2553
|
permissive: (rule.mode || "permissive").toUpperCase(),
|
|
2517
2554
|
cmd: (rule.operation || "ALL").toUpperCase(),
|
|
2518
|
-
roles: rule.roles
|
|
2555
|
+
roles: [...rule.roles ?? []],
|
|
2519
2556
|
qual: rule.using || null,
|
|
2520
2557
|
with_check: rule.withCheck || null
|
|
2521
2558
|
}),
|
|
2522
2559
|
children: "EDIT"
|
|
2523
2560
|
}), /* @__PURE__ */ jsx(IconButton, {
|
|
2524
2561
|
size: "small",
|
|
2562
|
+
disabled: readOnly,
|
|
2525
2563
|
onClick: () => {
|
|
2526
2564
|
setFieldValue("securityRules", rules.filter((r) => r.name !== rule.name));
|
|
2527
2565
|
},
|
|
@@ -2590,22 +2628,19 @@ function CollectionRLSTab() {
|
|
|
2590
2628
|
})]
|
|
2591
2629
|
}), /* @__PURE__ */ jsx("div", {
|
|
2592
2630
|
className: "flex items-center gap-1 sm:gap-2 shrink-0",
|
|
2593
|
-
children: /* @__PURE__ */ jsx(
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
setFieldValue("securityRules", [...rules, rule]);
|
|
2607
|
-
},
|
|
2608
|
-
children: "Import to codebase"
|
|
2631
|
+
children: /* @__PURE__ */ jsx(Tooltip, {
|
|
2632
|
+
title: readOnly ? readOnlyTitle : void 0,
|
|
2633
|
+
children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, {
|
|
2634
|
+
size: "small",
|
|
2635
|
+
variant: "outlined",
|
|
2636
|
+
color: "primary",
|
|
2637
|
+
disabled: readOnly,
|
|
2638
|
+
onClick: () => {
|
|
2639
|
+
const rule = toSecurityRule(dp);
|
|
2640
|
+
setFieldValue("securityRules", [...rules, rule]);
|
|
2641
|
+
},
|
|
2642
|
+
children: "Import to codebase"
|
|
2643
|
+
}) })
|
|
2609
2644
|
})
|
|
2610
2645
|
})]
|
|
2611
2646
|
}, dp.policyname))
|
|
@@ -2651,7 +2686,7 @@ function InlinePolicyEditor({ policy, table, availableRoles, rolesUnavailable, o
|
|
|
2651
2686
|
* from what users hold, so a role that is referenced here but assigned to
|
|
2652
2687
|
* nobody would otherwise vanish from its own policy on the next save.
|
|
2653
2688
|
*/
|
|
2654
|
-
const roleOptions = useMemo(() => Array.from(new Set([...availableRoles, ...roles])).sort(), [availableRoles, roles]);
|
|
2689
|
+
const roleOptions = useMemo(() => Array.from(/* @__PURE__ */ new Set([...availableRoles, ...roles])).sort(), [availableRoles, roles]);
|
|
2655
2690
|
const addCustomRole = () => {
|
|
2656
2691
|
const trimmed = customRole.trim();
|
|
2657
2692
|
if (!trimmed || roles.includes(trimmed)) {
|
|
@@ -2843,243 +2878,6 @@ function InlinePolicyEditor({ policy, table, availableRoles, rolesUnavailable, o
|
|
|
2843
2878
|
] });
|
|
2844
2879
|
}
|
|
2845
2880
|
//#endregion
|
|
2846
|
-
//#region src/collection_editor/pgColumnToProperty.ts
|
|
2847
|
-
/**
|
|
2848
|
-
* Maps a PostgreSQL column data type to a Rebase property type.
|
|
2849
|
-
*/
|
|
2850
|
-
function pgTypeToRebaseProperty(column) {
|
|
2851
|
-
const { column_name, data_type, udt_name, is_nullable, column_default, enum_values } = column;
|
|
2852
|
-
const required = is_nullable === "NO";
|
|
2853
|
-
const prettifiedName = prettifyIdentifier(column_name);
|
|
2854
|
-
const isAutoId = column_default != null && (column_default.includes("nextval") || column_default.includes("gen_random_uuid") || column_default.includes("uuid_generate") || column_default.includes("identity"));
|
|
2855
|
-
if (data_type === "USER-DEFINED" && enum_values && enum_values.length > 0) return {
|
|
2856
|
-
type: "string",
|
|
2857
|
-
name: prettifiedName,
|
|
2858
|
-
enum: enum_values.map((v) => ({
|
|
2859
|
-
id: v,
|
|
2860
|
-
label: prettifyIdentifier(v)
|
|
2861
|
-
})),
|
|
2862
|
-
validation: required ? { required: true } : void 0
|
|
2863
|
-
};
|
|
2864
|
-
const dt = data_type.toLowerCase();
|
|
2865
|
-
switch (dt) {
|
|
2866
|
-
case "character varying":
|
|
2867
|
-
case "varchar":
|
|
2868
|
-
case "text":
|
|
2869
|
-
case "char":
|
|
2870
|
-
case "character":
|
|
2871
|
-
case "citext": {
|
|
2872
|
-
let colType = "varchar";
|
|
2873
|
-
if (dt === "text" || dt === "citext") colType = "text";
|
|
2874
|
-
if (dt === "char" || dt === "character") colType = "char";
|
|
2875
|
-
const prop = {
|
|
2876
|
-
type: "string",
|
|
2877
|
-
name: prettifiedName,
|
|
2878
|
-
columnType: colType,
|
|
2879
|
-
validation: required ? { required: true } : void 0
|
|
2880
|
-
};
|
|
2881
|
-
if (isAutoId) prop.isId = "manual";
|
|
2882
|
-
return prop;
|
|
2883
|
-
}
|
|
2884
|
-
case "uuid": {
|
|
2885
|
-
const prop = {
|
|
2886
|
-
type: "string",
|
|
2887
|
-
name: prettifiedName,
|
|
2888
|
-
validation: required ? { required: true } : void 0
|
|
2889
|
-
};
|
|
2890
|
-
if (isAutoId) prop.isId = "uuid";
|
|
2891
|
-
return prop;
|
|
2892
|
-
}
|
|
2893
|
-
case "integer":
|
|
2894
|
-
case "bigint":
|
|
2895
|
-
case "smallint": {
|
|
2896
|
-
const prop = {
|
|
2897
|
-
type: "number",
|
|
2898
|
-
name: prettifiedName,
|
|
2899
|
-
columnType: dt === "bigint" ? "bigint" : "integer",
|
|
2900
|
-
validation: {
|
|
2901
|
-
...required ? { required: true } : {},
|
|
2902
|
-
integer: true
|
|
2903
|
-
}
|
|
2904
|
-
};
|
|
2905
|
-
if (isAutoId) prop.isId = "increment";
|
|
2906
|
-
return prop;
|
|
2907
|
-
}
|
|
2908
|
-
case "serial":
|
|
2909
|
-
case "bigserial":
|
|
2910
|
-
case "smallserial": return {
|
|
2911
|
-
type: "number",
|
|
2912
|
-
name: prettifiedName,
|
|
2913
|
-
columnType: dt === "bigserial" ? "bigserial" : "serial",
|
|
2914
|
-
isId: "increment",
|
|
2915
|
-
validation: {
|
|
2916
|
-
...required ? { required: true } : {},
|
|
2917
|
-
integer: true
|
|
2918
|
-
}
|
|
2919
|
-
};
|
|
2920
|
-
case "numeric":
|
|
2921
|
-
case "decimal":
|
|
2922
|
-
case "real":
|
|
2923
|
-
case "double precision": {
|
|
2924
|
-
let colType = "numeric";
|
|
2925
|
-
if (dt === "real") colType = "real";
|
|
2926
|
-
if (dt === "double precision") colType = "double precision";
|
|
2927
|
-
return {
|
|
2928
|
-
type: "number",
|
|
2929
|
-
name: prettifiedName,
|
|
2930
|
-
columnType: colType,
|
|
2931
|
-
validation: required ? { required: true } : void 0
|
|
2932
|
-
};
|
|
2933
|
-
}
|
|
2934
|
-
case "boolean": return {
|
|
2935
|
-
type: "boolean",
|
|
2936
|
-
name: prettifiedName,
|
|
2937
|
-
validation: required ? { required: true } : void 0
|
|
2938
|
-
};
|
|
2939
|
-
case "timestamp with time zone":
|
|
2940
|
-
case "timestamp without time zone":
|
|
2941
|
-
case "timestamp":
|
|
2942
|
-
case "timestamptz":
|
|
2943
|
-
case "date":
|
|
2944
|
-
case "time with time zone":
|
|
2945
|
-
case "time without time zone":
|
|
2946
|
-
case "time": {
|
|
2947
|
-
let colType = "timestamp";
|
|
2948
|
-
if (dt.startsWith("date")) colType = "date";
|
|
2949
|
-
if (dt.startsWith("time ") || dt === "time") colType = "time";
|
|
2950
|
-
return {
|
|
2951
|
-
type: "date",
|
|
2952
|
-
name: prettifiedName,
|
|
2953
|
-
columnType: colType,
|
|
2954
|
-
validation: required ? { required: true } : void 0
|
|
2955
|
-
};
|
|
2956
|
-
}
|
|
2957
|
-
case "jsonb":
|
|
2958
|
-
case "json": return {
|
|
2959
|
-
type: "map",
|
|
2960
|
-
name: prettifiedName,
|
|
2961
|
-
columnType: dt === "jsonb" ? "jsonb" : "json",
|
|
2962
|
-
keyValue: true,
|
|
2963
|
-
properties: {}
|
|
2964
|
-
};
|
|
2965
|
-
case "array":
|
|
2966
|
-
case "ARRAY": {
|
|
2967
|
-
let innerType = "string";
|
|
2968
|
-
let colType = void 0;
|
|
2969
|
-
if (udt_name === "_text" || udt_name === "_varchar") {
|
|
2970
|
-
innerType = "string";
|
|
2971
|
-
colType = "text[]";
|
|
2972
|
-
} else if (udt_name === "_int4" || udt_name === "_int2" || udt_name === "_int8") {
|
|
2973
|
-
innerType = "number";
|
|
2974
|
-
colType = "integer[]";
|
|
2975
|
-
} else if (udt_name === "_bool") {
|
|
2976
|
-
innerType = "boolean";
|
|
2977
|
-
colType = "boolean[]";
|
|
2978
|
-
} else if (udt_name === "_numeric") {
|
|
2979
|
-
innerType = "number";
|
|
2980
|
-
colType = "numeric[]";
|
|
2981
|
-
}
|
|
2982
|
-
return {
|
|
2983
|
-
type: "array",
|
|
2984
|
-
name: prettifiedName,
|
|
2985
|
-
columnType: colType,
|
|
2986
|
-
of: { type: innerType }
|
|
2987
|
-
};
|
|
2988
|
-
}
|
|
2989
|
-
default: return {
|
|
2990
|
-
type: "string",
|
|
2991
|
-
name: prettifiedName,
|
|
2992
|
-
validation: required ? { required: true } : void 0
|
|
2993
|
-
};
|
|
2994
|
-
}
|
|
2995
|
-
}
|
|
2996
|
-
/**
|
|
2997
|
-
* Builds a partial AdminCollection from PostgreSQL table metadata.
|
|
2998
|
-
* This is used when creating a new collection from an existing database table.
|
|
2999
|
-
*/
|
|
3000
|
-
function buildCollectionFromTableMetadata(tableName, metadata) {
|
|
3001
|
-
const properties = {};
|
|
3002
|
-
const propertiesOrder = [];
|
|
3003
|
-
const relations = [];
|
|
3004
|
-
const securityRules = [];
|
|
3005
|
-
for (const column of metadata.columns) {
|
|
3006
|
-
const property = pgTypeToRebaseProperty(column);
|
|
3007
|
-
if (property) {
|
|
3008
|
-
const propRecord = property;
|
|
3009
|
-
Object.keys(propRecord).forEach((key) => propRecord[key] === void 0 && delete propRecord[key]);
|
|
3010
|
-
properties[column.column_name] = property;
|
|
3011
|
-
propertiesOrder.push(column.column_name);
|
|
3012
|
-
}
|
|
3013
|
-
}
|
|
3014
|
-
if (metadata.foreignKeys) for (const fk of metadata.foreignKeys) {
|
|
3015
|
-
const relName = fk.column_name.endsWith("_id") ? fk.column_name.substring(0, fk.column_name.length - 3) : fk.column_name;
|
|
3016
|
-
relations.push({
|
|
3017
|
-
id: fk.column_name,
|
|
3018
|
-
relationName: relName,
|
|
3019
|
-
target: fk.foreign_table_name,
|
|
3020
|
-
cardinality: "one",
|
|
3021
|
-
direction: "owning",
|
|
3022
|
-
localKey: fk.column_name
|
|
3023
|
-
});
|
|
3024
|
-
}
|
|
3025
|
-
if (metadata.junctions) for (const junction of metadata.junctions) {
|
|
3026
|
-
const relName = junction.target_table_name;
|
|
3027
|
-
relations.push({
|
|
3028
|
-
id: junction.target_table_name + "_relation",
|
|
3029
|
-
relationName: relName,
|
|
3030
|
-
target: junction.target_table_name,
|
|
3031
|
-
cardinality: "many",
|
|
3032
|
-
direction: "owning",
|
|
3033
|
-
through: {
|
|
3034
|
-
table: junction.junction_table_name,
|
|
3035
|
-
sourceColumn: junction.source_column_name,
|
|
3036
|
-
targetColumn: junction.target_column_name
|
|
3037
|
-
}
|
|
3038
|
-
});
|
|
3039
|
-
}
|
|
3040
|
-
if (metadata.policies) for (const policy of metadata.policies) {
|
|
3041
|
-
let operations = [];
|
|
3042
|
-
switch (policy.cmd) {
|
|
3043
|
-
case "ALL":
|
|
3044
|
-
operations = [
|
|
3045
|
-
"read",
|
|
3046
|
-
"create",
|
|
3047
|
-
"update",
|
|
3048
|
-
"delete"
|
|
3049
|
-
];
|
|
3050
|
-
break;
|
|
3051
|
-
case "SELECT":
|
|
3052
|
-
operations = ["read"];
|
|
3053
|
-
break;
|
|
3054
|
-
case "INSERT":
|
|
3055
|
-
operations = ["create"];
|
|
3056
|
-
break;
|
|
3057
|
-
case "UPDATE":
|
|
3058
|
-
operations = ["update"];
|
|
3059
|
-
break;
|
|
3060
|
-
case "DELETE":
|
|
3061
|
-
operations = ["delete"];
|
|
3062
|
-
break;
|
|
3063
|
-
}
|
|
3064
|
-
securityRules.push({
|
|
3065
|
-
name: policy.policy_name,
|
|
3066
|
-
operations,
|
|
3067
|
-
roles: policy.roles ?? [],
|
|
3068
|
-
qual: policy.qual,
|
|
3069
|
-
with_check: policy.with_check
|
|
3070
|
-
});
|
|
3071
|
-
}
|
|
3072
|
-
return {
|
|
3073
|
-
name: prettifyIdentifier(tableName),
|
|
3074
|
-
slug: tableName,
|
|
3075
|
-
table: tableName,
|
|
3076
|
-
properties,
|
|
3077
|
-
propertiesOrder,
|
|
3078
|
-
...relations.length > 0 ? { relations } : {},
|
|
3079
|
-
...securityRules.length > 0 ? { securityRules } : {}
|
|
3080
|
-
};
|
|
3081
|
-
}
|
|
3082
|
-
//#endregion
|
|
3083
2881
|
//#region src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx
|
|
3084
2882
|
var CollectionEditorDialog_exports = /* @__PURE__ */ __exportAll({
|
|
3085
2883
|
CollectionEditor: () => CollectionEditor,
|
|
@@ -3168,10 +2966,12 @@ function CollectionEditor(props) {
|
|
|
3168
2966
|
}, [collection, fallbackSlug]);
|
|
3169
2967
|
const initialValues = React$1.useMemo(() => {
|
|
3170
2968
|
return initialCollection ? applyPropertyConfigs(initialCollection, propertyConfigs) : copyFromProp ? (() => {
|
|
3171
|
-
const { subcollections: _sub, ...rest } = copyFromProp;
|
|
2969
|
+
const { subcollections: _sub, schema: _schema, auth: _auth, ...rest } = copyFromProp;
|
|
3172
2970
|
return {
|
|
3173
2971
|
...rest,
|
|
3174
2972
|
name: "",
|
|
2973
|
+
slug: fallbackSlug,
|
|
2974
|
+
table: "",
|
|
3175
2975
|
ownerId: authController.user?.uid ?? ""
|
|
3176
2976
|
};
|
|
3177
2977
|
})() : {
|
|
@@ -3206,6 +3006,8 @@ function CollectionEditor(props) {
|
|
|
3206
3006
|
});
|
|
3207
3007
|
}
|
|
3208
3008
|
function CollectionEditorInternal({ isNewCollection, configController, editedCollectionId, parentCollectionSlugs, parentEntityIds, path, collectionInference, handleClose, extraView, handleCancel, setFormDirty, getUser, parentCollection, getData, existingPaths, existingIds, includeTemplates, collection, setCollection, initialValues, propertyConfigs, existingEntities, initialView: initialViewProp, expandKanban, generateCollection, onAnalyticsEvent, fullScreen, unmappedTables, onFetchTableMetadata, propertyTypePresets, hiddenPropertyTypes, renderExtraPropertyFields, renderExtraCollectionFields, visibleTabs, standalone }) {
|
|
3009
|
+
/** Why the submit buttons below are dead, straight from the backend. */
|
|
3010
|
+
const readOnlyTitle = configController?.readOnlyReason || "This backend does not accept collection edits.";
|
|
3209
3011
|
const importConfigRaw = useImportConfig();
|
|
3210
3012
|
const urlControllerRaw = useUrlController();
|
|
3211
3013
|
const collectionRegistryRaw = useCollectionRegistryController();
|
|
@@ -3489,14 +3291,17 @@ function CollectionEditorInternal({ isNewCollection, configController, editedCol
|
|
|
3489
3291
|
onAnalyticsEvent
|
|
3490
3292
|
}), fullScreen && !isNewCollection && /* @__PURE__ */ jsx("div", {
|
|
3491
3293
|
className: "flex items-center gap-2",
|
|
3492
|
-
children: /* @__PURE__ */ jsx(
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3294
|
+
children: /* @__PURE__ */ jsx(Tooltip, {
|
|
3295
|
+
title: configController?.readOnly ? readOnlyTitle : void 0,
|
|
3296
|
+
children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(LoadingButton, {
|
|
3297
|
+
variant: "filled",
|
|
3298
|
+
color: "primary",
|
|
3299
|
+
type: "submit",
|
|
3300
|
+
onClick: () => formController.handleSubmit(),
|
|
3301
|
+
disabled: !dirty || isSubmitting || configController?.readOnly,
|
|
3302
|
+
loading: isSubmitting,
|
|
3303
|
+
children: configController?.readOnly ? "Update (Read-only)" : "Update"
|
|
3304
|
+
}) })
|
|
3500
3305
|
})
|
|
3501
3306
|
})]
|
|
3502
3307
|
})]
|
|
@@ -3575,10 +3380,11 @@ function CollectionEditorInternal({ isNewCollection, configController, editedCol
|
|
|
3575
3380
|
showErrors: submitCount > 0,
|
|
3576
3381
|
isNewCollection,
|
|
3577
3382
|
onPropertyError: (propertyKey, namespace, error) => {
|
|
3578
|
-
|
|
3383
|
+
const current = removeUndefined({
|
|
3579
3384
|
...propertyErrorsRef.current,
|
|
3580
3385
|
[getFullIdPath(propertyKey, namespace)]: removeUndefined(error, true)
|
|
3581
3386
|
}, true);
|
|
3387
|
+
propertyErrorsRef.current = current;
|
|
3582
3388
|
formController.validate();
|
|
3583
3389
|
},
|
|
3584
3390
|
getUser,
|
|
@@ -3666,13 +3472,16 @@ function CollectionEditorInternal({ isNewCollection, configController, editedCol
|
|
|
3666
3472
|
startIcon: currentView === "properties" ? /* @__PURE__ */ jsx(CheckIcon, {}) : void 0,
|
|
3667
3473
|
children: [currentView === "general" && "Next", currentView === "properties" && "Create collection"]
|
|
3668
3474
|
}),
|
|
3669
|
-
!isNewCollection && !fullScreen && /* @__PURE__ */ jsx(
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3475
|
+
!isNewCollection && !fullScreen && /* @__PURE__ */ jsx(Tooltip, {
|
|
3476
|
+
title: configController?.readOnly ? readOnlyTitle : void 0,
|
|
3477
|
+
children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(LoadingButton, {
|
|
3478
|
+
variant: "filled",
|
|
3479
|
+
color: "primary",
|
|
3480
|
+
type: "submit",
|
|
3481
|
+
disabled: isSubmitting || configController?.readOnly,
|
|
3482
|
+
loading: isSubmitting,
|
|
3483
|
+
children: configController?.readOnly ? "Update collection (Read-only)" : "Update collection"
|
|
3484
|
+
}) })
|
|
3676
3485
|
})
|
|
3677
3486
|
]
|
|
3678
3487
|
})]
|
|
@@ -3741,4 +3550,4 @@ var validateId = (value, isNewCollection, existingPaths, existingIds) => {
|
|
|
3741
3550
|
//#endregion
|
|
3742
3551
|
export { CollectionEditorDialog as n, CollectionEditorDialog_exports as r, CollectionEditor as t };
|
|
3743
3552
|
|
|
3744
|
-
//# sourceMappingURL=CollectionEditorDialog-
|
|
3553
|
+
//# sourceMappingURL=CollectionEditorDialog-B-iVE9y3.js.map
|