@firecms/core 3.0.1 → 3.1.0-canary.24c8270
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 +1 -1
- package/dist/components/AIIcon.d.ts +16 -0
- package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +7 -1
- package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +1 -1
- package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +14 -0
- package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +6 -0
- package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +5 -4
- package/dist/components/EntityCollectionTable/internal/EntityTableCell.d.ts +6 -0
- package/dist/components/EntityCollectionTable/internal/popup_field/useDraggable.d.ts +2 -2
- package/dist/components/EntityCollectionView/Board.d.ts +2 -0
- package/dist/components/EntityCollectionView/BoardColumn.d.ts +42 -0
- package/dist/components/EntityCollectionView/BoardColumnTitle.d.ts +9 -0
- package/dist/components/EntityCollectionView/BoardSortableList.d.ts +14 -0
- package/dist/components/EntityCollectionView/EntityBoardCard.d.ts +26 -0
- package/dist/components/EntityCollectionView/EntityCard.d.ts +19 -0
- package/dist/components/EntityCollectionView/EntityCollectionBoardView.d.ts +20 -0
- package/dist/components/EntityCollectionView/EntityCollectionCardView.d.ts +31 -0
- package/dist/components/EntityCollectionView/EntityCollectionViewActions.d.ts +2 -2
- package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +7 -3
- package/dist/components/EntityCollectionView/FiltersDialog.d.ts +14 -0
- package/dist/components/EntityCollectionView/ViewModeToggle.d.ts +44 -0
- package/dist/components/EntityCollectionView/board_types.d.ts +105 -0
- package/dist/components/EntityCollectionView/useBoardDataController.d.ts +60 -0
- package/dist/components/ErrorBoundary.d.ts +1 -1
- package/dist/components/SelectableTable/SelectableTable.d.ts +5 -1
- package/dist/components/SelectableTable/filters/DateTimeFilterField.d.ts +2 -1
- package/dist/components/VirtualTable/VirtualTableCell.d.ts +6 -0
- package/dist/components/VirtualTable/VirtualTableHeader.d.ts +3 -1
- package/dist/components/VirtualTable/VirtualTableHeaderRow.d.ts +1 -1
- package/dist/components/VirtualTable/VirtualTableProps.d.ts +11 -0
- package/dist/components/VirtualTable/fields/VirtualTableDateField.d.ts +1 -0
- package/dist/components/VirtualTable/types.d.ts +2 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/contexts/index.d.ts +10 -0
- package/dist/core/DrawerNavigationGroup.d.ts +45 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/form/components/ErrorFocus.d.ts +1 -1
- package/dist/form/validation.d.ts +3 -2
- package/dist/hooks/useBreadcrumbsController.d.ts +16 -0
- package/dist/hooks/useCollapsedGroups.d.ts +4 -1
- package/dist/index.es.js +5316 -1592
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +5309 -1586
- package/dist/index.umd.js.map +1 -1
- package/dist/internal/useRestoreScroll.d.ts +1 -1
- package/dist/preview/PropertyPreviewProps.d.ts +5 -0
- package/dist/preview/components/DatePreview.d.ts +13 -3
- package/dist/preview/components/ImagePreview.d.ts +5 -1
- package/dist/preview/components/StorageThumbnail.d.ts +2 -1
- package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
- package/dist/preview/property_previews/ArrayOfStorageComponentsPreview.d.ts +1 -1
- package/dist/preview/property_previews/ArrayOfStringsPreview.d.ts +1 -1
- package/dist/preview/property_previews/SkeletonPropertyComponent.d.ts +1 -1
- package/dist/types/analytics.d.ts +1 -1
- package/dist/types/collections.d.ts +50 -2
- package/dist/types/datasource.d.ts +0 -1
- package/dist/types/plugins.d.ts +62 -1
- package/dist/types/properties.d.ts +259 -4
- package/dist/util/__tests__/conditions.test.d.ts +1 -0
- package/dist/util/__tests__/objects.test.d.ts +1 -0
- package/dist/util/conditions.d.ts +26 -0
- package/dist/util/entities.d.ts +2 -3
- package/dist/util/index.d.ts +2 -1
- package/dist/util/property_utils.d.ts +2 -1
- package/dist/util/resolutions.d.ts +3 -3
- package/package.json +14 -11
- package/src/app/Scaffold.tsx +14 -15
- package/src/components/AIIcon.tsx +39 -0
- package/src/components/ArrayContainer.tsx +1 -4
- package/src/components/ClearFilterSortButton.tsx +19 -16
- package/src/components/ConfirmationDialog.tsx +0 -2
- package/src/components/DeleteEntityDialog.tsx +2 -4
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +74 -41
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +130 -79
- package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +121 -104
- package/src/components/EntityCollectionTable/PropertyTableCell.tsx +132 -103
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +20 -42
- package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +90 -49
- package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +1 -1
- package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +11 -11
- package/src/components/EntityCollectionView/Board.tsx +324 -0
- package/src/components/EntityCollectionView/BoardColumn.tsx +158 -0
- package/src/components/EntityCollectionView/BoardColumnTitle.tsx +45 -0
- package/src/components/EntityCollectionView/BoardSortableList.tsx +172 -0
- package/src/components/EntityCollectionView/EntityBoardCard.tsx +212 -0
- package/src/components/EntityCollectionView/EntityCard.tsx +235 -0
- package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +733 -0
- package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +244 -0
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +519 -203
- package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +31 -19
- package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +84 -15
- package/src/components/EntityCollectionView/FiltersDialog.tsx +249 -0
- package/src/components/EntityCollectionView/ViewModeToggle.tsx +199 -0
- package/src/components/EntityCollectionView/board_types.ts +113 -0
- package/src/components/EntityCollectionView/useBoardDataController.tsx +490 -0
- package/src/components/ErrorTooltip.tsx +2 -1
- package/src/components/HomePage/DefaultHomePage.tsx +47 -10
- package/src/components/HomePage/HomePageDnD.tsx +56 -41
- package/src/components/HomePage/NavigationCard.tsx +20 -18
- package/src/components/HomePage/NavigationGroup.tsx +17 -16
- package/src/components/HomePage/RenameGroupDialog.tsx +0 -2
- package/src/components/HomePage/SmallNavigationCard.tsx +10 -9
- package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +3 -10
- package/src/components/ReferenceWidget.tsx +2 -4
- package/src/components/SelectableTable/SelectableTable.tsx +75 -67
- package/src/components/SelectableTable/filters/BooleanFilterField.tsx +7 -6
- package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +39 -40
- package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +38 -38
- package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +49 -58
- package/src/components/UnsavedChangesDialog.tsx +0 -2
- package/src/components/UserDisplay.tsx +4 -4
- package/src/components/VirtualTable/VirtualTable.tsx +272 -118
- package/src/components/VirtualTable/VirtualTableCell.tsx +18 -2
- package/src/components/VirtualTable/VirtualTableHeader.tsx +59 -50
- package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +158 -42
- package/src/components/VirtualTable/VirtualTableProps.tsx +14 -1
- package/src/components/VirtualTable/VirtualTableRow.tsx +1 -1
- package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +3 -0
- package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +19 -6
- package/src/components/VirtualTable/types.tsx +2 -0
- package/src/components/common/useColumnsIds.tsx +95 -3
- package/src/components/common/useDataSourceTableController.tsx +21 -4
- package/src/components/index.tsx +4 -0
- package/src/contexts/BreacrumbsContext.tsx +15 -8
- package/src/contexts/index.ts +10 -0
- package/src/core/DefaultAppBar.tsx +40 -27
- package/src/core/DefaultDrawer.tsx +42 -56
- package/src/core/DrawerNavigationGroup.tsx +118 -0
- package/src/core/DrawerNavigationItem.tsx +4 -3
- package/src/core/EntityEditView.tsx +41 -43
- package/src/core/EntitySidePanel.tsx +28 -26
- package/src/core/SideDialogs.tsx +4 -2
- package/src/core/field_configs.tsx +14 -9
- package/src/core/index.tsx +1 -0
- package/src/form/EntityForm.tsx +69 -60
- package/src/form/PropertyFieldBinding.tsx +61 -46
- package/src/form/components/ErrorFocus.tsx +3 -3
- package/src/form/components/StorageItemPreview.tsx +2 -1
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +0 -1
- package/src/form/field_bindings/DateTimeFieldBinding.tsx +17 -16
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +0 -1
- package/src/form/field_bindings/MapFieldBinding.tsx +69 -67
- package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +22 -18
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +83 -83
- package/src/form/field_bindings/TextFieldBinding.tsx +71 -35
- package/src/form/validation.ts +245 -160
- package/src/hooks/useBreadcrumbsController.tsx +18 -0
- package/src/hooks/useBuildNavigationController.tsx +71 -28
- package/src/hooks/useCollapsedGroups.ts +12 -4
- package/src/hooks/useValidateAuthenticator.tsx +1 -1
- package/src/internal/useBuildDataSource.ts +68 -34
- package/src/internal/useBuildSideDialogsController.tsx +11 -8
- package/src/internal/useBuildSideEntityController.tsx +24 -24
- package/src/internal/useRestoreScroll.tsx +26 -14
- package/src/preview/PropertyPreview.tsx +41 -32
- package/src/preview/PropertyPreviewProps.tsx +6 -0
- package/src/preview/components/DatePreview.tsx +72 -4
- package/src/preview/components/EmptyValue.tsx +1 -1
- package/src/preview/components/ImagePreview.tsx +37 -21
- package/src/preview/components/StorageThumbnail.tsx +16 -12
- package/src/preview/components/UrlComponentPreview.tsx +28 -25
- package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +9 -7
- package/src/preview/property_previews/ArrayOfStringsPreview.tsx +11 -9
- package/src/preview/property_previews/ArrayPropertyPreview.tsx +26 -24
- package/src/preview/property_previews/SkeletonPropertyComponent.tsx +61 -56
- package/src/routes/CustomCMSRoute.tsx +1 -0
- package/src/routes/FireCMSRoute.tsx +26 -13
- package/src/types/analytics.ts +10 -0
- package/src/types/collections.ts +57 -3
- package/src/types/datasource.ts +54 -56
- package/src/types/plugins.tsx +69 -1
- package/src/types/properties.ts +347 -27
- package/src/util/__tests__/conditions.test.ts +506 -0
- package/src/util/__tests__/objects.test.ts +196 -0
- package/src/util/callbacks.ts +6 -3
- package/src/util/collections.ts +51 -6
- package/src/util/conditions.ts +339 -0
- package/src/util/entities.ts +29 -30
- package/src/util/entity_cache.ts +2 -1
- package/src/util/index.ts +2 -1
- package/src/util/join_collections.ts +10 -8
- package/src/util/objects.ts +31 -13
- package/src/util/{references.ts → previews.ts} +16 -2
- package/src/util/property_utils.tsx +37 -11
- package/src/util/resolutions.ts +62 -58
- /package/dist/util/{references.d.ts → previews.d.ts} +0 -0
|
@@ -12,12 +12,12 @@ import { ErrorBoundary } from "../../components";
|
|
|
12
12
|
* @group Preview components
|
|
13
13
|
*/
|
|
14
14
|
export function ArrayPropertyPreview({
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
propertyKey,
|
|
16
|
+
value,
|
|
17
|
+
property: inputProperty,
|
|
18
|
+
// entity,
|
|
19
|
+
size
|
|
20
|
+
}: PropertyPreviewProps<any[]>) {
|
|
21
21
|
|
|
22
22
|
const authController = useAuthController();
|
|
23
23
|
const customizationController = useCustomizationController();
|
|
@@ -28,6 +28,8 @@ export function ArrayPropertyPreview({
|
|
|
28
28
|
authController
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
+
if (!property) return null;
|
|
32
|
+
|
|
31
33
|
if (!property.of) {
|
|
32
34
|
throw Error(`You need to specify an 'of' prop (or specify a custom field) in your array property ${propertyKey}`);
|
|
33
35
|
}
|
|
@@ -45,24 +47,24 @@ export function ArrayPropertyPreview({
|
|
|
45
47
|
<div className="w-full flex flex-col gap-2">
|
|
46
48
|
{values &&
|
|
47
49
|
values.map((value, index) => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
50
|
+
const of: ResolvedProperty = property.resolvedProperties[index] ??
|
|
51
|
+
(property.resolvedProperties[index] ?? (Array.isArray(property.of) ? property.of[index] : property.of));
|
|
52
|
+
return of
|
|
53
|
+
? <React.Fragment
|
|
54
|
+
key={"preview_array_" + index}>
|
|
55
|
+
<div className={cls(defaultBorderMixin, "m-1 border-b last:border-b-0")}>
|
|
56
|
+
<ErrorBoundary>
|
|
57
|
+
<PropertyPreview
|
|
58
|
+
propertyKey={propertyKey}
|
|
59
|
+
// entity={entity}
|
|
60
|
+
value={value}
|
|
61
|
+
property={of}
|
|
62
|
+
size={childSize} />
|
|
63
|
+
</ErrorBoundary>
|
|
64
|
+
</div>
|
|
65
|
+
</React.Fragment>
|
|
66
|
+
: null;
|
|
67
|
+
}
|
|
66
68
|
)}
|
|
67
69
|
</div>
|
|
68
70
|
);
|
|
@@ -19,9 +19,9 @@ export interface SkeletonPropertyComponentProps {
|
|
|
19
19
|
* @group Preview components
|
|
20
20
|
*/
|
|
21
21
|
export function SkeletonPropertyComponent({
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
property,
|
|
23
|
+
size
|
|
24
|
+
}: SkeletonPropertyComponentProps
|
|
25
25
|
) {
|
|
26
26
|
|
|
27
27
|
if (!property) {
|
|
@@ -101,7 +101,7 @@ function renderMap<T extends Record<string, any>>(property: ResolvedMapProperty<
|
|
|
101
101
|
{property.properties && property.properties[key] &&
|
|
102
102
|
<SkeletonPropertyComponent
|
|
103
103
|
property={property.properties[key]}
|
|
104
|
-
size={"medium"}/>}
|
|
104
|
+
size={"medium"} />}
|
|
105
105
|
</div>
|
|
106
106
|
))}
|
|
107
107
|
</div>
|
|
@@ -110,29 +110,29 @@ function renderMap<T extends Record<string, any>>(property: ResolvedMapProperty<
|
|
|
110
110
|
return (
|
|
111
111
|
<table className="table-auto">
|
|
112
112
|
<tbody>
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
113
|
+
{mapPropertyKeys &&
|
|
114
|
+
mapPropertyKeys.map((key, index) => {
|
|
115
|
+
return (
|
|
116
|
+
<tr
|
|
117
|
+
key={`map_preview_table__${index}`}
|
|
118
|
+
className="border-b last:border-b-0">
|
|
119
|
+
<th key={`table-cell-title--${key}`}
|
|
120
|
+
className="align-top"
|
|
121
|
+
style={{ width: "30%" }}>
|
|
122
|
+
<p className="text-xs text-secondary">
|
|
123
|
+
{property.properties![key].name}
|
|
124
|
+
</p>
|
|
125
|
+
</th>
|
|
126
|
+
<th key={`table-cell-${key}`}
|
|
127
|
+
style={{ width: "70%" }}>
|
|
128
|
+
{property.properties && property.properties[key] &&
|
|
129
|
+
<SkeletonPropertyComponent
|
|
130
|
+
property={property.properties[key]}
|
|
131
|
+
size={"medium"} />}
|
|
132
|
+
</th>
|
|
133
|
+
</tr>
|
|
134
|
+
);
|
|
135
|
+
})}
|
|
136
136
|
</tbody>
|
|
137
137
|
</table>
|
|
138
138
|
);
|
|
@@ -149,24 +149,24 @@ function renderArrayOfMaps<M extends Record<string, any>>(properties: ResolvedPr
|
|
|
149
149
|
return (
|
|
150
150
|
<table className="table-auto">
|
|
151
151
|
<tbody>
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
152
|
+
{
|
|
153
|
+
[0, 1, 2].map((value, index) => {
|
|
154
|
+
return (
|
|
155
|
+
<tr key={`table_${value}_${index}`}>
|
|
156
|
+
{tableProperties && tableProperties.map(
|
|
157
|
+
(key) => (
|
|
158
|
+
<th
|
|
159
|
+
key={`table-cell-${key}`}
|
|
160
|
+
>
|
|
161
|
+
<SkeletonPropertyComponent
|
|
162
|
+
property={(properties)[key]}
|
|
163
|
+
size={"medium"} />
|
|
164
|
+
</th>
|
|
165
|
+
)
|
|
166
|
+
)}
|
|
167
|
+
</tr>
|
|
168
|
+
);
|
|
169
|
+
})}
|
|
170
170
|
</tbody>
|
|
171
171
|
</table>
|
|
172
172
|
);
|
|
@@ -203,14 +203,14 @@ function renderGenericArrayCell(
|
|
|
203
203
|
return (
|
|
204
204
|
|
|
205
205
|
<div key={"array_index_" + index}
|
|
206
|
-
|
|
206
|
+
className={"flex flex-col gap-2"}>
|
|
207
207
|
|
|
208
208
|
{
|
|
209
209
|
[0, 1].map((value, index) =>
|
|
210
210
|
<>
|
|
211
211
|
<SkeletonPropertyComponent key={`i_${index}`}
|
|
212
|
-
|
|
213
|
-
|
|
212
|
+
property={property}
|
|
213
|
+
size={"medium"} />
|
|
214
214
|
</>
|
|
215
215
|
)}
|
|
216
216
|
</div>
|
|
@@ -220,16 +220,21 @@ function renderGenericArrayCell(
|
|
|
220
220
|
function renderUrlAudioComponent() {
|
|
221
221
|
return (
|
|
222
222
|
<Skeleton width={300}
|
|
223
|
-
|
|
223
|
+
height={100} />
|
|
224
224
|
);
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
export function renderSkeletonImageThumbnail(size: PreviewSize) {
|
|
227
|
+
export function renderSkeletonImageThumbnail(size: PreviewSize, fill?: boolean) {
|
|
228
|
+
if (fill) {
|
|
229
|
+
return (
|
|
230
|
+
<Skeleton className="w-full h-full" />
|
|
231
|
+
);
|
|
232
|
+
}
|
|
228
233
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
229
234
|
const imageSize = size === "small" ? 40 : size === "medium" ? 100 : 200;
|
|
230
235
|
return (
|
|
231
236
|
<Skeleton width={imageSize}
|
|
232
|
-
|
|
237
|
+
height={imageSize} />
|
|
233
238
|
);
|
|
234
239
|
}
|
|
235
240
|
|
|
@@ -237,12 +242,12 @@ function renderUrlVideo(size: PreviewSize) {
|
|
|
237
242
|
|
|
238
243
|
return (
|
|
239
244
|
<Skeleton width={size !== "large" ? 300 : 500}
|
|
240
|
-
|
|
245
|
+
height={size !== "large" ? 200 : 250} />
|
|
241
246
|
);
|
|
242
247
|
}
|
|
243
248
|
|
|
244
249
|
function renderReference() {
|
|
245
|
-
return <Skeleton width={200} height={100}/>;
|
|
250
|
+
return <Skeleton width={200} height={100} />;
|
|
246
251
|
}
|
|
247
252
|
|
|
248
253
|
function renderUrlComponent(property: ResolvedStringProperty, size: PreviewSize = "large") {
|
|
@@ -270,14 +275,14 @@ function renderUrlFile(size: PreviewSize) {
|
|
|
270
275
|
}
|
|
271
276
|
|
|
272
277
|
export function renderSkeletonText(index?: number, width = 120) {
|
|
273
|
-
return <Skeleton width={width} key={`skeleton_${index}`}/>;
|
|
278
|
+
return <Skeleton width={width} key={`skeleton_${index}`} />;
|
|
274
279
|
}
|
|
275
280
|
|
|
276
281
|
export function renderSkeletonCaptionText(index?: number) {
|
|
277
282
|
return <Skeleton
|
|
278
|
-
height={20}/>;
|
|
283
|
+
height={20} />;
|
|
279
284
|
}
|
|
280
285
|
|
|
281
286
|
export function renderSkeletonIcon() {
|
|
282
|
-
return <Skeleton width={24} height={24}/>;
|
|
287
|
+
return <Skeleton width={24} height={24} />;
|
|
283
288
|
}
|
|
@@ -35,22 +35,34 @@ export function FireCMSRoute() {
|
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
useEffect(() => {
|
|
38
|
+
const lastEntry = navigationEntries[navigationEntries.length - 1];
|
|
39
|
+
const isViewingCollection = lastEntry?.type === "collection";
|
|
40
|
+
|
|
38
41
|
breadcrumbs.set({
|
|
39
|
-
breadcrumbs: navigationEntries.map(entry => {
|
|
42
|
+
breadcrumbs: navigationEntries.map((entry, index) => {
|
|
43
|
+
const isLastEntry = index === navigationEntries.length - 1;
|
|
44
|
+
|
|
40
45
|
if (entry.type === "entity") {
|
|
41
46
|
return ({
|
|
42
47
|
title: entry.entityId,
|
|
43
48
|
url: navigation.buildUrlCollectionPath(entry.fullPath)
|
|
49
|
+
// count: undefined (not applicable for entities)
|
|
44
50
|
});
|
|
45
51
|
} else if (entry.type === "custom_view") {
|
|
46
52
|
return ({
|
|
47
53
|
title: entry.view.name,
|
|
48
54
|
url: navigation.buildUrlCollectionPath(entry.fullPath)
|
|
55
|
+
// count: undefined (not applicable for custom views)
|
|
49
56
|
});
|
|
50
57
|
} else if (entry.type === "collection") {
|
|
58
|
+
// Only show count badge (loading state) when viewing this collection directly
|
|
59
|
+
// Don't show count for parent collections when viewing an entity
|
|
60
|
+
const showCount = isLastEntry && isViewingCollection;
|
|
51
61
|
return ({
|
|
52
62
|
title: entry.collection.name,
|
|
53
|
-
url: navigation.buildUrlCollectionPath(entry.fullPath)
|
|
63
|
+
url: navigation.buildUrlCollectionPath(entry.fullPath),
|
|
64
|
+
id: entry.fullPath,
|
|
65
|
+
...(showCount ? { count: null } : {}) // null = loading, undefined = no badge
|
|
54
66
|
});
|
|
55
67
|
} else {
|
|
56
68
|
throw new Error("Unexpected navigation entry type");
|
|
@@ -59,6 +71,7 @@ export function FireCMSRoute() {
|
|
|
59
71
|
});
|
|
60
72
|
}, [navigationEntries.map(entry => entry.path).join(",")]);
|
|
61
73
|
|
|
74
|
+
|
|
62
75
|
if (isNew) {
|
|
63
76
|
return <EntityFullScreenRoute
|
|
64
77
|
pathname={pathname}
|
|
@@ -83,7 +96,7 @@ export function FireCMSRoute() {
|
|
|
83
96
|
fullIdPath={collection.id}
|
|
84
97
|
updateUrl={true}
|
|
85
98
|
{...collection}
|
|
86
|
-
Actions={toArray(collection.Actions)}/>
|
|
99
|
+
Actions={toArray(collection.Actions)} />
|
|
87
100
|
}
|
|
88
101
|
|
|
89
102
|
if (isSidePanel) {
|
|
@@ -104,7 +117,7 @@ export function FireCMSRoute() {
|
|
|
104
117
|
fullPath={collection.path}
|
|
105
118
|
updateUrl={true}
|
|
106
119
|
{...collection}
|
|
107
|
-
Actions={toArray(collection.Actions)}/>;
|
|
120
|
+
Actions={toArray(collection.Actions)} />;
|
|
108
121
|
}
|
|
109
122
|
}
|
|
110
123
|
|
|
@@ -131,11 +144,11 @@ function getSelectedTabFromUrl(isNew: boolean, lastCustomView: NavigationViewCol
|
|
|
131
144
|
}
|
|
132
145
|
|
|
133
146
|
function EntityFullScreenRoute({
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
147
|
+
pathname,
|
|
148
|
+
navigationEntries,
|
|
149
|
+
isNew,
|
|
150
|
+
isCopy
|
|
151
|
+
}: {
|
|
139
152
|
pathname: string;
|
|
140
153
|
navigationEntries: NavigationViewInternal[],
|
|
141
154
|
isNew: boolean,
|
|
@@ -178,8 +191,8 @@ function EntityFullScreenRoute({
|
|
|
178
191
|
let blocker: Blocker | undefined = undefined;
|
|
179
192
|
try {
|
|
180
193
|
blocker = useBlocker(({
|
|
181
|
-
|
|
182
|
-
|
|
194
|
+
nextLocation
|
|
195
|
+
}) => {
|
|
183
196
|
if (nextLocation.pathname.startsWith(entityPath))
|
|
184
197
|
return false;
|
|
185
198
|
return blocked.current;
|
|
@@ -195,7 +208,7 @@ function EntityFullScreenRoute({
|
|
|
195
208
|
}
|
|
196
209
|
|
|
197
210
|
if (!isNew && !lastEntityEntry) {
|
|
198
|
-
return <NotFoundPage/>;
|
|
211
|
+
return <NotFoundPage />;
|
|
199
212
|
}
|
|
200
213
|
|
|
201
214
|
const collection = isNew ? lastCollectionEntry!.collection : lastEntityEntry!.parentCollection;
|
|
@@ -240,7 +253,7 @@ function EntityFullScreenRoute({
|
|
|
240
253
|
open={blocker?.state === "blocked"}
|
|
241
254
|
handleOk={() => blocker?.proceed?.()}
|
|
242
255
|
handleCancel={() => blocker?.reset?.()}
|
|
243
|
-
body={"You have unsaved changes in this entity."}/>
|
|
256
|
+
body={"You have unsaved changes in this entity."} />
|
|
244
257
|
|
|
245
258
|
</>;
|
|
246
259
|
}
|
package/src/types/analytics.ts
CHANGED
|
@@ -34,5 +34,15 @@ export type CMSAnalyticsEvent =
|
|
|
34
34
|
|
|
35
35
|
| "collection_inline_editing"
|
|
36
36
|
|
|
37
|
+
| "view_mode_changed"
|
|
38
|
+
|
|
39
|
+
| "kanban_card_moved"
|
|
40
|
+
| "kanban_column_reorder"
|
|
41
|
+
| "kanban_property_changed"
|
|
42
|
+
| "kanban_new_entity_in_column"
|
|
43
|
+
| "kanban_backfill_order"
|
|
44
|
+
|
|
45
|
+
| "card_view_entity_click"
|
|
46
|
+
|
|
37
47
|
| "unmapped_event"
|
|
38
48
|
;
|
package/src/types/collections.ts
CHANGED
|
@@ -364,8 +364,61 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
|
|
|
364
364
|
* Defaults to `manual_apply`.
|
|
365
365
|
*/
|
|
366
366
|
localChangesBackup?: "manual_apply" | "auto_apply" | false;
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Default view mode for displaying this collection.
|
|
370
|
+
* - "table": Display entities in a spreadsheet-like table (default)
|
|
371
|
+
* - "cards": Display entities as a grid of cards with thumbnails
|
|
372
|
+
* - "kanban": Display entities in a Kanban board grouped by a property
|
|
373
|
+
* Defaults to "table".
|
|
374
|
+
*/
|
|
375
|
+
defaultViewMode?: ViewMode;
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Which view modes are available for this collection.
|
|
379
|
+
* Possible values: "table", "cards", "kanban".
|
|
380
|
+
* Defaults to all three: ["table", "cards", "kanban"].
|
|
381
|
+
* Note: "kanban" will only be available if the collection has at least
|
|
382
|
+
* one string property with enumValues defined, regardless of this setting.
|
|
383
|
+
*/
|
|
384
|
+
enabledViews?: ViewMode[];
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Configuration for Kanban board view mode.
|
|
388
|
+
* When set, the Kanban view mode becomes available.
|
|
389
|
+
*/
|
|
390
|
+
kanban?: KanbanConfig<M>;
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Property key to use for ordering items.
|
|
394
|
+
* Must reference a number property. When items are reordered,
|
|
395
|
+
* this property will be updated to reflect the new order using
|
|
396
|
+
* fractional indexing. Used by Kanban view for ordering within columns
|
|
397
|
+
* and can be used for general ordering purposes.
|
|
398
|
+
*/
|
|
399
|
+
orderProperty?: Extract<keyof M, string>;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Configuration for Kanban board view mode.
|
|
404
|
+
* @group Collections
|
|
405
|
+
*/
|
|
406
|
+
export interface KanbanConfig<M extends Record<string, any> = any> {
|
|
407
|
+
/**
|
|
408
|
+
* Property key to use for Kanban board columns.
|
|
409
|
+
* Must reference a string property with enumValues defined.
|
|
410
|
+
* Entities will be grouped into columns based on this property's value.
|
|
411
|
+
* The column order is determined by the order of enumValues in the property.
|
|
412
|
+
*/
|
|
413
|
+
columnProperty: Extract<keyof M, string>;
|
|
367
414
|
}
|
|
368
415
|
|
|
416
|
+
/**
|
|
417
|
+
* View mode for displaying a collection.
|
|
418
|
+
* @group Collections
|
|
419
|
+
*/
|
|
420
|
+
export type ViewMode = "table" | "cards" | "kanban";
|
|
421
|
+
|
|
369
422
|
/**
|
|
370
423
|
* Parameter passed to the `Actions` prop in the collection configuration.
|
|
371
424
|
* The component will receive this prop when it is rendered in the collection
|
|
@@ -413,9 +466,10 @@ export interface CollectionActionsProps<M extends Record<string, any> = any, USE
|
|
|
413
466
|
context: FireCMSContext<USER>;
|
|
414
467
|
|
|
415
468
|
/**
|
|
416
|
-
* Count of the entities in this collection
|
|
469
|
+
* Count of the entities in this collection.
|
|
470
|
+
* undefined means the count is still loading.
|
|
417
471
|
*/
|
|
418
|
-
collectionEntitiesCount
|
|
472
|
+
collectionEntitiesCount?: number;
|
|
419
473
|
|
|
420
474
|
}
|
|
421
475
|
|
|
@@ -647,7 +701,7 @@ export type EntityTableController<M extends Record<string, any> = any> = {
|
|
|
647
701
|
paginationEnabled?: boolean;
|
|
648
702
|
pageSize?: number;
|
|
649
703
|
checkFilterCombination?: (filterValues: FilterValues<any>,
|
|
650
|
-
|
|
704
|
+
sortBy?: [string, "asc" | "desc"]) => boolean;
|
|
651
705
|
popupCell?: SelectedCellProps<M>;
|
|
652
706
|
setPopupCell?: (popupCell?: SelectedCellProps<M>) => void;
|
|
653
707
|
|
package/src/types/datasource.ts
CHANGED
|
@@ -19,9 +19,9 @@ export interface FetchEntityProps<M extends Record<string, any> = any> {
|
|
|
19
19
|
export type ListenEntityProps<M extends Record<string, any> = any> =
|
|
20
20
|
FetchEntityProps<M>
|
|
21
21
|
& {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
22
|
+
onUpdate: (entity: Entity<M>) => void,
|
|
23
|
+
onError?: (error: Error) => void,
|
|
24
|
+
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* @group Datasource
|
|
@@ -88,15 +88,15 @@ export interface DataSource {
|
|
|
88
88
|
* @see useCollectionFetch if you need this functionality implemented as a hook
|
|
89
89
|
*/
|
|
90
90
|
fetchCollection<M extends Record<string, any> = any>({
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
91
|
+
path,
|
|
92
|
+
collection,
|
|
93
|
+
filter,
|
|
94
|
+
limit,
|
|
95
|
+
startAfter,
|
|
96
|
+
orderBy,
|
|
97
|
+
order,
|
|
98
|
+
searchString
|
|
99
|
+
}: FetchCollectionProps<M>
|
|
100
100
|
): Promise<Entity<M>[]>;
|
|
101
101
|
|
|
102
102
|
/**
|
|
@@ -137,11 +137,11 @@ export interface DataSource {
|
|
|
137
137
|
* @param collection
|
|
138
138
|
*/
|
|
139
139
|
fetchEntity<M extends Record<string, any> = any>({
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
140
|
+
path,
|
|
141
|
+
entityId,
|
|
142
|
+
databaseId,
|
|
143
|
+
collection
|
|
144
|
+
}: FetchEntityProps<M>
|
|
145
145
|
): Promise<Entity<M> | undefined>;
|
|
146
146
|
|
|
147
147
|
/**
|
|
@@ -154,12 +154,12 @@ export interface DataSource {
|
|
|
154
154
|
* @return Function to cancel subscription
|
|
155
155
|
*/
|
|
156
156
|
listenEntity?<M extends Record<string, any> = any>({
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
157
|
+
path,
|
|
158
|
+
entityId,
|
|
159
|
+
collection,
|
|
160
|
+
onUpdate,
|
|
161
|
+
onError
|
|
162
|
+
}: ListenEntityProps<M>): () => void;
|
|
163
163
|
|
|
164
164
|
/**
|
|
165
165
|
* Save entity to the specified path
|
|
@@ -274,14 +274,14 @@ export interface DataSourceDelegate {
|
|
|
274
274
|
* @see useCollectionFetch if you need this functionality implemented as a hook
|
|
275
275
|
*/
|
|
276
276
|
fetchCollection<M extends Record<string, any> = any>({
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
277
|
+
path,
|
|
278
|
+
filter,
|
|
279
|
+
limit,
|
|
280
|
+
startAfter,
|
|
281
|
+
orderBy,
|
|
282
|
+
order,
|
|
283
|
+
searchString
|
|
284
|
+
}: FetchCollectionDelegateProps<M>): Promise<Entity<M>[]>;
|
|
285
285
|
|
|
286
286
|
/**
|
|
287
287
|
* Listen to a collection in a given path. If you don't implement this method
|
|
@@ -299,16 +299,16 @@ export interface DataSourceDelegate {
|
|
|
299
299
|
* @see useCollectionFetch if you need this functionality implemented as a hook
|
|
300
300
|
*/
|
|
301
301
|
listenCollection?<M extends Record<string, any> = any>({
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
302
|
+
path,
|
|
303
|
+
filter,
|
|
304
|
+
limit,
|
|
305
|
+
startAfter,
|
|
306
|
+
searchString,
|
|
307
|
+
orderBy,
|
|
308
|
+
order,
|
|
309
|
+
onUpdate,
|
|
310
|
+
onError
|
|
311
|
+
}: ListenCollectionDelegateProps<M>): () => void;
|
|
312
312
|
|
|
313
313
|
/**
|
|
314
314
|
* Retrieve an entity given a path and a collection
|
|
@@ -316,9 +316,9 @@ export interface DataSourceDelegate {
|
|
|
316
316
|
* @param entityId
|
|
317
317
|
*/
|
|
318
318
|
fetchEntity<M extends Record<string, any> = any>({
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
319
|
+
path,
|
|
320
|
+
entityId,
|
|
321
|
+
}: FetchEntityProps<M>): Promise<Entity<M> | undefined>;
|
|
322
322
|
|
|
323
323
|
/**
|
|
324
324
|
* Get realtime updates on one entity.
|
|
@@ -330,11 +330,11 @@ export interface DataSourceDelegate {
|
|
|
330
330
|
* @return Function to cancel subscription
|
|
331
331
|
*/
|
|
332
332
|
listenEntity?<M extends Record<string, any> = any>({
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
333
|
+
path,
|
|
334
|
+
entityId,
|
|
335
|
+
onUpdate,
|
|
336
|
+
onError
|
|
337
|
+
}: ListenEntityProps<M>): () => void;
|
|
338
338
|
|
|
339
339
|
/**
|
|
340
340
|
* Save entity to the specified path
|
|
@@ -344,11 +344,11 @@ export interface DataSourceDelegate {
|
|
|
344
344
|
* @param status
|
|
345
345
|
*/
|
|
346
346
|
saveEntity<M extends Record<string, any> = any>({
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
347
|
+
path,
|
|
348
|
+
entityId,
|
|
349
|
+
values,
|
|
350
|
+
status
|
|
351
|
+
}: SaveEntityDelegateProps<M>): Promise<Entity<M>>;
|
|
352
352
|
|
|
353
353
|
/**
|
|
354
354
|
* Delete an entity
|
|
@@ -395,8 +395,6 @@ export interface DataSourceDelegate {
|
|
|
395
395
|
|
|
396
396
|
cmsToDelegateModel: (data: any) => any;
|
|
397
397
|
|
|
398
|
-
setDateToMidnight: (input?: any) => any;
|
|
399
|
-
|
|
400
398
|
initTextSearch?: (props: {
|
|
401
399
|
context: FireCMSContext,
|
|
402
400
|
path: string,
|