@firecms/collection_editor 3.0.0-canary.21 → 3.0.0-canary.211
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/LICENSE +114 -21
- package/dist/ConfigControllerProvider.d.ts +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +10060 -4770
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +10750 -3
- package/dist/index.umd.js.map +1 -1
- package/dist/types/collection_editor_controller.d.ts +4 -2
- package/dist/types/collection_inference.d.ts +1 -1
- package/dist/types/config_permissions.d.ts +2 -2
- package/dist/types/persisted_collection.d.ts +1 -1
- package/dist/ui/CollectionViewHeaderAction.d.ts +3 -2
- package/dist/ui/EditorCollectionActionStart.d.ts +2 -0
- package/dist/ui/PropertyAddColumnComponent.d.ts +3 -1
- package/dist/ui/collection_editor/CollectionDetailsForm.d.ts +3 -1
- package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +3 -2
- package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +1 -1
- package/dist/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +1 -1
- package/dist/ui/collection_editor/LayoutModeSwitch.d.ts +5 -0
- package/dist/ui/collection_editor/PropertyEditView.d.ts +8 -0
- package/dist/ui/collection_editor/PropertyTree.d.ts +9 -9
- package/dist/ui/collection_editor/SubcollectionsEditTab.d.ts +1 -1
- package/dist/ui/collection_editor/import/CollectionEditorImportMapping.d.ts +7 -0
- package/dist/ui/collection_editor/properties/MarkdownPropertyField.d.ts +4 -0
- package/dist/ui/collection_editor/properties/StringPropertyField.d.ts +1 -1
- package/dist/useCollectionEditorPlugin.d.ts +8 -11
- package/dist/utils/collections.d.ts +6 -0
- package/package.json +24 -35
- package/src/ConfigControllerProvider.tsx +67 -64
- package/src/index.ts +1 -0
- package/src/types/collection_editor_controller.tsx +7 -4
- package/src/types/collection_inference.ts +1 -1
- package/src/types/config_permissions.ts +1 -1
- package/src/types/persisted_collection.ts +2 -3
- package/src/ui/CollectionViewHeaderAction.tsx +10 -5
- package/src/ui/EditorCollectionAction.tsx +10 -63
- package/src/ui/EditorCollectionActionStart.tsx +88 -0
- package/src/ui/HomePageEditorCollectionAction.tsx +19 -13
- package/src/ui/NewCollectionButton.tsx +1 -1
- package/src/ui/NewCollectionCard.tsx +3 -3
- package/src/ui/PropertyAddColumnComponent.tsx +11 -6
- package/src/ui/collection_editor/CollectionDetailsForm.tsx +89 -12
- package/src/ui/collection_editor/CollectionEditorDialog.tsx +101 -34
- package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +8 -7
- package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +37 -36
- package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +6 -5
- package/src/ui/collection_editor/EnumForm.tsx +10 -6
- package/src/ui/collection_editor/GetCodeDialog.tsx +56 -26
- package/src/ui/collection_editor/LayoutModeSwitch.tsx +54 -0
- package/src/ui/collection_editor/PropertyEditView.tsx +257 -79
- package/src/ui/collection_editor/PropertyFieldPreview.tsx +7 -10
- package/src/ui/collection_editor/PropertyTree.tsx +9 -7
- package/src/ui/collection_editor/SubcollectionsEditTab.tsx +26 -19
- package/src/ui/collection_editor/UnsavedChangesDialog.tsx +3 -5
- package/src/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +26 -9
- package/src/ui/collection_editor/import/CollectionEditorImportMapping.tsx +42 -9
- package/src/ui/collection_editor/properties/BlockPropertyField.tsx +32 -20
- package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +54 -47
- package/src/ui/collection_editor/properties/EnumPropertyField.tsx +3 -1
- package/src/ui/collection_editor/properties/MapPropertyField.tsx +7 -6
- package/src/ui/collection_editor/properties/MarkdownPropertyField.tsx +139 -0
- package/src/ui/collection_editor/properties/ReferencePropertyField.tsx +2 -0
- package/src/ui/collection_editor/properties/RepeatPropertyField.tsx +0 -1
- package/src/ui/collection_editor/properties/StoragePropertyField.tsx +34 -19
- package/src/ui/collection_editor/properties/StringPropertyField.tsx +1 -10
- package/src/ui/collection_editor/properties/UrlPropertyField.tsx +1 -0
- package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +2 -2
- package/src/ui/collection_editor/templates/pages_template.ts +1 -6
- package/src/useCollectionEditorPlugin.tsx +33 -32
- package/src/utils/collections.ts +36 -0
- package/dist/ui/RootCollectionSuggestions.d.ts +0 -3
- package/dist/ui/collection_editor/PropertySelectItem.d.ts +0 -8
- package/src/ui/RootCollectionSuggestions.tsx +0 -63
- package/src/ui/collection_editor/PropertySelectItem.tsx +0 -32
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useEffect, useMemo, useState } from "react";
|
|
2
2
|
|
|
3
3
|
import { Field, getIn, useFormex } from "@firecms/formex";
|
|
4
4
|
import {
|
|
@@ -16,10 +16,10 @@ import {
|
|
|
16
16
|
} from "@firecms/core";
|
|
17
17
|
import {
|
|
18
18
|
AddIcon,
|
|
19
|
-
|
|
19
|
+
AutorenewIcon,
|
|
20
20
|
Button,
|
|
21
21
|
CircularProgress,
|
|
22
|
-
|
|
22
|
+
cls,
|
|
23
23
|
CodeIcon,
|
|
24
24
|
DebouncedTextField,
|
|
25
25
|
defaultBorderMixin,
|
|
@@ -43,7 +43,7 @@ type CollectionEditorFormProps = {
|
|
|
43
43
|
setDirty?: (dirty: boolean) => void;
|
|
44
44
|
reservedGroups?: string[];
|
|
45
45
|
extraIcon: React.ReactNode;
|
|
46
|
-
getUser
|
|
46
|
+
getUser?: (uid: string) => User | null;
|
|
47
47
|
getData?: () => Promise<object[]>;
|
|
48
48
|
doCollectionInference: (collection: PersistedCollection) => Promise<Partial<EntityCollection> | null> | undefined;
|
|
49
49
|
propertyConfigs: Record<string, PropertyConfig>;
|
|
@@ -158,20 +158,20 @@ export function CollectionPropertiesEditorForm({
|
|
|
158
158
|
}
|
|
159
159
|
: undefined;
|
|
160
160
|
|
|
161
|
-
const getCurrentPropertiesOrder =
|
|
162
|
-
if (!namespace) return currentPropertiesOrderRef.current[""];
|
|
161
|
+
const getCurrentPropertiesOrder = (namespace?: string) => {
|
|
162
|
+
if (!namespace) return currentPropertiesOrderRef.current[""] ?? getIn(values, namespaceToPropertiesOrderPath());
|
|
163
163
|
return currentPropertiesOrderRef.current[namespace] ?? getIn(values, namespaceToPropertiesOrderPath(namespace));
|
|
164
|
-
}
|
|
164
|
+
};
|
|
165
165
|
|
|
166
|
-
const updatePropertiesOrder =
|
|
166
|
+
const updatePropertiesOrder = (newPropertiesOrder: string[], namespace?: string) => {
|
|
167
167
|
const propertiesOrderPath = namespaceToPropertiesOrderPath(namespace);
|
|
168
168
|
|
|
169
169
|
setFieldValue(propertiesOrderPath, newPropertiesOrder, false);
|
|
170
170
|
currentPropertiesOrderRef.current[namespace ?? ""] = newPropertiesOrder;
|
|
171
171
|
|
|
172
|
-
}
|
|
172
|
+
};
|
|
173
173
|
|
|
174
|
-
const deleteProperty =
|
|
174
|
+
const deleteProperty = (propertyKey?: string, namespace?: string) => {
|
|
175
175
|
const fullId = propertyKey ? getFullId(propertyKey, namespace) : undefined;
|
|
176
176
|
if (!fullId)
|
|
177
177
|
throw Error("collection editor miss config");
|
|
@@ -179,15 +179,17 @@ export function CollectionPropertiesEditorForm({
|
|
|
179
179
|
setFieldValue(idToPropertiesPath(fullId), undefined, false);
|
|
180
180
|
|
|
181
181
|
const currentPropertiesOrder = getCurrentPropertiesOrder(namespace);
|
|
182
|
-
|
|
183
|
-
|
|
182
|
+
if (currentPropertiesOrder) {
|
|
183
|
+
const newPropertiesOrder = currentPropertiesOrder.filter((p) => p !== propertyKey);
|
|
184
|
+
updatePropertiesOrder(newPropertiesOrder, namespace);
|
|
185
|
+
}
|
|
184
186
|
|
|
185
187
|
setNewPropertyDialogOpen(false);
|
|
186
188
|
|
|
187
189
|
setSelectedPropertyIndex(undefined);
|
|
188
190
|
setSelectedPropertyKey(undefined);
|
|
189
191
|
setSelectedPropertyNamespace(undefined);
|
|
190
|
-
}
|
|
192
|
+
};
|
|
191
193
|
|
|
192
194
|
const onPropertyMove = (propertiesOrder: string[], namespace?: string) => {
|
|
193
195
|
setFieldValue(namespaceToPropertiesOrderPath(namespace), propertiesOrder, false);
|
|
@@ -207,8 +209,8 @@ export function CollectionPropertiesEditorForm({
|
|
|
207
209
|
...(values.properties ?? {}),
|
|
208
210
|
[id]: property
|
|
209
211
|
}, false);
|
|
210
|
-
const newPropertiesOrder = [...(values.propertiesOrder ?? Object.keys(values.properties)), id];
|
|
211
212
|
|
|
213
|
+
const newPropertiesOrder = [...(values.propertiesOrder ?? Object.keys(values.properties)), id];
|
|
212
214
|
updatePropertiesOrder(newPropertiesOrder);
|
|
213
215
|
|
|
214
216
|
setNewPropertyDialogOpen(false);
|
|
@@ -231,12 +233,6 @@ export function CollectionPropertiesEditorForm({
|
|
|
231
233
|
|
|
232
234
|
// If the id has changed we need to a little cleanup
|
|
233
235
|
if (previousId && previousId !== id) {
|
|
234
|
-
console.debug("onPropertyChanged, id change", {
|
|
235
|
-
id,
|
|
236
|
-
property,
|
|
237
|
-
previousId,
|
|
238
|
-
namespace
|
|
239
|
-
})
|
|
240
236
|
|
|
241
237
|
const previousFullId = getFullId(previousId, namespace);
|
|
242
238
|
const previousPropertyPath = idToPropertiesPath(previousFullId);
|
|
@@ -273,7 +269,7 @@ export function CollectionPropertiesEditorForm({
|
|
|
273
269
|
|
|
274
270
|
};
|
|
275
271
|
|
|
276
|
-
const onPropertyErrorInternal =
|
|
272
|
+
const onPropertyErrorInternal = (id: string, namespace?: string, error?: Record<string, any>) => {
|
|
277
273
|
const propertyPath = id ? getFullId(id, namespace) : undefined;
|
|
278
274
|
console.debug("onPropertyErrorInternal", {
|
|
279
275
|
id,
|
|
@@ -286,7 +282,7 @@ export function CollectionPropertiesEditorForm({
|
|
|
286
282
|
onPropertyError(id, namespace, hasError ? error : undefined);
|
|
287
283
|
setFieldError(idToPropertiesPath(propertyPath), hasError ? "Property error" : undefined);
|
|
288
284
|
}
|
|
289
|
-
}
|
|
285
|
+
}
|
|
290
286
|
|
|
291
287
|
const closePropertyDialog = () => {
|
|
292
288
|
setSelectedPropertyIndex(undefined);
|
|
@@ -301,9 +297,9 @@ export function CollectionPropertiesEditorForm({
|
|
|
301
297
|
? values.propertiesOrder
|
|
302
298
|
: Object.keys(values.properties)) as string[];
|
|
303
299
|
|
|
304
|
-
const owner = useMemo(() => values.ownerId ? getUser(values.ownerId) : null, [getUser, values.ownerId]);
|
|
300
|
+
const owner = useMemo(() => values.ownerId && getUser ? getUser(values.ownerId) : null, [getUser, values.ownerId]);
|
|
305
301
|
|
|
306
|
-
const onPropertyClick =
|
|
302
|
+
const onPropertyClick = (propertyKey: string, namespace?: string) => {
|
|
307
303
|
console.debug("CollectionEditor: onPropertyClick", {
|
|
308
304
|
propertyKey,
|
|
309
305
|
namespace
|
|
@@ -311,11 +307,11 @@ export function CollectionPropertiesEditorForm({
|
|
|
311
307
|
setSelectedPropertyIndex(usedPropertiesOrder.indexOf(propertyKey));
|
|
312
308
|
setSelectedPropertyKey(propertyKey);
|
|
313
309
|
setSelectedPropertyNamespace(namespace);
|
|
314
|
-
}
|
|
310
|
+
};
|
|
315
311
|
|
|
316
312
|
const body = (
|
|
317
|
-
<div className={"grid grid-cols-12 gap-2 h-full bg-
|
|
318
|
-
<div className={
|
|
313
|
+
<div className={"grid grid-cols-12 gap-2 h-full bg-surface-50 dark:bg-surface-900"}>
|
|
314
|
+
<div className={cls(
|
|
319
315
|
"p-4 md:p-8 pb-20 md:pb-20",
|
|
320
316
|
"col-span-12 lg:col-span-5 h-full overflow-auto",
|
|
321
317
|
!asDialog && "border-r " + defaultBorderMixin
|
|
@@ -349,7 +345,8 @@ export function CollectionPropertiesEditorForm({
|
|
|
349
345
|
</div>}
|
|
350
346
|
|
|
351
347
|
<div className="ml-1 mt-2 flex flex-row gap-2">
|
|
352
|
-
<Tooltip title={"Get the code for this collection"}
|
|
348
|
+
<Tooltip title={"Get the code for this collection"}
|
|
349
|
+
asChild={true}>
|
|
353
350
|
<IconButton
|
|
354
351
|
variant={"filled"}
|
|
355
352
|
disabled={inferringProperties}
|
|
@@ -357,15 +354,17 @@ export function CollectionPropertiesEditorForm({
|
|
|
357
354
|
<CodeIcon/>
|
|
358
355
|
</IconButton>
|
|
359
356
|
</Tooltip>
|
|
360
|
-
{inferPropertiesFromData && <Tooltip title={"Add new properties based on data"}
|
|
357
|
+
{inferPropertiesFromData && <Tooltip title={"Add new properties based on data"}
|
|
358
|
+
asChild={true}>
|
|
361
359
|
<IconButton
|
|
362
360
|
variant={"filled"}
|
|
363
361
|
disabled={inferringProperties}
|
|
364
362
|
onClick={inferPropertiesFromData}>
|
|
365
|
-
{inferringProperties ? <CircularProgress size={"small"}/> : <
|
|
363
|
+
{inferringProperties ? <CircularProgress size={"small"}/> : <AutorenewIcon/>}
|
|
366
364
|
</IconButton>
|
|
367
365
|
</Tooltip>}
|
|
368
|
-
<Tooltip title={"Add new property"}
|
|
366
|
+
<Tooltip title={"Add new property"}
|
|
367
|
+
asChild={true}>
|
|
369
368
|
<Button
|
|
370
369
|
variant={"outlined"}
|
|
371
370
|
onClick={() => setNewPropertyDialogOpen(true)}>
|
|
@@ -469,6 +468,7 @@ export function CollectionPropertiesEditorForm({
|
|
|
469
468
|
getData={getData}
|
|
470
469
|
propertyConfigs={propertyConfigs}
|
|
471
470
|
collectionEditable={collectionEditable}
|
|
471
|
+
onCancel={closePropertyDialog}
|
|
472
472
|
onOkClicked={asDialog
|
|
473
473
|
? closePropertyDialog
|
|
474
474
|
: undefined
|
|
@@ -496,11 +496,12 @@ export function CollectionPropertiesEditorForm({
|
|
|
496
496
|
collectionEditable={collectionEditable}
|
|
497
497
|
existingPropertyKeys={values.propertiesOrder as string[]}/>
|
|
498
498
|
|
|
499
|
-
<
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
499
|
+
<ErrorBoundary>
|
|
500
|
+
<GetCodeDialog
|
|
501
|
+
collection={values}
|
|
502
|
+
open={codeDialogOpen}
|
|
503
|
+
onOpenChange={setCodeDialogOpen}/>
|
|
504
|
+
</ErrorBoundary>
|
|
504
505
|
</>
|
|
505
506
|
);
|
|
506
507
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { useCustomizationController } from "@firecms/core";
|
|
2
|
-
import { Button, Dialog, DialogActions, DialogContent, Typography } from "@firecms/ui";
|
|
2
|
+
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Typography } from "@firecms/ui";
|
|
3
3
|
import React from "react";
|
|
4
4
|
|
|
5
|
-
export function EntityCustomViewsSelectDialog({
|
|
5
|
+
export function EntityCustomViewsSelectDialog({
|
|
6
|
+
open,
|
|
7
|
+
onClose
|
|
8
|
+
}: { open: boolean, onClose: (selectedViewKey?: string) => void }) {
|
|
6
9
|
const {
|
|
7
10
|
entityViews,
|
|
8
11
|
} = useCustomizationController();
|
|
@@ -10,10 +13,8 @@ export function EntityCustomViewsSelectDialog({ open, onClose }: { open: boolean
|
|
|
10
13
|
return <Dialog
|
|
11
14
|
maxWidth={"md"}
|
|
12
15
|
open={open}>
|
|
16
|
+
<DialogTitle>Select custom view</DialogTitle>
|
|
13
17
|
<DialogContent className={"flex flex-col gap-4"}>
|
|
14
|
-
<Typography variant={"h6"}>
|
|
15
|
-
Select view
|
|
16
|
-
</Typography>
|
|
17
18
|
{entityViews?.map((view) => {
|
|
18
19
|
return <Button
|
|
19
20
|
key={view.key}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React, { useEffect } from "react";
|
|
2
2
|
import equal from "react-fast-compare"
|
|
3
3
|
|
|
4
|
-
import { ArrayContainer, EnumValueConfig, EnumValues, FieldCaption, } from "@firecms/core";
|
|
4
|
+
import { ArrayContainer, ArrayEntryParams, EnumValueConfig, EnumValues, FieldCaption, } from "@firecms/core";
|
|
5
5
|
import {
|
|
6
|
-
|
|
6
|
+
AutorenewIcon,
|
|
7
7
|
Badge,
|
|
8
8
|
Button,
|
|
9
9
|
CircularProgress,
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
Dialog,
|
|
12
12
|
DialogActions,
|
|
13
13
|
DialogContent,
|
|
14
|
+
DialogTitle,
|
|
14
15
|
IconButton,
|
|
15
16
|
ListIcon,
|
|
16
17
|
Paper,
|
|
@@ -121,7 +122,10 @@ function EnumFormFields({
|
|
|
121
122
|
const inferredValuesRef = React.useRef(new Set());
|
|
122
123
|
const inferredValues = inferredValuesRef.current;
|
|
123
124
|
|
|
124
|
-
const buildEntry = (
|
|
125
|
+
const buildEntry = ({
|
|
126
|
+
index,
|
|
127
|
+
internalId
|
|
128
|
+
}:ArrayEntryParams) => {
|
|
125
129
|
const justAdded = lastInternalIdAdded === internalId;
|
|
126
130
|
const entryError = errors?.enumValues && errors?.enumValues[index];
|
|
127
131
|
return <EnumEntry index={index}
|
|
@@ -179,7 +183,7 @@ function EnumFormFields({
|
|
|
179
183
|
variant={"text"}
|
|
180
184
|
size={"small"}
|
|
181
185
|
onClick={inferValues}>
|
|
182
|
-
{inferring ? <CircularProgress size={"
|
|
186
|
+
{inferring ? <CircularProgress size={"smallest"}/> : <AutorenewIcon/>}
|
|
183
187
|
Infer values from data
|
|
184
188
|
</Button>}
|
|
185
189
|
</div>
|
|
@@ -263,7 +267,7 @@ const EnumEntry = React.memo(
|
|
|
263
267
|
size="small"
|
|
264
268
|
autoFocus={autoFocus}
|
|
265
269
|
autoComplete="off"
|
|
266
|
-
endAdornment={inferredEntry && <
|
|
270
|
+
endAdornment={inferredEntry && <AutorenewIcon size={"small"}/>}
|
|
267
271
|
error={Boolean(entryError?.label)}/>
|
|
268
272
|
|
|
269
273
|
{!disabled &&
|
|
@@ -324,7 +328,7 @@ function EnumEntryDialog({
|
|
|
324
328
|
open={open}
|
|
325
329
|
onOpenChange={(open) => !open ? onClose() : undefined}
|
|
326
330
|
>
|
|
327
|
-
|
|
331
|
+
<DialogTitle hidden>Enum form dialog</DialogTitle>
|
|
328
332
|
<DialogContent>
|
|
329
333
|
{index !== undefined &&
|
|
330
334
|
<div>
|
|
@@ -1,35 +1,47 @@
|
|
|
1
|
-
import { EntityCollection, useSnackbarController } from "@firecms/core";
|
|
2
|
-
import { Button, ContentCopyIcon, Dialog, DialogActions, DialogContent, Typography, } from "@firecms/ui";
|
|
1
|
+
import { EntityCollection, isEmptyObject, useSnackbarController } from "@firecms/core";
|
|
2
|
+
import { Button, ContentCopyIcon, Dialog, DialogActions, DialogContent, DialogTitle, Typography, } from "@firecms/ui";
|
|
3
3
|
import React from "react";
|
|
4
4
|
import JSON5 from "json5";
|
|
5
5
|
import { Highlight, themes } from "prism-react-renderer"
|
|
6
6
|
import { camelCase } from "./utils/strings";
|
|
7
|
+
import { clone } from "@firecms/formex";
|
|
7
8
|
|
|
8
|
-
export function GetCodeDialog({
|
|
9
|
+
export function GetCodeDialog({
|
|
10
|
+
collection,
|
|
11
|
+
onOpenChange,
|
|
12
|
+
open
|
|
13
|
+
}: { onOpenChange: (open: boolean) => void, collection: any, open: any }) {
|
|
9
14
|
|
|
10
15
|
const snackbarController = useSnackbarController();
|
|
11
16
|
|
|
12
|
-
const code =
|
|
17
|
+
const code = collection
|
|
18
|
+
? "import { EntityCollection } from \"@firecms/core\";\n\nconst " + (collection?.name ? camelCase(collection.name) : "my") + "Collection:EntityCollection = " + JSON5.stringify(collectionToCode({ ...collection }), null, "\t")
|
|
19
|
+
: "No collection selected";
|
|
13
20
|
return <Dialog open={open}
|
|
14
21
|
onOpenChange={onOpenChange}
|
|
15
22
|
maxWidth={"4xl"}>
|
|
23
|
+
<DialogTitle variant={"h6"}>Code for {collection.name}</DialogTitle>
|
|
16
24
|
<DialogContent>
|
|
17
|
-
|
|
18
|
-
Code for {collection.name}
|
|
19
|
-
</Typography>
|
|
25
|
+
|
|
20
26
|
<Typography variant={"body2"} className={"my-4 mb-8"}>
|
|
21
27
|
If you want to customise the collection in code, you can add this collection code to your CMS
|
|
22
28
|
app configuration.
|
|
23
29
|
More info in the <a
|
|
24
30
|
rel="noopener noreferrer"
|
|
25
|
-
href={"https://firecms.co/docs/
|
|
31
|
+
href={"https://firecms.co/docs/cloud/quickstart"}>docs</a>.
|
|
26
32
|
</Typography>
|
|
27
33
|
<Highlight
|
|
28
34
|
theme={themes.vsDark}
|
|
29
35
|
code={code}
|
|
30
36
|
language="typescript"
|
|
31
37
|
>
|
|
32
|
-
{({
|
|
38
|
+
{({
|
|
39
|
+
className,
|
|
40
|
+
style,
|
|
41
|
+
tokens,
|
|
42
|
+
getLineProps,
|
|
43
|
+
getTokenProps
|
|
44
|
+
}) => (
|
|
33
45
|
<pre style={style} className={"p-4 rounded text-sm"}>
|
|
34
46
|
{tokens.map((line, i) => (
|
|
35
47
|
<div key={i} {...getLineProps({ line })}>
|
|
@@ -66,24 +78,40 @@ export function GetCodeDialog({ collection, onOpenChange, open }: { onOpenChange
|
|
|
66
78
|
|
|
67
79
|
function collectionToCode(collection: EntityCollection): object {
|
|
68
80
|
|
|
69
|
-
const propertyCleanup = (
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
81
|
+
const propertyCleanup = (value: any): any => {
|
|
82
|
+
if (value === undefined || value === null) {
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
const valueCopy = clone(value);
|
|
86
|
+
if (typeof valueCopy === "function") {
|
|
87
|
+
return valueCopy;
|
|
88
|
+
}
|
|
89
|
+
if (Array.isArray(valueCopy)) {
|
|
90
|
+
return valueCopy.map((v: any) => propertyCleanup(v));
|
|
91
|
+
}
|
|
92
|
+
if (typeof valueCopy === "object") {
|
|
93
|
+
if (valueCopy === null)
|
|
94
|
+
return valueCopy;
|
|
95
|
+
Object.keys(valueCopy).forEach((key) => {
|
|
96
|
+
if (!isEmptyObject(valueCopy)) {
|
|
97
|
+
const childRes = propertyCleanup(valueCopy[key]);
|
|
98
|
+
if (childRes !== null && childRes !== undefined && childRes !== false && !isEmptyObject(childRes)) {
|
|
99
|
+
valueCopy[key] = childRes;
|
|
100
|
+
} else {
|
|
101
|
+
delete valueCopy[key];
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
delete valueCopy.fromBuilder;
|
|
106
|
+
delete valueCopy.resolved;
|
|
107
|
+
delete valueCopy.propertiesOrder;
|
|
108
|
+
delete valueCopy.propertyConfig;
|
|
109
|
+
delete valueCopy.resolvedProperties;
|
|
110
|
+
delete valueCopy.editable;
|
|
79
111
|
|
|
80
|
-
if (updatedProperty.type === "map") {
|
|
81
|
-
return {
|
|
82
|
-
...updatedProperty,
|
|
83
|
-
properties: updatedProperty.properties.map(propertyCleanup)
|
|
84
|
-
}
|
|
85
112
|
}
|
|
86
|
-
|
|
113
|
+
|
|
114
|
+
return valueCopy;
|
|
87
115
|
}
|
|
88
116
|
|
|
89
117
|
return {
|
|
@@ -99,7 +127,9 @@ function collectionToCode(collection: EntityCollection): object {
|
|
|
99
127
|
customId: collection.customId,
|
|
100
128
|
initialFilter: collection.initialFilter,
|
|
101
129
|
initialSort: collection.initialSort,
|
|
102
|
-
properties: Object.entries(
|
|
130
|
+
properties: Object.entries({
|
|
131
|
+
...(collection.properties ?? {})
|
|
132
|
+
})
|
|
103
133
|
.map(([key, value]) => ({
|
|
104
134
|
[key]: propertyCleanup(value)
|
|
105
135
|
}))
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Card, cls, SquareIcon, Tooltip, Typography, VerticalSplitIcon } from "@firecms/ui";
|
|
2
|
+
|
|
3
|
+
export function LayoutModeSwitch({
|
|
4
|
+
value,
|
|
5
|
+
onChange,
|
|
6
|
+
className
|
|
7
|
+
}: {
|
|
8
|
+
value: "side_panel" | "full_screen";
|
|
9
|
+
onChange: (value: "side_panel" | "full_screen") => void;
|
|
10
|
+
className?: string;
|
|
11
|
+
}) {
|
|
12
|
+
|
|
13
|
+
return <div className={cls(className)}>
|
|
14
|
+
<Typography variant={"label"} color={"secondary"} className={"ml-3.5"}>Document view</Typography>
|
|
15
|
+
<div className={cls("flex flex-row gap-4")}>
|
|
16
|
+
|
|
17
|
+
<Tooltip title={"Documents are open in a side panel"}>
|
|
18
|
+
<Card
|
|
19
|
+
onClick={() => onChange("side_panel")}
|
|
20
|
+
className={cls(
|
|
21
|
+
"my-2 rounded-md mx-0 p-4 focus:outline-none transition ease-in-out duration-150 flex flex-row gap-4 items-center",
|
|
22
|
+
"text-surface-700 dark:text-surface-accent-300",
|
|
23
|
+
"hover:text-primary-dark dark:hover:text-primary focus:ring-primary hover:ring-1 hover:ring-primary",
|
|
24
|
+
value === "side_panel" ? "border-primary dark:border-primary" : "border-surface-400 dark:border-surface-600",
|
|
25
|
+
)}
|
|
26
|
+
>
|
|
27
|
+
<VerticalSplitIcon/>
|
|
28
|
+
<Typography variant={"label"}>
|
|
29
|
+
Side panel
|
|
30
|
+
</Typography>
|
|
31
|
+
</Card>
|
|
32
|
+
</Tooltip>
|
|
33
|
+
|
|
34
|
+
<Tooltip title={"Documents are open full-screen"}>
|
|
35
|
+
<Card
|
|
36
|
+
onClick={() => onChange("full_screen")}
|
|
37
|
+
className={cls(
|
|
38
|
+
"my-2 rounded-md mx-0 p-4 focus:outline-none transition ease-in-out duration-150 flex flex-row gap-4 items-center",
|
|
39
|
+
"text-surface-700 dark:text-surface-accent-300",
|
|
40
|
+
"hover:text-primary-dark dark:hover:text-primary focus:ring-primary hover:ring-1 hover:ring-primary",
|
|
41
|
+
value === "full_screen" ? "border-primary dark:border-primary" : "border-surface-400 dark:border-surface-600",
|
|
42
|
+
)}
|
|
43
|
+
>
|
|
44
|
+
<SquareIcon/>
|
|
45
|
+
<Typography variant={"label"}>
|
|
46
|
+
Full screen
|
|
47
|
+
</Typography>
|
|
48
|
+
</Card>
|
|
49
|
+
</Tooltip>
|
|
50
|
+
|
|
51
|
+
</div>
|
|
52
|
+
<Typography variant={"caption"} color={"secondary"} className={"ml-3.5"}>Should documents be opened full screen or in an inline side dialog</Typography>
|
|
53
|
+
</div>
|
|
54
|
+
}
|