@rebasepro/admin 0.6.1 → 0.8.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-BO_aQ-Z4.js} +236 -155
- package/dist/CollectionEditorDialog-BO_aQ-Z4.js.map +1 -0
- package/dist/{PropertyEditView-C2wp8kQ9.js → PropertyEditView-DKzOpMjR.js} +190 -50
- package/dist/PropertyEditView-DKzOpMjR.js.map +1 -0
- package/dist/{CollectionsStudioView-B1mN33GB.js → RouterCollectionsStudioView-BQTIExjA.js} +61 -39
- package/dist/RouterCollectionsStudioView-BQTIExjA.js.map +1 -0
- package/dist/collection_editor/_cms_internals.d.ts +1 -1
- package/dist/collection_editor/api/generateCollectionApi.d.ts +3 -2
- 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 +370 -0
- package/dist/collection_editor/serializable_utils.d.ts +50 -0
- package/dist/collection_editor/ui/collection_editor/CollectionEditorDialog.d.ts +3 -3
- 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/EntityCollectionTable/EntityCollectionTable.d.ts +1 -1
- package/dist/components/EntityCollectionTable/index.d.ts +1 -1
- 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/components/SelectableTable/SelectionStore.d.ts +12 -21
- package/dist/components/field_configs.d.ts +1 -1
- package/dist/editor/editor.d.ts +0 -6
- package/dist/editor.js +1 -3
- package/dist/editor.js.map +1 -1
- package/dist/form/EntityForm.d.ts +10 -9
- package/dist/form/EntityFormBinding.d.ts +27 -0
- package/dist/form/components/StorageUploadProgress.d.ts +6 -1
- package/dist/form/form_utils.d.ts +8 -0
- package/dist/form/index.d.ts +5 -2
- package/dist/{history-BO6VT85a.js → history-B3cqBzEV.js} +2 -2
- package/dist/{history-BO6VT85a.js.map → history-B3cqBzEV.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 +3 -1
- package/dist/index.js +2 -2
- package/dist/preview/components/StorageThumbnail.d.ts +3 -1
- package/dist/routes/CustomViewRoute.d.ts +2 -1
- package/dist/{src-BYniefVu.js → src-cxV1ODRG.js} +1731 -1710
- package/dist/src-cxV1ODRG.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/components/PropertyPreviewProps.d.ts +2 -1
- package/dist/types/fields.d.ts +10 -7
- 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 +8 -8
- package/src/collection_editor/_cms_internals.ts +1 -1
- package/src/collection_editor/api/generateCollectionApi.ts +3 -2
- package/src/collection_editor/extensibility_types.ts +168 -0
- package/src/collection_editor/index.ts +46 -0
- package/src/collection_editor/pgColumnToProperty.ts +2 -2
- package/src/collection_editor/serializable_types.ts +474 -0
- package/src/collection_editor/serializable_utils.ts +576 -0
- package/src/collection_editor/ui/collection_editor/AICollectionGeneratorPopover.tsx +6 -6
- package/src/collection_editor/ui/collection_editor/CollectionEditorDialog.tsx +170 -89
- 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 +154 -18
- 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/ui/collection_editor/properties/StoragePropertyField.tsx +35 -1
- package/src/collection_editor/ui/collection_editor/templates/blog_template.ts +1 -1
- package/src/collection_editor/ui/collection_editor/utils/supported_fields.tsx +0 -1
- package/src/collection_editor/ui/collection_editor/utils/update_property_for_widget.ts +7 -29
- 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 +14 -4
- package/src/components/DrawerNavigationGroup.tsx +2 -2
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +11 -9
- package/src/components/EntityCollectionTable/fields/TableMultipleRelationField.tsx +2 -1
- package/src/components/EntityCollectionTable/fields/TableRelationField.tsx +2 -1
- package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +23 -20
- package/src/components/EntityCollectionTable/index.tsx +1 -1
- package/src/components/EntityCollectionTable/table_bindings.tsx +24 -44
- package/src/components/EntityCollectionView/EntityBoardCard.tsx +6 -6
- package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +13 -12
- package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +40 -190
- package/src/components/EntityCollectionView/EntityCollectionListView.tsx +66 -184
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +8 -25
- package/src/components/EntityCollectionView/hooks/useCollectionInlineEditor.ts +1 -1
- package/src/components/EntityCollectionView/hooks/useKanbanDragAndDrop.ts +6 -6
- package/src/components/EntityCollectionView/useBoardDataController.tsx +12 -40
- package/src/components/EntityCollectionView/useEntityPreviewSlots.ts +3 -3
- package/src/components/EntityDetailView.tsx +2 -2
- package/src/components/EntityEditView.tsx +7 -6
- package/src/components/EntityEditViewFormActions.tsx +35 -29
- package/src/components/HomePage/ContentHomePage.tsx +14 -5
- package/src/components/RebaseCMS.tsx +3 -3
- package/src/components/RebaseNavigation.tsx +74 -9
- package/src/components/RelationSelector.tsx +2 -2
- package/src/components/SelectableTable/SelectableTable.tsx +13 -5
- package/src/components/SelectableTable/SelectionStore.ts +18 -48
- package/src/components/SideDialogs.tsx +0 -7
- package/src/components/common/default_entity_actions.tsx +22 -11
- package/src/components/field_configs.tsx +0 -14
- package/src/contexts/BreacrumbsContext.tsx +15 -6
- package/src/editor/editor.tsx +4 -7
- package/src/editor/selectors/ai-selector.tsx +0 -1
- package/src/form/EntityForm.tsx +191 -428
- package/src/form/EntityFormActions.tsx +35 -49
- package/src/form/EntityFormBinding.tsx +323 -0
- package/src/form/components/FormLayout.tsx +1 -1
- package/src/form/components/StorageUploadProgress.tsx +9 -2
- package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +12 -1
- package/src/form/field_bindings/MultipleRelationFieldBinding.tsx +4 -4
- package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +7 -2
- package/src/form/field_bindings/RelationFieldBinding.tsx +5 -7
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +19 -15
- package/src/form/form_utils.ts +163 -0
- package/src/form/index.tsx +14 -6
- 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 +6 -1
- package/src/preview/PropertyPreview.tsx +1 -16
- package/src/preview/components/StorageThumbnail.tsx +24 -7
- 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/components/PropertyPreviewProps.tsx +1 -1
- package/src/types/fields.tsx +9 -8
- package/src/util/dataControllerAdapter.ts +93 -0
- package/src/util/navigation_utils.ts +1 -1
- package/src/util/previews.ts +20 -0
- package/src/util/propertyConfigMapper.ts +134 -0
- package/src/util/property_utils.tsx +1 -2
- 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/EntityCollectionTable/fields/VirtualTableDateField.d.ts +0 -12
- package/dist/components/EntityCollectionTable/fields/VirtualTableInput.d.ts +0 -10
- package/dist/components/EntityCollectionTable/fields/VirtualTableNumberInput.d.ts +0 -9
- package/dist/components/EntityCollectionTable/fields/VirtualTableSwitch.d.ts +0 -8
- 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/form/field_bindings/ReferenceAsStringFieldBinding.d.ts +0 -11
- 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/EntityCollectionTable/fields/VirtualTableDateField.tsx +0 -39
- package/src/components/EntityCollectionTable/fields/VirtualTableInput.tsx +0 -90
- package/src/components/EntityCollectionTable/fields/VirtualTableNumberInput.tsx +0 -83
- package/src/components/EntityCollectionTable/fields/VirtualTableSwitch.tsx +0 -32
- 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/form/field_bindings/ReferenceAsStringFieldBinding.tsx +0 -141
- 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" ||
|
|
@@ -454,13 +505,6 @@ function PropertyEditFormFields({
|
|
|
454
505
|
existing={existing}
|
|
455
506
|
multiple={false}
|
|
456
507
|
disabled={disabled}/>;
|
|
457
|
-
} else if (selectedFieldConfigId === "reference_as_string") {
|
|
458
|
-
childComponent =
|
|
459
|
-
<ReferencePropertyField showErrors={showErrors}
|
|
460
|
-
existing={existing}
|
|
461
|
-
asString={true}
|
|
462
|
-
multiple={false}
|
|
463
|
-
disabled={disabled}/>;
|
|
464
508
|
} else if (selectedFieldConfigId === "date_time") {
|
|
465
509
|
childComponent = <DateTimePropertyField disabled={disabled}/>;
|
|
466
510
|
} else if (selectedFieldConfigId === "multi_references") {
|
|
@@ -520,7 +564,10 @@ function PropertyEditFormFields({
|
|
|
520
564
|
showError={Boolean(selectedWidgetError)}
|
|
521
565
|
existing={existing}
|
|
522
566
|
propertyConfigs={propertyConfigs}
|
|
523
|
-
inArray={inArray}
|
|
567
|
+
inArray={inArray}
|
|
568
|
+
propertyTypePresets={propertyTypePresets}
|
|
569
|
+
hiddenPropertyTypes={hiddenPropertyTypes}
|
|
570
|
+
onPresetSelected={onPresetSelected}/>
|
|
524
571
|
|
|
525
572
|
{!!selectedWidgetError &&
|
|
526
573
|
<Typography variant="caption"
|
|
@@ -553,6 +600,23 @@ function PropertyEditFormFields({
|
|
|
553
600
|
|
|
554
601
|
{childComponent}
|
|
555
602
|
|
|
603
|
+
{renderExtraPropertyFields && collectionValues && (
|
|
604
|
+
<div className="col-span-12 mt-4 px-2">
|
|
605
|
+
{renderExtraPropertyFields({
|
|
606
|
+
metadata: ((values as unknown as Record<string, unknown>).metadata as Record<string, unknown>) ?? {},
|
|
607
|
+
onMetadataChange: (key: string, value: unknown) => {
|
|
608
|
+
const currentMetadata = ((values as unknown as Record<string, unknown>).metadata as Record<string, unknown>) ?? {};
|
|
609
|
+
setValues({
|
|
610
|
+
...values,
|
|
611
|
+
metadata: { ...currentMetadata, [key]: value },
|
|
612
|
+
} as PropertyWithId);
|
|
613
|
+
},
|
|
614
|
+
property: toSerializableProperty(values as Property),
|
|
615
|
+
collection: toSerializableCollection(collectionValues),
|
|
616
|
+
})}
|
|
617
|
+
</div>
|
|
618
|
+
)}
|
|
619
|
+
|
|
556
620
|
<div className={"col-span-12"}>
|
|
557
621
|
<AdvancedPropertyValidation disabled={disabled}/>
|
|
558
622
|
</div>
|
|
@@ -615,7 +679,6 @@ const WIDGET_TYPE_MAP: Record<PropertyConfigId, string> = {
|
|
|
615
679
|
multi_file_upload: "File",
|
|
616
680
|
relation: "Relation",
|
|
617
681
|
reference: "Reference",
|
|
618
|
-
reference_as_string: "Text",
|
|
619
682
|
multi_references: "Reference",
|
|
620
683
|
date_time: "Date",
|
|
621
684
|
group: "Group",
|
|
@@ -626,6 +689,33 @@ const WIDGET_TYPE_MAP: Record<PropertyConfigId, string> = {
|
|
|
626
689
|
vector_input: "Number"
|
|
627
690
|
};
|
|
628
691
|
|
|
692
|
+
const WIDGET_BASE_TYPE_MAP: Record<string, PropertyType> = {
|
|
693
|
+
text_field: "string",
|
|
694
|
+
multiline: "string",
|
|
695
|
+
markdown: "string",
|
|
696
|
+
url: "string",
|
|
697
|
+
email: "string",
|
|
698
|
+
select: "string",
|
|
699
|
+
multi_select: "string",
|
|
700
|
+
file_upload: "string",
|
|
701
|
+
multi_file_upload: "string",
|
|
702
|
+
user_select: "string",
|
|
703
|
+
number_input: "number",
|
|
704
|
+
number_select: "number",
|
|
705
|
+
multi_number_select: "number",
|
|
706
|
+
switch: "boolean",
|
|
707
|
+
date_time: "date",
|
|
708
|
+
reference: "reference",
|
|
709
|
+
multi_references: "reference",
|
|
710
|
+
relation: "relation",
|
|
711
|
+
group: "map",
|
|
712
|
+
key_value: "map",
|
|
713
|
+
block: "map",
|
|
714
|
+
repeat: "array",
|
|
715
|
+
custom_array: "array",
|
|
716
|
+
vector_input: "vector",
|
|
717
|
+
};
|
|
718
|
+
|
|
629
719
|
function WidgetSelectView({
|
|
630
720
|
initialProperty,
|
|
631
721
|
value,
|
|
@@ -636,7 +726,10 @@ function WidgetSelectView({
|
|
|
636
726
|
showError,
|
|
637
727
|
existing,
|
|
638
728
|
propertyConfigs,
|
|
639
|
-
inArray
|
|
729
|
+
inArray,
|
|
730
|
+
propertyTypePresets,
|
|
731
|
+
hiddenPropertyTypes,
|
|
732
|
+
onPresetSelected
|
|
640
733
|
}: {
|
|
641
734
|
initialProperty?: PropertyWithId,
|
|
642
735
|
value?: PropertyConfigId,
|
|
@@ -647,14 +740,24 @@ function WidgetSelectView({
|
|
|
647
740
|
disabled: boolean,
|
|
648
741
|
existing: boolean,
|
|
649
742
|
propertyConfigs: Record<string, PropertyConfig>,
|
|
650
|
-
inArray?: boolean
|
|
743
|
+
inArray?: boolean,
|
|
744
|
+
propertyTypePresets?: PropertyTypePreset[],
|
|
745
|
+
hiddenPropertyTypes?: PropertyType[],
|
|
746
|
+
onPresetSelected?: (preset: PropertyTypePreset) => void,
|
|
651
747
|
}) {
|
|
652
748
|
|
|
653
749
|
const allSupportedFields = Object.entries(supportedFields).concat(Object.entries(propertyConfigs));
|
|
654
750
|
|
|
751
|
+
const filteredFields = hiddenPropertyTypes && !propertyTypePresets
|
|
752
|
+
? allSupportedFields.filter(([key]) => {
|
|
753
|
+
const baseType = WIDGET_BASE_TYPE_MAP[key];
|
|
754
|
+
return !baseType || !hiddenPropertyTypes.includes(baseType);
|
|
755
|
+
})
|
|
756
|
+
: allSupportedFields;
|
|
757
|
+
|
|
655
758
|
const displayedWidgets = (inArray
|
|
656
|
-
?
|
|
657
|
-
:
|
|
759
|
+
? filteredFields.filter(([_, propertyConfig]) => !isPropertyBuilder(propertyConfig.property as Property) && (propertyConfig.property as Property)?.type !== "array")
|
|
760
|
+
: filteredFields)
|
|
658
761
|
.map(([key, propertyConfig]) => ({
|
|
659
762
|
[key]: propertyConfig
|
|
660
763
|
}))
|
|
@@ -665,6 +768,11 @@ function WidgetSelectView({
|
|
|
665
768
|
}
|
|
666
769
|
}, {});
|
|
667
770
|
|
|
771
|
+
const activePreset = useMemo(() => {
|
|
772
|
+
if (!propertyTypePresets || !initialProperty) return undefined;
|
|
773
|
+
return propertyTypePresets.find(p => p.detect?.(toSerializableProperty(initialProperty as Property)));
|
|
774
|
+
}, [propertyTypePresets, initialProperty]);
|
|
775
|
+
|
|
668
776
|
const key = value;
|
|
669
777
|
const propertyConfig = key ? (DEFAULT_FIELD_CONFIGS[key] ?? propertyConfigs[key]) : undefined;
|
|
670
778
|
const baseProperty = propertyConfig?.property;
|
|
@@ -711,9 +819,36 @@ function WidgetSelectView({
|
|
|
711
819
|
onOpenChange={(open: boolean) => onOpenChange(open, Boolean(value))}
|
|
712
820
|
maxWidth={"4xl"}>
|
|
713
821
|
<DialogTitle>
|
|
714
|
-
Select a property widget
|
|
822
|
+
{propertyTypePresets ? "Select a property type" : "Select a property widget"}
|
|
715
823
|
</DialogTitle>
|
|
716
824
|
<DialogContent>
|
|
825
|
+
{propertyTypePresets ? (
|
|
826
|
+
<div className={"grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-2 mt-4"}>
|
|
827
|
+
{propertyTypePresets.map((preset) => (
|
|
828
|
+
<Card
|
|
829
|
+
key={preset.id}
|
|
830
|
+
onClick={() => {
|
|
831
|
+
onPresetSelected?.(preset);
|
|
832
|
+
onOpenChange(false, true);
|
|
833
|
+
}}
|
|
834
|
+
className={cls(
|
|
835
|
+
"flex flex-row items-center px-4 py-2 m-1",
|
|
836
|
+
activePreset?.id === preset.id && "ring-2 ring-primary"
|
|
837
|
+
)}>
|
|
838
|
+
<div className={cls("flex flex-row items-center text-base min-h-[48px]")}>
|
|
839
|
+
{preset.icon && (
|
|
840
|
+
<div className={"mr-4 text-2xl"}>
|
|
841
|
+
{typeof preset.icon === "string" ? preset.icon : preset.icon}
|
|
842
|
+
</div>
|
|
843
|
+
)}
|
|
844
|
+
<div>
|
|
845
|
+
<Typography variant={"label"}>{preset.label}</Typography>
|
|
846
|
+
</div>
|
|
847
|
+
</div>
|
|
848
|
+
</Card>
|
|
849
|
+
))}
|
|
850
|
+
</div>
|
|
851
|
+
) : (
|
|
717
852
|
<div>
|
|
718
853
|
{groups.map(group => {
|
|
719
854
|
return <div key={group} className={"mt-4"}>
|
|
@@ -749,6 +884,7 @@ function WidgetSelectView({
|
|
|
749
884
|
{/* existing={existing}/>;*/}
|
|
750
885
|
{/*})}*/}
|
|
751
886
|
</div>
|
|
887
|
+
)}
|
|
752
888
|
</DialogContent>
|
|
753
889
|
</Dialog>
|
|
754
890
|
</>;
|
|
@@ -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
|
})
|
|
@@ -13,7 +13,8 @@ import {
|
|
|
13
13
|
} from "@rebasepro/ui";
|
|
14
14
|
|
|
15
15
|
import { Field, FormexFieldProps, getIn, useFormex } from "@rebasepro/formex";
|
|
16
|
-
import { useTranslation } from "@rebasepro/core";
|
|
16
|
+
import { useStorageSources, useTranslation } from "@rebasepro/core";
|
|
17
|
+
import { DEFAULT_STORAGE_SOURCE_KEY } from "@rebasepro/types";
|
|
17
18
|
import { GeneralPropertyValidation } from "./validation/GeneralPropertyValidation";
|
|
18
19
|
import { ArrayPropertyValidation } from "./validation/ArrayPropertyValidation";
|
|
19
20
|
import { ValidationPanel } from "./validation/ValidationPanel";
|
|
@@ -42,9 +43,11 @@ export function StoragePropertyField({
|
|
|
42
43
|
setFieldValue
|
|
43
44
|
} = useFormex();
|
|
44
45
|
const { t } = useTranslation();
|
|
46
|
+
const storageSources = useStorageSources();
|
|
45
47
|
|
|
46
48
|
const baseStoragePath = multiple ? "of.storage" : "storage";
|
|
47
49
|
const acceptedFiles = `${baseStoragePath}.acceptedFiles`;
|
|
50
|
+
const storageSource = `${baseStoragePath}.storageSource`;
|
|
48
51
|
|
|
49
52
|
const metadata = `${baseStoragePath}.metadata`;
|
|
50
53
|
const fileName = `${baseStoragePath}.fileName`;
|
|
@@ -76,6 +79,11 @@ export function StoragePropertyField({
|
|
|
76
79
|
const fileTypesValue: string[] | undefined = Array.isArray(storedValue) ? storedValue : undefined;
|
|
77
80
|
const allFileTypesSelected = !fileTypesValue || fileTypesValue.length === 0;
|
|
78
81
|
|
|
82
|
+
// Available storage backends (from `<Rebase storageSources={...}>`).
|
|
83
|
+
const sourceKeys = Object.keys(storageSources.sources)
|
|
84
|
+
.filter((key) => key !== DEFAULT_STORAGE_SOURCE_KEY);
|
|
85
|
+
const storageSourceValue = (getIn(values, storageSource) as string | undefined) ?? DEFAULT_STORAGE_SOURCE_KEY;
|
|
86
|
+
|
|
79
87
|
const handleTypesChange = (value: string[]) => {
|
|
80
88
|
if (!value) setFieldValue(acceptedFiles, undefined);
|
|
81
89
|
else setFieldValue(acceptedFiles, value);
|
|
@@ -102,6 +110,32 @@ export function StoragePropertyField({
|
|
|
102
110
|
|
|
103
111
|
<div className={"grid grid-cols-12 gap-2 p-4"}>
|
|
104
112
|
|
|
113
|
+
{sourceKeys.length > 0 && (
|
|
114
|
+
<div className={"col-span-12"}>
|
|
115
|
+
<Select
|
|
116
|
+
className={"w-full"}
|
|
117
|
+
disabled={disabled}
|
|
118
|
+
name={storageSource}
|
|
119
|
+
value={storageSourceValue}
|
|
120
|
+
onValueChange={(value) =>
|
|
121
|
+
setFieldValue(storageSource, !value || value === DEFAULT_STORAGE_SOURCE_KEY ? undefined : value)}
|
|
122
|
+
label={"Storage backend"}
|
|
123
|
+
renderValue={(key) => {
|
|
124
|
+
const label = storageSources.registry[key]?.label;
|
|
125
|
+
return label ?? (key === DEFAULT_STORAGE_SOURCE_KEY ? "Default" : key);
|
|
126
|
+
}}>
|
|
127
|
+
<SelectItem value={DEFAULT_STORAGE_SOURCE_KEY}>
|
|
128
|
+
Default
|
|
129
|
+
</SelectItem>
|
|
130
|
+
{sourceKeys.map((key) => (
|
|
131
|
+
<SelectItem key={key} value={key}>
|
|
132
|
+
{storageSources.registry[key]?.label ?? key}
|
|
133
|
+
</SelectItem>
|
|
134
|
+
))}
|
|
135
|
+
</Select>
|
|
136
|
+
</div>
|
|
137
|
+
)}
|
|
138
|
+
|
|
105
139
|
<div className={"col-span-12"}>
|
|
106
140
|
|
|
107
141
|
<MultiSelect
|