@firecms/core 3.1.0-canary.1df3b2c → 3.1.0-canary.768c91f

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 (47) hide show
  1. package/dist/components/EntityCollectionTable/internal/popup_field/useDraggable.d.ts +2 -2
  2. package/dist/components/EntityCollectionView/ViewModeToggle.d.ts +5 -10
  3. package/dist/components/ErrorBoundary.d.ts +1 -1
  4. package/dist/components/VirtualTable/VirtualTableHeader.d.ts +1 -1
  5. package/dist/form/components/ErrorFocus.d.ts +1 -1
  6. package/dist/index.es.js +249 -210
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/index.umd.js +248 -209
  9. package/dist/index.umd.js.map +1 -1
  10. package/dist/internal/useRestoreScroll.d.ts +1 -1
  11. package/dist/types/analytics.d.ts +1 -1
  12. package/dist/types/collections.d.ts +8 -0
  13. package/dist/types/plugins.d.ts +16 -0
  14. package/dist/util/entities.d.ts +1 -1
  15. package/dist/util/resolutions.d.ts +2 -2
  16. package/package.json +9 -9
  17. package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +1 -1
  18. package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +11 -11
  19. package/src/components/EntityCollectionView/EntityBoardCard.tsx +1 -1
  20. package/src/components/EntityCollectionView/EntityCard.tsx +4 -0
  21. package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +23 -3
  22. package/src/components/EntityCollectionView/EntityCollectionView.tsx +50 -16
  23. package/src/components/EntityCollectionView/ViewModeToggle.tsx +27 -30
  24. package/src/components/VirtualTable/VirtualTable.tsx +116 -113
  25. package/src/components/VirtualTable/VirtualTableHeader.tsx +42 -42
  26. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +1 -1
  27. package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +3 -3
  28. package/src/core/DefaultAppBar.tsx +1 -1
  29. package/src/core/EntitySidePanel.tsx +28 -26
  30. package/src/core/field_configs.tsx +14 -9
  31. package/src/form/EntityForm.tsx +69 -60
  32. package/src/form/PropertyFieldBinding.tsx +3 -3
  33. package/src/form/components/ErrorFocus.tsx +3 -3
  34. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +1 -1
  35. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +83 -83
  36. package/src/hooks/useBuildNavigationController.tsx +4 -4
  37. package/src/hooks/useValidateAuthenticator.tsx +1 -1
  38. package/src/internal/useBuildDataSource.ts +1 -2
  39. package/src/preview/PropertyPreview.tsx +1 -0
  40. package/src/types/analytics.ts +10 -0
  41. package/src/types/collections.ts +9 -0
  42. package/src/types/plugins.tsx +18 -0
  43. package/src/util/entities.ts +1 -1
  44. package/src/util/join_collections.ts +10 -8
  45. package/src/util/previews.ts +2 -2
  46. package/src/util/property_utils.tsx +1 -1
  47. package/src/util/resolutions.ts +5 -3
package/dist/index.es.js CHANGED
@@ -2,7 +2,7 @@ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import { c } from "react-compiler-runtime";
3
3
  import * as React from "react";
4
4
  import React__default, { useState, useRef, useEffect, useContext, useCallback, useMemo, createElement, createRef, createContext, forwardRef, memo, useLayoutEffect } from "react";
5
- import { getColorSchemeForSeed, CHIP_COLORS, FunctionsIcon, CircleIcon, iconKeys, coolIconKeys, Icon, Tooltip, ErrorIcon, Typography, IconButton, ContentCopyIcon, OpenInNewIcon, DescriptionIcon, cls, Skeleton, Chip, defaultBorderMixin, KeyboardTabIcon, Checkbox, AccountCircleIcon, Markdown, TextareaAutosize, focusedDisabled, MultiSelect, MultiSelectItem, Select, SelectItem, BooleanSwitch, DateTimeField, paperMixin, EditIcon, DoNotDisturbOnIcon, Menu, MenuItem, MoreVertIcon, Badge, CircularProgress, SearchBar, ArrowUpwardIcon, Popover, FilterListIcon, Button, CenteredView, AssignmentIcon, Label, CloseIcon, TextField, BooleanSwitchWithLabel, useOutsideAlerter, Dialog, DialogTitle, DialogContent, DialogActions, FileCopyIcon, DeleteIcon, AddIcon, StarIcon, Collapse, ExpandablePanel, ArrowForwardIcon, Card, cardMixin, cardClickableMixin, Container, getColorSchemeForKey, RefreshIcon, ViewColumnIcon, ViewKanbanIcon, AppsIcon, ListIcon, ToggleButtonGroup, LoadingButton, WarningIcon, KeyboardArrowDownIcon, VisibilityIcon, CheckIcon, CancelIcon, Alert, NotesIcon, InfoIcon, fieldBackgroundMixin, RemoveIcon, fieldBackgroundDisabledMixin, fieldBackgroundHoverMixin, ArrowDropDownIcon, FilterListOffIcon, SearchIcon, Avatar, DarkModeIcon, LightModeIcon, BrightnessMediumIcon, LogoutIcon, HandleIcon, KeyboardArrowUpIcon, debounce, AutoAwesomeIcon, OpenInFullIcon, Sheet, Tab, Tabs, CodeIcon, ExpandMoreIcon, ViewStreamIcon, RepeatIcon, BallotIcon, ScheduleIcon, AddLinkIcon, LinkIcon, DriveFolderUploadIcon, UploadFileIcon, FormatListNumberedIcon, NumbersIcon, PersonIcon, ListAltIcon, FlagIcon, MailIcon, HttpIcon, FormatQuoteIcon, SubjectIcon, ShortTextIcon, MenuIcon, ChevronLeftIcon } from "@firecms/ui";
5
+ import { getColorSchemeForSeed, CHIP_COLORS, FunctionsIcon, CircleIcon, iconKeys, coolIconKeys, Icon, Tooltip, ErrorIcon, Typography, IconButton, ContentCopyIcon, OpenInNewIcon, DescriptionIcon, cls, Skeleton, Chip, defaultBorderMixin, KeyboardTabIcon, Checkbox, AccountCircleIcon, Markdown, TextareaAutosize, focusedDisabled, MultiSelect, MultiSelectItem, Select, SelectItem, BooleanSwitch, DateTimeField, paperMixin, EditIcon, DoNotDisturbOnIcon, Menu, MenuItem, MoreVertIcon, Badge, CircularProgress, SearchBar, ArrowUpwardIcon, Popover, FilterListIcon, Button, CenteredView, AssignmentIcon, Label, CloseIcon, TextField, BooleanSwitchWithLabel, useOutsideAlerter, Dialog, DialogTitle, DialogContent, DialogActions, FileCopyIcon, DeleteIcon, AddIcon, StarIcon, Collapse, ExpandablePanel, ArrowForwardIcon, Card, cardMixin, cardClickableMixin, Container, getColorSchemeForKey, RefreshIcon, ToggleButtonGroup, ViewColumnIcon, ViewKanbanIcon, AppsIcon, ListIcon, LoadingButton, WarningIcon, KeyboardArrowDownIcon, VisibilityIcon, CheckIcon, CancelIcon, Alert, NotesIcon, InfoIcon, fieldBackgroundMixin, RemoveIcon, fieldBackgroundDisabledMixin, fieldBackgroundHoverMixin, ArrowDropDownIcon, FilterListOffIcon, SearchIcon, Avatar, DarkModeIcon, LightModeIcon, BrightnessMediumIcon, LogoutIcon, HandleIcon, KeyboardArrowUpIcon, debounce, AutoAwesomeIcon, OpenInFullIcon, Sheet, Tab, Tabs, CodeIcon, ExpandMoreIcon, ViewStreamIcon, RepeatIcon, BallotIcon, ScheduleIcon, AddLinkIcon, LinkIcon, DriveFolderUploadIcon, UploadFileIcon, FormatListNumberedIcon, NumbersIcon, PersonIcon, ListAltIcon, FlagIcon, MailIcon, HttpIcon, FormatQuoteIcon, SubjectIcon, ShortTextIcon, MenuIcon, ChevronLeftIcon } from "@firecms/ui";
6
6
  import { SnackbarProvider as SnackbarProvider$1, useSnackbar } from "notistack";
7
7
  import hash from "object-hash";
8
8
  import { getIn, setIn, useFormex, useCreateFormex, Formex, Field } from "@firecms/formex";
@@ -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,
@@ -18344,13 +18380,13 @@ function EntityCollectionBoardView({
18344
18380
  ] })
18345
18381
  ] });
18346
18382
  }
18383
+ const ALL_VIEW_MODES = ["table", "cards", "kanban"];
18347
18384
  function ViewModeToggle(t0) {
18348
- const $ = c(42);
18385
+ const $ = c(36);
18349
18386
  const {
18350
18387
  viewMode: t1,
18351
18388
  onViewModeChange,
18352
- kanbanEnabled: t2,
18353
- hasKanbanConfigPlugin: t3,
18389
+ enabledViews: t2,
18354
18390
  size,
18355
18391
  onSizeChanged,
18356
18392
  open,
@@ -18360,14 +18396,13 @@ function ViewModeToggle(t0) {
18360
18396
  onKanbanPropertyChange
18361
18397
  } = t0;
18362
18398
  const viewMode = t1 === void 0 ? "table" : t1;
18363
- const kanbanEnabled = t2 === void 0 ? false : t2;
18364
- const hasKanbanConfigPlugin = t3 === void 0 ? false : t3;
18399
+ const enabledViews = t2 === void 0 ? ALL_VIEW_MODES : t2;
18365
18400
  if (!onViewModeChange) {
18366
18401
  return null;
18367
18402
  }
18368
- let t4;
18403
+ let t3;
18369
18404
  if ($[0] !== viewMode) {
18370
- t4 = () => {
18405
+ t3 = () => {
18371
18406
  if (viewMode === "kanban") {
18372
18407
  return /* @__PURE__ */ jsx(ViewKanbanIcon, { size: "small" });
18373
18408
  }
@@ -18377,14 +18412,14 @@ function ViewModeToggle(t0) {
18377
18412
  return /* @__PURE__ */ jsx(ListIcon, { size: "small" });
18378
18413
  };
18379
18414
  $[0] = viewMode;
18380
- $[1] = t4;
18415
+ $[1] = t3;
18381
18416
  } else {
18382
- t4 = $[1];
18417
+ t3 = $[1];
18383
18418
  }
18384
- const getViewModeIcon = t4;
18385
- let t5;
18419
+ const getViewModeIcon = t3;
18420
+ let t4;
18386
18421
  if ($[2] !== viewMode) {
18387
- t5 = () => {
18422
+ t4 = () => {
18388
18423
  if (viewMode === "kanban") {
18389
18424
  return "Board";
18390
18425
  }
@@ -18394,177 +18429,151 @@ function ViewModeToggle(t0) {
18394
18429
  return "List";
18395
18430
  };
18396
18431
  $[2] = viewMode;
18397
- $[3] = t5;
18432
+ $[3] = t4;
18398
18433
  } else {
18399
- t5 = $[3];
18434
+ t4 = $[3];
18400
18435
  }
18401
- const getViewModeName = t5;
18402
- const showKanban = kanbanEnabled || hasKanbanConfigPlugin;
18436
+ const getViewModeName = t4;
18403
18437
  const showSizeSelector = size && onSizeChanged && (viewMode === "table" || viewMode === "cards");
18404
18438
  const showKanbanPropertySelector = viewMode === "kanban" && kanbanPropertyOptions && kanbanPropertyOptions.length > 0 && onKanbanPropertyChange;
18439
+ let t5;
18405
18440
  let t6;
18406
- let t7;
18407
18441
  if ($[4] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
18408
- t7 = {
18409
- value: "table",
18410
- label: "List",
18411
- icon: /* @__PURE__ */ jsx(ListIcon, { size: "small" })
18412
- };
18413
- $[4] = t7;
18442
+ t6 = /* @__PURE__ */ jsx(ListIcon, { size: "small" });
18443
+ $[4] = t6;
18414
18444
  } else {
18415
- t7 = $[4];
18445
+ t6 = $[4];
18416
18446
  }
18417
- let t8;
18418
- if ($[5] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
18419
- t8 = {
18447
+ let t7;
18448
+ if ($[5] !== enabledViews) {
18449
+ const allOptions = [{
18450
+ value: "table",
18451
+ label: "List",
18452
+ icon: t6
18453
+ }, {
18420
18454
  value: "cards",
18421
18455
  label: "Cards",
18422
18456
  icon: /* @__PURE__ */ jsx(AppsIcon, { size: "small" })
18423
- };
18424
- $[5] = t8;
18457
+ }, {
18458
+ value: "kanban",
18459
+ label: "Board",
18460
+ icon: /* @__PURE__ */ jsx(ViewKanbanIcon, { size: "small" })
18461
+ }];
18462
+ t7 = allOptions.filter((option) => enabledViews.includes(option.value));
18463
+ $[5] = enabledViews;
18464
+ $[6] = t7;
18425
18465
  } else {
18426
- t8 = $[5];
18466
+ t7 = $[6];
18427
18467
  }
18428
- let options;
18429
- if ($[6] !== hasKanbanConfigPlugin || $[7] !== kanbanEnabled || $[8] !== showKanban) {
18430
- options = [t7, t8];
18431
- if (showKanban) {
18432
- let t92;
18433
- if ($[10] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
18434
- t92 = /* @__PURE__ */ jsx(ViewKanbanIcon, { size: "small" });
18435
- $[10] = t92;
18436
- } else {
18437
- t92 = $[10];
18438
- }
18439
- const t102 = !kanbanEnabled && !hasKanbanConfigPlugin;
18440
- let t112;
18441
- if ($[11] !== t102) {
18442
- t112 = {
18443
- value: "kanban",
18444
- label: "Board",
18445
- icon: t92,
18446
- disabled: t102
18447
- };
18448
- $[11] = t102;
18449
- $[12] = t112;
18450
- } else {
18451
- t112 = $[12];
18452
- }
18453
- options.push(t112);
18454
- }
18455
- $[6] = hasKanbanConfigPlugin;
18456
- $[7] = kanbanEnabled;
18457
- $[8] = showKanban;
18458
- $[9] = options;
18468
+ t5 = t7;
18469
+ const viewModeOptions = t5;
18470
+ if (viewModeOptions.length <= 1 && !showSizeSelector) {
18471
+ return null;
18472
+ }
18473
+ let t8;
18474
+ if ($[7] !== getViewModeIcon) {
18475
+ t8 = getViewModeIcon();
18476
+ $[7] = getViewModeIcon;
18477
+ $[8] = t8;
18459
18478
  } else {
18460
- options = $[9];
18479
+ t8 = $[8];
18461
18480
  }
18462
- t6 = options;
18463
- const viewModeOptions = t6;
18464
- let t9;
18465
- if ($[13] !== getViewModeIcon) {
18466
- t9 = getViewModeIcon();
18467
- $[13] = getViewModeIcon;
18468
- $[14] = t9;
18481
+ const t9 = getViewModeName();
18482
+ let t10;
18483
+ if ($[9] !== t9) {
18484
+ t10 = /* @__PURE__ */ jsx("span", { className: "ml-1 text-sm", children: t9 });
18485
+ $[9] = t9;
18486
+ $[10] = t10;
18469
18487
  } else {
18470
- t9 = $[14];
18488
+ t10 = $[10];
18471
18489
  }
18472
- const t10 = getViewModeName();
18473
18490
  let t11;
18474
- if ($[15] !== t10) {
18475
- t11 = /* @__PURE__ */ jsx("span", { className: "ml-1 text-sm", children: t10 });
18476
- $[15] = t10;
18477
- $[16] = t11;
18491
+ if ($[11] !== t10 || $[12] !== t8) {
18492
+ t11 = /* @__PURE__ */ jsxs(Button, { size: "small", children: [
18493
+ t8,
18494
+ t10
18495
+ ] });
18496
+ $[11] = t10;
18497
+ $[12] = t8;
18498
+ $[13] = t11;
18478
18499
  } else {
18479
- t11 = $[16];
18500
+ t11 = $[13];
18480
18501
  }
18481
18502
  let t12;
18482
- if ($[17] !== t11 || $[18] !== t9) {
18483
- t12 = /* @__PURE__ */ jsxs(Button, { size: "small", children: [
18484
- t9,
18485
- t11
18486
- ] });
18487
- $[17] = t11;
18488
- $[18] = t9;
18489
- $[19] = t12;
18503
+ if ($[14] !== onViewModeChange || $[15] !== viewMode || $[16] !== viewModeOptions) {
18504
+ t12 = viewModeOptions.length > 1 && /* @__PURE__ */ jsx(ToggleButtonGroup, { value: viewMode, onValueChange: onViewModeChange, options: viewModeOptions });
18505
+ $[14] = onViewModeChange;
18506
+ $[15] = viewMode;
18507
+ $[16] = viewModeOptions;
18508
+ $[17] = t12;
18490
18509
  } else {
18491
- t12 = $[19];
18510
+ t12 = $[17];
18492
18511
  }
18493
18512
  let t13;
18494
- if ($[20] !== onViewModeChange || $[21] !== viewMode || $[22] !== viewModeOptions) {
18495
- t13 = /* @__PURE__ */ jsx(ToggleButtonGroup, { value: viewMode, onValueChange: onViewModeChange, options: viewModeOptions });
18496
- $[20] = onViewModeChange;
18497
- $[21] = viewMode;
18498
- $[22] = viewModeOptions;
18499
- $[23] = t13;
18500
- } else {
18501
- t13 = $[23];
18502
- }
18503
- let t14;
18504
- if ($[24] !== onSizeChanged || $[25] !== showSizeSelector || $[26] !== size) {
18505
- t14 = showSizeSelector && /* @__PURE__ */ jsxs("div", { className: "flex flex-row items-center justify-between gap-2", children: [
18513
+ if ($[18] !== onSizeChanged || $[19] !== showSizeSelector || $[20] !== size) {
18514
+ t13 = showSizeSelector && /* @__PURE__ */ jsxs("div", { className: "flex flex-row items-center justify-between gap-2", children: [
18506
18515
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-surface-600 dark:text-surface-300", children: [
18507
18516
  /* @__PURE__ */ jsx(ViewColumnIcon, { size: "small" }),
18508
18517
  /* @__PURE__ */ jsx("span", { children: "Size" })
18509
18518
  ] }),
18510
18519
  /* @__PURE__ */ jsx(Select, { value: size, size: "small", className: "w-20", onValueChange: (v) => onSizeChanged?.(v), renderValue: _temp$e, children: ["xs", "s", "m", "l", "xl"].map(_temp2$5) })
18511
18520
  ] });
18512
- $[24] = onSizeChanged;
18513
- $[25] = showSizeSelector;
18514
- $[26] = size;
18515
- $[27] = t14;
18521
+ $[18] = onSizeChanged;
18522
+ $[19] = showSizeSelector;
18523
+ $[20] = size;
18524
+ $[21] = t13;
18516
18525
  } else {
18517
- t14 = $[27];
18526
+ t13 = $[21];
18518
18527
  }
18519
- let t15;
18520
- if ($[28] !== kanbanPropertyOptions || $[29] !== onKanbanPropertyChange || $[30] !== selectedKanbanProperty || $[31] !== showKanbanPropertySelector) {
18521
- t15 = showKanbanPropertySelector && /* @__PURE__ */ jsxs("div", { className: "flex flex-row items-center justify-between gap-2", children: [
18528
+ let t14;
18529
+ if ($[22] !== kanbanPropertyOptions || $[23] !== onKanbanPropertyChange || $[24] !== selectedKanbanProperty || $[25] !== showKanbanPropertySelector) {
18530
+ t14 = showKanbanPropertySelector && /* @__PURE__ */ jsxs("div", { className: "flex flex-row items-center justify-between gap-2", children: [
18522
18531
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-surface-600 dark:text-surface-300", children: [
18523
18532
  /* @__PURE__ */ jsx(ViewKanbanIcon, { size: "small" }),
18524
18533
  /* @__PURE__ */ jsx("span", { children: "Group by" })
18525
18534
  ] }),
18526
18535
  /* @__PURE__ */ jsx(Select, { value: selectedKanbanProperty, size: "small", className: "w-32", onValueChange: (v_1) => onKanbanPropertyChange?.(v_1), renderValue: (v_2) => {
18527
- const option = kanbanPropertyOptions?.find((o) => o.key === v_2);
18528
- return /* @__PURE__ */ jsx("span", { className: "font-medium truncate", children: option?.label ?? v_2 });
18536
+ const option_0 = kanbanPropertyOptions?.find((o) => o.key === v_2);
18537
+ return /* @__PURE__ */ jsx("span", { className: "font-medium truncate", children: option_0?.label ?? v_2 });
18529
18538
  }, children: kanbanPropertyOptions?.map(_temp3$3) })
18530
18539
  ] });
18531
- $[28] = kanbanPropertyOptions;
18532
- $[29] = onKanbanPropertyChange;
18533
- $[30] = selectedKanbanProperty;
18534
- $[31] = showKanbanPropertySelector;
18535
- $[32] = t15;
18540
+ $[22] = kanbanPropertyOptions;
18541
+ $[23] = onKanbanPropertyChange;
18542
+ $[24] = selectedKanbanProperty;
18543
+ $[25] = showKanbanPropertySelector;
18544
+ $[26] = t14;
18536
18545
  } else {
18537
- t15 = $[32];
18546
+ t14 = $[26];
18538
18547
  }
18539
- let t16;
18540
- if ($[33] !== t13 || $[34] !== t14 || $[35] !== t15) {
18541
- t16 = /* @__PURE__ */ jsxs("div", { className: "p-3 flex flex-col gap-3 min-w-[240px]", children: [
18548
+ let t15;
18549
+ if ($[27] !== t12 || $[28] !== t13 || $[29] !== t14) {
18550
+ t15 = /* @__PURE__ */ jsxs("div", { className: "p-3 flex flex-col gap-3 min-w-[240px]", children: [
18551
+ t12,
18542
18552
  t13,
18543
- t14,
18544
- t15
18553
+ t14
18545
18554
  ] });
18546
- $[33] = t13;
18547
- $[34] = t14;
18548
- $[35] = t15;
18549
- $[36] = t16;
18555
+ $[27] = t12;
18556
+ $[28] = t13;
18557
+ $[29] = t14;
18558
+ $[30] = t15;
18550
18559
  } else {
18551
- t16 = $[36];
18560
+ t15 = $[30];
18552
18561
  }
18553
- let t17;
18554
- if ($[37] !== onOpenChange || $[38] !== open || $[39] !== t12 || $[40] !== t16) {
18555
- t17 = /* @__PURE__ */ jsx(Popover, { open, onOpenChange, modal: true, trigger: t12, children: t16 });
18556
- $[37] = onOpenChange;
18557
- $[38] = open;
18558
- $[39] = t12;
18559
- $[40] = t16;
18560
- $[41] = t17;
18562
+ let t16;
18563
+ if ($[31] !== onOpenChange || $[32] !== open || $[33] !== t11 || $[34] !== t15) {
18564
+ t16 = /* @__PURE__ */ jsx(Popover, { open, onOpenChange, modal: true, trigger: t11, children: t15 });
18565
+ $[31] = onOpenChange;
18566
+ $[32] = open;
18567
+ $[33] = t11;
18568
+ $[34] = t15;
18569
+ $[35] = t16;
18561
18570
  } else {
18562
- t17 = $[41];
18571
+ t16 = $[35];
18563
18572
  }
18564
- return t17;
18573
+ return t16;
18565
18574
  }
18566
- function _temp3$3(option_0) {
18567
- return /* @__PURE__ */ jsx(SelectItem, { value: option_0.key, children: option_0.label }, option_0.key);
18575
+ function _temp3$3(option_1) {
18576
+ return /* @__PURE__ */ jsx(SelectItem, { value: option_1.key, children: option_1.label }, option_1.key);
18568
18577
  }
18569
18578
  function _temp2$5(s) {
18570
18579
  return /* @__PURE__ */ jsx(SelectItem, { value: s, className: "font-medium text-center", children: s.toUpperCase() }, s);
@@ -19511,6 +19520,7 @@ function EntityForm({
19511
19520
  console.error(error);
19512
19521
  }, [snackbarController]);
19513
19522
  const pluginActions = [];
19523
+ const pluginBeforeTitle = [];
19514
19524
  const plugins = customizationController.plugins;
19515
19525
  const actionsDisabled = disabled || formex.isSubmitting || status === "existing" && !formex.dirty || Boolean(disabledProp);
19516
19526
  const parentCollectionIds = navigationController.getParentCollectionIds(path);
@@ -19527,6 +19537,7 @@ function EntityForm({
19527
19537
  disabled: actionsDisabled
19528
19538
  };
19529
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));
19530
19541
  }
19531
19542
  const titlePropertyKey = getEntityTitlePropertyKey(resolvedCollection, customizationController.propertyConfigs);
19532
19543
  const title = (formex.values && titlePropertyKey ? getValueInPath(formex.values, titlePropertyKey) : void 0) ?? collection.singularName ?? collection.name;
@@ -19623,6 +19634,7 @@ function EntityForm({
19623
19634
  };
19624
19635
  const formRef = useRef(null);
19625
19636
  const formView = /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsxs(Fragment, { children: [
19637
+ pluginBeforeTitle,
19626
19638
  !Builder && /* @__PURE__ */ jsxs("div", { className: "w-full py-2 flex flex-col items-start my-4 lg:my-6", children: [
19627
19639
  /* @__PURE__ */ jsx(Typography, { className: "my-4 flex-grow line-clamp-1 " + (collection.hideIdFromForm ? "mb-6" : ""), variant: "h4", children: title ?? collection.singularName ?? collection.name }),
19628
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" }),
@@ -21880,7 +21892,7 @@ function PropertyFieldBindingInternal(t0) {
21880
21892
  index,
21881
21893
  authController
21882
21894
  });
21883
- Component = configProperty.Field;
21895
+ Component = configProperty?.Field;
21884
21896
  }
21885
21897
  }
21886
21898
  }
@@ -24505,13 +24517,18 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
24505
24517
  });
24506
24518
  }, [onCollectionModifiedForUser, fullPath, userConfigPersistence]);
24507
24519
  const onViewModeChange = useCallback((mode) => {
24520
+ analyticsController.onAnalyticsEvent?.("view_mode_changed", {
24521
+ path: fullPath,
24522
+ from: viewMode,
24523
+ to: mode
24524
+ });
24508
24525
  setViewMode(mode);
24509
24526
  if (userConfigPersistence) {
24510
24527
  onCollectionModifiedForUser(fullPath, {
24511
24528
  defaultViewMode: mode
24512
24529
  });
24513
24530
  }
24514
- }, [setViewMode, userConfigPersistence, onCollectionModifiedForUser, fullPath]);
24531
+ }, [setViewMode, userConfigPersistence, onCollectionModifiedForUser, fullPath, analyticsController, viewMode]);
24515
24532
  const createEnabled = canCreateEntity(collection, authController, fullPath, null);
24516
24533
  const uniqueFieldValidator = useCallback(({
24517
24534
  name,
@@ -24565,24 +24582,26 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
24565
24582
  propertyConfigs: customizationController.propertyConfigs,
24566
24583
  authController
24567
24584
  }), [collection, fullPath]);
24568
- const kanbanEnabled = useMemo(() => {
24569
- if (!collection.kanban?.columnProperty) return false;
24570
- const property_0 = getPropertyInPath(resolvedCollection.properties, collection.kanban.columnProperty);
24571
- if (!property_0 || !("dataType" in property_0) || property_0.dataType !== "string") return false;
24572
- return Boolean(property_0.enumValues);
24573
- }, [collection.kanban?.columnProperty, resolvedCollection.properties]);
24574
- const hasKanbanConfigPlugin = useMemo(() => {
24575
- return customizationController.plugins?.some((plugin_0) => plugin_0.collectionView?.KanbanSetupComponent) ?? false;
24576
- }, [customizationController.plugins]);
24585
+ const hasEnumProperty = useMemo(() => {
24586
+ const properties = resolvedCollection.properties;
24587
+ return Object.values(properties).some((prop) => prop && prop.dataType === "string" && prop.enumValues);
24588
+ }, [resolvedCollection.properties]);
24589
+ const enabledViews = useMemo(() => {
24590
+ const configured = collection.enabledViews ?? ["table", "cards", "kanban"];
24591
+ if (!hasEnumProperty) {
24592
+ return configured.filter((v) => v !== "kanban");
24593
+ }
24594
+ return configured;
24595
+ }, [collection.enabledViews, hasEnumProperty]);
24577
24596
  const kanbanPropertyOptions = useMemo(() => {
24578
24597
  const options = [];
24579
- const properties = resolvedCollection.properties;
24580
- for (const [key_0, property_1] of Object.entries(properties)) {
24581
- const prop = property_1;
24582
- if (prop && prop.dataType === "string" && prop.enumValues) {
24598
+ const properties_0 = resolvedCollection.properties;
24599
+ for (const [key_0, property_0] of Object.entries(properties_0)) {
24600
+ const prop_0 = property_0;
24601
+ if (prop_0 && prop_0.dataType === "string" && prop_0.enumValues) {
24583
24602
  options.push({
24584
24603
  key: key_0,
24585
- label: prop.name || key_0
24604
+ label: prop_0.name || key_0
24586
24605
  });
24587
24606
  }
24588
24607
  }
@@ -24610,14 +24629,18 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
24610
24629
  }
24611
24630
  }
24612
24631
  }, [kanbanPropertyOptions, selectedKanbanProperty, getSavedKanbanProperty, collection.kanban?.columnProperty]);
24613
- const onKanbanPropertyChange = useCallback((property_2) => {
24614
- setSelectedKanbanProperty(property_2);
24632
+ const onKanbanPropertyChange = useCallback((property_1) => {
24633
+ analyticsController.onAnalyticsEvent?.("kanban_property_changed", {
24634
+ path: fullPath,
24635
+ property: property_1
24636
+ });
24637
+ setSelectedKanbanProperty(property_1);
24615
24638
  if (userConfigPersistence) {
24616
24639
  onCollectionModifiedForUser(fullPath, {
24617
- kanbanColumnProperty: property_2
24640
+ kanbanColumnProperty: property_1
24618
24641
  });
24619
24642
  }
24620
- }, [userConfigPersistence, onCollectionModifiedForUser, fullPath]);
24643
+ }, [userConfigPersistence, onCollectionModifiedForUser, fullPath, analyticsController]);
24621
24644
  const getPropertyFor = useCallback(({
24622
24645
  propertyKey: propertyKey_0,
24623
24646
  entity: entity_2
@@ -24729,15 +24752,15 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
24729
24752
  }, [docsCount, fullPath, breadcrumbs.updateCount]);
24730
24753
  const countFetcher = /* @__PURE__ */ jsx(EntitiesCount, { fullPath, collection, filter: tableController.filterValues, sortBy: tableController.sortBy, onCountChange: setDocsCount });
24731
24754
  const buildAdditionalHeaderWidget = useCallback(({
24732
- property: property_3,
24755
+ property: property_2,
24733
24756
  propertyKey: propertyKey_1,
24734
24757
  onHover
24735
24758
  }) => {
24736
24759
  const collection_4 = collectionRef.current;
24737
24760
  if (!customizationController.plugins) return null;
24738
- return /* @__PURE__ */ jsx(Fragment, { children: customizationController.plugins.filter((plugin_1) => plugin_1.collectionView?.HeaderAction).map((plugin_2, i) => {
24739
- const HeaderAction = plugin_2.collectionView.HeaderAction;
24740
- return /* @__PURE__ */ jsx(HeaderAction, { onHover, propertyKey: propertyKey_1, property: property_3, fullPath, collection: collection_4, tableController, parentCollectionIds: parentCollectionIds ?? [] }, `plugin_header_action_${i}`);
24761
+ return /* @__PURE__ */ jsx(Fragment, { children: customizationController.plugins.filter((plugin_0) => plugin_0.collectionView?.HeaderAction).map((plugin_1, i) => {
24762
+ const HeaderAction = plugin_1.collectionView.HeaderAction;
24763
+ return /* @__PURE__ */ jsx(HeaderAction, { onHover, propertyKey: propertyKey_1, property: property_2, fullPath, collection: collection_4, tableController, parentCollectionIds: parentCollectionIds ?? [] }, `plugin_header_action_${i}`);
24741
24764
  }) });
24742
24765
  }, [customizationController.plugins, fullPath, parentCollectionIds]);
24743
24766
  const addColumnComponentInternal = AddColumnComponent ? function() {
@@ -24755,11 +24778,22 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
24755
24778
  parentCollectionIds
24756
24779
  });
24757
24780
  const [viewModePopoverOpen, setViewModePopoverOpen] = useState(false);
24758
- const viewModeToggleElement = /* @__PURE__ */ jsx(ViewModeToggle, { viewMode, onViewModeChange, kanbanEnabled, hasKanbanConfigPlugin, 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 });
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]);
24759
24793
  return /* @__PURE__ */ jsxs("div", { className: cls("overflow-hidden h-full w-full rounded-md flex flex-col", className), ref: containerRef, children: [
24760
24794
  countFetcher,
24761
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 }) }),
24762
- viewMode === "kanban" && (kanbanEnabled || hasKanbanConfigPlugin) ? /* @__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: [
24763
24797
  /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", children: "So empty..." }),
24764
24798
  /* @__PURE__ */ jsxs(Button, { onClick: onNewClick, className: "mt-4", children: [
24765
24799
  /* @__PURE__ */ jsx(AddIcon, {}),
@@ -26151,10 +26185,10 @@ function useBuildNavigationController(props) {
26151
26185
  navigationGroupMappings
26152
26186
  } = props;
26153
26187
  const navigate = useNavigate();
26154
- const collectionsRef = useRef();
26155
- const viewsRef = useRef();
26156
- const adminViewsRef = useRef();
26157
- 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);
26158
26192
  const [initialised, setInitialised] = useState(false);
26159
26193
  const [topLevelNavigation, setTopLevelNavigation] = useState(void 0);
26160
26194
  const [navigationLoading, setNavigationLoading] = useState(true);
@@ -26859,7 +26893,7 @@ function useValidateAuthenticator(t0) {
26859
26893
  t2 = $[2];
26860
26894
  }
26861
26895
  useEffect(t1, t2);
26862
- const checkedUserRef = useRef();
26896
+ const checkedUserRef = useRef(void 0);
26863
26897
  let t3;
26864
26898
  if ($[3] !== authController || $[4] !== authenticator || $[5] !== dataSourceDelegate || $[6] !== disabled || $[7] !== storageSource) {
26865
26899
  t3 = async () => {
@@ -27188,13 +27222,13 @@ function EntitySidePanel(props) {
27188
27222
  status,
27189
27223
  values
27190
27224
  }) => /* @__PURE__ */ jsxs(Fragment, { children: [
27191
- /* @__PURE__ */ jsx(IconButton, { className: "self-center", onClick: onClose, children: /* @__PURE__ */ jsx(CloseIcon, { size: "small" }) }),
27192
- 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: () => {
27193
27227
  const key = status === "new" || status === "copy" ? path + "#new" : path + "/" + entityId;
27194
27228
  saveEntityToMemoryCache(key, values);
27195
27229
  if (entityId) navigate(location.pathname);
27196
27230
  else navigate(location.pathname + "#new");
27197
- }, children: /* @__PURE__ */ jsx(OpenInFullIcon, { size: "small" }) })
27231
+ }, children: /* @__PURE__ */ jsx(OpenInFullIcon, { size: "smallest" }) })
27198
27232
  ] }), onTabChange: ({
27199
27233
  entityId: entityId_0,
27200
27234
  selectedTab,
@@ -28470,7 +28504,7 @@ function useBuildDataSource({
28470
28504
  const orderProperty = collection_3?.orderProperty;
28471
28505
  if (orderProperty && (status === "new" || status === "copy")) {
28472
28506
  const orderProp = properties?.[orderProperty];
28473
- if (orderProp?.disabled === true) {
28507
+ if (orderProp) {
28474
28508
  const currentValue = updatedValues[orderProperty];
28475
28509
  if (currentValue === void 0 || currentValue === null) {
28476
28510
  try {
@@ -29691,14 +29725,19 @@ function getDefaultFieldId(property) {
29691
29725
  return "custom_array";
29692
29726
  } else if (isPropertyBuilder(of)) {
29693
29727
  return "repeat";
29694
- } else if (of?.dataType === "string" && of.enumValues) {
29695
- return "multi_select";
29696
- } else if (of?.dataType === "number" && of.enumValues) {
29697
- return "multi_number_select";
29698
- } else if (of?.dataType === "string" && of.storage) {
29699
- return "multi_file_upload";
29700
- } else if (of?.dataType === "reference") {
29701
- 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
+ }
29702
29741
  } else {
29703
29742
  return "repeat";
29704
29743
  }