@firecms/collection_editor 3.0.1 → 3.1.0-canary.768c91f

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.
Files changed (90) hide show
  1. package/dist/ConfigControllerProvider.d.ts +6 -0
  2. package/dist/api/generateCollectionApi.d.ts +71 -0
  3. package/dist/api/index.d.ts +1 -0
  4. package/dist/index.d.ts +5 -1
  5. package/dist/index.es.js +9466 -5588
  6. package/dist/index.es.js.map +1 -1
  7. package/dist/index.umd.js +9461 -5583
  8. package/dist/index.umd.js.map +1 -1
  9. package/dist/types/collection_editor_controller.d.ts +14 -0
  10. package/dist/types/collection_inference.d.ts +8 -2
  11. package/dist/types/config_controller.d.ts +23 -2
  12. package/dist/ui/AddKanbanColumnAction.d.ts +11 -0
  13. package/dist/ui/KanbanSetupAction.d.ts +10 -0
  14. package/dist/ui/collection_editor/AICollectionGeneratorPopover.d.ts +37 -0
  15. package/dist/ui/collection_editor/AIModifiedPathsContext.d.ts +20 -0
  16. package/dist/ui/collection_editor/CollectionDetailsForm.d.ts +2 -3
  17. package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +24 -0
  18. package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +4 -1
  19. package/dist/ui/collection_editor/CollectionJsonImportDialog.d.ts +7 -0
  20. package/dist/ui/collection_editor/CollectionYupValidation.d.ts +9 -13
  21. package/dist/ui/collection_editor/DisplaySettingsForm.d.ts +3 -0
  22. package/dist/ui/collection_editor/EntityActionsEditTab.d.ts +2 -1
  23. package/dist/ui/collection_editor/ExtendSettingsForm.d.ts +14 -0
  24. package/dist/ui/collection_editor/GeneralSettingsForm.d.ts +7 -0
  25. package/dist/ui/collection_editor/KanbanConfigSection.d.ts +4 -0
  26. package/dist/ui/collection_editor/PropertyEditView.d.ts +6 -1
  27. package/dist/ui/collection_editor/PropertyTree.d.ts +2 -1
  28. package/dist/ui/collection_editor/SubcollectionsEditTab.d.ts +2 -1
  29. package/dist/ui/collection_editor/ViewModeSwitch.d.ts +6 -0
  30. package/dist/ui/collection_editor/properties/EnumPropertyField.d.ts +2 -1
  31. package/dist/ui/collection_editor/properties/conditions/ConditionsEditor.d.ts +10 -0
  32. package/dist/ui/collection_editor/properties/conditions/ConditionsPanel.d.ts +2 -0
  33. package/dist/ui/collection_editor/properties/conditions/EnumConditionsEditor.d.ts +6 -0
  34. package/dist/ui/collection_editor/properties/conditions/index.d.ts +6 -0
  35. package/dist/ui/collection_editor/properties/conditions/property_paths.d.ts +19 -0
  36. package/dist/useCollectionEditorPlugin.d.ts +7 -1
  37. package/dist/utils/validateCollectionJson.d.ts +22 -0
  38. package/package.json +15 -15
  39. package/src/ConfigControllerProvider.tsx +82 -47
  40. package/src/api/generateCollectionApi.ts +119 -0
  41. package/src/api/index.ts +1 -0
  42. package/src/index.ts +28 -1
  43. package/src/types/collection_editor_controller.tsx +16 -3
  44. package/src/types/collection_inference.ts +15 -2
  45. package/src/types/config_controller.tsx +27 -2
  46. package/src/ui/AddKanbanColumnAction.tsx +203 -0
  47. package/src/ui/EditorCollectionActionStart.tsx +1 -2
  48. package/src/ui/HomePageEditorCollectionAction.tsx +41 -13
  49. package/src/ui/KanbanSetupAction.tsx +38 -0
  50. package/src/ui/MissingReferenceWidget.tsx +1 -1
  51. package/src/ui/NewCollectionButton.tsx +1 -1
  52. package/src/ui/PropertyAddColumnComponent.tsx +1 -1
  53. package/src/ui/collection_editor/AICollectionGeneratorPopover.tsx +242 -0
  54. package/src/ui/collection_editor/AIModifiedPathsContext.tsx +88 -0
  55. package/src/ui/collection_editor/CollectionDetailsForm.tsx +212 -259
  56. package/src/ui/collection_editor/CollectionEditorDialog.tsx +237 -169
  57. package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +133 -67
  58. package/src/ui/collection_editor/CollectionJsonImportDialog.tsx +171 -0
  59. package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +190 -91
  60. package/src/ui/collection_editor/DisplaySettingsForm.tsx +333 -0
  61. package/src/ui/collection_editor/EntityActionsEditTab.tsx +106 -96
  62. package/src/ui/collection_editor/EntityActionsSelectDialog.tsx +6 -7
  63. package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +1 -3
  64. package/src/ui/collection_editor/EnumForm.tsx +147 -100
  65. package/src/ui/collection_editor/ExtendSettingsForm.tsx +93 -0
  66. package/src/ui/collection_editor/GeneralSettingsForm.tsx +337 -0
  67. package/src/ui/collection_editor/GetCodeDialog.tsx +57 -36
  68. package/src/ui/collection_editor/KanbanConfigSection.tsx +207 -0
  69. package/src/ui/collection_editor/LayoutModeSwitch.tsx +22 -41
  70. package/src/ui/collection_editor/PropertyEditView.tsx +206 -142
  71. package/src/ui/collection_editor/PropertyFieldPreview.tsx +1 -1
  72. package/src/ui/collection_editor/PropertyTree.tsx +130 -58
  73. package/src/ui/collection_editor/SubcollectionsEditTab.tsx +171 -162
  74. package/src/ui/collection_editor/UnsavedChangesDialog.tsx +0 -2
  75. package/src/ui/collection_editor/ViewModeSwitch.tsx +41 -0
  76. package/src/ui/collection_editor/properties/BlockPropertyField.tsx +0 -2
  77. package/src/ui/collection_editor/properties/BooleanPropertyField.tsx +1 -0
  78. package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +117 -35
  79. package/src/ui/collection_editor/properties/EnumPropertyField.tsx +28 -21
  80. package/src/ui/collection_editor/properties/MapPropertyField.tsx +0 -2
  81. package/src/ui/collection_editor/properties/MarkdownPropertyField.tsx +115 -39
  82. package/src/ui/collection_editor/properties/StoragePropertyField.tsx +1 -1
  83. package/src/ui/collection_editor/properties/conditions/ConditionsEditor.tsx +861 -0
  84. package/src/ui/collection_editor/properties/conditions/ConditionsPanel.tsx +28 -0
  85. package/src/ui/collection_editor/properties/conditions/EnumConditionsEditor.tsx +599 -0
  86. package/src/ui/collection_editor/properties/conditions/index.ts +6 -0
  87. package/src/ui/collection_editor/properties/conditions/property_paths.ts +92 -0
  88. package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +1 -1
  89. package/src/useCollectionEditorPlugin.tsx +32 -17
  90. package/src/utils/validateCollectionJson.ts +380 -0
@@ -1,5 +1,5 @@
1
- import React, { useEffect, useState } from "react";
2
- import { EntityCollection, FieldCaption, IconForView, SearchIconsView, singular, toSnakeCase, } from "@firecms/core";
1
+ import React, { useMemo, useState } from "react";
2
+ import { EntityCollection, FieldCaption, getFieldConfig, IconForView, Property, PropertyConfigBadge, resolveCollection, SearchIconsView, singular, toSnakeCase, unslugify, useAuthController, useCustomizationController } from "@firecms/core";
3
3
  import {
4
4
  BooleanSwitchWithLabel,
5
5
  Chip,
@@ -8,11 +8,10 @@ import {
8
8
  Container,
9
9
  DebouncedTextField,
10
10
  Dialog,
11
- ExpandablePanel,
11
+ HistoryIcon,
12
12
  IconButton,
13
13
  Select,
14
14
  SelectItem,
15
- SettingsIcon,
16
15
  TextField,
17
16
  Tooltip,
18
17
  Typography,
@@ -22,16 +21,19 @@ import {
22
21
  import { Field, getIn, useFormex } from "@firecms/formex";
23
22
  import { useCollectionEditorController } from "../../useCollectionEditorController";
24
23
  import { LayoutModeSwitch } from "./LayoutModeSwitch";
24
+ import { ViewModeSwitch } from "./ViewModeSwitch";
25
+ import { KanbanConfigSection } from "./KanbanConfigSection";
26
+ import { PropertyFormDialog } from "./PropertyEditView";
25
27
 
26
28
  export function CollectionDetailsForm({
27
- isNewCollection,
28
- reservedGroups,
29
- existingPaths,
30
- existingIds,
31
- groups,
32
- parentCollection,
33
- children
34
- }: {
29
+ isNewCollection,
30
+ reservedGroups,
31
+ existingPaths,
32
+ existingIds,
33
+ groups,
34
+ parentCollection,
35
+ expandKanban
36
+ }: {
35
37
  isNewCollection: boolean,
36
38
  reservedGroups?: string[];
37
39
  existingPaths?: string[];
@@ -39,7 +41,7 @@ export function CollectionDetailsForm({
39
41
  groups: string[] | null;
40
42
  parentCollection?: EntityCollection;
41
43
  parentCollectionIds?: string[];
42
- children?: React.ReactNode;
44
+ expandKanban?: boolean;
43
45
  }) {
44
46
 
45
47
  const groupRef = React.useRef<HTMLInputElement>(null);
@@ -57,7 +59,35 @@ export function CollectionDetailsForm({
57
59
  const collectionEditor = useCollectionEditorController();
58
60
 
59
61
  const [iconDialogOpen, setIconDialogOpen] = useState(false);
60
- const [advancedPanelExpanded, setAdvancedPanelExpanded] = useState(false);
62
+ const [orderPropertyDialogOpen, setOrderPropertyDialogOpen] = useState(false);
63
+
64
+ const authController = useAuthController();
65
+ const customizationController = useCustomizationController();
66
+
67
+ // Resolve collection to get properties for order property select
68
+ const resolvedCollection = useMemo(() => resolveCollection({
69
+ collection: values,
70
+ path: values.path,
71
+ propertyConfigs: customizationController.propertyConfigs,
72
+ authController
73
+ }), [values, customizationController.propertyConfigs, authController]);
74
+
75
+ // Get number properties (for orderProperty)
76
+ const numberProperties = useMemo(() => {
77
+ const result: { key: string; label: string; property: Property; }[] = [];
78
+ if (!resolvedCollection.properties) return result;
79
+
80
+ Object.entries(resolvedCollection.properties).forEach(([key, prop]) => {
81
+ if (prop && 'dataType' in prop && prop.dataType === 'number') {
82
+ result.push({
83
+ key,
84
+ label: (prop as Property).name || key,
85
+ property: prop as Property
86
+ });
87
+ }
88
+ });
89
+ return result;
90
+ }, [resolvedCollection.properties]);
61
91
 
62
92
  const updateDatabaseId = (databaseId: string) => {
63
93
  setFieldValue("databaseId", databaseId ?? undefined);
@@ -83,13 +113,7 @@ export function CollectionDetailsForm({
83
113
 
84
114
  };
85
115
 
86
- useEffect(() => {
87
- if (errors.id) {
88
- setAdvancedPanelExpanded(true);
89
- }
90
- }, [errors.id]);
91
-
92
- const collectionIcon = <IconForView collectionOrView={values}/>;
116
+ const collectionIcon = <IconForView collectionOrView={values} />;
93
117
 
94
118
  const groupOptions = groups?.filter((group) => !reservedGroups?.includes(group));
95
119
 
@@ -103,17 +127,6 @@ export function CollectionDetailsForm({
103
127
 
104
128
  const isSubcollection = !!parentCollection;
105
129
 
106
- let customIdValue: "true" | "false" | "optional" | "code_defined" | undefined;
107
- if (typeof values.customId === "object") {
108
- customIdValue = "code_defined";
109
- } else if (values.customId === true) {
110
- customIdValue = "true";
111
- } else if (values.customId === false) {
112
- customIdValue = "false";
113
- } else if (values.customId === "optional") {
114
- customIdValue = "optional";
115
- }
116
-
117
130
  const showErrors = submitCount > 0;
118
131
 
119
132
  return (
@@ -127,10 +140,10 @@ export function CollectionDetailsForm({
127
140
  {isNewCollection ? "New collection" : `${values?.name} collection`}
128
141
  </Typography>
129
142
  <DefaultDatabaseField databaseId={values.databaseId}
130
- onDatabaseIdUpdate={updateDatabaseId}/>
143
+ onDatabaseIdUpdate={updateDatabaseId} />
131
144
 
132
145
  <Tooltip title={"Change icon"}
133
- asChild={true}>
146
+ asChild={true}>
134
147
  <IconButton
135
148
  shape={"square"}
136
149
  onClick={() => setIconDialogOpen(true)}>
@@ -155,7 +168,7 @@ export function CollectionDetailsForm({
155
168
  label={"Name"}
156
169
  autoFocus={true}
157
170
  required
158
- error={showErrors && Boolean(errors.name)}/>
171
+ error={showErrors && Boolean(errors.name)} />
159
172
  <FieldCaption error={touched.name && Boolean(errors.name)}>
160
173
  {touched.name && Boolean(errors.name) ? errors.name : "Name of this collection, usually a plural name (e.g. Products)"}
161
174
  </FieldCaption>
@@ -163,10 +176,10 @@ export function CollectionDetailsForm({
163
176
 
164
177
  <div className={cls("col-span-12 ")}>
165
178
  <Field name={"path"}
166
- as={DebouncedTextField}
167
- label={"Path"}
168
- required
169
- error={showErrors && Boolean(errors.path)}/>
179
+ as={DebouncedTextField}
180
+ label={"Path"}
181
+ required
182
+ error={showErrors && Boolean(errors.path)} />
170
183
 
171
184
  <FieldCaption error={touched.path && Boolean(errors.path)}>
172
185
  {touched.path && Boolean(errors.path)
@@ -214,16 +227,158 @@ export function CollectionDetailsForm({
214
227
  <LayoutModeSwitch
215
228
  className={"col-span-12"}
216
229
  value={values.openEntityMode ?? "side_panel"}
217
- onChange={(value) => setFieldValue("openEntityMode", value)}/>
230
+ onChange={(value) => setFieldValue("openEntityMode", value)} />
231
+
232
+ <ViewModeSwitch
233
+ className={"col-span-12"}
234
+ value={values.defaultViewMode ?? "table"}
235
+ onChange={(value) => setFieldValue("defaultViewMode", value)} />
236
+
237
+ <KanbanConfigSection className={"col-span-12"} forceExpanded={expandKanban} />
238
+
239
+ <div className={"col-span-12 mt-4"}>
240
+ {(() => {
241
+ // Check if orderProperty references a non-existent property
242
+ const orderPropertyMissing = Boolean(values.orderProperty) &&
243
+ !numberProperties.some(p => p.key === values.orderProperty);
244
+
245
+ return (
246
+ <>
247
+ <Select
248
+ key={`order-select-${numberProperties.length}`}
249
+ name="orderProperty"
250
+ label="Order Property"
251
+ size={"large"}
252
+ fullWidth={true}
253
+ position={"item-aligned"}
254
+ disabled={numberProperties.length === 0}
255
+ error={orderPropertyMissing}
256
+ value={values.orderProperty ?? ""}
257
+ onValueChange={(v) => {
258
+ setFieldValue("orderProperty", v || undefined);
259
+ }}
260
+ renderValue={(value) => {
261
+ if (orderPropertyMissing) {
262
+ return <span className="text-red-500">{value} (not found)</span>;
263
+ }
264
+ const prop = numberProperties.find(p => p.key === value);
265
+ if (!prop) return "Select a property";
266
+ const fieldConfig = getFieldConfig(prop.property, customizationController.propertyConfigs);
267
+ return (
268
+ <div className="flex items-center gap-2">
269
+ <PropertyConfigBadge propertyConfig={fieldConfig} />
270
+ <span>{prop.label}</span>
271
+ </div>
272
+ );
273
+ }}
274
+ endAdornment={values.orderProperty ? (
275
+ <IconButton
276
+ size="small"
277
+ onClick={(e) => {
278
+ e.stopPropagation();
279
+ setFieldValue("orderProperty", undefined);
280
+ }}
281
+ >
282
+ <CloseIcon size="small" />
283
+ </IconButton>
284
+ ) : undefined}
285
+ >
286
+ {numberProperties.map((prop) => {
287
+ const fieldConfig = getFieldConfig(prop.property, customizationController.propertyConfigs);
288
+ return (
289
+ <SelectItem key={prop.key} value={prop.key}>
290
+ <div className="flex items-center gap-3">
291
+ <PropertyConfigBadge propertyConfig={fieldConfig} />
292
+ <div>
293
+ <div>{prop.label}</div>
294
+ <Typography variant="caption" color="secondary">
295
+ {fieldConfig?.name || "Number"}
296
+ </Typography>
297
+ </div>
298
+ </div>
299
+ </SelectItem>
300
+ );
301
+ })}
302
+ </Select>
303
+ <FieldCaption error={orderPropertyMissing}>
304
+ {orderPropertyMissing
305
+ ? `Property "${values.orderProperty}" does not exist or is not a number property. Please select a valid property or clear the selection.`
306
+ : numberProperties.length === 0
307
+ ? "No number properties found. Add a number property to enable ordering."
308
+ : "Select a number property to persist the order of items"
309
+ }
310
+ </FieldCaption>
311
+ </>
312
+ );
313
+ })()}
314
+ {(() => {
315
+ // Check if orderProperty references a non-existent property
316
+ const orderPropertyMissing = Boolean(values.orderProperty) &&
317
+ !numberProperties.some(p => p.key === values.orderProperty);
318
+ const showCreateButton = !values.orderProperty || orderPropertyMissing;
319
+
320
+ // Pre-fill with missing property id or default "__order"
321
+ const dialogPropertyKey = orderPropertyMissing && values.orderProperty
322
+ ? values.orderProperty
323
+ : "__order";
324
+ const dialogPropertyName = orderPropertyMissing && values.orderProperty
325
+ ? unslugify(values.orderProperty)
326
+ : "Order";
327
+
328
+ if (!showCreateButton) return null;
329
+
330
+ return (
331
+ <>
332
+ <button
333
+ type="button"
334
+ className="ml-3.5 text-sm text-primary hover:text-primary-dark mt-2"
335
+ onClick={() => setOrderPropertyDialogOpen(true)}
336
+ >
337
+ + Create "{dialogPropertyKey}" property
338
+ </button>
339
+ <PropertyFormDialog
340
+ open={orderPropertyDialogOpen}
341
+ onCancel={() => setOrderPropertyDialogOpen(false)}
342
+ property={{
343
+ dataType: "number",
344
+ name: dialogPropertyName,
345
+ disabled: true,
346
+ hideFromCollection: true
347
+ }}
348
+ propertyKey={dialogPropertyKey}
349
+ existingProperty={false}
350
+ autoOpenTypeSelect={false}
351
+ autoUpdateId={false}
352
+ inArray={false}
353
+ allowDataInference={false}
354
+ propertyConfigs={customizationController.propertyConfigs}
355
+ collectionEditable={true}
356
+ existingPropertyKeys={Object.keys(values.properties ?? {})}
357
+ onPropertyChanged={({ id, property }) => {
358
+ const newProperties = {
359
+ ...values.properties,
360
+ [id!]: property
361
+ };
362
+ const newPropertiesOrder = [...(values.propertiesOrder ?? Object.keys(values.properties ?? {})), id];
363
+ setFieldValue("properties", newProperties);
364
+ setFieldValue("propertiesOrder", newPropertiesOrder);
365
+ setFieldValue("orderProperty", id);
366
+ setOrderPropertyDialogOpen(false);
367
+ }}
368
+ />
369
+ </>
370
+ );
371
+ })()}
372
+ </div>
218
373
 
219
374
  <div className={"col-span-12"}>
220
375
  <BooleanSwitchWithLabel
221
376
  position={"start"}
222
377
  size={"large"}
223
378
  allowIndeterminate={true}
224
- label={values.history === null || values.history === undefined ? "Document history revisions enabled if enabled globally" : (
379
+ label={<span className="flex items-center gap-2"><HistoryIcon size={"smallest"} />{values.history === null || values.history === undefined ? "Document history revisions enabled if enabled globally" : (
225
380
  values.history ? "Document history revisions ENABLED" : "Document history revisions NOT enabled"
226
- )}
381
+ )}</span>}
227
382
  onValueChange={(v) => setFieldValue("history", v)}
228
383
  value={values.history === undefined ? null : values.history}
229
384
  />
@@ -236,214 +391,12 @@ export function CollectionDetailsForm({
236
391
 
237
392
 
238
393
  <div className={"col-span-12 mt-8"}>
239
- <ExpandablePanel
240
- expanded={advancedPanelExpanded}
241
- onExpandedChange={setAdvancedPanelExpanded}
242
- title={
243
- <div className="flex flex-row text-surface-500">
244
- <SettingsIcon/>
245
- <Typography variant={"subtitle2"}
246
- className="ml-2">
247
- Advanced
248
- </Typography>
249
- </div>}
250
- initiallyExpanded={false}>
251
- <div className={"grid grid-cols-12 gap-4 p-4"}>
252
-
253
- <div className={"col-span-12"}>
254
- <Field name={"id"}
255
- as={DebouncedTextField}
256
- disabled={!isNewCollection}
257
- label={"Collection id"}
258
- error={showErrors && Boolean(errors.id)}/>
259
- <FieldCaption error={touched.id && Boolean(errors.id)}>
260
- {touched.id && Boolean(errors.id) ? errors.id : "This id identifies this collection. Typically the same as the path."}
261
- </FieldCaption>
262
- </div>
263
-
264
- <div className={"col-span-12"}>
265
- <TextField
266
- error={showErrors && Boolean(errors.singularName)}
267
- name={"singularName"}
268
- aria-describedby={"singularName-helper"}
269
- onChange={(e) => {
270
- setFieldTouched("singularName", true);
271
- return handleChange(e);
272
- }}
273
- value={values.singularName ?? ""}
274
- label={"Singular name"}/>
275
- <FieldCaption error={showErrors && Boolean(errors.singularName)}>
276
- {showErrors && Boolean(errors.singularName) ? errors.singularName : "Optionally define a singular name for your entities"}
277
- </FieldCaption>
278
- </div>
279
- <div className={"col-span-12"}>
280
- <TextField
281
- error={showErrors && Boolean(errors.sideDialogWidth)}
282
- name={"sideDialogWidth"}
283
- type={"number"}
284
- aria-describedby={"sideDialogWidth-helper"}
285
- onChange={(e) => {
286
- setFieldTouched("sideDialogWidth", true);
287
- const value = e.target.value;
288
- if (!value) {
289
- setFieldValue("sideDialogWidth", null);
290
- } else if (!isNaN(Number(value))) {
291
- setFieldValue("sideDialogWidth", Number(value));
292
- }
293
- }}
294
- endAdornment={<IconButton
295
- size={"small"}
296
- onClick={() => {
297
- setFieldValue("sideDialogWidth", null);
298
- }}
299
- disabled={!values.sideDialogWidth}>
300
- <CloseIcon size={"small"}/>
301
- </IconButton>}
302
- value={values.sideDialogWidth ?? ""}
303
- label={"Side dialog width"}/>
304
- <FieldCaption error={showErrors && Boolean(errors.singularName)}>
305
- {showErrors && Boolean(errors.singularName) ? errors.singularName : "Optionally define the width (in pixels) of entities side dialog. Default is 768px"}
306
- </FieldCaption>
307
- </div>
308
- <div className={"col-span-12"}>
309
- <TextField
310
- error={showErrors && Boolean(errors.description)}
311
- name="description"
312
- value={values.description ?? ""}
313
- onChange={handleChange}
314
- multiline
315
- minRows={2}
316
- aria-describedby="description-helper-text"
317
- label="Description"
318
- />
319
- <FieldCaption error={showErrors && Boolean(errors.description)}>
320
- {showErrors && Boolean(errors.description) ? errors.description : "Description of the collection, you can use markdown"}
321
- </FieldCaption>
322
- </div>
323
-
324
- <div className={"col-span-12"}>
325
- <Select
326
- name="defaultSize"
327
- size={"large"}
328
- fullWidth={true}
329
- label="Default row size"
330
- position={"item-aligned"}
331
- onChange={handleChange}
332
- value={values.defaultSize ?? ""}
333
- renderValue={(value: any) => value.toUpperCase()}
334
- >
335
- {["xs", "s", "m", "l", "xl"].map((value) => (
336
- <SelectItem
337
- key={`size-select-${value}`}
338
- value={value}>
339
- {value.toUpperCase()}
340
- </SelectItem>
341
- ))}
342
- </Select>
343
- </div>
344
-
345
- <div className={"col-span-12"}>
346
- <BooleanSwitchWithLabel
347
- position={"start"}
348
- size={"large"}
349
- label={values.includeJsonView === undefined || values.includeJsonView ? "Include JSON view" : "Do not include JSON view"}
350
- onValueChange={(v) => setFieldValue("includeJsonView", v)}
351
- value={values.includeJsonView === undefined ? true : values.includeJsonView}
352
- />
353
- <FieldCaption>
354
- Include the JSON representation of the document.
355
- </FieldCaption>
356
- </div>
357
-
358
- <div className={"col-span-12"}>
359
- <BooleanSwitchWithLabel
360
- position={"start"}
361
- size={"large"}
362
- label={values.inlineEditing === undefined || values.inlineEditing ? "Data can be edited directly in the table view" : "Data can be edited only in the form view"}
363
- onValueChange={(v) => setFieldValue("inlineEditing", v)}
364
- value={values.inlineEditing === undefined ? true : values.inlineEditing}
365
- />
366
- <FieldCaption>
367
- Allow editing data directly in the table view, without opening the form view.
368
- </FieldCaption>
369
- </div>
370
-
371
- <div className={"col-span-12"}>
372
- <Select
373
- name="customId"
374
- label="Document IDs generation"
375
- position={"item-aligned"}
376
- size={"large"}
377
- fullWidth={true}
378
- disabled={customIdValue === "code_defined"}
379
- onValueChange={(v) => {
380
- if (v === "code_defined")
381
- throw new Error("This should not happen");
382
- setFieldValue("customId", v);
383
- }}
384
- value={customIdValue ?? ""}
385
- renderValue={(value: any) => {
386
- if (value === "code_defined")
387
- return "Code defined";
388
- else if (value === "true")
389
- return "Users must define an ID";
390
- else if (value === "optional")
391
- return "Users can define an ID, but it is not required";
392
- else
393
- return "Document ID is generated automatically";
394
- }}
395
- >
396
- <SelectItem value={"false"}>
397
- Document ID is generated automatically
398
- </SelectItem>
399
- <SelectItem value={"true"}>
400
- Users must define an ID
401
- </SelectItem>
402
- <SelectItem value={"optional"}>
403
- Users can define an ID, but it is not required
404
- </SelectItem>
405
- </Select>
406
- </div>
407
- <div className={"col-span-12 mt-4"}>
408
- <BooleanSwitchWithLabel
409
- position={"start"}
410
- size={"large"}
411
- label="Collection group"
412
- onValueChange={(v) => setFieldValue("collectionGroup", v)}
413
- value={values.collectionGroup ?? false}
414
- />
415
- <FieldCaption>
416
- A collection group consists of all collections with the same path. This allows
417
- you
418
- to query over multiple collections at once.
419
- </FieldCaption>
420
- </div>
421
- <div className={"col-span-12"}>
422
- <BooleanSwitchWithLabel
423
- position={"start"}
424
- size={"large"}
425
- label="Enable text search for this collection"
426
- onValueChange={(v) => setFieldValue("textSearchEnabled", v)}
427
- value={values.textSearchEnabled ?? false}
428
- />
429
- <FieldCaption>
430
- Allow text search for this collection. If you have not specified a text search
431
- delegate, this will use the built-in local text search. This is not recommended
432
- for large collections, as it may incur in performance and cost issues.
433
- </FieldCaption>
434
- </div>
435
-
436
-
437
- </div>
438
- </ExpandablePanel>
439
-
440
- {children}
441
394
 
442
395
  </div>
443
396
 
444
397
  </div>
445
398
 
446
- <div style={{ height: "52px" }}/>
399
+ <div style={{ height: "52px" }} />
447
400
 
448
401
  <Dialog
449
402
  open={iconDialogOpen}
@@ -453,10 +406,10 @@ export function CollectionDetailsForm({
453
406
  >
454
407
  <div className={"p-4 overflow-auto min-h-[200px]"}>
455
408
  <SearchIconsView selectedIcon={typeof values.icon === "string" ? values.icon : undefined}
456
- onIconSelected={(icon: string) => {
457
- setIconDialogOpen(false);
458
- setFieldValue("icon", icon);
459
- }}/>
409
+ onIconSelected={(icon: string) => {
410
+ setIconDialogOpen(false);
411
+ setFieldValue("icon", icon);
412
+ }} />
460
413
  </div>
461
414
 
462
415
  </Dialog>
@@ -467,18 +420,18 @@ export function CollectionDetailsForm({
467
420
  }
468
421
 
469
422
  function DefaultDatabaseField({
470
- databaseId,
471
- onDatabaseIdUpdate
472
- }: { databaseId?: string, onDatabaseIdUpdate: (databaseId: string) => void }) {
423
+ databaseId,
424
+ onDatabaseIdUpdate
425
+ }: { databaseId?: string, onDatabaseIdUpdate: (databaseId: string) => void }) {
473
426
 
474
427
  return <Tooltip title={"Database ID"}
475
- side={"top"}
476
- align={"start"}>
428
+ side={"top"}
429
+ align={"start"}>
477
430
  <TextField size={"small"}
478
- invisible={true}
479
- inputClassName={"text-end"}
480
- value={databaseId ?? ""}
481
- onChange={(e: any) => onDatabaseIdUpdate(e.target.value)}
482
- placeholder={"(default)"}></TextField>
431
+ invisible={true}
432
+ inputClassName={"text-end"}
433
+ value={databaseId ?? ""}
434
+ onChange={(e: any) => onDatabaseIdUpdate(e.target.value)}
435
+ placeholder={"(default)"}></TextField>
483
436
  </Tooltip>
484
437
  }