@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
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
2
  interface DraggableProps {
3
- containerRef: React.RefObject<HTMLDivElement>;
4
- innerRef: React.RefObject<HTMLDivElement>;
3
+ containerRef: React.RefObject<HTMLDivElement | null>;
4
+ innerRef: React.RefObject<HTMLDivElement | null>;
5
5
  x?: number;
6
6
  y?: number;
7
7
  onMove: (params: {
@@ -7,5 +7,5 @@ export declare class ErrorBoundary extends React.Component<PropsWithChildren<Rec
7
7
  error: Error;
8
8
  };
9
9
  componentDidCatch(error: Error, errorInfo: ErrorInfo): void;
10
- render(): string | number | boolean | Iterable<React.ReactNode> | import("react/jsx-runtime").JSX.Element | null | undefined;
10
+ render(): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element | null | undefined;
11
11
  }
@@ -9,7 +9,7 @@ export type FilterFormFieldProps<CustomProps> = {
9
9
  setHidden: (hidden: boolean) => void;
10
10
  };
11
11
  type VirtualTableHeaderProps<M extends Record<string, any>> = {
12
- resizeHandleRef: RefObject<HTMLDivElement>;
12
+ resizeHandleRef: RefObject<HTMLDivElement | null>;
13
13
  columnIndex: number;
14
14
  isResizingIndex: number;
15
15
  column: VirtualTableColumn<any>;
@@ -1,4 +1,4 @@
1
1
  import React from "react";
2
2
  export declare const ErrorFocus: ({ containerRef }: {
3
- containerRef?: React.RefObject<HTMLDivElement>;
3
+ containerRef?: React.RefObject<HTMLDivElement | null>;
4
4
  }) => null;
package/dist/index.es.js CHANGED
@@ -788,7 +788,7 @@ const resolveCollection = ({
788
788
  const defaultValues = getDefaultValuesFor(collection.properties);
789
789
  const usedValues = values ?? defaultValues;
790
790
  const usedPreviousValues = previousValues ?? values ?? defaultValues;
791
- const resolvedProperties = Object.entries(collection.properties).map(([key, propertyOrBuilder]) => {
791
+ const resolvedProperties = Object.entries(collection.properties).filter(([, propertyOrBuilder]) => propertyOrBuilder != null).map(([key, propertyOrBuilder]) => {
792
792
  const childResolvedProperty = resolveProperty({
793
793
  propertyKey: key,
794
794
  propertyOrBuilder,
@@ -827,7 +827,7 @@ function resolveProperty({
827
827
  ignoreMissingFields = false,
828
828
  ...props
829
829
  }) {
830
- if (typeof propertyOrBuilder === "object" && "resolved" in propertyOrBuilder) {
830
+ if (propertyOrBuilder !== null && typeof propertyOrBuilder === "object" && "resolved" in propertyOrBuilder) {
831
831
  return propertyOrBuilder;
832
832
  }
833
833
  let resolvedProperty = null;
@@ -3827,6 +3827,8 @@ function mergeCollection(target, source, parentPaths = [], modifyCollection) {
3827
3827
  return resultCollection;
3828
3828
  }
3829
3829
  function mergePropertyOrBuilder(target, source) {
3830
+ if (!source) return target;
3831
+ if (!target) return source;
3830
3832
  if (isPropertyBuilder(source)) {
3831
3833
  return source;
3832
3834
  } else if (isPropertyBuilder(target)) {
@@ -7580,7 +7582,7 @@ const PropertyPreview = React__default.memo(function PropertyPreview2(props) {
7580
7582
  } else {
7581
7583
  if (property.dataType === "map") {
7582
7584
  if (typeof value === "object") {
7583
- content = /* @__PURE__ */ jsx(MapPropertyPreview, { ...props, property });
7585
+ content = /* @__PURE__ */ jsx(MapPropertyPreview, { ...props, value, property });
7584
7586
  } else {
7585
7587
  content = buildWrongValueType(propertyKey, property.dataType, value);
7586
7588
  }
@@ -8464,7 +8466,7 @@ function VirtualTableSelect(props) {
8464
8466
  const handleOpenChange = t4;
8465
8467
  let t5;
8466
8468
  if ($[11] !== disabled || $[12] !== enumValues || $[13] !== internalValue || $[14] !== multiple || $[15] !== onChange || $[16] !== renderValue || $[17] !== small || $[18] !== validValue) {
8467
- t5 = multiple ? /* @__PURE__ */ jsx(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__ */ jsx(MultiSelectItem, { value: String(enumConfig.id), children: /* @__PURE__ */ jsx(EnumValuesChip, { enumKey: enumConfig.id, enumValues, size: small ? "small" : "medium" }) }, enumConfig.id)) }) : /* @__PURE__ */ jsx(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__ */ jsx(SelectItem, { value: String(enumConfig_0.id), children: /* @__PURE__ */ jsx(EnumValuesChip, { enumKey: enumConfig_0.id, enumValues, size: small ? "small" : "medium" }) }, enumConfig_0.id)) });
8469
+ t5 = multiple ? /* @__PURE__ */ jsx(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__ */ jsx(MultiSelectItem, { value: String(enumConfig.id), children: /* @__PURE__ */ jsx(EnumValuesChip, { enumKey: enumConfig.id, enumValues, size: small ? "small" : "medium" }) }, enumConfig.id)) }) : /* @__PURE__ */ jsx(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__ */ jsx(SelectItem, { value: String(enumConfig_0.id), children: /* @__PURE__ */ jsx(EnumValuesChip, { enumKey: enumConfig_0.id, enumValues, size: small ? "small" : "medium" }) }, enumConfig_0.id)) });
8468
8470
  $[11] = disabled;
8469
8471
  $[12] = enumValues;
8470
8472
  $[13] = internalValue;
@@ -9024,7 +9026,7 @@ function EntityTableCellActions({
9024
9026
  openPopup(cellRect);
9025
9027
  }
9026
9028
  }, []);
9027
- const iconRef = useRef();
9029
+ const iconRef = useRef(void 0);
9028
9030
  useEffect(() => {
9029
9031
  if (iconRef.current && selected) {
9030
9032
  iconRef.current.focus({
@@ -12172,7 +12174,7 @@ const VirtualTable = React__default.memo(function VirtualTable2({
12172
12174
  onColumnResize(params_0);
12173
12175
  }
12174
12176
  }, [columns, onColumnResize]);
12175
- const filterRef = useRef();
12177
+ const filterRef = useRef(void 0);
12176
12178
  useEffect(() => {
12177
12179
  filterRef.current = filterInput;
12178
12180
  }, [filterInput]);
@@ -12284,7 +12286,7 @@ const VirtualTable = React__default.memo(function VirtualTable2({
12284
12286
  return tableContent;
12285
12287
  }, equal);
12286
12288
  const SortableCellWrapper = (t0) => {
12287
- const $ = c(15);
12289
+ const $ = c(17);
12288
12290
  const {
12289
12291
  columnKey,
12290
12292
  width,
@@ -12312,10 +12314,22 @@ const SortableCellWrapper = (t0) => {
12312
12314
  transform,
12313
12315
  transition
12314
12316
  } = useSortable(t2);
12317
+ let attrsWithoutTabIndex;
12318
+ if ($[3] !== attributes) {
12319
+ const {
12320
+ tabIndex: _tabIndex,
12321
+ ...t32
12322
+ } = attributes;
12323
+ attrsWithoutTabIndex = t32;
12324
+ $[3] = attributes;
12325
+ $[4] = attrsWithoutTabIndex;
12326
+ } else {
12327
+ attrsWithoutTabIndex = $[4];
12328
+ }
12315
12329
  const t3 = transform ? `translateX(${transform.x}px)` : void 0;
12316
12330
  const t4 = isDragging ? void 0 : transition;
12317
12331
  let t5;
12318
- if ($[3] !== t3 || $[4] !== t4 || $[5] !== width) {
12332
+ if ($[5] !== t3 || $[6] !== t4 || $[7] !== width) {
12319
12333
  t5 = {
12320
12334
  transform: t3,
12321
12335
  transition: t4,
@@ -12323,34 +12337,34 @@ const SortableCellWrapper = (t0) => {
12323
12337
  maxWidth: width,
12324
12338
  width
12325
12339
  };
12326
- $[3] = t3;
12327
- $[4] = t4;
12328
- $[5] = width;
12329
- $[6] = t5;
12340
+ $[5] = t3;
12341
+ $[6] = t4;
12342
+ $[7] = width;
12343
+ $[8] = t5;
12330
12344
  } else {
12331
- t5 = $[6];
12345
+ t5 = $[8];
12332
12346
  }
12333
12347
  const style = t5;
12334
12348
  const t6 = frozen && "sticky left-0 z-10 bg-white dark:bg-surface-950";
12335
12349
  let t7;
12336
- if ($[7] !== t6) {
12350
+ if ($[9] !== t6) {
12337
12351
  t7 = cls("flex-shrink-0", t6);
12338
- $[7] = t6;
12339
- $[8] = t7;
12352
+ $[9] = t6;
12353
+ $[10] = t7;
12340
12354
  } else {
12341
- t7 = $[8];
12355
+ t7 = $[10];
12342
12356
  }
12343
12357
  let t8;
12344
- if ($[9] !== attributes || $[10] !== children || $[11] !== setNodeRef || $[12] !== style || $[13] !== t7) {
12345
- t8 = /* @__PURE__ */ jsx("div", { ref: setNodeRef, style, className: t7, ...attributes, children });
12346
- $[9] = attributes;
12347
- $[10] = children;
12348
- $[11] = setNodeRef;
12349
- $[12] = style;
12350
- $[13] = t7;
12351
- $[14] = t8;
12358
+ if ($[11] !== attrsWithoutTabIndex || $[12] !== children || $[13] !== setNodeRef || $[14] !== style || $[15] !== t7) {
12359
+ t8 = /* @__PURE__ */ jsx("div", { ref: setNodeRef, style, className: t7, ...attrsWithoutTabIndex, children });
12360
+ $[11] = attrsWithoutTabIndex;
12361
+ $[12] = children;
12362
+ $[13] = setNodeRef;
12363
+ $[14] = style;
12364
+ $[15] = t7;
12365
+ $[16] = t8;
12352
12366
  } else {
12353
- t8 = $[14];
12367
+ t8 = $[16];
12354
12368
  }
12355
12369
  return t8;
12356
12370
  };
@@ -16253,7 +16267,7 @@ function EntityCard({
16253
16267
  size = "m"
16254
16268
  }) {
16255
16269
  const authController = useAuthController();
16256
- useAnalyticsController();
16270
+ const analyticsController = useAnalyticsController();
16257
16271
  useSideEntityController();
16258
16272
  const customizationController = useCustomizationController();
16259
16273
  useNavigationController();
@@ -16280,6 +16294,10 @@ function EntityCard({
16280
16294
  return;
16281
16295
  }
16282
16296
  if (onClick) {
16297
+ analyticsController.onAnalyticsEvent?.("card_view_entity_click", {
16298
+ path: entity.path,
16299
+ entityId: entity.id
16300
+ });
16283
16301
  onClick(entity);
16284
16302
  }
16285
16303
  };
@@ -17566,7 +17584,7 @@ function EntityBoardCardInner({
17566
17584
  return /* @__PURE__ */ jsx("div", { style, className: "py-1", "data-is-dragging": isDragging, "data-testid": item.id, onClick: handleClick, children: /* @__PURE__ */ jsxs("div", { className: cardClassName, children: [
17567
17585
  usedImageProperty && usedImageValue ? /* @__PURE__ */ jsx("div", { className: "w-10 h-10 rounded-md overflow-hidden shrink-0 mr-2", children: /* @__PURE__ */ jsx(PropertyPreview, { property: usedImageProperty, propertyKey: imagePropertyKey, size: "small", value: usedImageValue, fill: true }) }) : /* @__PURE__ */ 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__ */ jsx(IconForView, { collectionOrView: collection, color: "disabled", size: "small" }) }),
17568
17586
  /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
17569
- /* @__PURE__ */ jsx("div", { className: "truncate text-sm font-medium", children: titleProperty && titleValue ? /* @__PURE__ */ jsx(PropertyPreview, { propertyKey: titlePropertyKey, value: titleValue, property: titleProperty, size: "small" }) : /* @__PURE__ */ jsx("span", { className: "text-surface-500", children: entity.id }) }),
17587
+ /* @__PURE__ */ jsx("div", { className: "line-clamp-2 text-sm font-medium", children: titleProperty && titleValue ? /* @__PURE__ */ jsx(PropertyPreview, { propertyKey: titlePropertyKey, value: titleValue, property: titleProperty, size: "small" }) : /* @__PURE__ */ jsx("span", { className: "text-surface-500", children: entity.id }) }),
17570
17588
  /* @__PURE__ */ jsx("div", { className: "text-xs text-surface-500 font-mono truncate", children: entity.id })
17571
17589
  ] }),
17572
17590
  selectionEnabled && /* @__PURE__ */ jsx("div", { className: "ml-2 shrink-0", onClick: handleCheckboxClick, children: /* @__PURE__ */ jsx(Checkbox, { checked: selected ?? false, onCheckedChange: handleSelectionChange, size: "smallest" }) })
@@ -17922,6 +17940,7 @@ function EntityCollectionBoardView({
17922
17940
  const context = useFireCMSContext();
17923
17941
  const dataSource = useDataSource();
17924
17942
  const sideEntityController = useSideEntityController();
17943
+ const analyticsController = useAnalyticsController();
17925
17944
  const plugins = customizationController.plugins ?? [];
17926
17945
  const [showBackfillDialog, setShowBackfillDialog] = useState(false);
17927
17946
  const [backfillLoading, setBackfillLoading] = useState(false);
@@ -18037,6 +18056,10 @@ function EntityCollectionBoardView({
18037
18056
  return plugins.some((plugin) => plugin.collectionView?.onKanbanColumnsReorder);
18038
18057
  }, [plugins]);
18039
18058
  const handleColumnReorder = useCallback((newColumns) => {
18059
+ analyticsController.onAnalyticsEvent?.("kanban_column_reorder", {
18060
+ path: fullPath,
18061
+ columnProperty
18062
+ });
18040
18063
  setHasUserReordered(true);
18041
18064
  setLocalColumnsOrder(newColumns);
18042
18065
  plugins.filter((plugin_0) => plugin_0.collectionView?.onKanbanColumnsReorder).forEach((plugin_1) => {
@@ -18048,7 +18071,7 @@ function EntityCollectionBoardView({
18048
18071
  newColumnsOrder: newColumns
18049
18072
  });
18050
18073
  });
18051
- }, [plugins, fullPath, parentCollectionIds, collection, columnProperty]);
18074
+ }, [plugins, fullPath, parentCollectionIds, collection, columnProperty, analyticsController]);
18052
18075
  const [missingOrderCount, setMissingOrderCount] = useState(0);
18053
18076
  const dataSourceRef = useRef(dataSource);
18054
18077
  const collectionRef = useRef(collection);
@@ -18160,6 +18183,12 @@ function EntityCollectionBoardView({
18160
18183
  const handleItemsReorder = useCallback(async (items_0, moveInfo) => {
18161
18184
  const entity_2 = items_0.find((item_5) => item_5.id === moveInfo?.itemId)?.entity;
18162
18185
  if (!entity_2) return;
18186
+ analyticsController.onAnalyticsEvent?.("kanban_card_moved", {
18187
+ path: fullPath,
18188
+ entityId: entity_2.id,
18189
+ sourceColumn: moveInfo?.sourceColumn,
18190
+ targetColumn: moveInfo?.targetColumn
18191
+ });
18163
18192
  const isColumnChange = moveInfo && moveInfo.sourceColumn !== moveInfo.targetColumn;
18164
18193
  if (!orderProperty && !isColumnChange) return;
18165
18194
  if (isColumnChange) {
@@ -18197,7 +18226,7 @@ function EntityCollectionBoardView({
18197
18226
  } catch (e_1) {
18198
18227
  console.error("Error saving entity:", e_1);
18199
18228
  }
18200
- }, [collection, columnProperty, orderProperty, context, dataSource, calculateNewOrder, boardDataController]);
18229
+ }, [collection, columnProperty, orderProperty, context, dataSource, calculateNewOrder, boardDataController, analyticsController, fullPath]);
18201
18230
  const handleBackfill = useCallback(async () => {
18202
18231
  console.log("handleBackfill called", {
18203
18232
  orderProperty
@@ -18206,6 +18235,9 @@ function EntityCollectionBoardView({
18206
18235
  console.log("No orderProperty, returning");
18207
18236
  return;
18208
18237
  }
18238
+ analyticsController.onAnalyticsEvent?.("kanban_backfill_order", {
18239
+ path: fullPath
18240
+ });
18209
18241
  setBackfillLoading(true);
18210
18242
  try {
18211
18243
  console.log("Fetching all documents from collection...");
@@ -18259,7 +18291,7 @@ function EntityCollectionBoardView({
18259
18291
  } finally {
18260
18292
  setBackfillLoading(false);
18261
18293
  }
18262
- }, [orderProperty, fullPath, collection, dataSource, context, boardDataController]);
18294
+ }, [orderProperty, fullPath, collection, dataSource, context, boardDataController, analyticsController]);
18263
18295
  const handleEntityClick = useCallback((entity_5) => {
18264
18296
  onEntityClick?.(entity_5);
18265
18297
  }, [onEntityClick]);
@@ -18320,6 +18352,10 @@ function EntityCollectionBoardView({
18320
18352
  /* @__PURE__ */ jsx(Button, { size: "small", variant: "text", onClick: () => setShowBackfillDialog(true), children: "Initialize Order" })
18321
18353
  ] }),
18322
18354
  /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-auto no-scrollbar", children: /* @__PURE__ */ jsx(Board, { data: boardItems, columns, columnLabels, columnColors, assignColumn, allowColumnReorder, onColumnReorder: handleColumnReorder, onItemsReorder: handleItemsReorder, ItemComponent, columnLoadingState, onLoadMoreColumn: (column) => boardDataController.loadMoreColumn(column), onAddItemToColumn: (column_0) => {
18355
+ analyticsController.onAnalyticsEvent?.("kanban_new_entity_in_column", {
18356
+ path: fullPath,
18357
+ column: column_0
18358
+ });
18323
18359
  sideEntityController.open({
18324
18360
  path: fullPath,
18325
18361
  collection,
@@ -19484,6 +19520,7 @@ function EntityForm({
19484
19520
  console.error(error);
19485
19521
  }, [snackbarController]);
19486
19522
  const pluginActions = [];
19523
+ const pluginBeforeTitle = [];
19487
19524
  const plugins = customizationController.plugins;
19488
19525
  const actionsDisabled = disabled || formex.isSubmitting || status === "existing" && !formex.dirty || Boolean(disabledProp);
19489
19526
  const parentCollectionIds = navigationController.getParentCollectionIds(path);
@@ -19500,6 +19537,7 @@ function EntityForm({
19500
19537
  disabled: actionsDisabled
19501
19538
  };
19502
19539
  pluginActions.push(...plugins.map((plugin) => plugin.form?.Actions ? /* @__PURE__ */ jsx(plugin.form.Actions, { ...actionProps }, `actions_${plugin.key}`) : null).filter(Boolean));
19540
+ pluginBeforeTitle.push(...plugins.map((plugin_0) => plugin_0.form?.BeforeTitle ? /* @__PURE__ */ jsx(plugin_0.form.BeforeTitle, { ...actionProps }, `before_title_${plugin_0.key}`) : null).filter(Boolean));
19503
19541
  }
19504
19542
  const titlePropertyKey = getEntityTitlePropertyKey(resolvedCollection, customizationController.propertyConfigs);
19505
19543
  const title = (formex.values && titlePropertyKey ? getValueInPath(formex.values, titlePropertyKey) : void 0) ?? collection.singularName ?? collection.name;
@@ -19596,6 +19634,7 @@ function EntityForm({
19596
19634
  };
19597
19635
  const formRef = useRef(null);
19598
19636
  const formView = /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsxs(Fragment, { children: [
19637
+ pluginBeforeTitle,
19599
19638
  !Builder && /* @__PURE__ */ jsxs("div", { className: "w-full py-2 flex flex-col items-start my-4 lg:my-6", children: [
19600
19639
  /* @__PURE__ */ jsx(Typography, { className: "my-4 flex-grow line-clamp-1 " + (collection.hideIdFromForm ? "mb-6" : ""), variant: "h4", children: title ?? collection.singularName ?? collection.name }),
19601
19640
  !entity?.values && initialStatus === "existing" && /* @__PURE__ */ jsx(Alert, { color: "warning", size: "small", outerClassName: "w-full mb-4 text-xs", children: "This entity does not exist in the database" }),
@@ -21853,7 +21892,7 @@ function PropertyFieldBindingInternal(t0) {
21853
21892
  index,
21854
21893
  authController
21855
21894
  });
21856
- Component = configProperty.Field;
21895
+ Component = configProperty?.Field;
21857
21896
  }
21858
21897
  }
21859
21898
  }
@@ -24478,13 +24517,18 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
24478
24517
  });
24479
24518
  }, [onCollectionModifiedForUser, fullPath, userConfigPersistence]);
24480
24519
  const onViewModeChange = useCallback((mode) => {
24520
+ analyticsController.onAnalyticsEvent?.("view_mode_changed", {
24521
+ path: fullPath,
24522
+ from: viewMode,
24523
+ to: mode
24524
+ });
24481
24525
  setViewMode(mode);
24482
24526
  if (userConfigPersistence) {
24483
24527
  onCollectionModifiedForUser(fullPath, {
24484
24528
  defaultViewMode: mode
24485
24529
  });
24486
24530
  }
24487
- }, [setViewMode, userConfigPersistence, onCollectionModifiedForUser, fullPath]);
24531
+ }, [setViewMode, userConfigPersistence, onCollectionModifiedForUser, fullPath, analyticsController, viewMode]);
24488
24532
  const createEnabled = canCreateEntity(collection, authController, fullPath, null);
24489
24533
  const uniqueFieldValidator = useCallback(({
24490
24534
  name,
@@ -24586,13 +24630,17 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
24586
24630
  }
24587
24631
  }, [kanbanPropertyOptions, selectedKanbanProperty, getSavedKanbanProperty, collection.kanban?.columnProperty]);
24588
24632
  const onKanbanPropertyChange = useCallback((property_1) => {
24633
+ analyticsController.onAnalyticsEvent?.("kanban_property_changed", {
24634
+ path: fullPath,
24635
+ property: property_1
24636
+ });
24589
24637
  setSelectedKanbanProperty(property_1);
24590
24638
  if (userConfigPersistence) {
24591
24639
  onCollectionModifiedForUser(fullPath, {
24592
24640
  kanbanColumnProperty: property_1
24593
24641
  });
24594
24642
  }
24595
- }, [userConfigPersistence, onCollectionModifiedForUser, fullPath]);
24643
+ }, [userConfigPersistence, onCollectionModifiedForUser, fullPath, analyticsController]);
24596
24644
  const getPropertyFor = useCallback(({
24597
24645
  propertyKey: propertyKey_0,
24598
24646
  entity: entity_2
@@ -24731,10 +24779,21 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
24731
24779
  });
24732
24780
  const [viewModePopoverOpen, setViewModePopoverOpen] = useState(false);
24733
24781
  const viewModeToggleElement = /* @__PURE__ */ 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 });
24782
+ const pluginErrorView = useMemo(() => {
24783
+ const error = tableController.dataLoadingError;
24784
+ if (!error || !customizationController.plugins) return null;
24785
+ for (const plugin_2 of customizationController.plugins) {
24786
+ if (plugin_2.collectionView?.CollectionError) {
24787
+ const CollectionError = plugin_2.collectionView.CollectionError;
24788
+ return /* @__PURE__ */ jsx(CollectionError, { path: fullPath, collection, parentCollectionIds, error });
24789
+ }
24790
+ }
24791
+ return null;
24792
+ }, [tableController.dataLoadingError, customizationController.plugins, fullPath, collection, parentCollectionIds]);
24734
24793
  return /* @__PURE__ */ jsxs("div", { className: cls("overflow-hidden h-full w-full rounded-md flex flex-col", className), ref: containerRef, children: [
24735
24794
  countFetcher,
24736
24795
  /* @__PURE__ */ jsx(CollectionTableToolbar, { loading: tableController.dataLoading, onTextSearch: textSearchEnabled && textSearchInitialised ? tableController.setSearchString : void 0, onTextSearchClick: textSearchEnabled && !textSearchInitialised ? onTextSearchClick : void 0, textSearchLoading, viewModeToggle: viewModeToggleElement, actionsStart: /* @__PURE__ */ jsx(EntityCollectionViewStartActions, { parentCollectionIds: parentCollectionIds ?? [], collection, tableController, path: fullPath, relativePath: collection.path, selectionController: usedSelectionController, collectionEntitiesCount: docsCount, resolvedProperties: resolvedCollection.properties }), actions: /* @__PURE__ */ jsx(EntityCollectionViewActions, { parentCollectionIds: parentCollectionIds ?? [], collection, tableController, onMultipleDeleteClick, onNewClick, path: fullPath, relativePath: collection.path, selectionController: usedSelectionController, selectionEnabled, collectionEntitiesCount: docsCount }) }),
24737
- viewMode === "kanban" && enabledViews.includes("kanban") ? /* @__PURE__ */ 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__ */ jsxs("div", { className: "flex flex-col items-center justify-center", children: [
24796
+ tableController.dataLoadingError && pluginErrorView ? pluginErrorView : viewMode === "kanban" && enabledViews.includes("kanban") ? /* @__PURE__ */ 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__ */ jsxs("div", { className: "flex flex-col items-center justify-center", children: [
24738
24797
  /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", children: "So empty..." }),
24739
24798
  /* @__PURE__ */ jsxs(Button, { onClick: onNewClick, className: "mt-4", children: [
24740
24799
  /* @__PURE__ */ jsx(AddIcon, {}),
@@ -24761,8 +24820,8 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
24761
24820
  });
24762
24821
  setLocalPropertiesOrder(newPropertiesOrder);
24763
24822
  if (customizationController?.plugins) {
24764
- customizationController.plugins.filter((plugin_2) => plugin_2.collectionView?.onColumnsReorder).forEach((plugin_3) => {
24765
- plugin_3.collectionView.onColumnsReorder({
24823
+ customizationController.plugins.filter((plugin_3) => plugin_3.collectionView?.onColumnsReorder).forEach((plugin_4) => {
24824
+ plugin_4.collectionView.onColumnsReorder({
24766
24825
  fullPath,
24767
24826
  parentCollectionIds: parentCollectionIds ?? [],
24768
24827
  collection,
@@ -26126,10 +26185,10 @@ function useBuildNavigationController(props) {
26126
26185
  navigationGroupMappings
26127
26186
  } = props;
26128
26187
  const navigate = useNavigate();
26129
- const collectionsRef = useRef();
26130
- const viewsRef = useRef();
26131
- const adminViewsRef = useRef();
26132
- const navigationEntriesOrderRef = useRef();
26188
+ const collectionsRef = useRef(void 0);
26189
+ const viewsRef = useRef(void 0);
26190
+ const adminViewsRef = useRef(void 0);
26191
+ const navigationEntriesOrderRef = useRef(void 0);
26133
26192
  const [initialised, setInitialised] = useState(false);
26134
26193
  const [topLevelNavigation, setTopLevelNavigation] = useState(void 0);
26135
26194
  const [navigationLoading, setNavigationLoading] = useState(true);
@@ -26834,7 +26893,7 @@ function useValidateAuthenticator(t0) {
26834
26893
  t2 = $[2];
26835
26894
  }
26836
26895
  useEffect(t1, t2);
26837
- const checkedUserRef = useRef();
26896
+ const checkedUserRef = useRef(void 0);
26838
26897
  let t3;
26839
26898
  if ($[3] !== authController || $[4] !== authenticator || $[5] !== dataSourceDelegate || $[6] !== disabled || $[7] !== storageSource) {
26840
26899
  t3 = async () => {
@@ -27163,13 +27222,13 @@ function EntitySidePanel(props) {
27163
27222
  status,
27164
27223
  values
27165
27224
  }) => /* @__PURE__ */ jsxs(Fragment, { children: [
27166
- /* @__PURE__ */ jsx(IconButton, { className: "self-center", onClick: onClose, children: /* @__PURE__ */ jsx(CloseIcon, { size: "small" }) }),
27167
- allowFullScreen && /* @__PURE__ */ jsx(IconButton, { className: "self-center", onClick: () => {
27225
+ /* @__PURE__ */ jsx(IconButton, { className: "self-center", size: "smallest", onClick: onClose, children: /* @__PURE__ */ jsx(CloseIcon, { size: "smallest" }) }),
27226
+ allowFullScreen && /* @__PURE__ */ jsx(IconButton, { className: "self-center", size: "smallest", onClick: () => {
27168
27227
  const key = status === "new" || status === "copy" ? path + "#new" : path + "/" + entityId;
27169
27228
  saveEntityToMemoryCache(key, values);
27170
27229
  if (entityId) navigate(location.pathname);
27171
27230
  else navigate(location.pathname + "#new");
27172
- }, children: /* @__PURE__ */ jsx(OpenInFullIcon, { size: "small" }) })
27231
+ }, children: /* @__PURE__ */ jsx(OpenInFullIcon, { size: "smallest" }) })
27173
27232
  ] }), onTabChange: ({
27174
27233
  entityId: entityId_0,
27175
27234
  selectedTab,
@@ -28445,7 +28504,7 @@ function useBuildDataSource({
28445
28504
  const orderProperty = collection_3?.orderProperty;
28446
28505
  if (orderProperty && (status === "new" || status === "copy")) {
28447
28506
  const orderProp = properties?.[orderProperty];
28448
- if (orderProp?.disabled === true) {
28507
+ if (orderProp) {
28449
28508
  const currentValue = updatedValues[orderProperty];
28450
28509
  if (currentValue === void 0 || currentValue === null) {
28451
28510
  try {
@@ -29666,14 +29725,19 @@ function getDefaultFieldId(property) {
29666
29725
  return "custom_array";
29667
29726
  } else if (isPropertyBuilder(of)) {
29668
29727
  return "repeat";
29669
- } else if (of?.dataType === "string" && of.enumValues) {
29670
- return "multi_select";
29671
- } else if (of?.dataType === "number" && of.enumValues) {
29672
- return "multi_number_select";
29673
- } else if (of?.dataType === "string" && of.storage) {
29674
- return "multi_file_upload";
29675
- } else if (of?.dataType === "reference") {
29676
- return "multi_references";
29728
+ } else if (of) {
29729
+ const ofProperty = of;
29730
+ if (ofProperty.dataType === "string" && ofProperty.enumValues) {
29731
+ return "multi_select";
29732
+ } else if (ofProperty.dataType === "number" && ofProperty.enumValues) {
29733
+ return "multi_number_select";
29734
+ } else if (ofProperty.dataType === "string" && ofProperty.storage) {
29735
+ return "multi_file_upload";
29736
+ } else if (ofProperty.dataType === "reference") {
29737
+ return "multi_references";
29738
+ } else {
29739
+ return "repeat";
29740
+ }
29677
29741
  } else {
29678
29742
  return "repeat";
29679
29743
  }