@rebasepro/admin 0.6.1 → 0.7.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-HNXGxXdO.js → CollectionEditorDialog-iGgS4rLX.js} +233 -152
- package/dist/CollectionEditorDialog-iGgS4rLX.js.map +1 -0
- package/dist/{PropertyEditView-C2wp8kQ9.js → PropertyEditView-C9yhLyja.js} +129 -15
- package/dist/PropertyEditView-C9yhLyja.js.map +1 -0
- package/dist/{CollectionsStudioView-B1mN33GB.js → RouterCollectionsStudioView-Dqx27GD8.js} +61 -39
- package/dist/RouterCollectionsStudioView-Dqx27GD8.js.map +1 -0
- package/dist/collection_editor/extensibility_types.d.ts +135 -0
- package/dist/collection_editor/index.d.ts +6 -0
- package/dist/collection_editor/serializable_types.d.ts +374 -0
- package/dist/collection_editor/serializable_utils.d.ts +50 -0
- package/dist/collection_editor/ui/collection_editor/CollectionEditorDialog.d.ts +2 -1
- package/dist/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +12 -1
- package/dist/collection_editor/ui/collection_editor/CollectionStudioView.d.ts +13 -1
- package/dist/collection_editor/ui/collection_editor/CollectionsStudioView.d.ts +24 -2
- package/dist/collection_editor/ui/collection_editor/DisplaySettingsForm.d.ts +2 -1
- package/dist/collection_editor/ui/collection_editor/GeneralSettingsForm.d.ts +4 -1
- package/dist/collection_editor/ui/collection_editor/PropertyEditView.d.ts +12 -1
- package/dist/collection_editor/ui/collection_editor/RouterCollectionStudioView.d.ts +15 -0
- package/dist/collection_editor/ui/collection_editor/RouterCollectionsStudioView.d.ts +14 -0
- package/dist/collection_editor/useJsonCollectionsConfigController.d.ts +37 -0
- package/dist/collection_editor/useSafeSnackbarController.d.ts +2 -0
- package/dist/collection_editor_ui.d.ts +4 -0
- package/dist/collection_editor_ui.js +33 -4
- package/dist/collection_editor_ui.js.map +1 -0
- package/dist/components/EntityCollectionView/EntityBoardCard.d.ts +3 -3
- package/dist/components/EntityCollectionView/hooks/useKanbanDragAndDrop.d.ts +3 -3
- package/dist/components/EntityEditView.d.ts +3 -2
- package/dist/components/RebaseCMS.d.ts +1 -1
- package/dist/form/EntityForm.d.ts +10 -9
- package/dist/form/EntityFormBinding.d.ts +27 -0
- package/dist/form/form_utils.d.ts +8 -0
- package/dist/form/index.d.ts +5 -1
- package/dist/{history-BO6VT85a.js → history-ChHgyyvM.js} +2 -2
- package/dist/{history-BO6VT85a.js.map → history-ChHgyyvM.js.map} +1 -1
- package/dist/hooks/navigation/contexts/CollectionRegistryContext.d.ts +1 -1
- package/dist/hooks/navigation/useAsyncResolver.d.ts +26 -0
- package/dist/hooks/navigation/useBuildCollectionRegistryController.d.ts +2 -0
- package/dist/hooks/navigation/useTopLevelNavigation.d.ts +1 -1
- package/dist/hooks/navigation/utils.d.ts +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -2
- package/dist/routes/CustomViewRoute.d.ts +2 -1
- package/dist/{src-BYniefVu.js → src-DOX2nOyh.js} +1586 -1283
- package/dist/src-DOX2nOyh.js.map +1 -0
- package/dist/types/components/EntityFormActionsProps.d.ts +1 -1
- package/dist/types/components/EntityFormProps.d.ts +59 -0
- package/dist/types/fields.d.ts +6 -1
- package/dist/util/dataControllerAdapter.d.ts +30 -0
- package/dist/util/navigation_utils.d.ts +1 -1
- package/dist/util/propertyConfigMapper.d.ts +17 -0
- package/package.json +18 -18
- package/src/collection_editor/extensibility_types.ts +168 -0
- package/src/collection_editor/index.ts +46 -0
- package/src/collection_editor/serializable_types.ts +487 -0
- package/src/collection_editor/serializable_utils.ts +588 -0
- package/src/collection_editor/ui/collection_editor/AICollectionGeneratorPopover.tsx +4 -4
- package/src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx +134 -70
- package/src/collection_editor/ui/collection_editor/CollectionPropertiesEditorForm.tsx +95 -78
- package/src/collection_editor/ui/collection_editor/CollectionStudioView.tsx +23 -20
- package/src/collection_editor/ui/collection_editor/CollectionsStudioView.tsx +79 -27
- package/src/collection_editor/ui/collection_editor/DisplaySettingsForm.tsx +9 -7
- package/src/collection_editor/ui/collection_editor/GeneralSettingsForm.tsx +22 -5
- package/src/collection_editor/ui/collection_editor/GetCodeDialog.tsx +3 -3
- package/src/collection_editor/ui/collection_editor/PropertyEditView.tsx +155 -10
- package/src/collection_editor/ui/collection_editor/PropertyFieldPreview.tsx +6 -6
- package/src/collection_editor/ui/collection_editor/PropertyTree.tsx +1 -0
- package/src/collection_editor/ui/collection_editor/RouterCollectionStudioView.tsx +44 -0
- package/src/collection_editor/ui/collection_editor/RouterCollectionsStudioView.tsx +41 -0
- package/src/collection_editor/ui/collection_editor/properties/EnumPropertyField.tsx +4 -3
- package/src/collection_editor/useJsonCollectionsConfigController.tsx +286 -0
- package/src/collection_editor/useSafeSnackbarController.ts +9 -0
- package/src/collection_editor_ui.ts +6 -0
- package/src/components/DefaultDrawer.tsx +13 -3
- package/src/components/DrawerNavigationGroup.tsx +2 -2
- package/src/components/EntityCollectionView/EntityBoardCard.tsx +6 -6
- package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +12 -11
- package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +40 -190
- package/src/components/EntityCollectionView/EntityCollectionListView.tsx +54 -183
- package/src/components/EntityCollectionView/hooks/useKanbanDragAndDrop.ts +6 -6
- package/src/components/EntityEditView.tsx +5 -4
- package/src/components/EntityEditViewFormActions.tsx +32 -26
- package/src/components/HomePage/ContentHomePage.tsx +13 -4
- package/src/components/RebaseCMS.tsx +3 -2
- package/src/components/RebaseNavigation.tsx +71 -7
- package/src/components/SelectableTable/SelectableTable.tsx +2 -2
- package/src/components/SideDialogs.tsx +0 -7
- package/src/components/common/default_entity_actions.tsx +9 -9
- package/src/contexts/BreacrumbsContext.tsx +15 -6
- package/src/editor/selectors/ai-selector.tsx +0 -1
- package/src/form/EntityForm.tsx +191 -428
- package/src/form/EntityFormActions.tsx +33 -47
- package/src/form/EntityFormBinding.tsx +323 -0
- package/src/form/components/FormLayout.tsx +1 -1
- package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +7 -2
- package/src/form/form_utils.ts +163 -0
- package/src/form/index.tsx +14 -5
- package/src/hooks/navigation/contexts/CollectionRegistryContext.tsx +2 -2
- package/src/hooks/navigation/contexts/NavigationStateContext.tsx +2 -2
- package/src/hooks/navigation/contexts/UrlContext.tsx +1 -2
- package/src/hooks/navigation/useAsyncResolver.ts +100 -0
- package/src/hooks/navigation/useBuildCollectionRegistryController.tsx +15 -8
- package/src/hooks/navigation/useBuildNavigationStateController.tsx +12 -8
- package/src/hooks/navigation/useNavigationResolution.ts +33 -0
- package/src/hooks/navigation/useResolvedCollections.ts +29 -71
- package/src/hooks/navigation/useResolvedViews.tsx +40 -70
- package/src/hooks/navigation/useTopLevelNavigation.ts +20 -16
- package/src/hooks/navigation/utils.ts +7 -4
- package/src/index.ts +5 -0
- package/src/routes/CustomViewRoute.tsx +14 -6
- package/src/types/components/EntityFormActionsProps.tsx +1 -1
- package/src/types/components/EntityFormProps.tsx +68 -0
- package/src/types/fields.tsx +7 -1
- package/src/util/dataControllerAdapter.ts +93 -0
- package/src/util/navigation_utils.ts +1 -1
- package/src/util/propertyConfigMapper.ts +134 -0
- package/LICENSE +0 -21
- package/dist/CollectionEditorDialog-HNXGxXdO.js.map +0 -1
- package/dist/CollectionsStudioView-B1mN33GB.js.map +0 -1
- package/dist/PropertyEditView-C2wp8kQ9.js.map +0 -1
- package/dist/components/EntityCollectionView/Board.d.ts +0 -3
- package/dist/components/EntityCollectionView/BoardColumn.d.ts +0 -42
- package/dist/components/EntityCollectionView/BoardColumnTitle.d.ts +0 -9
- package/dist/components/EntityCollectionView/BoardSortableList.d.ts +0 -14
- package/dist/components/EntityCollectionView/board_types.d.ts +0 -105
- package/dist/hooks/navigation/useNavigationRegistry.d.ts +0 -12
- package/dist/hooks/navigation/useNavigationURLs.d.ts +0 -11
- package/dist/src-BYniefVu.js.map +0 -1
- package/src/components/EntityCollectionView/Board.tsx +0 -475
- package/src/components/EntityCollectionView/BoardColumn.tsx +0 -165
- package/src/components/EntityCollectionView/BoardColumnTitle.tsx +0 -46
- package/src/components/EntityCollectionView/BoardSortableList.tsx +0 -177
- package/src/components/EntityCollectionView/board_types.ts +0 -113
- package/src/hooks/navigation/useNavigationRegistry.ts +0 -164
- package/src/hooks/navigation/useNavigationURLs.ts +0 -56
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { IconForView } from "@rebasepro/core";
|
|
3
3
|
import { FieldCaption } from "../../_cms_internals";
|
|
4
4
|
import React, { useState } from "react";
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
import { SearchIconsView } from "../../_cms_internals";
|
|
7
7
|
import type { EntityCollection, PostgresCollection } from "@rebasepro/types";
|
|
8
8
|
import {
|
|
@@ -26,17 +26,23 @@ import {
|
|
|
26
26
|
import { Field, getIn, useFormex } from "@rebasepro/formex";
|
|
27
27
|
import { useCollectionsConfigController } from "../../useCollectionsConfigController";
|
|
28
28
|
import { singular, toSnakeCase } from "@rebasepro/utils";
|
|
29
|
+
import type { ExtraCollectionFieldsParams } from "../../extensibility_types";
|
|
30
|
+
import { toSerializableCollection } from "../../serializable_utils";
|
|
29
31
|
|
|
30
32
|
export function GeneralSettingsForm({
|
|
31
33
|
isNewCollection,
|
|
32
34
|
existingPaths,
|
|
33
35
|
existingIds,
|
|
34
|
-
parentCollection
|
|
36
|
+
parentCollection,
|
|
37
|
+
renderExtraCollectionFields,
|
|
38
|
+
standalone,
|
|
35
39
|
}: {
|
|
36
40
|
isNewCollection: boolean;
|
|
37
41
|
existingPaths?: string[];
|
|
38
42
|
existingIds?: string[];
|
|
39
43
|
parentCollection?: EntityCollection;
|
|
44
|
+
renderExtraCollectionFields?: (params: ExtraCollectionFieldsParams) => React.ReactNode;
|
|
45
|
+
standalone?: boolean;
|
|
40
46
|
}) {
|
|
41
47
|
|
|
42
48
|
const {
|
|
@@ -51,9 +57,8 @@ export function GeneralSettingsForm({
|
|
|
51
57
|
|
|
52
58
|
const [iconDialogOpen, setIconDialogOpen] = useState(false);
|
|
53
59
|
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
const configController = useCollectionsConfigController();
|
|
60
|
+
const configControllerFromContext = useCollectionsConfigController();
|
|
61
|
+
const configController = standalone ? { readOnly: false } : configControllerFromContext;
|
|
57
62
|
|
|
58
63
|
const updateDatabaseId = (databaseId: string) => {
|
|
59
64
|
setFieldValue("databaseId", databaseId ?? undefined);
|
|
@@ -243,6 +248,18 @@ export function GeneralSettingsForm({
|
|
|
243
248
|
</div>
|
|
244
249
|
</Dialog>
|
|
245
250
|
|
|
251
|
+
{renderExtraCollectionFields && (
|
|
252
|
+
<div className="mt-4">
|
|
253
|
+
{renderExtraCollectionFields({
|
|
254
|
+
metadata: (values.metadata ?? {}) as Record<string, unknown>,
|
|
255
|
+
onMetadataChange: (key: string, value: unknown) => {
|
|
256
|
+
setFieldValue(`metadata.${key}`, value);
|
|
257
|
+
},
|
|
258
|
+
collection: toSerializableCollection(values),
|
|
259
|
+
})}
|
|
260
|
+
</div>
|
|
261
|
+
)}
|
|
262
|
+
|
|
246
263
|
</Container>
|
|
247
264
|
</div>
|
|
248
265
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useSafeSnackbarController } from "../../useSafeSnackbarController";
|
|
2
2
|
import { EntityCollection } from "@rebasepro/types";
|
|
3
3
|
import { Button, CopyIcon, Dialog, DialogActions, DialogContent, DialogTitle, Typography } from "@rebasepro/ui";
|
|
4
4
|
import React from "react";
|
|
@@ -14,7 +14,7 @@ export function GetCodeDialog({
|
|
|
14
14
|
open
|
|
15
15
|
}: { onOpenChange: (open: boolean) => void, collection: EntityCollection, open: boolean }) {
|
|
16
16
|
|
|
17
|
-
const snackbarController =
|
|
17
|
+
const snackbarController = useSafeSnackbarController();
|
|
18
18
|
|
|
19
19
|
const code = collection
|
|
20
20
|
? "import { EntityCollection } from \"@rebasepro/core\";\n\nconst " + (collection?.name ? camelCase(collection.name) : "my") + "Collection:EntityCollection = " + JSON5.stringify(collectionToCode({ ...collection }), null, "\t")
|
|
@@ -64,7 +64,7 @@ export function GetCodeDialog({
|
|
|
64
64
|
onClick={(e) => {
|
|
65
65
|
e.stopPropagation();
|
|
66
66
|
e.preventDefault();
|
|
67
|
-
snackbarController
|
|
67
|
+
snackbarController?.open({
|
|
68
68
|
type: "success",
|
|
69
69
|
message: "Copied"
|
|
70
70
|
})
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
|
|
2
|
-
import React, { useDeferredValue, useEffect, useRef, useState } from "react";
|
|
2
|
+
import React, { useCallback, useDeferredValue, useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { deepEqual as equal } from "fast-equals"
|
|
4
4
|
|
|
5
5
|
import { Formex, FormexController, getIn, useCreateFormex } from "@rebasepro/formex";
|
|
6
6
|
import { ConfirmationDialog } from "@rebasepro/core";
|
|
7
7
|
import { DEFAULT_FIELD_CONFIGS, getFieldConfig, getFieldId } from "../../../components/field_configs";
|
|
8
8
|
import { PropertyConfigBadge } from "../../../components/PropertyConfigBadge";
|
|
9
|
-
import { Property, PropertyConfig, PropertyConfigId } from "@rebasepro/types";
|
|
9
|
+
import { EntityCollection, Property, PropertyConfig, PropertyConfigId } from "@rebasepro/types";
|
|
10
|
+
import type { PropertyTypePreset, PropertyType } from "../../extensibility_types";
|
|
11
|
+
import { toSerializableProperty, toSerializableCollection } from "../../serializable_utils";
|
|
12
|
+
import type { SerializableProperty, SerializableCollection } from "../../serializable_types";
|
|
10
13
|
import { isPropertyBuilder } from "@rebasepro/common";
|
|
11
14
|
import {
|
|
12
15
|
AlertTriangleIcon,
|
|
@@ -82,6 +85,15 @@ export type PropertyFormProps = {
|
|
|
82
85
|
getData?: () => Promise<object[]>;
|
|
83
86
|
getController?: (formex: FormexController<PropertyWithId>) => void;
|
|
84
87
|
propertyConfigs: Record<string, PropertyConfig>;
|
|
88
|
+
propertyTypePresets?: PropertyTypePreset[];
|
|
89
|
+
hiddenPropertyTypes?: PropertyType[];
|
|
90
|
+
renderExtraPropertyFields?: (params: {
|
|
91
|
+
metadata: Record<string, unknown>;
|
|
92
|
+
onMetadataChange: (key: string, value: unknown) => void;
|
|
93
|
+
property: SerializableProperty;
|
|
94
|
+
collection: SerializableCollection;
|
|
95
|
+
}) => React.ReactNode;
|
|
96
|
+
collectionValues?: EntityCollection;
|
|
85
97
|
|
|
86
98
|
};
|
|
87
99
|
|
|
@@ -108,7 +120,11 @@ export const PropertyForm = React.memo(
|
|
|
108
120
|
allowDataInference,
|
|
109
121
|
getController,
|
|
110
122
|
getData,
|
|
111
|
-
propertyConfigs
|
|
123
|
+
propertyConfigs,
|
|
124
|
+
propertyTypePresets,
|
|
125
|
+
hiddenPropertyTypes,
|
|
126
|
+
renderExtraPropertyFields,
|
|
127
|
+
collectionValues
|
|
112
128
|
} = props;
|
|
113
129
|
|
|
114
130
|
const initialValue: PropertyWithId = {
|
|
@@ -228,6 +244,10 @@ export const PropertyForm = React.memo(
|
|
|
228
244
|
getData={getData}
|
|
229
245
|
allowDataInference={allowDataInference}
|
|
230
246
|
propertyConfigs={propertyConfigs}
|
|
247
|
+
propertyTypePresets={propertyTypePresets}
|
|
248
|
+
hiddenPropertyTypes={hiddenPropertyTypes}
|
|
249
|
+
renderExtraPropertyFields={renderExtraPropertyFields}
|
|
250
|
+
collectionValues={collectionValues}
|
|
231
251
|
{...formexController}/>
|
|
232
252
|
</Formex>;
|
|
233
253
|
}, (a, b) =>
|
|
@@ -324,7 +344,11 @@ function PropertyEditFormFields({
|
|
|
324
344
|
inArray,
|
|
325
345
|
getData,
|
|
326
346
|
allowDataInference,
|
|
327
|
-
propertyConfigs
|
|
347
|
+
propertyConfigs,
|
|
348
|
+
propertyTypePresets,
|
|
349
|
+
hiddenPropertyTypes,
|
|
350
|
+
renderExtraPropertyFields,
|
|
351
|
+
collectionValues
|
|
328
352
|
}: {
|
|
329
353
|
includeIdAndTitle?: boolean;
|
|
330
354
|
existing: boolean;
|
|
@@ -341,6 +365,10 @@ function PropertyEditFormFields({
|
|
|
341
365
|
getData?: () => Promise<object[]>;
|
|
342
366
|
allowDataInference: boolean;
|
|
343
367
|
propertyConfigs: Record<string, PropertyConfig>;
|
|
368
|
+
propertyTypePresets?: PropertyTypePreset[];
|
|
369
|
+
hiddenPropertyTypes?: PropertyType[];
|
|
370
|
+
renderExtraPropertyFields?: PropertyFormProps["renderExtraPropertyFields"];
|
|
371
|
+
collectionValues?: EntityCollection;
|
|
344
372
|
|
|
345
373
|
} & FormexController<PropertyWithId>) {
|
|
346
374
|
|
|
@@ -389,6 +417,29 @@ function PropertyEditFormFields({
|
|
|
389
417
|
}, 0);
|
|
390
418
|
};
|
|
391
419
|
|
|
420
|
+
const onPresetSelected = useCallback((preset: PropertyTypePreset) => {
|
|
421
|
+
// Map baseType to the default widgetId
|
|
422
|
+
const BASE_TYPE_TO_WIDGET: Record<string, string> = {
|
|
423
|
+
"string": "text_field",
|
|
424
|
+
"number": "number_input",
|
|
425
|
+
"boolean": "switch",
|
|
426
|
+
"date": "date_time",
|
|
427
|
+
"reference": "reference",
|
|
428
|
+
"relation": "relation",
|
|
429
|
+
"map": "group",
|
|
430
|
+
"array": "repeat",
|
|
431
|
+
"vector": "vector_input",
|
|
432
|
+
"geopoint": "text_field",
|
|
433
|
+
"binary": "text_field",
|
|
434
|
+
};
|
|
435
|
+
const widgetId = BASE_TYPE_TO_WIDGET[preset.baseType] || "text_field";
|
|
436
|
+
setSelectedFieldConfigId(widgetId);
|
|
437
|
+
// Merge preset defaults into the property
|
|
438
|
+
const updatedValues = updatePropertyFromWidget(values, widgetId, propertyConfigs);
|
|
439
|
+
const mergedValues = { ...updatedValues, ...preset.defaults, propertyConfig: widgetId };
|
|
440
|
+
setValues(mergedValues as PropertyWithId);
|
|
441
|
+
}, [values, propertyConfigs, setValues]);
|
|
442
|
+
|
|
392
443
|
let childComponent;
|
|
393
444
|
if (selectedFieldConfigId === "text_field" ||
|
|
394
445
|
selectedFieldConfigId === "multiline" ||
|
|
@@ -520,7 +571,10 @@ function PropertyEditFormFields({
|
|
|
520
571
|
showError={Boolean(selectedWidgetError)}
|
|
521
572
|
existing={existing}
|
|
522
573
|
propertyConfigs={propertyConfigs}
|
|
523
|
-
inArray={inArray}
|
|
574
|
+
inArray={inArray}
|
|
575
|
+
propertyTypePresets={propertyTypePresets}
|
|
576
|
+
hiddenPropertyTypes={hiddenPropertyTypes}
|
|
577
|
+
onPresetSelected={onPresetSelected}/>
|
|
524
578
|
|
|
525
579
|
{!!selectedWidgetError &&
|
|
526
580
|
<Typography variant="caption"
|
|
@@ -553,6 +607,23 @@ function PropertyEditFormFields({
|
|
|
553
607
|
|
|
554
608
|
{childComponent}
|
|
555
609
|
|
|
610
|
+
{renderExtraPropertyFields && collectionValues && (
|
|
611
|
+
<div className="col-span-12 mt-4 px-2">
|
|
612
|
+
{renderExtraPropertyFields({
|
|
613
|
+
metadata: ((values as unknown as Record<string, unknown>).metadata as Record<string, unknown>) ?? {},
|
|
614
|
+
onMetadataChange: (key: string, value: unknown) => {
|
|
615
|
+
const currentMetadata = ((values as unknown as Record<string, unknown>).metadata as Record<string, unknown>) ?? {};
|
|
616
|
+
setValues({
|
|
617
|
+
...values,
|
|
618
|
+
metadata: { ...currentMetadata, [key]: value },
|
|
619
|
+
} as PropertyWithId);
|
|
620
|
+
},
|
|
621
|
+
property: toSerializableProperty(values as Property),
|
|
622
|
+
collection: toSerializableCollection(collectionValues),
|
|
623
|
+
})}
|
|
624
|
+
</div>
|
|
625
|
+
)}
|
|
626
|
+
|
|
556
627
|
<div className={"col-span-12"}>
|
|
557
628
|
<AdvancedPropertyValidation disabled={disabled}/>
|
|
558
629
|
</div>
|
|
@@ -626,6 +697,34 @@ const WIDGET_TYPE_MAP: Record<PropertyConfigId, string> = {
|
|
|
626
697
|
vector_input: "Number"
|
|
627
698
|
};
|
|
628
699
|
|
|
700
|
+
const WIDGET_BASE_TYPE_MAP: Record<string, PropertyType> = {
|
|
701
|
+
text_field: "string",
|
|
702
|
+
multiline: "string",
|
|
703
|
+
markdown: "string",
|
|
704
|
+
url: "string",
|
|
705
|
+
email: "string",
|
|
706
|
+
select: "string",
|
|
707
|
+
multi_select: "string",
|
|
708
|
+
file_upload: "string",
|
|
709
|
+
multi_file_upload: "string",
|
|
710
|
+
reference_as_string: "string",
|
|
711
|
+
user_select: "string",
|
|
712
|
+
number_input: "number",
|
|
713
|
+
number_select: "number",
|
|
714
|
+
multi_number_select: "number",
|
|
715
|
+
switch: "boolean",
|
|
716
|
+
date_time: "date",
|
|
717
|
+
reference: "reference",
|
|
718
|
+
multi_references: "reference",
|
|
719
|
+
relation: "relation",
|
|
720
|
+
group: "map",
|
|
721
|
+
key_value: "map",
|
|
722
|
+
block: "map",
|
|
723
|
+
repeat: "array",
|
|
724
|
+
custom_array: "array",
|
|
725
|
+
vector_input: "vector",
|
|
726
|
+
};
|
|
727
|
+
|
|
629
728
|
function WidgetSelectView({
|
|
630
729
|
initialProperty,
|
|
631
730
|
value,
|
|
@@ -636,7 +735,10 @@ function WidgetSelectView({
|
|
|
636
735
|
showError,
|
|
637
736
|
existing,
|
|
638
737
|
propertyConfigs,
|
|
639
|
-
inArray
|
|
738
|
+
inArray,
|
|
739
|
+
propertyTypePresets,
|
|
740
|
+
hiddenPropertyTypes,
|
|
741
|
+
onPresetSelected
|
|
640
742
|
}: {
|
|
641
743
|
initialProperty?: PropertyWithId,
|
|
642
744
|
value?: PropertyConfigId,
|
|
@@ -647,14 +749,24 @@ function WidgetSelectView({
|
|
|
647
749
|
disabled: boolean,
|
|
648
750
|
existing: boolean,
|
|
649
751
|
propertyConfigs: Record<string, PropertyConfig>,
|
|
650
|
-
inArray?: boolean
|
|
752
|
+
inArray?: boolean,
|
|
753
|
+
propertyTypePresets?: PropertyTypePreset[],
|
|
754
|
+
hiddenPropertyTypes?: PropertyType[],
|
|
755
|
+
onPresetSelected?: (preset: PropertyTypePreset) => void,
|
|
651
756
|
}) {
|
|
652
757
|
|
|
653
758
|
const allSupportedFields = Object.entries(supportedFields).concat(Object.entries(propertyConfigs));
|
|
654
759
|
|
|
760
|
+
const filteredFields = hiddenPropertyTypes && !propertyTypePresets
|
|
761
|
+
? allSupportedFields.filter(([key]) => {
|
|
762
|
+
const baseType = WIDGET_BASE_TYPE_MAP[key];
|
|
763
|
+
return !baseType || !hiddenPropertyTypes.includes(baseType);
|
|
764
|
+
})
|
|
765
|
+
: allSupportedFields;
|
|
766
|
+
|
|
655
767
|
const displayedWidgets = (inArray
|
|
656
|
-
?
|
|
657
|
-
:
|
|
768
|
+
? filteredFields.filter(([_, propertyConfig]) => !isPropertyBuilder(propertyConfig.property as Property) && (propertyConfig.property as Property)?.type !== "array")
|
|
769
|
+
: filteredFields)
|
|
658
770
|
.map(([key, propertyConfig]) => ({
|
|
659
771
|
[key]: propertyConfig
|
|
660
772
|
}))
|
|
@@ -665,6 +777,11 @@ function WidgetSelectView({
|
|
|
665
777
|
}
|
|
666
778
|
}, {});
|
|
667
779
|
|
|
780
|
+
const activePreset = useMemo(() => {
|
|
781
|
+
if (!propertyTypePresets || !initialProperty) return undefined;
|
|
782
|
+
return propertyTypePresets.find(p => p.detect?.(toSerializableProperty(initialProperty as Property)));
|
|
783
|
+
}, [propertyTypePresets, initialProperty]);
|
|
784
|
+
|
|
668
785
|
const key = value;
|
|
669
786
|
const propertyConfig = key ? (DEFAULT_FIELD_CONFIGS[key] ?? propertyConfigs[key]) : undefined;
|
|
670
787
|
const baseProperty = propertyConfig?.property;
|
|
@@ -711,9 +828,36 @@ function WidgetSelectView({
|
|
|
711
828
|
onOpenChange={(open: boolean) => onOpenChange(open, Boolean(value))}
|
|
712
829
|
maxWidth={"4xl"}>
|
|
713
830
|
<DialogTitle>
|
|
714
|
-
Select a property widget
|
|
831
|
+
{propertyTypePresets ? "Select a property type" : "Select a property widget"}
|
|
715
832
|
</DialogTitle>
|
|
716
833
|
<DialogContent>
|
|
834
|
+
{propertyTypePresets ? (
|
|
835
|
+
<div className={"grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-2 mt-4"}>
|
|
836
|
+
{propertyTypePresets.map((preset) => (
|
|
837
|
+
<Card
|
|
838
|
+
key={preset.id}
|
|
839
|
+
onClick={() => {
|
|
840
|
+
onPresetSelected?.(preset);
|
|
841
|
+
onOpenChange(false, true);
|
|
842
|
+
}}
|
|
843
|
+
className={cls(
|
|
844
|
+
"flex flex-row items-center px-4 py-2 m-1",
|
|
845
|
+
activePreset?.id === preset.id && "ring-2 ring-primary"
|
|
846
|
+
)}>
|
|
847
|
+
<div className={cls("flex flex-row items-center text-base min-h-[48px]")}>
|
|
848
|
+
{preset.icon && (
|
|
849
|
+
<div className={"mr-4 text-2xl"}>
|
|
850
|
+
{typeof preset.icon === "string" ? preset.icon : preset.icon}
|
|
851
|
+
</div>
|
|
852
|
+
)}
|
|
853
|
+
<div>
|
|
854
|
+
<Typography variant={"label"}>{preset.label}</Typography>
|
|
855
|
+
</div>
|
|
856
|
+
</div>
|
|
857
|
+
</Card>
|
|
858
|
+
))}
|
|
859
|
+
</div>
|
|
860
|
+
) : (
|
|
717
861
|
<div>
|
|
718
862
|
{groups.map(group => {
|
|
719
863
|
return <div key={group} className={"mt-4"}>
|
|
@@ -749,6 +893,7 @@ function WidgetSelectView({
|
|
|
749
893
|
{/* existing={existing}/>;*/}
|
|
750
894
|
{/*})}*/}
|
|
751
895
|
</div>
|
|
896
|
+
)}
|
|
752
897
|
</DialogContent>
|
|
753
898
|
</Dialog>
|
|
754
899
|
</>;
|
|
@@ -36,9 +36,9 @@ export function PropertyFieldPreview({
|
|
|
36
36
|
|
|
37
37
|
return <ErrorBoundary>
|
|
38
38
|
<div onClick={onClick} className={onClick ? "cursor-pointer" : ""}>
|
|
39
|
-
<
|
|
39
|
+
<div
|
|
40
40
|
className={cls(
|
|
41
|
-
"w-full flex flex-row gap-3 items-center px-3 py-2 rounded-lg transition-all duration-200 border bg-white dark:bg-surface-
|
|
41
|
+
"w-full flex flex-row gap-3 items-center px-3 py-2 rounded-lg transition-all duration-200 border bg-white dark:bg-surface-900 shadow-xs",
|
|
42
42
|
borderColorClass || "border-surface-200 dark:border-surface-700",
|
|
43
43
|
selected
|
|
44
44
|
? "bg-primary/10 text-primary dark:bg-primary/20 dark:text-primary-light ring-1 ring-inset ring-primary border-primary/30"
|
|
@@ -81,7 +81,7 @@ export function PropertyFieldPreview({
|
|
|
81
81
|
</ErrorBoundary>
|
|
82
82
|
|
|
83
83
|
{includeEditButton && <Typography variant={"button"}>EDIT</Typography>}
|
|
84
|
-
</
|
|
84
|
+
</div>
|
|
85
85
|
</div>
|
|
86
86
|
</ErrorBoundary>
|
|
87
87
|
}
|
|
@@ -103,9 +103,9 @@ export function NonEditablePropertyPreview({
|
|
|
103
103
|
|
|
104
104
|
return (
|
|
105
105
|
<div onClick={onClick} className={onClick ? "cursor-pointer" : ""}>
|
|
106
|
-
<
|
|
106
|
+
<div
|
|
107
107
|
className={cls(
|
|
108
|
-
"w-full flex flex-row gap-3 items-center px-3 py-2 rounded-lg transition-all duration-200 border bg-white dark:bg-surface-
|
|
108
|
+
"w-full flex flex-row gap-3 items-center px-3 py-2 rounded-lg transition-all duration-200 border bg-white dark:bg-surface-900 border-surface-200 dark:border-surface-700 shadow-xs",
|
|
109
109
|
selected
|
|
110
110
|
? "bg-primary/10 text-primary dark:bg-primary/20 dark:text-primary-light ring-1 ring-inset ring-primary border-primary/30"
|
|
111
111
|
: "hover:bg-surface-50 dark:hover:bg-surface-700"
|
|
@@ -149,7 +149,7 @@ export function NonEditablePropertyPreview({
|
|
|
149
149
|
{"columnType" in property ? (property as { columnType?: string }).columnType ?? property.type : property.type}
|
|
150
150
|
</Typography>
|
|
151
151
|
</ErrorBoundary>}
|
|
152
|
-
</
|
|
152
|
+
</div>
|
|
153
153
|
</div>
|
|
154
154
|
)
|
|
155
155
|
}
|
|
@@ -276,6 +276,7 @@ export function PropertyTreeEntry({
|
|
|
276
276
|
{!isPropertyBuilder(property) && !additionalField && editable
|
|
277
277
|
? <PropertyFieldPreview
|
|
278
278
|
property={property}
|
|
279
|
+
propertyKey={propertyKey}
|
|
279
280
|
onClick={onPropertyClick ? () => onPropertyClick(propertyKey, namespace) : undefined}
|
|
280
281
|
includeName={true}
|
|
281
282
|
selected={selected}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Router-aware wrapper around CollectionStudioView.
|
|
3
|
+
*
|
|
4
|
+
* This component provides the react-router-based navigation behavior
|
|
5
|
+
* that Rebase Studio expects: cancel navigates to the root path,
|
|
6
|
+
* save navigates to the saved collection's slug, and a snackbar
|
|
7
|
+
* toast is shown on success.
|
|
8
|
+
*
|
|
9
|
+
* External consumers should use `CollectionStudioView` directly
|
|
10
|
+
* (which has no react-router dependency).
|
|
11
|
+
*/
|
|
12
|
+
import React from "react";
|
|
13
|
+
import { useNavigate } from "react-router-dom";
|
|
14
|
+
import { useUrlController } from "../../_cms_internals";
|
|
15
|
+
import { useSnackbarController } from "@rebasepro/core";
|
|
16
|
+
import { CollectionStudioView, CollectionStudioViewProps } from "./CollectionStudioView";
|
|
17
|
+
|
|
18
|
+
export type RouterCollectionStudioViewProps = Omit<CollectionStudioViewProps, "onSave" | "onCancel">;
|
|
19
|
+
|
|
20
|
+
export function RouterCollectionStudioView(props: RouterCollectionStudioViewProps) {
|
|
21
|
+
const navigate = useNavigate();
|
|
22
|
+
const urlController = useUrlController();
|
|
23
|
+
const snackbarController = useSnackbarController();
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<CollectionStudioView
|
|
27
|
+
{...props}
|
|
28
|
+
onCancel={() => {
|
|
29
|
+
navigate(urlController.buildAppUrlPath("/"));
|
|
30
|
+
}}
|
|
31
|
+
onSave={(savedCollection) => {
|
|
32
|
+
if (savedCollection) {
|
|
33
|
+
snackbarController.open({
|
|
34
|
+
type: "success",
|
|
35
|
+
message: `Collection ${savedCollection.name || savedCollection.slug} saved`
|
|
36
|
+
});
|
|
37
|
+
if (props.collectionId === "new") {
|
|
38
|
+
navigate(urlController.buildAppUrlPath(`s/schema/${savedCollection.slug}`));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}}
|
|
42
|
+
/>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Router-aware wrapper around CollectionsStudioView.
|
|
3
|
+
*
|
|
4
|
+
* This component provides the react-router-based navigation behavior
|
|
5
|
+
* that Rebase Studio expects: the active collection is derived from the
|
|
6
|
+
* URL, and clicking a collection navigates via react-router.
|
|
7
|
+
*
|
|
8
|
+
* External consumers should use `CollectionsStudioView` directly
|
|
9
|
+
* (which has no react-router dependency).
|
|
10
|
+
*/
|
|
11
|
+
import React from "react";
|
|
12
|
+
import { useLocation, useNavigate } from "react-router-dom";
|
|
13
|
+
import { useUrlController } from "../../_cms_internals";
|
|
14
|
+
import { CollectionsStudioView, CollectionsStudioViewProps } from "./CollectionsStudioView";
|
|
15
|
+
|
|
16
|
+
export type RouterCollectionsStudioViewProps = Omit<CollectionsStudioViewProps, "activeCollectionId" | "onActiveCollectionChange">;
|
|
17
|
+
|
|
18
|
+
export function RouterCollectionsStudioView(props: RouterCollectionsStudioViewProps) {
|
|
19
|
+
const navigate = useNavigate();
|
|
20
|
+
const urlController = useUrlController();
|
|
21
|
+
const location = useLocation();
|
|
22
|
+
|
|
23
|
+
// Determine the active collection from the URL segment after "schema/"
|
|
24
|
+
const basePath = urlController.buildAppUrlPath("schema");
|
|
25
|
+
const relativePath = location.pathname.replace(basePath, "").replace(/^\//, "");
|
|
26
|
+
const activeCollectionId = relativePath.split("/")[0] || undefined;
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<CollectionsStudioView
|
|
30
|
+
{...props}
|
|
31
|
+
activeCollectionId={activeCollectionId}
|
|
32
|
+
onActiveCollectionChange={(id) => {
|
|
33
|
+
if (id) {
|
|
34
|
+
navigate(urlController.buildAppUrlPath(`schema/${id}`));
|
|
35
|
+
} else {
|
|
36
|
+
navigate(urlController.buildAppUrlPath("schema"));
|
|
37
|
+
}
|
|
38
|
+
}}
|
|
39
|
+
/>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useMemo } from "react";
|
|
2
2
|
import { getIn, useFormex } from "@rebasepro/formex";
|
|
3
|
-
import {
|
|
3
|
+
import { useTranslation } from "@rebasepro/core";
|
|
4
|
+
import { useSafeSnackbarController } from "../../../useSafeSnackbarController";
|
|
4
5
|
import { EnumValueConfig, EnumValues } from "@rebasepro/types";
|
|
5
6
|
import { resolveEnumValues } from "@rebasepro/common";
|
|
6
7
|
import { Select, SelectItem } from "@rebasepro/ui";
|
|
@@ -34,7 +35,7 @@ export function EnumPropertyField({
|
|
|
34
35
|
setFieldValue
|
|
35
36
|
} = useFormex<PropertyWithId>();
|
|
36
37
|
|
|
37
|
-
const snackbarContext =
|
|
38
|
+
const snackbarContext = useSafeSnackbarController();
|
|
38
39
|
const { t } = useTranslation();
|
|
39
40
|
|
|
40
41
|
const enumValuesPath = multiselect ? "of.enum" : "enum";
|
|
@@ -56,7 +57,7 @@ export function EnumPropertyField({
|
|
|
56
57
|
const enumIds = value.filter(v => Boolean(v?.id)).map((v: EnumValueConfig) => v.id);
|
|
57
58
|
if (defaultValue && !enumIds.includes(defaultValue)) {
|
|
58
59
|
setFieldValue("defaultValue", undefined);
|
|
59
|
-
snackbarContext
|
|
60
|
+
snackbarContext?.open({
|
|
60
61
|
type: "warning",
|
|
61
62
|
message: "Default value was cleared"
|
|
62
63
|
})
|