@firecms/core 3.1.0-canary.9e89e98 → 3.1.0

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 (43) hide show
  1. package/dist/components/EntityCollectionTable/internal/popup_field/useDraggable.d.ts +2 -2
  2. package/dist/components/ErrorBoundary.d.ts +1 -1
  3. package/dist/components/VirtualTable/VirtualTableHeader.d.ts +1 -1
  4. package/dist/form/components/ErrorFocus.d.ts +1 -1
  5. package/dist/index.es.js +118 -54
  6. package/dist/index.es.js.map +1 -1
  7. package/dist/index.umd.js +118 -54
  8. package/dist/index.umd.js.map +1 -1
  9. package/dist/internal/useRestoreScroll.d.ts +1 -1
  10. package/dist/types/analytics.d.ts +1 -1
  11. package/dist/types/plugins.d.ts +16 -0
  12. package/dist/util/entities.d.ts +1 -1
  13. package/dist/util/resolutions.d.ts +2 -2
  14. package/package.json +9 -9
  15. package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +1 -1
  16. package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +11 -11
  17. package/src/components/EntityCollectionView/EntityBoardCard.tsx +1 -1
  18. package/src/components/EntityCollectionView/EntityCard.tsx +4 -0
  19. package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +23 -3
  20. package/src/components/EntityCollectionView/EntityCollectionView.tsx +32 -3
  21. package/src/components/VirtualTable/VirtualTable.tsx +116 -113
  22. package/src/components/VirtualTable/VirtualTableHeader.tsx +42 -42
  23. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +1 -1
  24. package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +3 -3
  25. package/src/core/DefaultAppBar.tsx +1 -1
  26. package/src/core/EntitySidePanel.tsx +28 -26
  27. package/src/core/field_configs.tsx +14 -9
  28. package/src/form/EntityForm.tsx +69 -60
  29. package/src/form/PropertyFieldBinding.tsx +3 -3
  30. package/src/form/components/ErrorFocus.tsx +3 -3
  31. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +1 -1
  32. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +83 -83
  33. package/src/hooks/useBuildNavigationController.tsx +4 -4
  34. package/src/hooks/useValidateAuthenticator.tsx +1 -1
  35. package/src/internal/useBuildDataSource.ts +1 -2
  36. package/src/preview/PropertyPreview.tsx +1 -0
  37. package/src/types/analytics.ts +10 -0
  38. package/src/types/plugins.tsx +18 -0
  39. package/src/util/entities.ts +1 -1
  40. package/src/util/join_collections.ts +10 -8
  41. package/src/util/previews.ts +2 -2
  42. package/src/util/property_utils.tsx +1 -1
  43. package/src/util/resolutions.ts +5 -3
package/dist/index.umd.js CHANGED
@@ -785,7 +785,7 @@
785
785
  const defaultValues = getDefaultValuesFor(collection.properties);
786
786
  const usedValues = values ?? defaultValues;
787
787
  const usedPreviousValues = previousValues ?? values ?? defaultValues;
788
- const resolvedProperties = Object.entries(collection.properties).map(([key, propertyOrBuilder]) => {
788
+ const resolvedProperties = Object.entries(collection.properties).filter(([, propertyOrBuilder]) => propertyOrBuilder != null).map(([key, propertyOrBuilder]) => {
789
789
  const childResolvedProperty = resolveProperty({
790
790
  propertyKey: key,
791
791
  propertyOrBuilder,
@@ -824,7 +824,7 @@
824
824
  ignoreMissingFields = false,
825
825
  ...props
826
826
  }) {
827
- if (typeof propertyOrBuilder === "object" && "resolved" in propertyOrBuilder) {
827
+ if (propertyOrBuilder !== null && typeof propertyOrBuilder === "object" && "resolved" in propertyOrBuilder) {
828
828
  return propertyOrBuilder;
829
829
  }
830
830
  let resolvedProperty = null;
@@ -3824,6 +3824,8 @@
3824
3824
  return resultCollection;
3825
3825
  }
3826
3826
  function mergePropertyOrBuilder(target, source) {
3827
+ if (!source) return target;
3828
+ if (!target) return source;
3827
3829
  if (isPropertyBuilder(source)) {
3828
3830
  return source;
3829
3831
  } else if (isPropertyBuilder(target)) {
@@ -7577,7 +7579,7 @@
7577
7579
  } else {
7578
7580
  if (property.dataType === "map") {
7579
7581
  if (typeof value === "object") {
7580
- content = /* @__PURE__ */ jsxRuntime.jsx(MapPropertyPreview, { ...props, property });
7582
+ content = /* @__PURE__ */ jsxRuntime.jsx(MapPropertyPreview, { ...props, value, property });
7581
7583
  } else {
7582
7584
  content = buildWrongValueType(propertyKey, property.dataType, value);
7583
7585
  }
@@ -8461,7 +8463,7 @@
8461
8463
  const handleOpenChange = t4;
8462
8464
  let t5;
8463
8465
  if ($[11] !== disabled || $[12] !== enumValues || $[13] !== internalValue || $[14] !== multiple || $[15] !== onChange || $[16] !== renderValue || $[17] !== small || $[18] !== validValue) {
8464
- t5 = multiple ? /* @__PURE__ */ jsxRuntime.jsx(ui.MultiSelect, { inputRef: ref, className: "w-full h-full p-0 bg-transparent", position: "item-aligned", disabled, includeClear: false, useChips: false, value: validValue ? internalValue.map(_temp2$b) : [], onValueChange: onChange, onOpenChange: handleOpenChange, children: enumValues?.map((enumConfig) => /* @__PURE__ */ jsxRuntime.jsx(ui.MultiSelectItem, { value: String(enumConfig.id), children: /* @__PURE__ */ jsxRuntime.jsx(EnumValuesChip, { enumKey: enumConfig.id, enumValues, size: small ? "small" : "medium" }) }, enumConfig.id)) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Select, { inputRef: ref, size: "large", fullWidth: true, className: "w-full h-full p-0 bg-transparent", inputClassName: "focus:ring-0 focus-visible:ring-0 outline-none focus:outline-none focus-visible:outline-none", position: "item-aligned", disabled, padding: false, value: validValue ? internalValue?.toString() : "", onValueChange: onChange, onOpenChange: handleOpenChange, renderValue, children: enumValues?.map((enumConfig_0) => /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: String(enumConfig_0.id), children: /* @__PURE__ */ jsxRuntime.jsx(EnumValuesChip, { enumKey: enumConfig_0.id, enumValues, size: small ? "small" : "medium" }) }, enumConfig_0.id)) });
8466
+ t5 = multiple ? /* @__PURE__ */ jsxRuntime.jsx(ui.MultiSelect, { inputRef: ref, className: "w-full h-full p-0 bg-transparent outline-none", position: "item-aligned", disabled, includeClear: false, useChips: false, value: validValue ? internalValue.map(_temp2$b) : [], onValueChange: onChange, onOpenChange: handleOpenChange, children: enumValues?.map((enumConfig) => /* @__PURE__ */ jsxRuntime.jsx(ui.MultiSelectItem, { value: String(enumConfig.id), children: /* @__PURE__ */ jsxRuntime.jsx(EnumValuesChip, { enumKey: enumConfig.id, enumValues, size: small ? "small" : "medium" }) }, enumConfig.id)) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Select, { inputRef: ref, size: "large", fullWidth: true, className: "w-full h-full p-0 bg-transparent outline-none [&_button]:ring-0 [&_button]:ring-offset-0", inputClassName: "ring-0 ring-offset-0 focus:ring-0 focus-visible:ring-0 outline-none focus:outline-none focus-visible:outline-none focus-visible:ring-offset-0", position: "item-aligned", disabled, padding: false, value: validValue ? internalValue?.toString() : "", onValueChange: onChange, onOpenChange: handleOpenChange, renderValue, children: enumValues?.map((enumConfig_0) => /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: String(enumConfig_0.id), children: /* @__PURE__ */ jsxRuntime.jsx(EnumValuesChip, { enumKey: enumConfig_0.id, enumValues, size: small ? "small" : "medium" }) }, enumConfig_0.id)) });
8465
8467
  $[11] = disabled;
8466
8468
  $[12] = enumValues;
8467
8469
  $[13] = internalValue;
@@ -9021,7 +9023,7 @@
9021
9023
  openPopup(cellRect);
9022
9024
  }
9023
9025
  }, []);
9024
- const iconRef = React.useRef();
9026
+ const iconRef = React.useRef(void 0);
9025
9027
  React.useEffect(() => {
9026
9028
  if (iconRef.current && selected) {
9027
9029
  iconRef.current.focus({
@@ -12169,7 +12171,7 @@
12169
12171
  onColumnResize(params_0);
12170
12172
  }
12171
12173
  }, [columns, onColumnResize]);
12172
- const filterRef = React.useRef();
12174
+ const filterRef = React.useRef(void 0);
12173
12175
  React.useEffect(() => {
12174
12176
  filterRef.current = filterInput;
12175
12177
  }, [filterInput]);
@@ -12281,7 +12283,7 @@
12281
12283
  return tableContent;
12282
12284
  }, equal);
12283
12285
  const SortableCellWrapper = (t0) => {
12284
- const $ = reactCompilerRuntime.c(15);
12286
+ const $ = reactCompilerRuntime.c(17);
12285
12287
  const {
12286
12288
  columnKey,
12287
12289
  width,
@@ -12309,10 +12311,22 @@
12309
12311
  transform,
12310
12312
  transition
12311
12313
  } = sortable.useSortable(t2);
12314
+ let attrsWithoutTabIndex;
12315
+ if ($[3] !== attributes) {
12316
+ const {
12317
+ tabIndex: _tabIndex,
12318
+ ...t32
12319
+ } = attributes;
12320
+ attrsWithoutTabIndex = t32;
12321
+ $[3] = attributes;
12322
+ $[4] = attrsWithoutTabIndex;
12323
+ } else {
12324
+ attrsWithoutTabIndex = $[4];
12325
+ }
12312
12326
  const t3 = transform ? `translateX(${transform.x}px)` : void 0;
12313
12327
  const t4 = isDragging ? void 0 : transition;
12314
12328
  let t5;
12315
- if ($[3] !== t3 || $[4] !== t4 || $[5] !== width) {
12329
+ if ($[5] !== t3 || $[6] !== t4 || $[7] !== width) {
12316
12330
  t5 = {
12317
12331
  transform: t3,
12318
12332
  transition: t4,
@@ -12320,34 +12334,34 @@
12320
12334
  maxWidth: width,
12321
12335
  width
12322
12336
  };
12323
- $[3] = t3;
12324
- $[4] = t4;
12325
- $[5] = width;
12326
- $[6] = t5;
12337
+ $[5] = t3;
12338
+ $[6] = t4;
12339
+ $[7] = width;
12340
+ $[8] = t5;
12327
12341
  } else {
12328
- t5 = $[6];
12342
+ t5 = $[8];
12329
12343
  }
12330
12344
  const style = t5;
12331
12345
  const t6 = frozen && "sticky left-0 z-10 bg-white dark:bg-surface-950";
12332
12346
  let t7;
12333
- if ($[7] !== t6) {
12347
+ if ($[9] !== t6) {
12334
12348
  t7 = ui.cls("flex-shrink-0", t6);
12335
- $[7] = t6;
12336
- $[8] = t7;
12349
+ $[9] = t6;
12350
+ $[10] = t7;
12337
12351
  } else {
12338
- t7 = $[8];
12352
+ t7 = $[10];
12339
12353
  }
12340
12354
  let t8;
12341
- if ($[9] !== attributes || $[10] !== children || $[11] !== setNodeRef || $[12] !== style || $[13] !== t7) {
12342
- t8 = /* @__PURE__ */ jsxRuntime.jsx("div", { ref: setNodeRef, style, className: t7, ...attributes, children });
12343
- $[9] = attributes;
12344
- $[10] = children;
12345
- $[11] = setNodeRef;
12346
- $[12] = style;
12347
- $[13] = t7;
12348
- $[14] = t8;
12355
+ if ($[11] !== attrsWithoutTabIndex || $[12] !== children || $[13] !== setNodeRef || $[14] !== style || $[15] !== t7) {
12356
+ t8 = /* @__PURE__ */ jsxRuntime.jsx("div", { ref: setNodeRef, style, className: t7, ...attrsWithoutTabIndex, children });
12357
+ $[11] = attrsWithoutTabIndex;
12358
+ $[12] = children;
12359
+ $[13] = setNodeRef;
12360
+ $[14] = style;
12361
+ $[15] = t7;
12362
+ $[16] = t8;
12349
12363
  } else {
12350
- t8 = $[14];
12364
+ t8 = $[16];
12351
12365
  }
12352
12366
  return t8;
12353
12367
  };
@@ -16250,7 +16264,7 @@
16250
16264
  size = "m"
16251
16265
  }) {
16252
16266
  const authController = useAuthController();
16253
- useAnalyticsController();
16267
+ const analyticsController = useAnalyticsController();
16254
16268
  useSideEntityController();
16255
16269
  const customizationController = useCustomizationController();
16256
16270
  useNavigationController();
@@ -16277,6 +16291,10 @@
16277
16291
  return;
16278
16292
  }
16279
16293
  if (onClick) {
16294
+ analyticsController.onAnalyticsEvent?.("card_view_entity_click", {
16295
+ path: entity.path,
16296
+ entityId: entity.id
16297
+ });
16280
16298
  onClick(entity);
16281
16299
  }
16282
16300
  };
@@ -17563,7 +17581,7 @@
17563
17581
  return /* @__PURE__ */ jsxRuntime.jsx("div", { style, className: "py-1", "data-is-dragging": isDragging, "data-testid": item.id, onClick: handleClick, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cardClassName, children: [
17564
17582
  usedImageProperty && usedImageValue ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-10 h-10 rounded-md overflow-hidden shrink-0 mr-2", children: /* @__PURE__ */ jsxRuntime.jsx(PropertyPreview, { property: usedImageProperty, propertyKey: imagePropertyKey, size: "small", value: usedImageValue, fill: true }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-10 h-10 rounded-md bg-surface-100 dark:bg-surface-800 shrink-0 mr-2 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(IconForView, { collectionOrView: collection, color: "disabled", size: "small" }) }),
17565
17583
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
17566
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-sm font-medium", children: titleProperty && titleValue ? /* @__PURE__ */ jsxRuntime.jsx(PropertyPreview, { propertyKey: titlePropertyKey, value: titleValue, property: titleProperty, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-surface-500", children: entity.id }) }),
17584
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "line-clamp-2 text-sm font-medium", children: titleProperty && titleValue ? /* @__PURE__ */ jsxRuntime.jsx(PropertyPreview, { propertyKey: titlePropertyKey, value: titleValue, property: titleProperty, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-surface-500", children: entity.id }) }),
17567
17585
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-surface-500 font-mono truncate", children: entity.id })
17568
17586
  ] }),
17569
17587
  selectionEnabled && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-2 shrink-0", onClick: handleCheckboxClick, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Checkbox, { checked: selected ?? false, onCheckedChange: handleSelectionChange, size: "smallest" }) })
@@ -17919,6 +17937,7 @@
17919
17937
  const context = useFireCMSContext();
17920
17938
  const dataSource = useDataSource();
17921
17939
  const sideEntityController = useSideEntityController();
17940
+ const analyticsController = useAnalyticsController();
17922
17941
  const plugins = customizationController.plugins ?? [];
17923
17942
  const [showBackfillDialog, setShowBackfillDialog] = React.useState(false);
17924
17943
  const [backfillLoading, setBackfillLoading] = React.useState(false);
@@ -18034,6 +18053,10 @@
18034
18053
  return plugins.some((plugin) => plugin.collectionView?.onKanbanColumnsReorder);
18035
18054
  }, [plugins]);
18036
18055
  const handleColumnReorder = React.useCallback((newColumns) => {
18056
+ analyticsController.onAnalyticsEvent?.("kanban_column_reorder", {
18057
+ path: fullPath,
18058
+ columnProperty
18059
+ });
18037
18060
  setHasUserReordered(true);
18038
18061
  setLocalColumnsOrder(newColumns);
18039
18062
  plugins.filter((plugin_0) => plugin_0.collectionView?.onKanbanColumnsReorder).forEach((plugin_1) => {
@@ -18045,7 +18068,7 @@
18045
18068
  newColumnsOrder: newColumns
18046
18069
  });
18047
18070
  });
18048
- }, [plugins, fullPath, parentCollectionIds, collection, columnProperty]);
18071
+ }, [plugins, fullPath, parentCollectionIds, collection, columnProperty, analyticsController]);
18049
18072
  const [missingOrderCount, setMissingOrderCount] = React.useState(0);
18050
18073
  const dataSourceRef = React.useRef(dataSource);
18051
18074
  const collectionRef = React.useRef(collection);
@@ -18157,6 +18180,12 @@
18157
18180
  const handleItemsReorder = React.useCallback(async (items_0, moveInfo) => {
18158
18181
  const entity_2 = items_0.find((item_5) => item_5.id === moveInfo?.itemId)?.entity;
18159
18182
  if (!entity_2) return;
18183
+ analyticsController.onAnalyticsEvent?.("kanban_card_moved", {
18184
+ path: fullPath,
18185
+ entityId: entity_2.id,
18186
+ sourceColumn: moveInfo?.sourceColumn,
18187
+ targetColumn: moveInfo?.targetColumn
18188
+ });
18160
18189
  const isColumnChange = moveInfo && moveInfo.sourceColumn !== moveInfo.targetColumn;
18161
18190
  if (!orderProperty && !isColumnChange) return;
18162
18191
  if (isColumnChange) {
@@ -18194,7 +18223,7 @@
18194
18223
  } catch (e_1) {
18195
18224
  console.error("Error saving entity:", e_1);
18196
18225
  }
18197
- }, [collection, columnProperty, orderProperty, context, dataSource, calculateNewOrder, boardDataController]);
18226
+ }, [collection, columnProperty, orderProperty, context, dataSource, calculateNewOrder, boardDataController, analyticsController, fullPath]);
18198
18227
  const handleBackfill = React.useCallback(async () => {
18199
18228
  console.log("handleBackfill called", {
18200
18229
  orderProperty
@@ -18203,6 +18232,9 @@
18203
18232
  console.log("No orderProperty, returning");
18204
18233
  return;
18205
18234
  }
18235
+ analyticsController.onAnalyticsEvent?.("kanban_backfill_order", {
18236
+ path: fullPath
18237
+ });
18206
18238
  setBackfillLoading(true);
18207
18239
  try {
18208
18240
  console.log("Fetching all documents from collection...");
@@ -18256,7 +18288,7 @@
18256
18288
  } finally {
18257
18289
  setBackfillLoading(false);
18258
18290
  }
18259
- }, [orderProperty, fullPath, collection, dataSource, context, boardDataController]);
18291
+ }, [orderProperty, fullPath, collection, dataSource, context, boardDataController, analyticsController]);
18260
18292
  const handleEntityClick = React.useCallback((entity_5) => {
18261
18293
  onEntityClick?.(entity_5);
18262
18294
  }, [onEntityClick]);
@@ -18317,6 +18349,10 @@
18317
18349
  /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "text", onClick: () => setShowBackfillDialog(true), children: "Initialize Order" })
18318
18350
  ] }),
18319
18351
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-auto no-scrollbar", children: /* @__PURE__ */ jsxRuntime.jsx(Board, { data: boardItems, columns, columnLabels, columnColors, assignColumn, allowColumnReorder, onColumnReorder: handleColumnReorder, onItemsReorder: handleItemsReorder, ItemComponent, columnLoadingState, onLoadMoreColumn: (column) => boardDataController.loadMoreColumn(column), onAddItemToColumn: (column_0) => {
18352
+ analyticsController.onAnalyticsEvent?.("kanban_new_entity_in_column", {
18353
+ path: fullPath,
18354
+ column: column_0
18355
+ });
18320
18356
  sideEntityController.open({
18321
18357
  path: fullPath,
18322
18358
  collection,
@@ -19481,6 +19517,7 @@
19481
19517
  console.error(error);
19482
19518
  }, [snackbarController]);
19483
19519
  const pluginActions = [];
19520
+ const pluginBeforeTitle = [];
19484
19521
  const plugins = customizationController.plugins;
19485
19522
  const actionsDisabled = disabled || formex$1.isSubmitting || status === "existing" && !formex$1.dirty || Boolean(disabledProp);
19486
19523
  const parentCollectionIds = navigationController.getParentCollectionIds(path);
@@ -19497,6 +19534,7 @@
19497
19534
  disabled: actionsDisabled
19498
19535
  };
19499
19536
  pluginActions.push(...plugins.map((plugin) => plugin.form?.Actions ? /* @__PURE__ */ jsxRuntime.jsx(plugin.form.Actions, { ...actionProps }, `actions_${plugin.key}`) : null).filter(Boolean));
19537
+ pluginBeforeTitle.push(...plugins.map((plugin_0) => plugin_0.form?.BeforeTitle ? /* @__PURE__ */ jsxRuntime.jsx(plugin_0.form.BeforeTitle, { ...actionProps }, `before_title_${plugin_0.key}`) : null).filter(Boolean));
19500
19538
  }
19501
19539
  const titlePropertyKey = getEntityTitlePropertyKey(resolvedCollection, customizationController.propertyConfigs);
19502
19540
  const title = (formex$1.values && titlePropertyKey ? getValueInPath(formex$1.values, titlePropertyKey) : void 0) ?? collection.singularName ?? collection.name;
@@ -19593,6 +19631,7 @@
19593
19631
  };
19594
19632
  const formRef = React.useRef(null);
19595
19633
  const formView = /* @__PURE__ */ jsxRuntime.jsx(ErrorBoundary, { children: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
19634
+ pluginBeforeTitle,
19596
19635
  !Builder && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full py-2 flex flex-col items-start my-4 lg:my-6", children: [
19597
19636
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { className: "my-4 flex-grow line-clamp-1 " + (collection.hideIdFromForm ? "mb-6" : ""), variant: "h4", children: title ?? collection.singularName ?? collection.name }),
19598
19637
  !entity?.values && initialStatus === "existing" && /* @__PURE__ */ jsxRuntime.jsx(ui.Alert, { color: "warning", size: "small", outerClassName: "w-full mb-4 text-xs", children: "This entity does not exist in the database" }),
@@ -21850,7 +21889,7 @@
21850
21889
  index,
21851
21890
  authController
21852
21891
  });
21853
- Component = configProperty.Field;
21892
+ Component = configProperty?.Field;
21854
21893
  }
21855
21894
  }
21856
21895
  }
@@ -24475,13 +24514,18 @@
24475
24514
  });
24476
24515
  }, [onCollectionModifiedForUser, fullPath, userConfigPersistence]);
24477
24516
  const onViewModeChange = React.useCallback((mode) => {
24517
+ analyticsController.onAnalyticsEvent?.("view_mode_changed", {
24518
+ path: fullPath,
24519
+ from: viewMode,
24520
+ to: mode
24521
+ });
24478
24522
  setViewMode(mode);
24479
24523
  if (userConfigPersistence) {
24480
24524
  onCollectionModifiedForUser(fullPath, {
24481
24525
  defaultViewMode: mode
24482
24526
  });
24483
24527
  }
24484
- }, [setViewMode, userConfigPersistence, onCollectionModifiedForUser, fullPath]);
24528
+ }, [setViewMode, userConfigPersistence, onCollectionModifiedForUser, fullPath, analyticsController, viewMode]);
24485
24529
  const createEnabled = canCreateEntity(collection, authController, fullPath, null);
24486
24530
  const uniqueFieldValidator = React.useCallback(({
24487
24531
  name,
@@ -24583,13 +24627,17 @@
24583
24627
  }
24584
24628
  }, [kanbanPropertyOptions, selectedKanbanProperty, getSavedKanbanProperty, collection.kanban?.columnProperty]);
24585
24629
  const onKanbanPropertyChange = React.useCallback((property_1) => {
24630
+ analyticsController.onAnalyticsEvent?.("kanban_property_changed", {
24631
+ path: fullPath,
24632
+ property: property_1
24633
+ });
24586
24634
  setSelectedKanbanProperty(property_1);
24587
24635
  if (userConfigPersistence) {
24588
24636
  onCollectionModifiedForUser(fullPath, {
24589
24637
  kanbanColumnProperty: property_1
24590
24638
  });
24591
24639
  }
24592
- }, [userConfigPersistence, onCollectionModifiedForUser, fullPath]);
24640
+ }, [userConfigPersistence, onCollectionModifiedForUser, fullPath, analyticsController]);
24593
24641
  const getPropertyFor = React.useCallback(({
24594
24642
  propertyKey: propertyKey_0,
24595
24643
  entity: entity_2
@@ -24728,10 +24776,21 @@
24728
24776
  });
24729
24777
  const [viewModePopoverOpen, setViewModePopoverOpen] = React.useState(false);
24730
24778
  const viewModeToggleElement = /* @__PURE__ */ jsxRuntime.jsx(ViewModeToggle, { viewMode, onViewModeChange, enabledViews, size: viewMode === "table" ? tableSize : viewMode === "cards" ? cardSize : void 0, onSizeChanged: viewMode === "table" ? onTableSizeChanged : viewMode === "cards" ? setCardSize : void 0, open: viewModePopoverOpen, onOpenChange: setViewModePopoverOpen, kanbanPropertyOptions, selectedKanbanProperty, onKanbanPropertyChange });
24779
+ const pluginErrorView = React.useMemo(() => {
24780
+ const error = tableController.dataLoadingError;
24781
+ if (!error || !customizationController.plugins) return null;
24782
+ for (const plugin_2 of customizationController.plugins) {
24783
+ if (plugin_2.collectionView?.CollectionError) {
24784
+ const CollectionError = plugin_2.collectionView.CollectionError;
24785
+ return /* @__PURE__ */ jsxRuntime.jsx(CollectionError, { path: fullPath, collection, parentCollectionIds, error });
24786
+ }
24787
+ }
24788
+ return null;
24789
+ }, [tableController.dataLoadingError, customizationController.plugins, fullPath, collection, parentCollectionIds]);
24731
24790
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cls("overflow-hidden h-full w-full rounded-md flex flex-col", className), ref: containerRef, children: [
24732
24791
  countFetcher,
24733
24792
  /* @__PURE__ */ jsxRuntime.jsx(CollectionTableToolbar, { loading: tableController.dataLoading, onTextSearch: textSearchEnabled && textSearchInitialised ? tableController.setSearchString : void 0, onTextSearchClick: textSearchEnabled && !textSearchInitialised ? onTextSearchClick : void 0, textSearchLoading, viewModeToggle: viewModeToggleElement, actionsStart: /* @__PURE__ */ jsxRuntime.jsx(EntityCollectionViewStartActions, { parentCollectionIds: parentCollectionIds ?? [], collection, tableController, path: fullPath, relativePath: collection.path, selectionController: usedSelectionController, collectionEntitiesCount: docsCount, resolvedProperties: resolvedCollection.properties }), actions: /* @__PURE__ */ jsxRuntime.jsx(EntityCollectionViewActions, { parentCollectionIds: parentCollectionIds ?? [], collection, tableController, onMultipleDeleteClick, onNewClick, path: fullPath, relativePath: collection.path, selectionController: usedSelectionController, selectionEnabled, collectionEntitiesCount: docsCount }) }),
24734
- viewMode === "kanban" && enabledViews.includes("kanban") ? /* @__PURE__ */ jsxRuntime.jsx(EntityCollectionBoardView, { collection, tableController, fullPath, parentCollectionIds, columnProperty: selectedKanbanProperty, onEntityClick, selectionController: usedSelectionController, selectionEnabled, highlightedEntities: highlightedEntity ? [highlightedEntity] : [], deletedEntities, emptyComponent: canCreateEntities && tableController.filterValues === void 0 && tableController.sortBy === void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center", children: [
24793
+ tableController.dataLoadingError && pluginErrorView ? pluginErrorView : viewMode === "kanban" && enabledViews.includes("kanban") ? /* @__PURE__ */ jsxRuntime.jsx(EntityCollectionBoardView, { collection, tableController, fullPath, parentCollectionIds, columnProperty: selectedKanbanProperty, onEntityClick, selectionController: usedSelectionController, selectionEnabled, highlightedEntities: highlightedEntity ? [highlightedEntity] : [], deletedEntities, emptyComponent: canCreateEntities && tableController.filterValues === void 0 && tableController.sortBy === void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center", children: [
24735
24794
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "subtitle2", children: "So empty..." }),
24736
24795
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { onClick: onNewClick, className: "mt-4", children: [
24737
24796
  /* @__PURE__ */ jsxRuntime.jsx(ui.AddIcon, {}),
@@ -24758,8 +24817,8 @@
24758
24817
  });
24759
24818
  setLocalPropertiesOrder(newPropertiesOrder);
24760
24819
  if (customizationController?.plugins) {
24761
- customizationController.plugins.filter((plugin_2) => plugin_2.collectionView?.onColumnsReorder).forEach((plugin_3) => {
24762
- plugin_3.collectionView.onColumnsReorder({
24820
+ customizationController.plugins.filter((plugin_3) => plugin_3.collectionView?.onColumnsReorder).forEach((plugin_4) => {
24821
+ plugin_4.collectionView.onColumnsReorder({
24763
24822
  fullPath,
24764
24823
  parentCollectionIds: parentCollectionIds ?? [],
24765
24824
  collection,
@@ -26123,10 +26182,10 @@
26123
26182
  navigationGroupMappings
26124
26183
  } = props;
26125
26184
  const navigate = reactRouterDom.useNavigate();
26126
- const collectionsRef = React.useRef();
26127
- const viewsRef = React.useRef();
26128
- const adminViewsRef = React.useRef();
26129
- const navigationEntriesOrderRef = React.useRef();
26185
+ const collectionsRef = React.useRef(void 0);
26186
+ const viewsRef = React.useRef(void 0);
26187
+ const adminViewsRef = React.useRef(void 0);
26188
+ const navigationEntriesOrderRef = React.useRef(void 0);
26130
26189
  const [initialised, setInitialised] = React.useState(false);
26131
26190
  const [topLevelNavigation, setTopLevelNavigation] = React.useState(void 0);
26132
26191
  const [navigationLoading, setNavigationLoading] = React.useState(true);
@@ -26831,7 +26890,7 @@
26831
26890
  t2 = $[2];
26832
26891
  }
26833
26892
  React.useEffect(t1, t2);
26834
- const checkedUserRef = React.useRef();
26893
+ const checkedUserRef = React.useRef(void 0);
26835
26894
  let t3;
26836
26895
  if ($[3] !== authController || $[4] !== authenticator || $[5] !== dataSourceDelegate || $[6] !== disabled || $[7] !== storageSource) {
26837
26896
  t3 = async () => {
@@ -27160,13 +27219,13 @@
27160
27219
  status,
27161
27220
  values
27162
27221
  }) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
27163
- /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { className: "self-center", onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(ui.CloseIcon, { size: "small" }) }),
27164
- allowFullScreen && /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { className: "self-center", onClick: () => {
27222
+ /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { className: "self-center", size: "smallest", onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(ui.CloseIcon, { size: "smallest" }) }),
27223
+ allowFullScreen && /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { className: "self-center", size: "smallest", onClick: () => {
27165
27224
  const key = status === "new" || status === "copy" ? path + "#new" : path + "/" + entityId;
27166
27225
  saveEntityToMemoryCache(key, values);
27167
27226
  if (entityId) navigate(location.pathname);
27168
27227
  else navigate(location.pathname + "#new");
27169
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.OpenInFullIcon, { size: "small" }) })
27228
+ }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.OpenInFullIcon, { size: "smallest" }) })
27170
27229
  ] }), onTabChange: ({
27171
27230
  entityId: entityId_0,
27172
27231
  selectedTab,
@@ -28442,7 +28501,7 @@
28442
28501
  const orderProperty = collection_3?.orderProperty;
28443
28502
  if (orderProperty && (status === "new" || status === "copy")) {
28444
28503
  const orderProp = properties?.[orderProperty];
28445
- if (orderProp?.disabled === true) {
28504
+ if (orderProp) {
28446
28505
  const currentValue = updatedValues[orderProperty];
28447
28506
  if (currentValue === void 0 || currentValue === null) {
28448
28507
  try {
@@ -29663,14 +29722,19 @@
29663
29722
  return "custom_array";
29664
29723
  } else if (isPropertyBuilder(of)) {
29665
29724
  return "repeat";
29666
- } else if (of?.dataType === "string" && of.enumValues) {
29667
- return "multi_select";
29668
- } else if (of?.dataType === "number" && of.enumValues) {
29669
- return "multi_number_select";
29670
- } else if (of?.dataType === "string" && of.storage) {
29671
- return "multi_file_upload";
29672
- } else if (of?.dataType === "reference") {
29673
- return "multi_references";
29725
+ } else if (of) {
29726
+ const ofProperty = of;
29727
+ if (ofProperty.dataType === "string" && ofProperty.enumValues) {
29728
+ return "multi_select";
29729
+ } else if (ofProperty.dataType === "number" && ofProperty.enumValues) {
29730
+ return "multi_number_select";
29731
+ } else if (ofProperty.dataType === "string" && ofProperty.storage) {
29732
+ return "multi_file_upload";
29733
+ } else if (ofProperty.dataType === "reference") {
29734
+ return "multi_references";
29735
+ } else {
29736
+ return "repeat";
29737
+ }
29674
29738
  } else {
29675
29739
  return "repeat";
29676
29740
  }