@rebasepro/admin 0.11.1-canary.gfd39654 → 0.12.1-canary.gdfba2a1
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-o7F_zbGY.js → CollectionEditorDialog-B8j6HArJ.js} +72 -268
- package/dist/CollectionEditorDialog-B8j6HArJ.js.map +1 -0
- package/dist/{PropertyEditView-DgB2b22q.js → PropertyEditView-D2b9_nbC.js} +12 -9
- package/dist/{PropertyEditView-DgB2b22q.js.map → PropertyEditView-D2b9_nbC.js.map} +1 -1
- package/dist/{RouterCollectionsStudioView-DaLRgPkj.js → RouterCollectionsStudioView-CXUtYIc1.js} +4 -4
- package/dist/{RouterCollectionsStudioView-DaLRgPkj.js.map → RouterCollectionsStudioView-CXUtYIc1.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 +40 -12
- 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.js +4 -4
- 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/DefaultDrawer.d.ts +3 -3
- package/dist/components/DrawerNavigationGroup.d.ts +8 -1
- package/dist/components/DrawerNavigationItem.d.ts +7 -1
- package/dist/components/EditViewBinding.d.ts +1 -1
- 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/editor.js +18 -10
- package/dist/editor.js.map +1 -1
- package/dist/{export-BvqhjdEb.js → export-CrDJOGKn.js} +3 -3
- package/dist/export-CrDJOGKn.js.map +1 -0
- package/dist/form/EntityForm.d.ts +2 -2
- package/dist/form/EntityFormBinding.d.ts +5 -5
- package/dist/{history-Dz20hH38.js → history-s6Nzt7RF.js} +2 -2
- package/dist/{history-Dz20hH38.js.map → history-s6Nzt7RF.js.map} +1 -1
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/useAdminContext.d.ts +29 -0
- package/dist/hooks/useHistory.d.ts +7 -11
- package/dist/{import-DINSB-Vu.js → import-Ci32nU0G.js} +2 -2
- package/dist/{import-DINSB-Vu.js.map → import-Ci32nU0G.js.map} +1 -1
- package/dist/index.js +72 -44
- package/dist/index.js.map +1 -1
- package/dist/markdown-CklalUUk.js.map +1 -1
- package/dist/types/components/EntityFormProps.d.ts +1 -1
- package/dist/types/fields.d.ts +1 -1
- package/dist/{util-BhhfHY1M.js → util-BwZuV81o.js} +378 -214
- package/dist/util-BwZuV81o.js.map +1 -0
- package/package.json +24 -24
- package/src/collection_editor/CollectionEditorDialogsContext.tsx +1 -1
- package/src/collection_editor/ConfigControllerProvider.tsx +1 -1
- 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 +44 -13
- package/src/collection_editor/serializable_utils.ts +68 -59
- package/src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx +1 -1
- package/src/collection_editor/ui/collection_editor/CollectionRLSTab.tsx +66 -41
- 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/SubcollectionsEditTab.tsx +2 -2
- 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/column_utils.tsx +19 -5
- package/src/components/CollectionTableBinding/table_bindings.tsx +10 -10
- package/src/components/CollectionViewBinding/CollectionListViewBinding.tsx +8 -7
- package/src/components/CollectionViewBinding/CollectionViewActions.tsx +2 -2
- package/src/components/CollectionViewBinding/CollectionViewBinding.tsx +2 -2
- package/src/components/CollectionViewBinding/CollectionViewStartActions.tsx +2 -2
- package/src/components/DefaultDrawer.tsx +19 -8
- package/src/components/DeleteEntityDialog.tsx +2 -2
- package/src/components/DetailViewBinding.tsx +21 -1
- package/src/components/DrawerNavigationGroup.tsx +47 -4
- package/src/components/DrawerNavigationItem.tsx +19 -5
- package/src/components/EditFormActions.tsx +4 -3
- package/src/components/EditViewBinding.tsx +1 -1
- package/src/components/HomePage/ContentHomePage.tsx +4 -4
- package/src/components/RebaseAdmin.tsx +3 -3
- package/src/components/RebaseAuthGate.tsx +1 -1
- package/src/components/RebaseLayout.tsx +8 -2
- package/src/components/RebaseNavigation.tsx +9 -9
- package/src/components/RebaseRouteDefs.tsx +2 -2
- package/src/components/RebaseShell.tsx +10 -1
- package/src/components/RelationSelector.tsx +18 -3
- 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/SidePanelProvider.tsx +2 -2
- package/src/components/app/Scaffold.tsx +16 -1
- package/src/data_export/export/ExportCollectionAction.tsx +2 -2
- package/src/form/EntityForm.tsx +2 -2
- package/src/form/EntityFormActions.tsx +2 -1
- package/src/form/EntityFormBinding.tsx +7 -7
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +3 -3
- package/src/form/field_bindings/MultipleRelationFieldBinding.tsx +16 -5
- package/src/form/field_bindings/ReferenceFieldBinding.tsx +3 -3
- package/src/form/field_bindings/RelationFieldBinding.tsx +17 -6
- package/src/form/field_bindings/RepeatFieldBinding.tsx +2 -2
- package/src/hooks/index.ts +1 -1
- package/src/hooks/navigation/useNavigationResolution.ts +10 -4
- package/src/hooks/{useCMSContext.tsx → useAdminContext.tsx} +10 -10
- package/src/hooks/useHistory.ts +7 -11
- package/src/hooks/useResolvedNavigationFrom.tsx +2 -2
- package/src/index.ts +4 -4
- package/src/preview/PropertyPreview.tsx +6 -6
- package/src/preview/components/RelationPreview.tsx +1 -1
- package/src/preview/property_previews/ArrayOfMapsPreview.tsx +1 -1
- package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +2 -2
- package/src/preview/property_previews/ArrayOfRelationsPreview.tsx +2 -2
- package/src/preview/property_previews/SkeletonPropertyComponent.tsx +2 -2
- package/src/types/components/EntityFormProps.tsx +2 -2
- package/src/types/fields.tsx +1 -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/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/README.md
CHANGED
|
@@ -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,10 +1,10 @@
|
|
|
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, In 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-
|
|
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, In 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-BwZuV81o.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-D2b9_nbC.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 { getEffectiveSecurityRules, getSubcollections, getTableName, isPropertyBuilder } from "@rebasepro/common";
|
|
7
|
+
import { buildCollectionFromTableMetadata, getEffectiveSecurityRules, 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";
|
|
@@ -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,6 +2335,53 @@ 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);
|
|
@@ -2353,7 +2406,7 @@ function CollectionRLSTab() {
|
|
|
2353
2406
|
if (Array.isArray(res)) return res;
|
|
2354
2407
|
return [];
|
|
2355
2408
|
};
|
|
2356
|
-
|
|
2409
|
+
const policies = extractRows(result).map((p) => {
|
|
2357
2410
|
let parsedRoles = [];
|
|
2358
2411
|
const r = p.roles || p.ROLES;
|
|
2359
2412
|
if (Array.isArray(r)) parsedRoles = r;
|
|
@@ -2367,7 +2420,8 @@ function CollectionRLSTab() {
|
|
|
2367
2420
|
qual: p.qual || p.QUAL || null,
|
|
2368
2421
|
with_check: p.with_check || p.WITH_CHECK || null
|
|
2369
2422
|
};
|
|
2370
|
-
})
|
|
2423
|
+
});
|
|
2424
|
+
setDbPolicies(policies);
|
|
2371
2425
|
} catch (e) {
|
|
2372
2426
|
console.error("Failed to fetch DB policies", e);
|
|
2373
2427
|
} finally {
|
|
@@ -2437,14 +2491,7 @@ function CollectionRLSTab() {
|
|
|
2437
2491
|
]);
|
|
2438
2492
|
const unmappedPolicies = dbPolicies.filter((dp) => !generatedPolicyNames.has(dp.policyname));
|
|
2439
2493
|
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
|
-
};
|
|
2494
|
+
const rule = toSecurityRule(newPolicy);
|
|
2448
2495
|
let newRules;
|
|
2449
2496
|
if (editingPolicy === "new") newRules = [...rules, rule];
|
|
2450
2497
|
else newRules = rules.map((r) => r.name === editingPolicy.policyname ? rule : r);
|
|
@@ -2511,11 +2558,11 @@ function CollectionRLSTab() {
|
|
|
2511
2558
|
size: "small",
|
|
2512
2559
|
variant: "text",
|
|
2513
2560
|
onClick: () => setEditingPolicy({
|
|
2514
|
-
policyname: rule.name,
|
|
2561
|
+
policyname: rule.name ?? "",
|
|
2515
2562
|
tablename: values.id || values.table || values.alias || "your_table",
|
|
2516
2563
|
permissive: (rule.mode || "permissive").toUpperCase(),
|
|
2517
2564
|
cmd: (rule.operation || "ALL").toUpperCase(),
|
|
2518
|
-
roles: rule.roles
|
|
2565
|
+
roles: [...rule.roles ?? []],
|
|
2519
2566
|
qual: rule.using || null,
|
|
2520
2567
|
with_check: rule.withCheck || null
|
|
2521
2568
|
}),
|
|
@@ -2595,14 +2642,7 @@ function CollectionRLSTab() {
|
|
|
2595
2642
|
variant: "outlined",
|
|
2596
2643
|
color: "primary",
|
|
2597
2644
|
onClick: () => {
|
|
2598
|
-
const rule =
|
|
2599
|
-
name: dp.policyname,
|
|
2600
|
-
operation: dp.cmd?.toLowerCase(),
|
|
2601
|
-
mode: dp.permissive?.toLowerCase(),
|
|
2602
|
-
using: dp.qual || void 0,
|
|
2603
|
-
withCheck: dp.with_check || void 0,
|
|
2604
|
-
roles: dp.roles
|
|
2605
|
-
};
|
|
2645
|
+
const rule = toSecurityRule(dp);
|
|
2606
2646
|
setFieldValue("securityRules", [...rules, rule]);
|
|
2607
2647
|
},
|
|
2608
2648
|
children: "Import to codebase"
|
|
@@ -2651,7 +2691,7 @@ function InlinePolicyEditor({ policy, table, availableRoles, rolesUnavailable, o
|
|
|
2651
2691
|
* from what users hold, so a role that is referenced here but assigned to
|
|
2652
2692
|
* nobody would otherwise vanish from its own policy on the next save.
|
|
2653
2693
|
*/
|
|
2654
|
-
const roleOptions = useMemo(() => Array.from(new Set([...availableRoles, ...roles])).sort(), [availableRoles, roles]);
|
|
2694
|
+
const roleOptions = useMemo(() => Array.from(/* @__PURE__ */ new Set([...availableRoles, ...roles])).sort(), [availableRoles, roles]);
|
|
2655
2695
|
const addCustomRole = () => {
|
|
2656
2696
|
const trimmed = customRole.trim();
|
|
2657
2697
|
if (!trimmed || roles.includes(trimmed)) {
|
|
@@ -2843,243 +2883,6 @@ function InlinePolicyEditor({ policy, table, availableRoles, rolesUnavailable, o
|
|
|
2843
2883
|
] });
|
|
2844
2884
|
}
|
|
2845
2885
|
//#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
2886
|
//#region src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx
|
|
3084
2887
|
var CollectionEditorDialog_exports = /* @__PURE__ */ __exportAll({
|
|
3085
2888
|
CollectionEditor: () => CollectionEditor,
|
|
@@ -3575,10 +3378,11 @@ function CollectionEditorInternal({ isNewCollection, configController, editedCol
|
|
|
3575
3378
|
showErrors: submitCount > 0,
|
|
3576
3379
|
isNewCollection,
|
|
3577
3380
|
onPropertyError: (propertyKey, namespace, error) => {
|
|
3578
|
-
|
|
3381
|
+
const current = removeUndefined({
|
|
3579
3382
|
...propertyErrorsRef.current,
|
|
3580
3383
|
[getFullIdPath(propertyKey, namespace)]: removeUndefined(error, true)
|
|
3581
3384
|
}, true);
|
|
3385
|
+
propertyErrorsRef.current = current;
|
|
3582
3386
|
formController.validate();
|
|
3583
3387
|
},
|
|
3584
3388
|
getUser,
|
|
@@ -3741,4 +3545,4 @@ var validateId = (value, isNewCollection, existingPaths, existingIds) => {
|
|
|
3741
3545
|
//#endregion
|
|
3742
3546
|
export { CollectionEditorDialog as n, CollectionEditorDialog_exports as r, CollectionEditor as t };
|
|
3743
3547
|
|
|
3744
|
-
//# sourceMappingURL=CollectionEditorDialog-
|
|
3548
|
+
//# sourceMappingURL=CollectionEditorDialog-B8j6HArJ.js.map
|