@firecms/core 3.1.0-canary.1df3b2c → 3.1.0-canary.8958c1b

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 (46) 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 +247 -210
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/index.umd.js +246 -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 +7 -7
  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/previews.ts +2 -2
  45. package/src/util/property_utils.tsx +1 -1
  46. 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;
@@ -7580,7 +7580,7 @@ const PropertyPreview = React__default.memo(function PropertyPreview2(props) {
7580
7580
  } else {
7581
7581
  if (property.dataType === "map") {
7582
7582
  if (typeof value === "object") {
7583
- content = /* @__PURE__ */ jsx(MapPropertyPreview, { ...props, property });
7583
+ content = /* @__PURE__ */ jsx(MapPropertyPreview, { ...props, value, property });
7584
7584
  } else {
7585
7585
  content = buildWrongValueType(propertyKey, property.dataType, value);
7586
7586
  }
@@ -8464,7 +8464,7 @@ function VirtualTableSelect(props) {
8464
8464
  const handleOpenChange = t4;
8465
8465
  let t5;
8466
8466
  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)) });
8467
+ 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
8468
  $[11] = disabled;
8469
8469
  $[12] = enumValues;
8470
8470
  $[13] = internalValue;
@@ -9024,7 +9024,7 @@ function EntityTableCellActions({
9024
9024
  openPopup(cellRect);
9025
9025
  }
9026
9026
  }, []);
9027
- const iconRef = useRef();
9027
+ const iconRef = useRef(void 0);
9028
9028
  useEffect(() => {
9029
9029
  if (iconRef.current && selected) {
9030
9030
  iconRef.current.focus({
@@ -12172,7 +12172,7 @@ const VirtualTable = React__default.memo(function VirtualTable2({
12172
12172
  onColumnResize(params_0);
12173
12173
  }
12174
12174
  }, [columns, onColumnResize]);
12175
- const filterRef = useRef();
12175
+ const filterRef = useRef(void 0);
12176
12176
  useEffect(() => {
12177
12177
  filterRef.current = filterInput;
12178
12178
  }, [filterInput]);
@@ -12284,7 +12284,7 @@ const VirtualTable = React__default.memo(function VirtualTable2({
12284
12284
  return tableContent;
12285
12285
  }, equal);
12286
12286
  const SortableCellWrapper = (t0) => {
12287
- const $ = c(15);
12287
+ const $ = c(17);
12288
12288
  const {
12289
12289
  columnKey,
12290
12290
  width,
@@ -12312,10 +12312,22 @@ const SortableCellWrapper = (t0) => {
12312
12312
  transform,
12313
12313
  transition
12314
12314
  } = useSortable(t2);
12315
+ let attrsWithoutTabIndex;
12316
+ if ($[3] !== attributes) {
12317
+ const {
12318
+ tabIndex: _tabIndex,
12319
+ ...t32
12320
+ } = attributes;
12321
+ attrsWithoutTabIndex = t32;
12322
+ $[3] = attributes;
12323
+ $[4] = attrsWithoutTabIndex;
12324
+ } else {
12325
+ attrsWithoutTabIndex = $[4];
12326
+ }
12315
12327
  const t3 = transform ? `translateX(${transform.x}px)` : void 0;
12316
12328
  const t4 = isDragging ? void 0 : transition;
12317
12329
  let t5;
12318
- if ($[3] !== t3 || $[4] !== t4 || $[5] !== width) {
12330
+ if ($[5] !== t3 || $[6] !== t4 || $[7] !== width) {
12319
12331
  t5 = {
12320
12332
  transform: t3,
12321
12333
  transition: t4,
@@ -12323,34 +12335,34 @@ const SortableCellWrapper = (t0) => {
12323
12335
  maxWidth: width,
12324
12336
  width
12325
12337
  };
12326
- $[3] = t3;
12327
- $[4] = t4;
12328
- $[5] = width;
12329
- $[6] = t5;
12338
+ $[5] = t3;
12339
+ $[6] = t4;
12340
+ $[7] = width;
12341
+ $[8] = t5;
12330
12342
  } else {
12331
- t5 = $[6];
12343
+ t5 = $[8];
12332
12344
  }
12333
12345
  const style = t5;
12334
12346
  const t6 = frozen && "sticky left-0 z-10 bg-white dark:bg-surface-950";
12335
12347
  let t7;
12336
- if ($[7] !== t6) {
12348
+ if ($[9] !== t6) {
12337
12349
  t7 = cls("flex-shrink-0", t6);
12338
- $[7] = t6;
12339
- $[8] = t7;
12350
+ $[9] = t6;
12351
+ $[10] = t7;
12340
12352
  } else {
12341
- t7 = $[8];
12353
+ t7 = $[10];
12342
12354
  }
12343
12355
  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;
12356
+ if ($[11] !== attrsWithoutTabIndex || $[12] !== children || $[13] !== setNodeRef || $[14] !== style || $[15] !== t7) {
12357
+ t8 = /* @__PURE__ */ jsx("div", { ref: setNodeRef, style, className: t7, ...attrsWithoutTabIndex, children });
12358
+ $[11] = attrsWithoutTabIndex;
12359
+ $[12] = children;
12360
+ $[13] = setNodeRef;
12361
+ $[14] = style;
12362
+ $[15] = t7;
12363
+ $[16] = t8;
12352
12364
  } else {
12353
- t8 = $[14];
12365
+ t8 = $[16];
12354
12366
  }
12355
12367
  return t8;
12356
12368
  };
@@ -16253,7 +16265,7 @@ function EntityCard({
16253
16265
  size = "m"
16254
16266
  }) {
16255
16267
  const authController = useAuthController();
16256
- useAnalyticsController();
16268
+ const analyticsController = useAnalyticsController();
16257
16269
  useSideEntityController();
16258
16270
  const customizationController = useCustomizationController();
16259
16271
  useNavigationController();
@@ -16280,6 +16292,10 @@ function EntityCard({
16280
16292
  return;
16281
16293
  }
16282
16294
  if (onClick) {
16295
+ analyticsController.onAnalyticsEvent?.("card_view_entity_click", {
16296
+ path: entity.path,
16297
+ entityId: entity.id
16298
+ });
16283
16299
  onClick(entity);
16284
16300
  }
16285
16301
  };
@@ -17566,7 +17582,7 @@ function EntityBoardCardInner({
17566
17582
  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
17583
  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
17584
  /* @__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 }) }),
17585
+ /* @__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
17586
  /* @__PURE__ */ jsx("div", { className: "text-xs text-surface-500 font-mono truncate", children: entity.id })
17571
17587
  ] }),
17572
17588
  selectionEnabled && /* @__PURE__ */ jsx("div", { className: "ml-2 shrink-0", onClick: handleCheckboxClick, children: /* @__PURE__ */ jsx(Checkbox, { checked: selected ?? false, onCheckedChange: handleSelectionChange, size: "smallest" }) })
@@ -17922,6 +17938,7 @@ function EntityCollectionBoardView({
17922
17938
  const context = useFireCMSContext();
17923
17939
  const dataSource = useDataSource();
17924
17940
  const sideEntityController = useSideEntityController();
17941
+ const analyticsController = useAnalyticsController();
17925
17942
  const plugins = customizationController.plugins ?? [];
17926
17943
  const [showBackfillDialog, setShowBackfillDialog] = useState(false);
17927
17944
  const [backfillLoading, setBackfillLoading] = useState(false);
@@ -18037,6 +18054,10 @@ function EntityCollectionBoardView({
18037
18054
  return plugins.some((plugin) => plugin.collectionView?.onKanbanColumnsReorder);
18038
18055
  }, [plugins]);
18039
18056
  const handleColumnReorder = useCallback((newColumns) => {
18057
+ analyticsController.onAnalyticsEvent?.("kanban_column_reorder", {
18058
+ path: fullPath,
18059
+ columnProperty
18060
+ });
18040
18061
  setHasUserReordered(true);
18041
18062
  setLocalColumnsOrder(newColumns);
18042
18063
  plugins.filter((plugin_0) => plugin_0.collectionView?.onKanbanColumnsReorder).forEach((plugin_1) => {
@@ -18048,7 +18069,7 @@ function EntityCollectionBoardView({
18048
18069
  newColumnsOrder: newColumns
18049
18070
  });
18050
18071
  });
18051
- }, [plugins, fullPath, parentCollectionIds, collection, columnProperty]);
18072
+ }, [plugins, fullPath, parentCollectionIds, collection, columnProperty, analyticsController]);
18052
18073
  const [missingOrderCount, setMissingOrderCount] = useState(0);
18053
18074
  const dataSourceRef = useRef(dataSource);
18054
18075
  const collectionRef = useRef(collection);
@@ -18160,6 +18181,12 @@ function EntityCollectionBoardView({
18160
18181
  const handleItemsReorder = useCallback(async (items_0, moveInfo) => {
18161
18182
  const entity_2 = items_0.find((item_5) => item_5.id === moveInfo?.itemId)?.entity;
18162
18183
  if (!entity_2) return;
18184
+ analyticsController.onAnalyticsEvent?.("kanban_card_moved", {
18185
+ path: fullPath,
18186
+ entityId: entity_2.id,
18187
+ sourceColumn: moveInfo?.sourceColumn,
18188
+ targetColumn: moveInfo?.targetColumn
18189
+ });
18163
18190
  const isColumnChange = moveInfo && moveInfo.sourceColumn !== moveInfo.targetColumn;
18164
18191
  if (!orderProperty && !isColumnChange) return;
18165
18192
  if (isColumnChange) {
@@ -18197,7 +18224,7 @@ function EntityCollectionBoardView({
18197
18224
  } catch (e_1) {
18198
18225
  console.error("Error saving entity:", e_1);
18199
18226
  }
18200
- }, [collection, columnProperty, orderProperty, context, dataSource, calculateNewOrder, boardDataController]);
18227
+ }, [collection, columnProperty, orderProperty, context, dataSource, calculateNewOrder, boardDataController, analyticsController, fullPath]);
18201
18228
  const handleBackfill = useCallback(async () => {
18202
18229
  console.log("handleBackfill called", {
18203
18230
  orderProperty
@@ -18206,6 +18233,9 @@ function EntityCollectionBoardView({
18206
18233
  console.log("No orderProperty, returning");
18207
18234
  return;
18208
18235
  }
18236
+ analyticsController.onAnalyticsEvent?.("kanban_backfill_order", {
18237
+ path: fullPath
18238
+ });
18209
18239
  setBackfillLoading(true);
18210
18240
  try {
18211
18241
  console.log("Fetching all documents from collection...");
@@ -18259,7 +18289,7 @@ function EntityCollectionBoardView({
18259
18289
  } finally {
18260
18290
  setBackfillLoading(false);
18261
18291
  }
18262
- }, [orderProperty, fullPath, collection, dataSource, context, boardDataController]);
18292
+ }, [orderProperty, fullPath, collection, dataSource, context, boardDataController, analyticsController]);
18263
18293
  const handleEntityClick = useCallback((entity_5) => {
18264
18294
  onEntityClick?.(entity_5);
18265
18295
  }, [onEntityClick]);
@@ -18320,6 +18350,10 @@ function EntityCollectionBoardView({
18320
18350
  /* @__PURE__ */ jsx(Button, { size: "small", variant: "text", onClick: () => setShowBackfillDialog(true), children: "Initialize Order" })
18321
18351
  ] }),
18322
18352
  /* @__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) => {
18353
+ analyticsController.onAnalyticsEvent?.("kanban_new_entity_in_column", {
18354
+ path: fullPath,
18355
+ column: column_0
18356
+ });
18323
18357
  sideEntityController.open({
18324
18358
  path: fullPath,
18325
18359
  collection,
@@ -18344,13 +18378,13 @@ function EntityCollectionBoardView({
18344
18378
  ] })
18345
18379
  ] });
18346
18380
  }
18381
+ const ALL_VIEW_MODES = ["table", "cards", "kanban"];
18347
18382
  function ViewModeToggle(t0) {
18348
- const $ = c(42);
18383
+ const $ = c(36);
18349
18384
  const {
18350
18385
  viewMode: t1,
18351
18386
  onViewModeChange,
18352
- kanbanEnabled: t2,
18353
- hasKanbanConfigPlugin: t3,
18387
+ enabledViews: t2,
18354
18388
  size,
18355
18389
  onSizeChanged,
18356
18390
  open,
@@ -18360,14 +18394,13 @@ function ViewModeToggle(t0) {
18360
18394
  onKanbanPropertyChange
18361
18395
  } = t0;
18362
18396
  const viewMode = t1 === void 0 ? "table" : t1;
18363
- const kanbanEnabled = t2 === void 0 ? false : t2;
18364
- const hasKanbanConfigPlugin = t3 === void 0 ? false : t3;
18397
+ const enabledViews = t2 === void 0 ? ALL_VIEW_MODES : t2;
18365
18398
  if (!onViewModeChange) {
18366
18399
  return null;
18367
18400
  }
18368
- let t4;
18401
+ let t3;
18369
18402
  if ($[0] !== viewMode) {
18370
- t4 = () => {
18403
+ t3 = () => {
18371
18404
  if (viewMode === "kanban") {
18372
18405
  return /* @__PURE__ */ jsx(ViewKanbanIcon, { size: "small" });
18373
18406
  }
@@ -18377,14 +18410,14 @@ function ViewModeToggle(t0) {
18377
18410
  return /* @__PURE__ */ jsx(ListIcon, { size: "small" });
18378
18411
  };
18379
18412
  $[0] = viewMode;
18380
- $[1] = t4;
18413
+ $[1] = t3;
18381
18414
  } else {
18382
- t4 = $[1];
18415
+ t3 = $[1];
18383
18416
  }
18384
- const getViewModeIcon = t4;
18385
- let t5;
18417
+ const getViewModeIcon = t3;
18418
+ let t4;
18386
18419
  if ($[2] !== viewMode) {
18387
- t5 = () => {
18420
+ t4 = () => {
18388
18421
  if (viewMode === "kanban") {
18389
18422
  return "Board";
18390
18423
  }
@@ -18394,177 +18427,151 @@ function ViewModeToggle(t0) {
18394
18427
  return "List";
18395
18428
  };
18396
18429
  $[2] = viewMode;
18397
- $[3] = t5;
18430
+ $[3] = t4;
18398
18431
  } else {
18399
- t5 = $[3];
18432
+ t4 = $[3];
18400
18433
  }
18401
- const getViewModeName = t5;
18402
- const showKanban = kanbanEnabled || hasKanbanConfigPlugin;
18434
+ const getViewModeName = t4;
18403
18435
  const showSizeSelector = size && onSizeChanged && (viewMode === "table" || viewMode === "cards");
18404
18436
  const showKanbanPropertySelector = viewMode === "kanban" && kanbanPropertyOptions && kanbanPropertyOptions.length > 0 && onKanbanPropertyChange;
18437
+ let t5;
18405
18438
  let t6;
18406
- let t7;
18407
18439
  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;
18440
+ t6 = /* @__PURE__ */ jsx(ListIcon, { size: "small" });
18441
+ $[4] = t6;
18414
18442
  } else {
18415
- t7 = $[4];
18443
+ t6 = $[4];
18416
18444
  }
18417
- let t8;
18418
- if ($[5] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
18419
- t8 = {
18445
+ let t7;
18446
+ if ($[5] !== enabledViews) {
18447
+ const allOptions = [{
18448
+ value: "table",
18449
+ label: "List",
18450
+ icon: t6
18451
+ }, {
18420
18452
  value: "cards",
18421
18453
  label: "Cards",
18422
18454
  icon: /* @__PURE__ */ jsx(AppsIcon, { size: "small" })
18423
- };
18424
- $[5] = t8;
18455
+ }, {
18456
+ value: "kanban",
18457
+ label: "Board",
18458
+ icon: /* @__PURE__ */ jsx(ViewKanbanIcon, { size: "small" })
18459
+ }];
18460
+ t7 = allOptions.filter((option) => enabledViews.includes(option.value));
18461
+ $[5] = enabledViews;
18462
+ $[6] = t7;
18425
18463
  } else {
18426
- t8 = $[5];
18464
+ t7 = $[6];
18427
18465
  }
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;
18466
+ t5 = t7;
18467
+ const viewModeOptions = t5;
18468
+ if (viewModeOptions.length <= 1 && !showSizeSelector) {
18469
+ return null;
18470
+ }
18471
+ let t8;
18472
+ if ($[7] !== getViewModeIcon) {
18473
+ t8 = getViewModeIcon();
18474
+ $[7] = getViewModeIcon;
18475
+ $[8] = t8;
18459
18476
  } else {
18460
- options = $[9];
18477
+ t8 = $[8];
18461
18478
  }
18462
- t6 = options;
18463
- const viewModeOptions = t6;
18464
- let t9;
18465
- if ($[13] !== getViewModeIcon) {
18466
- t9 = getViewModeIcon();
18467
- $[13] = getViewModeIcon;
18468
- $[14] = t9;
18479
+ const t9 = getViewModeName();
18480
+ let t10;
18481
+ if ($[9] !== t9) {
18482
+ t10 = /* @__PURE__ */ jsx("span", { className: "ml-1 text-sm", children: t9 });
18483
+ $[9] = t9;
18484
+ $[10] = t10;
18469
18485
  } else {
18470
- t9 = $[14];
18486
+ t10 = $[10];
18471
18487
  }
18472
- const t10 = getViewModeName();
18473
18488
  let t11;
18474
- if ($[15] !== t10) {
18475
- t11 = /* @__PURE__ */ jsx("span", { className: "ml-1 text-sm", children: t10 });
18476
- $[15] = t10;
18477
- $[16] = t11;
18489
+ if ($[11] !== t10 || $[12] !== t8) {
18490
+ t11 = /* @__PURE__ */ jsxs(Button, { size: "small", children: [
18491
+ t8,
18492
+ t10
18493
+ ] });
18494
+ $[11] = t10;
18495
+ $[12] = t8;
18496
+ $[13] = t11;
18478
18497
  } else {
18479
- t11 = $[16];
18498
+ t11 = $[13];
18480
18499
  }
18481
18500
  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;
18501
+ if ($[14] !== onViewModeChange || $[15] !== viewMode || $[16] !== viewModeOptions) {
18502
+ t12 = viewModeOptions.length > 1 && /* @__PURE__ */ jsx(ToggleButtonGroup, { value: viewMode, onValueChange: onViewModeChange, options: viewModeOptions });
18503
+ $[14] = onViewModeChange;
18504
+ $[15] = viewMode;
18505
+ $[16] = viewModeOptions;
18506
+ $[17] = t12;
18490
18507
  } else {
18491
- t12 = $[19];
18508
+ t12 = $[17];
18492
18509
  }
18493
18510
  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: [
18511
+ if ($[18] !== onSizeChanged || $[19] !== showSizeSelector || $[20] !== size) {
18512
+ t13 = showSizeSelector && /* @__PURE__ */ jsxs("div", { className: "flex flex-row items-center justify-between gap-2", children: [
18506
18513
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-surface-600 dark:text-surface-300", children: [
18507
18514
  /* @__PURE__ */ jsx(ViewColumnIcon, { size: "small" }),
18508
18515
  /* @__PURE__ */ jsx("span", { children: "Size" })
18509
18516
  ] }),
18510
18517
  /* @__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
18518
  ] });
18512
- $[24] = onSizeChanged;
18513
- $[25] = showSizeSelector;
18514
- $[26] = size;
18515
- $[27] = t14;
18519
+ $[18] = onSizeChanged;
18520
+ $[19] = showSizeSelector;
18521
+ $[20] = size;
18522
+ $[21] = t13;
18516
18523
  } else {
18517
- t14 = $[27];
18524
+ t13 = $[21];
18518
18525
  }
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: [
18526
+ let t14;
18527
+ if ($[22] !== kanbanPropertyOptions || $[23] !== onKanbanPropertyChange || $[24] !== selectedKanbanProperty || $[25] !== showKanbanPropertySelector) {
18528
+ t14 = showKanbanPropertySelector && /* @__PURE__ */ jsxs("div", { className: "flex flex-row items-center justify-between gap-2", children: [
18522
18529
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-surface-600 dark:text-surface-300", children: [
18523
18530
  /* @__PURE__ */ jsx(ViewKanbanIcon, { size: "small" }),
18524
18531
  /* @__PURE__ */ jsx("span", { children: "Group by" })
18525
18532
  ] }),
18526
18533
  /* @__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 });
18534
+ const option_0 = kanbanPropertyOptions?.find((o) => o.key === v_2);
18535
+ return /* @__PURE__ */ jsx("span", { className: "font-medium truncate", children: option_0?.label ?? v_2 });
18529
18536
  }, children: kanbanPropertyOptions?.map(_temp3$3) })
18530
18537
  ] });
18531
- $[28] = kanbanPropertyOptions;
18532
- $[29] = onKanbanPropertyChange;
18533
- $[30] = selectedKanbanProperty;
18534
- $[31] = showKanbanPropertySelector;
18535
- $[32] = t15;
18538
+ $[22] = kanbanPropertyOptions;
18539
+ $[23] = onKanbanPropertyChange;
18540
+ $[24] = selectedKanbanProperty;
18541
+ $[25] = showKanbanPropertySelector;
18542
+ $[26] = t14;
18536
18543
  } else {
18537
- t15 = $[32];
18544
+ t14 = $[26];
18538
18545
  }
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: [
18546
+ let t15;
18547
+ if ($[27] !== t12 || $[28] !== t13 || $[29] !== t14) {
18548
+ t15 = /* @__PURE__ */ jsxs("div", { className: "p-3 flex flex-col gap-3 min-w-[240px]", children: [
18549
+ t12,
18542
18550
  t13,
18543
- t14,
18544
- t15
18551
+ t14
18545
18552
  ] });
18546
- $[33] = t13;
18547
- $[34] = t14;
18548
- $[35] = t15;
18549
- $[36] = t16;
18553
+ $[27] = t12;
18554
+ $[28] = t13;
18555
+ $[29] = t14;
18556
+ $[30] = t15;
18550
18557
  } else {
18551
- t16 = $[36];
18558
+ t15 = $[30];
18552
18559
  }
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;
18560
+ let t16;
18561
+ if ($[31] !== onOpenChange || $[32] !== open || $[33] !== t11 || $[34] !== t15) {
18562
+ t16 = /* @__PURE__ */ jsx(Popover, { open, onOpenChange, modal: true, trigger: t11, children: t15 });
18563
+ $[31] = onOpenChange;
18564
+ $[32] = open;
18565
+ $[33] = t11;
18566
+ $[34] = t15;
18567
+ $[35] = t16;
18561
18568
  } else {
18562
- t17 = $[41];
18569
+ t16 = $[35];
18563
18570
  }
18564
- return t17;
18571
+ return t16;
18565
18572
  }
18566
- function _temp3$3(option_0) {
18567
- return /* @__PURE__ */ jsx(SelectItem, { value: option_0.key, children: option_0.label }, option_0.key);
18573
+ function _temp3$3(option_1) {
18574
+ return /* @__PURE__ */ jsx(SelectItem, { value: option_1.key, children: option_1.label }, option_1.key);
18568
18575
  }
18569
18576
  function _temp2$5(s) {
18570
18577
  return /* @__PURE__ */ jsx(SelectItem, { value: s, className: "font-medium text-center", children: s.toUpperCase() }, s);
@@ -19511,6 +19518,7 @@ function EntityForm({
19511
19518
  console.error(error);
19512
19519
  }, [snackbarController]);
19513
19520
  const pluginActions = [];
19521
+ const pluginBeforeTitle = [];
19514
19522
  const plugins = customizationController.plugins;
19515
19523
  const actionsDisabled = disabled || formex.isSubmitting || status === "existing" && !formex.dirty || Boolean(disabledProp);
19516
19524
  const parentCollectionIds = navigationController.getParentCollectionIds(path);
@@ -19527,6 +19535,7 @@ function EntityForm({
19527
19535
  disabled: actionsDisabled
19528
19536
  };
19529
19537
  pluginActions.push(...plugins.map((plugin) => plugin.form?.Actions ? /* @__PURE__ */ jsx(plugin.form.Actions, { ...actionProps }, `actions_${plugin.key}`) : null).filter(Boolean));
19538
+ 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
19539
  }
19531
19540
  const titlePropertyKey = getEntityTitlePropertyKey(resolvedCollection, customizationController.propertyConfigs);
19532
19541
  const title = (formex.values && titlePropertyKey ? getValueInPath(formex.values, titlePropertyKey) : void 0) ?? collection.singularName ?? collection.name;
@@ -19623,6 +19632,7 @@ function EntityForm({
19623
19632
  };
19624
19633
  const formRef = useRef(null);
19625
19634
  const formView = /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsxs(Fragment, { children: [
19635
+ pluginBeforeTitle,
19626
19636
  !Builder && /* @__PURE__ */ jsxs("div", { className: "w-full py-2 flex flex-col items-start my-4 lg:my-6", children: [
19627
19637
  /* @__PURE__ */ jsx(Typography, { className: "my-4 flex-grow line-clamp-1 " + (collection.hideIdFromForm ? "mb-6" : ""), variant: "h4", children: title ?? collection.singularName ?? collection.name }),
19628
19638
  !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 +21890,7 @@ function PropertyFieldBindingInternal(t0) {
21880
21890
  index,
21881
21891
  authController
21882
21892
  });
21883
- Component = configProperty.Field;
21893
+ Component = configProperty?.Field;
21884
21894
  }
21885
21895
  }
21886
21896
  }
@@ -24505,13 +24515,18 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
24505
24515
  });
24506
24516
  }, [onCollectionModifiedForUser, fullPath, userConfigPersistence]);
24507
24517
  const onViewModeChange = useCallback((mode) => {
24518
+ analyticsController.onAnalyticsEvent?.("view_mode_changed", {
24519
+ path: fullPath,
24520
+ from: viewMode,
24521
+ to: mode
24522
+ });
24508
24523
  setViewMode(mode);
24509
24524
  if (userConfigPersistence) {
24510
24525
  onCollectionModifiedForUser(fullPath, {
24511
24526
  defaultViewMode: mode
24512
24527
  });
24513
24528
  }
24514
- }, [setViewMode, userConfigPersistence, onCollectionModifiedForUser, fullPath]);
24529
+ }, [setViewMode, userConfigPersistence, onCollectionModifiedForUser, fullPath, analyticsController, viewMode]);
24515
24530
  const createEnabled = canCreateEntity(collection, authController, fullPath, null);
24516
24531
  const uniqueFieldValidator = useCallback(({
24517
24532
  name,
@@ -24565,24 +24580,26 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
24565
24580
  propertyConfigs: customizationController.propertyConfigs,
24566
24581
  authController
24567
24582
  }), [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]);
24583
+ const hasEnumProperty = useMemo(() => {
24584
+ const properties = resolvedCollection.properties;
24585
+ return Object.values(properties).some((prop) => prop && prop.dataType === "string" && prop.enumValues);
24586
+ }, [resolvedCollection.properties]);
24587
+ const enabledViews = useMemo(() => {
24588
+ const configured = collection.enabledViews ?? ["table", "cards", "kanban"];
24589
+ if (!hasEnumProperty) {
24590
+ return configured.filter((v) => v !== "kanban");
24591
+ }
24592
+ return configured;
24593
+ }, [collection.enabledViews, hasEnumProperty]);
24577
24594
  const kanbanPropertyOptions = useMemo(() => {
24578
24595
  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) {
24596
+ const properties_0 = resolvedCollection.properties;
24597
+ for (const [key_0, property_0] of Object.entries(properties_0)) {
24598
+ const prop_0 = property_0;
24599
+ if (prop_0 && prop_0.dataType === "string" && prop_0.enumValues) {
24583
24600
  options.push({
24584
24601
  key: key_0,
24585
- label: prop.name || key_0
24602
+ label: prop_0.name || key_0
24586
24603
  });
24587
24604
  }
24588
24605
  }
@@ -24610,14 +24627,18 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
24610
24627
  }
24611
24628
  }
24612
24629
  }, [kanbanPropertyOptions, selectedKanbanProperty, getSavedKanbanProperty, collection.kanban?.columnProperty]);
24613
- const onKanbanPropertyChange = useCallback((property_2) => {
24614
- setSelectedKanbanProperty(property_2);
24630
+ const onKanbanPropertyChange = useCallback((property_1) => {
24631
+ analyticsController.onAnalyticsEvent?.("kanban_property_changed", {
24632
+ path: fullPath,
24633
+ property: property_1
24634
+ });
24635
+ setSelectedKanbanProperty(property_1);
24615
24636
  if (userConfigPersistence) {
24616
24637
  onCollectionModifiedForUser(fullPath, {
24617
- kanbanColumnProperty: property_2
24638
+ kanbanColumnProperty: property_1
24618
24639
  });
24619
24640
  }
24620
- }, [userConfigPersistence, onCollectionModifiedForUser, fullPath]);
24641
+ }, [userConfigPersistence, onCollectionModifiedForUser, fullPath, analyticsController]);
24621
24642
  const getPropertyFor = useCallback(({
24622
24643
  propertyKey: propertyKey_0,
24623
24644
  entity: entity_2
@@ -24729,15 +24750,15 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
24729
24750
  }, [docsCount, fullPath, breadcrumbs.updateCount]);
24730
24751
  const countFetcher = /* @__PURE__ */ jsx(EntitiesCount, { fullPath, collection, filter: tableController.filterValues, sortBy: tableController.sortBy, onCountChange: setDocsCount });
24731
24752
  const buildAdditionalHeaderWidget = useCallback(({
24732
- property: property_3,
24753
+ property: property_2,
24733
24754
  propertyKey: propertyKey_1,
24734
24755
  onHover
24735
24756
  }) => {
24736
24757
  const collection_4 = collectionRef.current;
24737
24758
  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}`);
24759
+ return /* @__PURE__ */ jsx(Fragment, { children: customizationController.plugins.filter((plugin_0) => plugin_0.collectionView?.HeaderAction).map((plugin_1, i) => {
24760
+ const HeaderAction = plugin_1.collectionView.HeaderAction;
24761
+ return /* @__PURE__ */ jsx(HeaderAction, { onHover, propertyKey: propertyKey_1, property: property_2, fullPath, collection: collection_4, tableController, parentCollectionIds: parentCollectionIds ?? [] }, `plugin_header_action_${i}`);
24741
24762
  }) });
24742
24763
  }, [customizationController.plugins, fullPath, parentCollectionIds]);
24743
24764
  const addColumnComponentInternal = AddColumnComponent ? function() {
@@ -24755,11 +24776,22 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
24755
24776
  parentCollectionIds
24756
24777
  });
24757
24778
  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 });
24779
+ 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 });
24780
+ const pluginErrorView = useMemo(() => {
24781
+ const error = tableController.dataLoadingError;
24782
+ if (!error || !customizationController.plugins) return null;
24783
+ for (const plugin_2 of customizationController.plugins) {
24784
+ if (plugin_2.collectionView?.CollectionError) {
24785
+ const CollectionError = plugin_2.collectionView.CollectionError;
24786
+ return /* @__PURE__ */ jsx(CollectionError, { path: fullPath, collection, parentCollectionIds, error });
24787
+ }
24788
+ }
24789
+ return null;
24790
+ }, [tableController.dataLoadingError, customizationController.plugins, fullPath, collection, parentCollectionIds]);
24759
24791
  return /* @__PURE__ */ jsxs("div", { className: cls("overflow-hidden h-full w-full rounded-md flex flex-col", className), ref: containerRef, children: [
24760
24792
  countFetcher,
24761
24793
  /* @__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: [
24794
+ 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
24795
  /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", children: "So empty..." }),
24764
24796
  /* @__PURE__ */ jsxs(Button, { onClick: onNewClick, className: "mt-4", children: [
24765
24797
  /* @__PURE__ */ jsx(AddIcon, {}),
@@ -26151,10 +26183,10 @@ function useBuildNavigationController(props) {
26151
26183
  navigationGroupMappings
26152
26184
  } = props;
26153
26185
  const navigate = useNavigate();
26154
- const collectionsRef = useRef();
26155
- const viewsRef = useRef();
26156
- const adminViewsRef = useRef();
26157
- const navigationEntriesOrderRef = useRef();
26186
+ const collectionsRef = useRef(void 0);
26187
+ const viewsRef = useRef(void 0);
26188
+ const adminViewsRef = useRef(void 0);
26189
+ const navigationEntriesOrderRef = useRef(void 0);
26158
26190
  const [initialised, setInitialised] = useState(false);
26159
26191
  const [topLevelNavigation, setTopLevelNavigation] = useState(void 0);
26160
26192
  const [navigationLoading, setNavigationLoading] = useState(true);
@@ -26859,7 +26891,7 @@ function useValidateAuthenticator(t0) {
26859
26891
  t2 = $[2];
26860
26892
  }
26861
26893
  useEffect(t1, t2);
26862
- const checkedUserRef = useRef();
26894
+ const checkedUserRef = useRef(void 0);
26863
26895
  let t3;
26864
26896
  if ($[3] !== authController || $[4] !== authenticator || $[5] !== dataSourceDelegate || $[6] !== disabled || $[7] !== storageSource) {
26865
26897
  t3 = async () => {
@@ -27188,13 +27220,13 @@ function EntitySidePanel(props) {
27188
27220
  status,
27189
27221
  values
27190
27222
  }) => /* @__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: () => {
27223
+ /* @__PURE__ */ jsx(IconButton, { className: "self-center", size: "smallest", onClick: onClose, children: /* @__PURE__ */ jsx(CloseIcon, { size: "smallest" }) }),
27224
+ allowFullScreen && /* @__PURE__ */ jsx(IconButton, { className: "self-center", size: "smallest", onClick: () => {
27193
27225
  const key = status === "new" || status === "copy" ? path + "#new" : path + "/" + entityId;
27194
27226
  saveEntityToMemoryCache(key, values);
27195
27227
  if (entityId) navigate(location.pathname);
27196
27228
  else navigate(location.pathname + "#new");
27197
- }, children: /* @__PURE__ */ jsx(OpenInFullIcon, { size: "small" }) })
27229
+ }, children: /* @__PURE__ */ jsx(OpenInFullIcon, { size: "smallest" }) })
27198
27230
  ] }), onTabChange: ({
27199
27231
  entityId: entityId_0,
27200
27232
  selectedTab,
@@ -28470,7 +28502,7 @@ function useBuildDataSource({
28470
28502
  const orderProperty = collection_3?.orderProperty;
28471
28503
  if (orderProperty && (status === "new" || status === "copy")) {
28472
28504
  const orderProp = properties?.[orderProperty];
28473
- if (orderProp?.disabled === true) {
28505
+ if (orderProp) {
28474
28506
  const currentValue = updatedValues[orderProperty];
28475
28507
  if (currentValue === void 0 || currentValue === null) {
28476
28508
  try {
@@ -29691,14 +29723,19 @@ function getDefaultFieldId(property) {
29691
29723
  return "custom_array";
29692
29724
  } else if (isPropertyBuilder(of)) {
29693
29725
  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";
29726
+ } else if (of) {
29727
+ const ofProperty = of;
29728
+ if (ofProperty.dataType === "string" && ofProperty.enumValues) {
29729
+ return "multi_select";
29730
+ } else if (ofProperty.dataType === "number" && ofProperty.enumValues) {
29731
+ return "multi_number_select";
29732
+ } else if (ofProperty.dataType === "string" && ofProperty.storage) {
29733
+ return "multi_file_upload";
29734
+ } else if (ofProperty.dataType === "reference") {
29735
+ return "multi_references";
29736
+ } else {
29737
+ return "repeat";
29738
+ }
29702
29739
  } else {
29703
29740
  return "repeat";
29704
29741
  }