@firecms/collection_editor 3.0.1 → 3.1.0-canary.7d91b7c
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/ConfigControllerProvider.d.ts +6 -0
- package/dist/api/generateCollectionApi.d.ts +71 -0
- package/dist/api/index.d.ts +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.es.js +9466 -5588
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +9461 -5583
- package/dist/index.umd.js.map +1 -1
- package/dist/types/collection_editor_controller.d.ts +14 -0
- package/dist/types/collection_inference.d.ts +8 -2
- package/dist/types/config_controller.d.ts +23 -2
- package/dist/ui/AddKanbanColumnAction.d.ts +11 -0
- package/dist/ui/KanbanSetupAction.d.ts +10 -0
- package/dist/ui/collection_editor/AICollectionGeneratorPopover.d.ts +37 -0
- package/dist/ui/collection_editor/AIModifiedPathsContext.d.ts +20 -0
- package/dist/ui/collection_editor/CollectionDetailsForm.d.ts +2 -3
- package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +24 -0
- package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +4 -1
- package/dist/ui/collection_editor/CollectionJsonImportDialog.d.ts +7 -0
- package/dist/ui/collection_editor/CollectionYupValidation.d.ts +9 -13
- package/dist/ui/collection_editor/DisplaySettingsForm.d.ts +3 -0
- package/dist/ui/collection_editor/EntityActionsEditTab.d.ts +2 -1
- package/dist/ui/collection_editor/ExtendSettingsForm.d.ts +14 -0
- package/dist/ui/collection_editor/GeneralSettingsForm.d.ts +7 -0
- package/dist/ui/collection_editor/KanbanConfigSection.d.ts +4 -0
- package/dist/ui/collection_editor/PropertyEditView.d.ts +6 -1
- package/dist/ui/collection_editor/PropertyTree.d.ts +2 -1
- package/dist/ui/collection_editor/SubcollectionsEditTab.d.ts +2 -1
- package/dist/ui/collection_editor/ViewModeSwitch.d.ts +6 -0
- package/dist/ui/collection_editor/properties/EnumPropertyField.d.ts +2 -1
- package/dist/ui/collection_editor/properties/conditions/ConditionsEditor.d.ts +10 -0
- package/dist/ui/collection_editor/properties/conditions/ConditionsPanel.d.ts +2 -0
- package/dist/ui/collection_editor/properties/conditions/EnumConditionsEditor.d.ts +6 -0
- package/dist/ui/collection_editor/properties/conditions/index.d.ts +6 -0
- package/dist/ui/collection_editor/properties/conditions/property_paths.d.ts +19 -0
- package/dist/useCollectionEditorPlugin.d.ts +7 -1
- package/dist/utils/validateCollectionJson.d.ts +22 -0
- package/package.json +15 -15
- package/src/ConfigControllerProvider.tsx +82 -47
- package/src/api/generateCollectionApi.ts +119 -0
- package/src/api/index.ts +1 -0
- package/src/index.ts +28 -1
- package/src/types/collection_editor_controller.tsx +16 -3
- package/src/types/collection_inference.ts +15 -2
- package/src/types/config_controller.tsx +27 -2
- package/src/ui/AddKanbanColumnAction.tsx +203 -0
- package/src/ui/EditorCollectionActionStart.tsx +1 -2
- package/src/ui/HomePageEditorCollectionAction.tsx +41 -13
- package/src/ui/KanbanSetupAction.tsx +38 -0
- package/src/ui/MissingReferenceWidget.tsx +1 -1
- package/src/ui/NewCollectionButton.tsx +1 -1
- package/src/ui/PropertyAddColumnComponent.tsx +1 -1
- package/src/ui/collection_editor/AICollectionGeneratorPopover.tsx +242 -0
- package/src/ui/collection_editor/AIModifiedPathsContext.tsx +88 -0
- package/src/ui/collection_editor/CollectionDetailsForm.tsx +212 -259
- package/src/ui/collection_editor/CollectionEditorDialog.tsx +237 -169
- package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +133 -67
- package/src/ui/collection_editor/CollectionJsonImportDialog.tsx +171 -0
- package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +190 -91
- package/src/ui/collection_editor/DisplaySettingsForm.tsx +333 -0
- package/src/ui/collection_editor/EntityActionsEditTab.tsx +106 -96
- package/src/ui/collection_editor/EntityActionsSelectDialog.tsx +6 -7
- package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +1 -3
- package/src/ui/collection_editor/EnumForm.tsx +147 -100
- package/src/ui/collection_editor/ExtendSettingsForm.tsx +93 -0
- package/src/ui/collection_editor/GeneralSettingsForm.tsx +337 -0
- package/src/ui/collection_editor/GetCodeDialog.tsx +57 -36
- package/src/ui/collection_editor/KanbanConfigSection.tsx +207 -0
- package/src/ui/collection_editor/LayoutModeSwitch.tsx +22 -41
- package/src/ui/collection_editor/PropertyEditView.tsx +206 -142
- package/src/ui/collection_editor/PropertyFieldPreview.tsx +1 -1
- package/src/ui/collection_editor/PropertyTree.tsx +130 -58
- package/src/ui/collection_editor/SubcollectionsEditTab.tsx +171 -162
- package/src/ui/collection_editor/UnsavedChangesDialog.tsx +0 -2
- package/src/ui/collection_editor/ViewModeSwitch.tsx +41 -0
- package/src/ui/collection_editor/properties/BlockPropertyField.tsx +0 -2
- package/src/ui/collection_editor/properties/BooleanPropertyField.tsx +1 -0
- package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +117 -35
- package/src/ui/collection_editor/properties/EnumPropertyField.tsx +28 -21
- package/src/ui/collection_editor/properties/MapPropertyField.tsx +0 -2
- package/src/ui/collection_editor/properties/MarkdownPropertyField.tsx +115 -39
- package/src/ui/collection_editor/properties/StoragePropertyField.tsx +1 -1
- package/src/ui/collection_editor/properties/conditions/ConditionsEditor.tsx +861 -0
- package/src/ui/collection_editor/properties/conditions/ConditionsPanel.tsx +28 -0
- package/src/ui/collection_editor/properties/conditions/EnumConditionsEditor.tsx +599 -0
- package/src/ui/collection_editor/properties/conditions/index.ts +6 -0
- package/src/ui/collection_editor/properties/conditions/property_paths.ts +92 -0
- package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +1 -1
- package/src/useCollectionEditorPlugin.tsx +32 -17
- package/src/utils/validateCollectionJson.ts +380 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import React, { useMemo, useRef, useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
EntityCollection,
|
|
4
|
+
FieldCaption,
|
|
5
|
+
getFieldConfig,
|
|
6
|
+
Property,
|
|
7
|
+
PropertyConfigBadge,
|
|
8
|
+
resolveCollection,
|
|
9
|
+
unslugify,
|
|
10
|
+
useAuthController,
|
|
11
|
+
useCustomizationController
|
|
12
|
+
} from "@firecms/core";
|
|
13
|
+
import {
|
|
14
|
+
CloseIcon,
|
|
15
|
+
IconButton,
|
|
16
|
+
Select,
|
|
17
|
+
SelectItem,
|
|
18
|
+
Typography
|
|
19
|
+
} from "@firecms/ui";
|
|
20
|
+
import { useFormex } from "@firecms/formex";
|
|
21
|
+
import { PropertyFormDialog } from "./PropertyEditView";
|
|
22
|
+
|
|
23
|
+
export function KanbanConfigSection({
|
|
24
|
+
className,
|
|
25
|
+
forceExpanded
|
|
26
|
+
}: {
|
|
27
|
+
className?: string;
|
|
28
|
+
forceExpanded?: boolean;
|
|
29
|
+
}) {
|
|
30
|
+
const authController = useAuthController();
|
|
31
|
+
const customizationController = useCustomizationController();
|
|
32
|
+
const { values, setFieldValue } = useFormex<EntityCollection>();
|
|
33
|
+
const panelRef = useRef<HTMLDivElement>(null);
|
|
34
|
+
const [columnPropertyDialogOpen, setColumnPropertyDialogOpen] = useState(false);
|
|
35
|
+
|
|
36
|
+
// Resolve collection to get properties
|
|
37
|
+
const resolvedCollection = useMemo(() => resolveCollection({
|
|
38
|
+
collection: values,
|
|
39
|
+
path: values.path,
|
|
40
|
+
propertyConfigs: customizationController.propertyConfigs,
|
|
41
|
+
authController
|
|
42
|
+
}), [values, customizationController.propertyConfigs, authController]);
|
|
43
|
+
|
|
44
|
+
// Get enum string properties (for columnProperty)
|
|
45
|
+
const enumStringProperties = useMemo(() => {
|
|
46
|
+
const result: { key: string; label: string; property: Property }[] = [];
|
|
47
|
+
if (!resolvedCollection.properties) return result;
|
|
48
|
+
|
|
49
|
+
Object.entries(resolvedCollection.properties).forEach(([key, prop]) => {
|
|
50
|
+
if (prop && 'dataType' in prop && prop.dataType === 'string' && prop.enumValues) {
|
|
51
|
+
result.push({
|
|
52
|
+
key,
|
|
53
|
+
label: (prop as Property).name || key,
|
|
54
|
+
property: prop as Property
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
return result;
|
|
59
|
+
}, [resolvedCollection.properties]);
|
|
60
|
+
|
|
61
|
+
const kanbanConfig = values.kanban;
|
|
62
|
+
|
|
63
|
+
// Check if columnProperty references a non-existent property
|
|
64
|
+
const columnPropertyMissing = Boolean(kanbanConfig?.columnProperty) &&
|
|
65
|
+
!enumStringProperties.some(p => p.key === kanbanConfig?.columnProperty);
|
|
66
|
+
|
|
67
|
+
// Scroll to section when forceExpanded
|
|
68
|
+
React.useEffect(() => {
|
|
69
|
+
if (forceExpanded && panelRef.current) {
|
|
70
|
+
setTimeout(() => {
|
|
71
|
+
panelRef.current?.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
72
|
+
}, 100);
|
|
73
|
+
}
|
|
74
|
+
}, [forceExpanded]);
|
|
75
|
+
|
|
76
|
+
const showCreateButton = !kanbanConfig?.columnProperty || columnPropertyMissing;
|
|
77
|
+
const dialogPropertyKey = columnPropertyMissing && kanbanConfig?.columnProperty
|
|
78
|
+
? kanbanConfig.columnProperty
|
|
79
|
+
: "status";
|
|
80
|
+
const dialogPropertyName = columnPropertyMissing && kanbanConfig?.columnProperty
|
|
81
|
+
? unslugify(kanbanConfig.columnProperty)
|
|
82
|
+
: "Status";
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<div className={className} ref={panelRef}>
|
|
86
|
+
<Select
|
|
87
|
+
key={`column-select-${enumStringProperties.length}`}
|
|
88
|
+
name="kanban.columnProperty"
|
|
89
|
+
label="Kanban Column Property"
|
|
90
|
+
size={"large"}
|
|
91
|
+
fullWidth={true}
|
|
92
|
+
position={"item-aligned"}
|
|
93
|
+
disabled={enumStringProperties.length === 0}
|
|
94
|
+
error={columnPropertyMissing}
|
|
95
|
+
value={kanbanConfig?.columnProperty ?? ""}
|
|
96
|
+
onValueChange={(v) => {
|
|
97
|
+
if (v) {
|
|
98
|
+
setFieldValue("kanban", {
|
|
99
|
+
...kanbanConfig,
|
|
100
|
+
columnProperty: v
|
|
101
|
+
});
|
|
102
|
+
} else {
|
|
103
|
+
setFieldValue("kanban", undefined);
|
|
104
|
+
}
|
|
105
|
+
}}
|
|
106
|
+
renderValue={(value) => {
|
|
107
|
+
if (columnPropertyMissing) {
|
|
108
|
+
return <span className="text-red-500">{value} (not found)</span>;
|
|
109
|
+
}
|
|
110
|
+
const prop = enumStringProperties.find(p => p.key === value);
|
|
111
|
+
if (!prop) return "Select a property";
|
|
112
|
+
const fieldConfig = getFieldConfig(prop.property, customizationController.propertyConfigs);
|
|
113
|
+
return (
|
|
114
|
+
<div className="flex items-center gap-2">
|
|
115
|
+
<PropertyConfigBadge propertyConfig={fieldConfig} />
|
|
116
|
+
<span>{prop.label}</span>
|
|
117
|
+
</div>
|
|
118
|
+
);
|
|
119
|
+
}}
|
|
120
|
+
endAdornment={kanbanConfig?.columnProperty ? (
|
|
121
|
+
<IconButton
|
|
122
|
+
size="small"
|
|
123
|
+
onClick={(e) => {
|
|
124
|
+
e.stopPropagation();
|
|
125
|
+
setFieldValue("kanban", undefined);
|
|
126
|
+
}}
|
|
127
|
+
>
|
|
128
|
+
<CloseIcon size="small" />
|
|
129
|
+
</IconButton>
|
|
130
|
+
) : undefined}
|
|
131
|
+
>
|
|
132
|
+
{enumStringProperties.map((prop) => {
|
|
133
|
+
const fieldConfig = getFieldConfig(prop.property, customizationController.propertyConfigs);
|
|
134
|
+
return (
|
|
135
|
+
<SelectItem key={prop.key} value={prop.key}>
|
|
136
|
+
<div className="flex items-center gap-3">
|
|
137
|
+
<PropertyConfigBadge propertyConfig={fieldConfig} />
|
|
138
|
+
<div>
|
|
139
|
+
<div>{prop.label}</div>
|
|
140
|
+
<Typography variant="caption" color="secondary">
|
|
141
|
+
{fieldConfig?.name || "Enum"}
|
|
142
|
+
</Typography>
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
</SelectItem>
|
|
146
|
+
);
|
|
147
|
+
})}
|
|
148
|
+
</Select>
|
|
149
|
+
<FieldCaption error={columnPropertyMissing}>
|
|
150
|
+
{columnPropertyMissing
|
|
151
|
+
? `Property "${kanbanConfig?.columnProperty}" does not exist or is not an enum string property. Please select a valid property or clear the selection.`
|
|
152
|
+
: enumStringProperties.length === 0
|
|
153
|
+
? "No enum string properties found. Add a string property with enumValues to use Kanban view."
|
|
154
|
+
: "Select a string property with enum values to group entities into columns"
|
|
155
|
+
}
|
|
156
|
+
</FieldCaption>
|
|
157
|
+
|
|
158
|
+
{showCreateButton && (
|
|
159
|
+
<>
|
|
160
|
+
<button
|
|
161
|
+
type="button"
|
|
162
|
+
className="ml-3.5 text-sm text-primary hover:text-primary-dark mt-2"
|
|
163
|
+
onClick={() => setColumnPropertyDialogOpen(true)}
|
|
164
|
+
>
|
|
165
|
+
+ Create "{dialogPropertyKey}" property
|
|
166
|
+
</button>
|
|
167
|
+
<PropertyFormDialog
|
|
168
|
+
open={columnPropertyDialogOpen}
|
|
169
|
+
onCancel={() => setColumnPropertyDialogOpen(false)}
|
|
170
|
+
property={{
|
|
171
|
+
dataType: "string",
|
|
172
|
+
name: dialogPropertyName,
|
|
173
|
+
enumValues: [
|
|
174
|
+
{ id: "todo", label: "To Do" },
|
|
175
|
+
{ id: "in_progress", label: "In Progress" },
|
|
176
|
+
{ id: "done", label: "Done" }
|
|
177
|
+
]
|
|
178
|
+
}}
|
|
179
|
+
propertyKey={dialogPropertyKey}
|
|
180
|
+
existingProperty={false}
|
|
181
|
+
autoOpenTypeSelect={false}
|
|
182
|
+
autoUpdateId={false}
|
|
183
|
+
inArray={false}
|
|
184
|
+
allowDataInference={false}
|
|
185
|
+
propertyConfigs={customizationController.propertyConfigs}
|
|
186
|
+
collectionEditable={true}
|
|
187
|
+
existingPropertyKeys={Object.keys(values.properties ?? {})}
|
|
188
|
+
onPropertyChanged={({ id, property }) => {
|
|
189
|
+
const newProperties = {
|
|
190
|
+
...values.properties,
|
|
191
|
+
[id!]: property
|
|
192
|
+
};
|
|
193
|
+
const newPropertiesOrder = [...(values.propertiesOrder ?? Object.keys(values.properties ?? {})), id];
|
|
194
|
+
setFieldValue("properties", newProperties);
|
|
195
|
+
setFieldValue("propertiesOrder", newPropertiesOrder);
|
|
196
|
+
setFieldValue("kanban", {
|
|
197
|
+
...kanbanConfig,
|
|
198
|
+
columnProperty: id
|
|
199
|
+
});
|
|
200
|
+
setColumnPropertyDialogOpen(false);
|
|
201
|
+
}}
|
|
202
|
+
/>
|
|
203
|
+
</>
|
|
204
|
+
)}
|
|
205
|
+
</div>
|
|
206
|
+
);
|
|
207
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cls, SquareIcon, ToggleButtonGroup, Typography, VerticalSplitIcon } from "@firecms/ui";
|
|
2
2
|
|
|
3
3
|
export function LayoutModeSwitch({
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
value,
|
|
5
|
+
onChange,
|
|
6
|
+
className
|
|
7
|
+
}: {
|
|
8
8
|
value: "side_panel" | "full_screen";
|
|
9
9
|
onChange: (value: "side_panel" | "full_screen") => void;
|
|
10
10
|
className?: string;
|
|
@@ -12,42 +12,23 @@ export function LayoutModeSwitch({
|
|
|
12
12
|
|
|
13
13
|
return <div className={cls(className)}>
|
|
14
14
|
<Typography variant={"label"} color={"secondary"} className={"ml-3.5"}>Document view</Typography>
|
|
15
|
-
<div className={
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
15
|
+
<div className={"my-2"}>
|
|
16
|
+
<ToggleButtonGroup
|
|
17
|
+
value={value}
|
|
18
|
+
onValueChange={onChange}
|
|
19
|
+
options={[
|
|
20
|
+
{
|
|
21
|
+
value: "side_panel",
|
|
22
|
+
label: "Side panel",
|
|
23
|
+
icon: <VerticalSplitIcon />
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
value: "full_screen",
|
|
27
|
+
label: "Full screen",
|
|
28
|
+
icon: <SquareIcon />
|
|
29
|
+
}
|
|
30
|
+
]}
|
|
31
|
+
/>
|
|
51
32
|
</div>
|
|
52
33
|
<Typography variant={"caption"} color={"secondary"} className={"ml-3.5"}>Should documents be opened full screen or in an inline side dialog</Typography>
|
|
53
34
|
</div>
|