@firecms/collection_editor 3.0.0-beta.13 → 3.0.0-beta.15
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/README.md +165 -1
- package/dist/ConfigControllerProvider.d.ts +0 -1
- package/dist/index.es.js +1620 -948
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +1616 -947
- package/dist/index.umd.js.map +1 -1
- package/dist/types/collection_editor_controller.d.ts +0 -1
- package/dist/types/collection_inference.d.ts +3 -0
- package/dist/types/config_controller.d.ts +3 -1
- package/dist/ui/EditorEntityAction.d.ts +2 -0
- 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/EntityActionsEditTab.d.ts +4 -0
- package/dist/ui/collection_editor/EntityActionsSelectDialog.d.ts +4 -0
- package/dist/ui/collection_editor/PropertyTree.d.ts +2 -3
- package/dist/ui/collection_editor/properties/ReferencePropertyField.d.ts +2 -1
- package/dist/useCollectionEditorPlugin.d.ts +3 -3
- package/package.json +8 -9
- package/src/ConfigControllerProvider.tsx +0 -5
- package/src/types/collection_editor_controller.tsx +0 -2
- package/src/types/collection_inference.ts +3 -0
- package/src/types/config_controller.tsx +4 -1
- package/src/ui/EditorCollectionAction.tsx +2 -7
- package/src/ui/EditorEntityAction.tsx +51 -0
- package/src/ui/HomePageEditorCollectionAction.tsx +2 -1
- package/src/ui/collection_editor/CollectionDetailsForm.tsx +69 -37
- package/src/ui/collection_editor/CollectionEditorDialog.tsx +18 -5
- package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +15 -25
- package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +8 -6
- package/src/ui/collection_editor/EntityActionsEditTab.tsx +163 -0
- package/src/ui/collection_editor/EntityActionsSelectDialog.tsx +41 -0
- package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +5 -2
- package/src/ui/collection_editor/GetCodeDialog.tsx +5 -3
- package/src/ui/collection_editor/PropertyEditView.tsx +11 -3
- package/src/ui/collection_editor/PropertyFieldPreview.tsx +1 -0
- package/src/ui/collection_editor/PropertyTree.tsx +183 -139
- package/src/ui/collection_editor/UnsavedChangesDialog.tsx +6 -2
- package/src/ui/collection_editor/properties/MapPropertyField.tsx +1 -1
- package/src/ui/collection_editor/properties/ReferencePropertyField.tsx +5 -3
- package/src/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.tsx +2 -0
- package/src/ui/collection_editor/utils/supported_fields.tsx +1 -0
- package/src/ui/collection_editor/utils/update_property_for_widget.ts +9 -0
- package/src/useCollectionEditorPlugin.tsx +12 -7
- package/src/utils/collections.ts +15 -5
|
@@ -4,14 +4,30 @@ import equal from "react-fast-compare"
|
|
|
4
4
|
import {
|
|
5
5
|
AdditionalFieldDelegate,
|
|
6
6
|
CMSType,
|
|
7
|
-
ErrorBoundary,
|
|
8
7
|
isPropertyBuilder,
|
|
9
8
|
PropertiesOrBuilders,
|
|
10
9
|
PropertyOrBuilder
|
|
11
10
|
} from "@firecms/core";
|
|
12
11
|
import { AutorenewIcon, defaultBorderMixin, DragHandleIcon, IconButton, RemoveIcon, Tooltip } from "@firecms/ui";
|
|
13
12
|
import { NonEditablePropertyPreview, PropertyFieldPreview } from "./PropertyFieldPreview";
|
|
14
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
closestCenter,
|
|
15
|
+
DndContext,
|
|
16
|
+
DragEndEvent,
|
|
17
|
+
KeyboardSensor,
|
|
18
|
+
PointerSensor,
|
|
19
|
+
useSensor,
|
|
20
|
+
useSensors
|
|
21
|
+
} from "@dnd-kit/core";
|
|
22
|
+
import {
|
|
23
|
+
SortableContext,
|
|
24
|
+
sortableKeyboardCoordinates,
|
|
25
|
+
useSortable,
|
|
26
|
+
verticalListSortingStrategy
|
|
27
|
+
} from "@dnd-kit/sortable";
|
|
28
|
+
import { restrictToVerticalAxis } from "@dnd-kit/modifiers";
|
|
29
|
+
|
|
30
|
+
import { CSS } from "@dnd-kit/utilities";
|
|
15
31
|
import { getFullId, getFullIdPath } from "./util";
|
|
16
32
|
import { editableProperty } from "../../utils/entities";
|
|
17
33
|
|
|
@@ -48,103 +64,109 @@ export const PropertyTree = React.memo(
|
|
|
48
64
|
|
|
49
65
|
const propertiesOrder = propertiesOrderProp ?? Object.keys(properties);
|
|
50
66
|
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
67
|
+
const sensors = useSensors(
|
|
68
|
+
useSensor(PointerSensor, {
|
|
69
|
+
activationConstraint: {
|
|
70
|
+
distance: 5,
|
|
71
|
+
}
|
|
72
|
+
}),
|
|
73
|
+
useSensor(KeyboardSensor, {
|
|
74
|
+
coordinateGetter: sortableKeyboardCoordinates,
|
|
75
|
+
})
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const handleDragEnd = (event: DragEndEvent) => {
|
|
79
|
+
const {
|
|
80
|
+
active,
|
|
81
|
+
over
|
|
82
|
+
} = event;
|
|
83
|
+
|
|
84
|
+
if (!over || active.id === over.id) {
|
|
54
85
|
return;
|
|
55
86
|
}
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
87
|
+
|
|
88
|
+
const activeId = String(active.id);
|
|
89
|
+
const overId = String(over.id);
|
|
90
|
+
|
|
91
|
+
// Extract property keys from the full IDs
|
|
92
|
+
const activeKey = activeId.includes(".") ? activeId.split(".").pop() : activeId;
|
|
93
|
+
const overKey = overId.includes(".") ? overId.split(".").pop() : overId;
|
|
94
|
+
|
|
95
|
+
if (!activeKey || !overKey) return;
|
|
96
|
+
|
|
97
|
+
const oldIndex = propertiesOrder.indexOf(activeKey);
|
|
98
|
+
const newIndex = propertiesOrder.indexOf(overKey);
|
|
99
|
+
|
|
100
|
+
if (oldIndex !== -1 && newIndex !== -1) {
|
|
101
|
+
const newPropertiesOrder = [...propertiesOrder];
|
|
102
|
+
const [removed] = newPropertiesOrder.splice(oldIndex, 1);
|
|
103
|
+
newPropertiesOrder.splice(newIndex, 0, removed);
|
|
104
|
+
|
|
105
|
+
if (onPropertyMove) {
|
|
106
|
+
onPropertyMove(newPropertiesOrder, namespace);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const items = propertiesOrder.map(key => getFullId(key, namespace));
|
|
65
112
|
|
|
66
113
|
return (
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
{droppableProvided.placeholder}
|
|
114
|
-
|
|
115
|
-
</div>
|
|
116
|
-
)}
|
|
117
|
-
</Droppable>
|
|
118
|
-
</DragDropContext>
|
|
119
|
-
|
|
120
|
-
</>
|
|
114
|
+
<DndContext
|
|
115
|
+
sensors={sensors}
|
|
116
|
+
collisionDetection={closestCenter}
|
|
117
|
+
onDragEnd={handleDragEnd}
|
|
118
|
+
modifiers={[restrictToVerticalAxis]}
|
|
119
|
+
>
|
|
120
|
+
<SortableContext
|
|
121
|
+
items={items}
|
|
122
|
+
strategy={verticalListSortingStrategy}
|
|
123
|
+
>
|
|
124
|
+
<div className={className}>
|
|
125
|
+
|
|
126
|
+
{propertiesOrder && propertiesOrder
|
|
127
|
+
.map((propertyKey: string, index: number) => {
|
|
128
|
+
const property = properties[propertyKey] as PropertyOrBuilder;
|
|
129
|
+
const additionalField = additionalFields?.find(field => field.key === propertyKey);
|
|
130
|
+
|
|
131
|
+
if (!property && !additionalField) {
|
|
132
|
+
console.warn(`Property ${propertyKey} not found in properties or additionalFields`);
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const id = getFullId(propertyKey, namespace);
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<PropertyTreeEntry
|
|
140
|
+
key={id}
|
|
141
|
+
id={id}
|
|
142
|
+
propertyKey={propertyKey}
|
|
143
|
+
propertyOrBuilder={property}
|
|
144
|
+
additionalField={additionalField}
|
|
145
|
+
errors={errors}
|
|
146
|
+
namespace={namespace}
|
|
147
|
+
inferredPropertyKeys={inferredPropertyKeys}
|
|
148
|
+
onPropertyMove={onPropertyMove}
|
|
149
|
+
onPropertyRemove={onPropertyRemove}
|
|
150
|
+
onPropertyClick={onPropertyClick}
|
|
151
|
+
selectedPropertyKey={selectedPropertyKey}
|
|
152
|
+
collectionEditable={collectionEditable}
|
|
153
|
+
/>
|
|
154
|
+
);
|
|
155
|
+
}).filter(Boolean)}
|
|
156
|
+
</div>
|
|
157
|
+
</SortableContext>
|
|
158
|
+
</DndContext>
|
|
121
159
|
);
|
|
122
160
|
},
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const isSelected = nextProps.selectedPropertyKey?.startsWith(nextProps.namespace ?? "");
|
|
126
|
-
const wasSelected = prevProps.selectedPropertyKey?.startsWith(prevProps.namespace ?? "");
|
|
127
|
-
if (isSelected || wasSelected)
|
|
128
|
-
return false;
|
|
129
|
-
|
|
130
|
-
return equal(prevProps.properties, nextProps.properties) &&
|
|
131
|
-
prevProps.propertiesOrder === nextProps.propertiesOrder &&
|
|
132
|
-
equal(prevProps.additionalFields, nextProps.additionalFields) &&
|
|
133
|
-
equal(prevProps.errors, nextProps.errors) &&
|
|
134
|
-
equal(prevProps.onPropertyClick, nextProps.onPropertyClick) &&
|
|
135
|
-
// equal(prevProps.onPropertyMove, nextProps.onPropertyMove) &&
|
|
136
|
-
// equal(prevProps.onPropertyRemove, nextProps.onPropertyRemove) &&
|
|
137
|
-
prevProps.namespace === nextProps.namespace &&
|
|
138
|
-
prevProps.collectionEditable === nextProps.collectionEditable;
|
|
139
|
-
}
|
|
161
|
+
equal
|
|
140
162
|
);
|
|
141
163
|
|
|
142
164
|
export function PropertyTreeEntry({
|
|
165
|
+
id,
|
|
143
166
|
propertyKey,
|
|
144
167
|
namespace,
|
|
145
168
|
propertyOrBuilder,
|
|
146
169
|
additionalField,
|
|
147
|
-
provided,
|
|
148
170
|
selectedPropertyKey,
|
|
149
171
|
errors,
|
|
150
172
|
onPropertyClick,
|
|
@@ -153,12 +175,12 @@ export function PropertyTreeEntry({
|
|
|
153
175
|
inferredPropertyKeys,
|
|
154
176
|
collectionEditable
|
|
155
177
|
}: {
|
|
178
|
+
id: string;
|
|
156
179
|
propertyKey: string;
|
|
157
180
|
namespace?: string;
|
|
158
181
|
propertyOrBuilder: PropertyOrBuilder;
|
|
159
182
|
additionalField?: AdditionalFieldDelegate<any>;
|
|
160
183
|
selectedPropertyKey?: string;
|
|
161
|
-
provided: DraggableProvided;
|
|
162
184
|
errors: Record<string, any>;
|
|
163
185
|
onPropertyClick?: (propertyKey: string, namespace?: string) => void;
|
|
164
186
|
onPropertyMove?: (propertiesOrder: string[], namespace?: string) => void;
|
|
@@ -167,8 +189,27 @@ export function PropertyTreeEntry({
|
|
|
167
189
|
collectionEditable: boolean;
|
|
168
190
|
}) {
|
|
169
191
|
|
|
192
|
+
const {
|
|
193
|
+
attributes,
|
|
194
|
+
listeners,
|
|
195
|
+
setNodeRef,
|
|
196
|
+
transform,
|
|
197
|
+
transition,
|
|
198
|
+
isDragging
|
|
199
|
+
} = useSortable({
|
|
200
|
+
id
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
const style = {
|
|
204
|
+
// Key change: use Translate instead of Transform to prevent stretching
|
|
205
|
+
transform: CSS.Translate.toString(transform),
|
|
206
|
+
transition,
|
|
207
|
+
zIndex: isDragging ? 10 : undefined,
|
|
208
|
+
position: "relative" as const,
|
|
209
|
+
};
|
|
210
|
+
|
|
170
211
|
const isPropertyInferred = inferredPropertyKeys?.includes(namespace ? `${namespace}.${propertyKey}` : propertyKey);
|
|
171
|
-
const fullId =
|
|
212
|
+
const fullId = id;
|
|
172
213
|
const fullIdPath = getFullIdPath(propertyKey, namespace);
|
|
173
214
|
const hasError = fullIdPath in errors;
|
|
174
215
|
|
|
@@ -190,65 +231,68 @@ export function PropertyTreeEntry({
|
|
|
190
231
|
}
|
|
191
232
|
}
|
|
192
233
|
|
|
193
|
-
// const hasError = fullId ? getIn(errors, idToPropertiesPath(fullId)) : false;
|
|
194
234
|
const selected = selectedPropertyKey === fullId;
|
|
195
235
|
const editable = propertyOrBuilder && ((collectionEditable && !isPropertyBuilder(propertyOrBuilder)) || editableProperty(propertyOrBuilder));
|
|
196
236
|
|
|
197
237
|
return (
|
|
198
238
|
<div
|
|
199
|
-
ref={
|
|
200
|
-
{
|
|
201
|
-
{...provided.dragHandleProps}
|
|
239
|
+
ref={setNodeRef}
|
|
240
|
+
style={style}
|
|
202
241
|
className="relative -ml-8"
|
|
203
242
|
>
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
{!isPropertyBuilder(propertyOrBuilder) && !additionalField && editable
|
|
213
|
-
? <PropertyFieldPreview
|
|
214
|
-
property={propertyOrBuilder}
|
|
215
|
-
onClick={onPropertyClick ? () => onPropertyClick(propertyKey, namespace) : undefined}
|
|
216
|
-
includeName={true}
|
|
217
|
-
selected={selected}
|
|
218
|
-
hasError={hasError}/>
|
|
219
|
-
: <NonEditablePropertyPreview name={propertyKey}
|
|
220
|
-
property={propertyOrBuilder}
|
|
221
|
-
onClick={onPropertyClick ? () => onPropertyClick(propertyKey, namespace) : undefined}
|
|
222
|
-
selected={selected}/>}
|
|
223
|
-
|
|
224
|
-
<div className="absolute top-2 right-2 flex flex-row ">
|
|
225
|
-
|
|
226
|
-
{isPropertyInferred && <Tooltip title={"Inferred property"}>
|
|
227
|
-
<AutorenewIcon size="small" className={"p-2"}/>
|
|
228
|
-
</Tooltip>}
|
|
229
|
-
|
|
230
|
-
{onPropertyRemove && <Tooltip title={"Remove"}
|
|
231
|
-
asChild={true}>
|
|
232
|
-
<IconButton size="small"
|
|
233
|
-
color="inherit"
|
|
234
|
-
onClick={() => onPropertyRemove(propertyKey, namespace)}>
|
|
235
|
-
<RemoveIcon size={"small"}/>
|
|
236
|
-
</IconButton>
|
|
237
|
-
</Tooltip>}
|
|
238
|
-
|
|
239
|
-
{onPropertyMove && <Tooltip title={"Move"}
|
|
240
|
-
asChild={true}>
|
|
241
|
-
<IconButton
|
|
242
|
-
component={"span"}
|
|
243
|
-
size="small"
|
|
244
|
-
>
|
|
245
|
-
<DragHandleIcon size={"small"}/>
|
|
246
|
-
</IconButton>
|
|
247
|
-
</Tooltip>}
|
|
248
|
-
</div>
|
|
243
|
+
<div className="relative">
|
|
244
|
+
{subtree && <div
|
|
245
|
+
className={"absolute border-l " + defaultBorderMixin}
|
|
246
|
+
style={{
|
|
247
|
+
left: "32px",
|
|
248
|
+
top: "64px",
|
|
249
|
+
bottom: "16px"
|
|
250
|
+
}}/>}
|
|
249
251
|
|
|
250
|
-
|
|
252
|
+
<div>
|
|
253
|
+
{!isPropertyBuilder(propertyOrBuilder) && !additionalField && editable
|
|
254
|
+
? <PropertyFieldPreview
|
|
255
|
+
property={propertyOrBuilder}
|
|
256
|
+
onClick={onPropertyClick ? () => onPropertyClick(propertyKey, namespace) : undefined}
|
|
257
|
+
includeName={true}
|
|
258
|
+
selected={selected}
|
|
259
|
+
hasError={hasError}/>
|
|
260
|
+
: <NonEditablePropertyPreview name={propertyKey}
|
|
261
|
+
property={propertyOrBuilder}
|
|
262
|
+
onClick={onPropertyClick ? () => onPropertyClick(propertyKey, namespace) : undefined}
|
|
263
|
+
selected={selected}/>}
|
|
264
|
+
</div>
|
|
265
|
+
|
|
266
|
+
<div className="absolute top-2 right-2 flex flex-row">
|
|
267
|
+
{isPropertyInferred && <Tooltip title={"Inferred property"}>
|
|
268
|
+
<AutorenewIcon size="small" className={"p-2"}/>
|
|
269
|
+
</Tooltip>}
|
|
270
|
+
|
|
271
|
+
{onPropertyRemove && !isPropertyInferred && <Tooltip title={"Remove"}
|
|
272
|
+
asChild={true}>
|
|
273
|
+
<IconButton size="small"
|
|
274
|
+
color="inherit"
|
|
275
|
+
onClick={() => onPropertyRemove(propertyKey, namespace)}>
|
|
276
|
+
<RemoveIcon size={"small"}/>
|
|
277
|
+
</IconButton>
|
|
278
|
+
</Tooltip>}
|
|
279
|
+
|
|
280
|
+
{onPropertyMove && <Tooltip title={"Move"}
|
|
281
|
+
asChild={true}>
|
|
282
|
+
<IconButton
|
|
283
|
+
component={"span"}
|
|
284
|
+
size="small"
|
|
285
|
+
{...attributes}
|
|
286
|
+
{...listeners}
|
|
287
|
+
>
|
|
288
|
+
<DragHandleIcon size={"small"}/>
|
|
289
|
+
</IconButton>
|
|
290
|
+
</Tooltip>}
|
|
291
|
+
|
|
292
|
+
</div>
|
|
293
|
+
|
|
294
|
+
{subtree && <div className={"ml-16"}>{subtree}</div>}
|
|
295
|
+
</div>
|
|
251
296
|
</div>
|
|
252
297
|
);
|
|
253
|
-
|
|
254
298
|
}
|
|
@@ -37,8 +37,12 @@ export function UnsavedChangesDialog({
|
|
|
37
37
|
</DialogContent>
|
|
38
38
|
|
|
39
39
|
<DialogActions>
|
|
40
|
-
<Button variant="text"
|
|
41
|
-
|
|
40
|
+
<Button variant="text"
|
|
41
|
+
color={"primary"}
|
|
42
|
+
onClick={handleCancel} autoFocus> Cancel </Button>
|
|
43
|
+
<Button
|
|
44
|
+
color={"primary"}
|
|
45
|
+
onClick={handleOk}> Ok </Button>
|
|
42
46
|
</DialogActions>
|
|
43
47
|
</Dialog>
|
|
44
48
|
);
|
|
@@ -107,7 +107,7 @@ export function MapPropertyField({ disabled, getData, allowDataInference, proper
|
|
|
107
107
|
<div className={"col-span-12"}>
|
|
108
108
|
<BooleanSwitchWithLabel
|
|
109
109
|
position={"start"}
|
|
110
|
-
size={"
|
|
110
|
+
size={"medium"}
|
|
111
111
|
label="Spread children as columns"
|
|
112
112
|
onValueChange={(v) => setFieldValue("spreadChildren", v)}
|
|
113
113
|
value={values.spreadChildren ?? false}
|
|
@@ -7,12 +7,14 @@ export function ReferencePropertyField({
|
|
|
7
7
|
existing,
|
|
8
8
|
multiple,
|
|
9
9
|
disabled,
|
|
10
|
-
showErrors
|
|
10
|
+
showErrors,
|
|
11
|
+
asString
|
|
11
12
|
}: {
|
|
12
13
|
existing: boolean,
|
|
13
14
|
multiple: boolean,
|
|
14
15
|
disabled: boolean,
|
|
15
|
-
showErrors: boolean
|
|
16
|
+
showErrors: boolean,
|
|
17
|
+
asString?: boolean
|
|
16
18
|
}) {
|
|
17
19
|
|
|
18
20
|
const {
|
|
@@ -28,7 +30,7 @@ export function ReferencePropertyField({
|
|
|
28
30
|
<CircularProgress/>
|
|
29
31
|
</div>;
|
|
30
32
|
|
|
31
|
-
const pathPath = multiple ? "of.path" : "path";
|
|
33
|
+
const pathPath = asString ? "reference.path" : (multiple ? "of.path" : "path") ;
|
|
32
34
|
const pathValue: string | undefined = getIn(values, pathPath);
|
|
33
35
|
const pathError: string | undefined = showErrors && getIn(errors, pathPath);
|
|
34
36
|
|
|
@@ -19,6 +19,7 @@ export function AdvancedPropertyValidation({ disabled }: {
|
|
|
19
19
|
{({ field, form }: FormexFieldProps) => {
|
|
20
20
|
return <SwitchControl
|
|
21
21
|
label={"Hide from collection"}
|
|
22
|
+
size={"medium"}
|
|
22
23
|
disabled={disabled}
|
|
23
24
|
form={form}
|
|
24
25
|
tooltip={"Hide this field from the collection view. It will still be visible in the form view"}
|
|
@@ -33,6 +34,7 @@ export function AdvancedPropertyValidation({ disabled }: {
|
|
|
33
34
|
{({ field, form }: FormexFieldProps) => {
|
|
34
35
|
return <SwitchControl
|
|
35
36
|
label={"Read only"}
|
|
37
|
+
size={"medium"}
|
|
36
38
|
disabled={disabled}
|
|
37
39
|
tooltip={"Is this a read only field. Display only as a preview"}
|
|
38
40
|
form={form}
|
|
@@ -208,6 +208,15 @@ export function updatePropertyFromWidget(propertyData: any,
|
|
|
208
208
|
editable: propertyData.editable !== undefined ? propertyData.editable : true
|
|
209
209
|
} satisfies Property
|
|
210
210
|
);
|
|
211
|
+
} else if (selectedWidgetId === "reference_as_string") {
|
|
212
|
+
updatedProperty = mergeDeep(
|
|
213
|
+
propertyData,
|
|
214
|
+
{
|
|
215
|
+
dataType: "string",
|
|
216
|
+
propertyConfig: "reference_as_string",
|
|
217
|
+
editable: propertyData.editable !== undefined ? propertyData.editable : true
|
|
218
|
+
} satisfies Property
|
|
219
|
+
);
|
|
211
220
|
} else if (selectedWidgetId === "multi_references") {
|
|
212
221
|
updatedProperty = mergeDeep(
|
|
213
222
|
propertyData,
|
|
@@ -14,6 +14,7 @@ import { AddIcon, Button, Paper, Typography } from "@firecms/ui";
|
|
|
14
14
|
import { useCollectionEditorController } from "./useCollectionEditorController";
|
|
15
15
|
import { EditorCollectionActionStart } from "./ui/EditorCollectionActionStart";
|
|
16
16
|
import { NewCollectionCard } from "./ui/NewCollectionCard";
|
|
17
|
+
import { EditorEntityAction } from "./ui/EditorEntityAction";
|
|
17
18
|
|
|
18
19
|
export interface CollectionConfigControllerProps<EC extends PersistedCollection = PersistedCollection, USER extends User = User> {
|
|
19
20
|
|
|
@@ -41,8 +42,6 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
|
|
|
41
42
|
icon: React.ReactNode
|
|
42
43
|
};
|
|
43
44
|
|
|
44
|
-
getPathSuggestions?: (path?: string) => Promise<string[]>;
|
|
45
|
-
|
|
46
45
|
collectionInference?: CollectionInference;
|
|
47
46
|
|
|
48
47
|
getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
|
|
@@ -51,6 +50,8 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
|
|
|
51
50
|
|
|
52
51
|
onAnalyticsEvent?: (event: string, params?: object) => void;
|
|
53
52
|
|
|
53
|
+
includeIntroView?: boolean;
|
|
54
|
+
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
/**
|
|
@@ -70,11 +71,11 @@ export function useCollectionEditorPlugin<EC extends PersistedCollection = Persi
|
|
|
70
71
|
configPermissions,
|
|
71
72
|
reservedGroups,
|
|
72
73
|
extraView,
|
|
73
|
-
getPathSuggestions,
|
|
74
74
|
getUser,
|
|
75
75
|
collectionInference,
|
|
76
76
|
getData,
|
|
77
77
|
onAnalyticsEvent,
|
|
78
|
+
includeIntroView = true
|
|
78
79
|
}: CollectionConfigControllerProps<EC, USER>): FireCMSPlugin<any, any, PersistedCollection> {
|
|
79
80
|
|
|
80
81
|
return {
|
|
@@ -88,7 +89,6 @@ export function useCollectionEditorPlugin<EC extends PersistedCollection = Persi
|
|
|
88
89
|
collectionInference,
|
|
89
90
|
reservedGroups,
|
|
90
91
|
extraView,
|
|
91
|
-
getPathSuggestions,
|
|
92
92
|
getUser,
|
|
93
93
|
getData,
|
|
94
94
|
onAnalyticsEvent,
|
|
@@ -96,21 +96,26 @@ export function useCollectionEditorPlugin<EC extends PersistedCollection = Persi
|
|
|
96
96
|
},
|
|
97
97
|
homePage: {
|
|
98
98
|
additionalActions: <NewCollectionButton/>,
|
|
99
|
-
additionalChildrenStart: <IntroWidget
|
|
100
|
-
// additionalChildrenEnd: <RootCollectionSuggestions introMode={introMode}/>,
|
|
99
|
+
additionalChildrenStart: includeIntroView ? <IntroWidget/> : undefined,
|
|
101
100
|
CollectionActions: HomePageEditorCollectionAction,
|
|
102
101
|
AdditionalCards: NewCollectionCard,
|
|
102
|
+
allowDragAndDrop: true,
|
|
103
|
+
navigationEntries: collectionConfigController.navigationEntries,
|
|
104
|
+
onNavigationEntriesUpdate: collectionConfigController.saveNavigationEntries,
|
|
103
105
|
},
|
|
104
106
|
collectionView: {
|
|
105
107
|
CollectionActionsStart: EditorCollectionActionStart,
|
|
106
108
|
CollectionActions: EditorCollectionAction,
|
|
107
109
|
HeaderAction: CollectionViewHeaderAction,
|
|
108
110
|
AddColumnComponent: PropertyAddColumnComponent
|
|
111
|
+
},
|
|
112
|
+
form: {
|
|
113
|
+
ActionsTop: EditorEntityAction,
|
|
109
114
|
}
|
|
110
115
|
};
|
|
111
116
|
}
|
|
112
117
|
|
|
113
|
-
export function IntroWidget(
|
|
118
|
+
export function IntroWidget() {
|
|
114
119
|
|
|
115
120
|
const navigation = useNavigationController();
|
|
116
121
|
if (!navigation.topLevelNavigation)
|
package/src/utils/collections.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
EntityCallbacks,
|
|
2
3
|
EntityCollection,
|
|
3
4
|
joinCollectionLists,
|
|
4
5
|
makePropertiesEditable,
|
|
@@ -25,11 +26,20 @@ export const mergeCollections = (baseCollections: EntityCollection[],
|
|
|
25
26
|
const result = joinCollectionLists(baseCollections, backendCollections, [], modifyCollection);
|
|
26
27
|
|
|
27
28
|
// sort the collections so they are in the same order as the base collections
|
|
28
|
-
result.sort((a, b) =>
|
|
29
|
-
|
|
30
|
-
baseCollections
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
result.sort((a, b) => {
|
|
30
|
+
const indexA = baseCollections.findIndex(c => c.id === a.id);
|
|
31
|
+
const indexB = baseCollections.findIndex(c => c.id === b.id);
|
|
32
|
+
|
|
33
|
+
if (indexA === -1 && indexB === -1) {
|
|
34
|
+
return 0; // Keep original order for items not in baseCollections
|
|
35
|
+
}
|
|
36
|
+
if (indexA === -1) {
|
|
37
|
+
return 1; // a is not in base, so it goes to the end
|
|
38
|
+
}
|
|
39
|
+
if (indexB === -1) {
|
|
40
|
+
return -1; // b is not in base, so it goes to the end
|
|
41
|
+
}
|
|
42
|
+
return indexA - indexB;
|
|
33
43
|
});
|
|
34
44
|
|
|
35
45
|
return result;
|