@firecms/core 3.1.0-canary.1df3b2c → 3.1.0-canary.24c8270

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) 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 +302 -227
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/index.umd.js +300 -225
  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/components/common/useDataSourceTableController.tsx +21 -4
  29. package/src/core/DefaultAppBar.tsx +1 -1
  30. package/src/core/EntityEditView.tsx +1 -1
  31. package/src/core/EntitySidePanel.tsx +28 -26
  32. package/src/core/field_configs.tsx +14 -9
  33. package/src/form/EntityForm.tsx +69 -60
  34. package/src/form/PropertyFieldBinding.tsx +3 -3
  35. package/src/form/components/ErrorFocus.tsx +3 -3
  36. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +1 -1
  37. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +83 -83
  38. package/src/hooks/useBuildNavigationController.tsx +29 -9
  39. package/src/hooks/useValidateAuthenticator.tsx +1 -1
  40. package/src/internal/useBuildDataSource.ts +1 -2
  41. package/src/internal/useBuildSideEntityController.tsx +22 -20
  42. package/src/preview/PropertyPreview.tsx +1 -0
  43. package/src/types/analytics.ts +10 -0
  44. package/src/types/collections.ts +9 -0
  45. package/src/types/plugins.tsx +18 -0
  46. package/src/util/entities.ts +1 -1
  47. package/src/util/join_collections.ts +10 -8
  48. package/src/util/previews.ts +2 -2
  49. package/src/util/property_utils.tsx +1 -1
  50. package/src/util/resolutions.ts +5 -3
package/dist/index.es.js CHANGED
@@ -2,11 +2,11 @@ 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";
9
- import { useNavigate, useLocation, Link, NavLink, Routes, Route, createBrowserRouter, RouterProvider } from "react-router-dom";
9
+ import { useLocation, useNavigate, Link, NavLink, Routes, Route, createBrowserRouter, RouterProvider } from "react-router-dom";
10
10
  import Fuse from "fuse.js";
11
11
  import equal from "react-fast-compare";
12
12
  import jsonLogic from "json-logic-js";
@@ -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
  };
@@ -13343,12 +13357,29 @@ function useDataSourceTableController({
13343
13357
  }
13344
13358
  return initialSort;
13345
13359
  }, [initialSort, forceFilter]);
13360
+ const location = useLocation();
13346
13361
  const {
13347
13362
  filterValues: initialFilterUrl,
13348
13363
  sortBy: initialSortUrl
13349
- } = parseFilterAndSort(window.location.search);
13364
+ } = parseFilterAndSort(location.search);
13350
13365
  const [filterValues_0, setFilterValues] = React__default.useState(forceFilter ?? (updateUrl ? initialFilterUrl : void 0) ?? initialFilter ?? void 0);
13351
13366
  const [sortBy_0, setSortBy] = React__default.useState((updateUrl ? initialSortUrl : void 0) ?? initialSortInternal);
13367
+ useEffect(() => {
13368
+ if (updateUrl) {
13369
+ const {
13370
+ filterValues: urlFilterValues,
13371
+ sortBy: urlSortBy
13372
+ } = parseFilterAndSort(location.search);
13373
+ if (!forceFilter) {
13374
+ setFilterValues(urlFilterValues);
13375
+ }
13376
+ if (urlSortBy && forceFilter && !checkFilterCombination(forceFilter, urlSortBy)) {
13377
+ console.warn("URL sort is not compatible with the force filter.");
13378
+ } else {
13379
+ setSortBy(urlSortBy);
13380
+ }
13381
+ }
13382
+ }, [location.search, updateUrl, forceFilter, checkFilterCombination]);
13352
13383
  useUpdateUrl(filterValues_0, sortBy_0, searchString, updateUrl);
13353
13384
  const collectionScroll = scrollRestoration?.getCollectionScroll(fullPath, filterValues_0);
13354
13385
  const initialItemCount = collectionScroll?.data.length ?? pageSize;
@@ -16253,7 +16284,7 @@ function EntityCard({
16253
16284
  size = "m"
16254
16285
  }) {
16255
16286
  const authController = useAuthController();
16256
- useAnalyticsController();
16287
+ const analyticsController = useAnalyticsController();
16257
16288
  useSideEntityController();
16258
16289
  const customizationController = useCustomizationController();
16259
16290
  useNavigationController();
@@ -16280,6 +16311,10 @@ function EntityCard({
16280
16311
  return;
16281
16312
  }
16282
16313
  if (onClick) {
16314
+ analyticsController.onAnalyticsEvent?.("card_view_entity_click", {
16315
+ path: entity.path,
16316
+ entityId: entity.id
16317
+ });
16283
16318
  onClick(entity);
16284
16319
  }
16285
16320
  };
@@ -17566,7 +17601,7 @@ function EntityBoardCardInner({
17566
17601
  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
17602
  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
17603
  /* @__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 }) }),
17604
+ /* @__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
17605
  /* @__PURE__ */ jsx("div", { className: "text-xs text-surface-500 font-mono truncate", children: entity.id })
17571
17606
  ] }),
17572
17607
  selectionEnabled && /* @__PURE__ */ jsx("div", { className: "ml-2 shrink-0", onClick: handleCheckboxClick, children: /* @__PURE__ */ jsx(Checkbox, { checked: selected ?? false, onCheckedChange: handleSelectionChange, size: "smallest" }) })
@@ -17922,6 +17957,7 @@ function EntityCollectionBoardView({
17922
17957
  const context = useFireCMSContext();
17923
17958
  const dataSource = useDataSource();
17924
17959
  const sideEntityController = useSideEntityController();
17960
+ const analyticsController = useAnalyticsController();
17925
17961
  const plugins = customizationController.plugins ?? [];
17926
17962
  const [showBackfillDialog, setShowBackfillDialog] = useState(false);
17927
17963
  const [backfillLoading, setBackfillLoading] = useState(false);
@@ -18037,6 +18073,10 @@ function EntityCollectionBoardView({
18037
18073
  return plugins.some((plugin) => plugin.collectionView?.onKanbanColumnsReorder);
18038
18074
  }, [plugins]);
18039
18075
  const handleColumnReorder = useCallback((newColumns) => {
18076
+ analyticsController.onAnalyticsEvent?.("kanban_column_reorder", {
18077
+ path: fullPath,
18078
+ columnProperty
18079
+ });
18040
18080
  setHasUserReordered(true);
18041
18081
  setLocalColumnsOrder(newColumns);
18042
18082
  plugins.filter((plugin_0) => plugin_0.collectionView?.onKanbanColumnsReorder).forEach((plugin_1) => {
@@ -18048,7 +18088,7 @@ function EntityCollectionBoardView({
18048
18088
  newColumnsOrder: newColumns
18049
18089
  });
18050
18090
  });
18051
- }, [plugins, fullPath, parentCollectionIds, collection, columnProperty]);
18091
+ }, [plugins, fullPath, parentCollectionIds, collection, columnProperty, analyticsController]);
18052
18092
  const [missingOrderCount, setMissingOrderCount] = useState(0);
18053
18093
  const dataSourceRef = useRef(dataSource);
18054
18094
  const collectionRef = useRef(collection);
@@ -18160,6 +18200,12 @@ function EntityCollectionBoardView({
18160
18200
  const handleItemsReorder = useCallback(async (items_0, moveInfo) => {
18161
18201
  const entity_2 = items_0.find((item_5) => item_5.id === moveInfo?.itemId)?.entity;
18162
18202
  if (!entity_2) return;
18203
+ analyticsController.onAnalyticsEvent?.("kanban_card_moved", {
18204
+ path: fullPath,
18205
+ entityId: entity_2.id,
18206
+ sourceColumn: moveInfo?.sourceColumn,
18207
+ targetColumn: moveInfo?.targetColumn
18208
+ });
18163
18209
  const isColumnChange = moveInfo && moveInfo.sourceColumn !== moveInfo.targetColumn;
18164
18210
  if (!orderProperty && !isColumnChange) return;
18165
18211
  if (isColumnChange) {
@@ -18197,7 +18243,7 @@ function EntityCollectionBoardView({
18197
18243
  } catch (e_1) {
18198
18244
  console.error("Error saving entity:", e_1);
18199
18245
  }
18200
- }, [collection, columnProperty, orderProperty, context, dataSource, calculateNewOrder, boardDataController]);
18246
+ }, [collection, columnProperty, orderProperty, context, dataSource, calculateNewOrder, boardDataController, analyticsController, fullPath]);
18201
18247
  const handleBackfill = useCallback(async () => {
18202
18248
  console.log("handleBackfill called", {
18203
18249
  orderProperty
@@ -18206,6 +18252,9 @@ function EntityCollectionBoardView({
18206
18252
  console.log("No orderProperty, returning");
18207
18253
  return;
18208
18254
  }
18255
+ analyticsController.onAnalyticsEvent?.("kanban_backfill_order", {
18256
+ path: fullPath
18257
+ });
18209
18258
  setBackfillLoading(true);
18210
18259
  try {
18211
18260
  console.log("Fetching all documents from collection...");
@@ -18259,7 +18308,7 @@ function EntityCollectionBoardView({
18259
18308
  } finally {
18260
18309
  setBackfillLoading(false);
18261
18310
  }
18262
- }, [orderProperty, fullPath, collection, dataSource, context, boardDataController]);
18311
+ }, [orderProperty, fullPath, collection, dataSource, context, boardDataController, analyticsController]);
18263
18312
  const handleEntityClick = useCallback((entity_5) => {
18264
18313
  onEntityClick?.(entity_5);
18265
18314
  }, [onEntityClick]);
@@ -18320,6 +18369,10 @@ function EntityCollectionBoardView({
18320
18369
  /* @__PURE__ */ jsx(Button, { size: "small", variant: "text", onClick: () => setShowBackfillDialog(true), children: "Initialize Order" })
18321
18370
  ] }),
18322
18371
  /* @__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) => {
18372
+ analyticsController.onAnalyticsEvent?.("kanban_new_entity_in_column", {
18373
+ path: fullPath,
18374
+ column: column_0
18375
+ });
18323
18376
  sideEntityController.open({
18324
18377
  path: fullPath,
18325
18378
  collection,
@@ -18344,13 +18397,13 @@ function EntityCollectionBoardView({
18344
18397
  ] })
18345
18398
  ] });
18346
18399
  }
18400
+ const ALL_VIEW_MODES = ["table", "cards", "kanban"];
18347
18401
  function ViewModeToggle(t0) {
18348
- const $ = c(42);
18402
+ const $ = c(36);
18349
18403
  const {
18350
18404
  viewMode: t1,
18351
18405
  onViewModeChange,
18352
- kanbanEnabled: t2,
18353
- hasKanbanConfigPlugin: t3,
18406
+ enabledViews: t2,
18354
18407
  size,
18355
18408
  onSizeChanged,
18356
18409
  open,
@@ -18360,14 +18413,13 @@ function ViewModeToggle(t0) {
18360
18413
  onKanbanPropertyChange
18361
18414
  } = t0;
18362
18415
  const viewMode = t1 === void 0 ? "table" : t1;
18363
- const kanbanEnabled = t2 === void 0 ? false : t2;
18364
- const hasKanbanConfigPlugin = t3 === void 0 ? false : t3;
18416
+ const enabledViews = t2 === void 0 ? ALL_VIEW_MODES : t2;
18365
18417
  if (!onViewModeChange) {
18366
18418
  return null;
18367
18419
  }
18368
- let t4;
18420
+ let t3;
18369
18421
  if ($[0] !== viewMode) {
18370
- t4 = () => {
18422
+ t3 = () => {
18371
18423
  if (viewMode === "kanban") {
18372
18424
  return /* @__PURE__ */ jsx(ViewKanbanIcon, { size: "small" });
18373
18425
  }
@@ -18377,14 +18429,14 @@ function ViewModeToggle(t0) {
18377
18429
  return /* @__PURE__ */ jsx(ListIcon, { size: "small" });
18378
18430
  };
18379
18431
  $[0] = viewMode;
18380
- $[1] = t4;
18432
+ $[1] = t3;
18381
18433
  } else {
18382
- t4 = $[1];
18434
+ t3 = $[1];
18383
18435
  }
18384
- const getViewModeIcon = t4;
18385
- let t5;
18436
+ const getViewModeIcon = t3;
18437
+ let t4;
18386
18438
  if ($[2] !== viewMode) {
18387
- t5 = () => {
18439
+ t4 = () => {
18388
18440
  if (viewMode === "kanban") {
18389
18441
  return "Board";
18390
18442
  }
@@ -18394,177 +18446,151 @@ function ViewModeToggle(t0) {
18394
18446
  return "List";
18395
18447
  };
18396
18448
  $[2] = viewMode;
18397
- $[3] = t5;
18449
+ $[3] = t4;
18398
18450
  } else {
18399
- t5 = $[3];
18451
+ t4 = $[3];
18400
18452
  }
18401
- const getViewModeName = t5;
18402
- const showKanban = kanbanEnabled || hasKanbanConfigPlugin;
18453
+ const getViewModeName = t4;
18403
18454
  const showSizeSelector = size && onSizeChanged && (viewMode === "table" || viewMode === "cards");
18404
18455
  const showKanbanPropertySelector = viewMode === "kanban" && kanbanPropertyOptions && kanbanPropertyOptions.length > 0 && onKanbanPropertyChange;
18456
+ let t5;
18405
18457
  let t6;
18406
- let t7;
18407
18458
  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;
18459
+ t6 = /* @__PURE__ */ jsx(ListIcon, { size: "small" });
18460
+ $[4] = t6;
18414
18461
  } else {
18415
- t7 = $[4];
18462
+ t6 = $[4];
18416
18463
  }
18417
- let t8;
18418
- if ($[5] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
18419
- t8 = {
18464
+ let t7;
18465
+ if ($[5] !== enabledViews) {
18466
+ const allOptions = [{
18467
+ value: "table",
18468
+ label: "List",
18469
+ icon: t6
18470
+ }, {
18420
18471
  value: "cards",
18421
18472
  label: "Cards",
18422
18473
  icon: /* @__PURE__ */ jsx(AppsIcon, { size: "small" })
18423
- };
18424
- $[5] = t8;
18474
+ }, {
18475
+ value: "kanban",
18476
+ label: "Board",
18477
+ icon: /* @__PURE__ */ jsx(ViewKanbanIcon, { size: "small" })
18478
+ }];
18479
+ t7 = allOptions.filter((option) => enabledViews.includes(option.value));
18480
+ $[5] = enabledViews;
18481
+ $[6] = t7;
18425
18482
  } else {
18426
- t8 = $[5];
18483
+ t7 = $[6];
18427
18484
  }
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;
18485
+ t5 = t7;
18486
+ const viewModeOptions = t5;
18487
+ if (viewModeOptions.length <= 1 && !showSizeSelector) {
18488
+ return null;
18489
+ }
18490
+ let t8;
18491
+ if ($[7] !== getViewModeIcon) {
18492
+ t8 = getViewModeIcon();
18493
+ $[7] = getViewModeIcon;
18494
+ $[8] = t8;
18459
18495
  } else {
18460
- options = $[9];
18496
+ t8 = $[8];
18461
18497
  }
18462
- t6 = options;
18463
- const viewModeOptions = t6;
18464
- let t9;
18465
- if ($[13] !== getViewModeIcon) {
18466
- t9 = getViewModeIcon();
18467
- $[13] = getViewModeIcon;
18468
- $[14] = t9;
18498
+ const t9 = getViewModeName();
18499
+ let t10;
18500
+ if ($[9] !== t9) {
18501
+ t10 = /* @__PURE__ */ jsx("span", { className: "ml-1 text-sm", children: t9 });
18502
+ $[9] = t9;
18503
+ $[10] = t10;
18469
18504
  } else {
18470
- t9 = $[14];
18505
+ t10 = $[10];
18471
18506
  }
18472
- const t10 = getViewModeName();
18473
18507
  let t11;
18474
- if ($[15] !== t10) {
18475
- t11 = /* @__PURE__ */ jsx("span", { className: "ml-1 text-sm", children: t10 });
18476
- $[15] = t10;
18477
- $[16] = t11;
18508
+ if ($[11] !== t10 || $[12] !== t8) {
18509
+ t11 = /* @__PURE__ */ jsxs(Button, { size: "small", children: [
18510
+ t8,
18511
+ t10
18512
+ ] });
18513
+ $[11] = t10;
18514
+ $[12] = t8;
18515
+ $[13] = t11;
18478
18516
  } else {
18479
- t11 = $[16];
18517
+ t11 = $[13];
18480
18518
  }
18481
18519
  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;
18520
+ if ($[14] !== onViewModeChange || $[15] !== viewMode || $[16] !== viewModeOptions) {
18521
+ t12 = viewModeOptions.length > 1 && /* @__PURE__ */ jsx(ToggleButtonGroup, { value: viewMode, onValueChange: onViewModeChange, options: viewModeOptions });
18522
+ $[14] = onViewModeChange;
18523
+ $[15] = viewMode;
18524
+ $[16] = viewModeOptions;
18525
+ $[17] = t12;
18490
18526
  } else {
18491
- t12 = $[19];
18527
+ t12 = $[17];
18492
18528
  }
18493
18529
  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: [
18530
+ if ($[18] !== onSizeChanged || $[19] !== showSizeSelector || $[20] !== size) {
18531
+ t13 = showSizeSelector && /* @__PURE__ */ jsxs("div", { className: "flex flex-row items-center justify-between gap-2", children: [
18506
18532
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-surface-600 dark:text-surface-300", children: [
18507
18533
  /* @__PURE__ */ jsx(ViewColumnIcon, { size: "small" }),
18508
18534
  /* @__PURE__ */ jsx("span", { children: "Size" })
18509
18535
  ] }),
18510
18536
  /* @__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
18537
  ] });
18512
- $[24] = onSizeChanged;
18513
- $[25] = showSizeSelector;
18514
- $[26] = size;
18515
- $[27] = t14;
18538
+ $[18] = onSizeChanged;
18539
+ $[19] = showSizeSelector;
18540
+ $[20] = size;
18541
+ $[21] = t13;
18516
18542
  } else {
18517
- t14 = $[27];
18543
+ t13 = $[21];
18518
18544
  }
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: [
18545
+ let t14;
18546
+ if ($[22] !== kanbanPropertyOptions || $[23] !== onKanbanPropertyChange || $[24] !== selectedKanbanProperty || $[25] !== showKanbanPropertySelector) {
18547
+ t14 = showKanbanPropertySelector && /* @__PURE__ */ jsxs("div", { className: "flex flex-row items-center justify-between gap-2", children: [
18522
18548
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-surface-600 dark:text-surface-300", children: [
18523
18549
  /* @__PURE__ */ jsx(ViewKanbanIcon, { size: "small" }),
18524
18550
  /* @__PURE__ */ jsx("span", { children: "Group by" })
18525
18551
  ] }),
18526
18552
  /* @__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 });
18553
+ const option_0 = kanbanPropertyOptions?.find((o) => o.key === v_2);
18554
+ return /* @__PURE__ */ jsx("span", { className: "font-medium truncate", children: option_0?.label ?? v_2 });
18529
18555
  }, children: kanbanPropertyOptions?.map(_temp3$3) })
18530
18556
  ] });
18531
- $[28] = kanbanPropertyOptions;
18532
- $[29] = onKanbanPropertyChange;
18533
- $[30] = selectedKanbanProperty;
18534
- $[31] = showKanbanPropertySelector;
18535
- $[32] = t15;
18557
+ $[22] = kanbanPropertyOptions;
18558
+ $[23] = onKanbanPropertyChange;
18559
+ $[24] = selectedKanbanProperty;
18560
+ $[25] = showKanbanPropertySelector;
18561
+ $[26] = t14;
18536
18562
  } else {
18537
- t15 = $[32];
18563
+ t14 = $[26];
18538
18564
  }
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: [
18565
+ let t15;
18566
+ if ($[27] !== t12 || $[28] !== t13 || $[29] !== t14) {
18567
+ t15 = /* @__PURE__ */ jsxs("div", { className: "p-3 flex flex-col gap-3 min-w-[240px]", children: [
18568
+ t12,
18542
18569
  t13,
18543
- t14,
18544
- t15
18570
+ t14
18545
18571
  ] });
18546
- $[33] = t13;
18547
- $[34] = t14;
18548
- $[35] = t15;
18549
- $[36] = t16;
18572
+ $[27] = t12;
18573
+ $[28] = t13;
18574
+ $[29] = t14;
18575
+ $[30] = t15;
18550
18576
  } else {
18551
- t16 = $[36];
18577
+ t15 = $[30];
18552
18578
  }
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;
18579
+ let t16;
18580
+ if ($[31] !== onOpenChange || $[32] !== open || $[33] !== t11 || $[34] !== t15) {
18581
+ t16 = /* @__PURE__ */ jsx(Popover, { open, onOpenChange, modal: true, trigger: t11, children: t15 });
18582
+ $[31] = onOpenChange;
18583
+ $[32] = open;
18584
+ $[33] = t11;
18585
+ $[34] = t15;
18586
+ $[35] = t16;
18561
18587
  } else {
18562
- t17 = $[41];
18588
+ t16 = $[35];
18563
18589
  }
18564
- return t17;
18590
+ return t16;
18565
18591
  }
18566
- function _temp3$3(option_0) {
18567
- return /* @__PURE__ */ jsx(SelectItem, { value: option_0.key, children: option_0.label }, option_0.key);
18592
+ function _temp3$3(option_1) {
18593
+ return /* @__PURE__ */ jsx(SelectItem, { value: option_1.key, children: option_1.label }, option_1.key);
18568
18594
  }
18569
18595
  function _temp2$5(s) {
18570
18596
  return /* @__PURE__ */ jsx(SelectItem, { value: s, className: "font-medium text-center", children: s.toUpperCase() }, s);
@@ -19511,6 +19537,7 @@ function EntityForm({
19511
19537
  console.error(error);
19512
19538
  }, [snackbarController]);
19513
19539
  const pluginActions = [];
19540
+ const pluginBeforeTitle = [];
19514
19541
  const plugins = customizationController.plugins;
19515
19542
  const actionsDisabled = disabled || formex.isSubmitting || status === "existing" && !formex.dirty || Boolean(disabledProp);
19516
19543
  const parentCollectionIds = navigationController.getParentCollectionIds(path);
@@ -19527,6 +19554,7 @@ function EntityForm({
19527
19554
  disabled: actionsDisabled
19528
19555
  };
19529
19556
  pluginActions.push(...plugins.map((plugin) => plugin.form?.Actions ? /* @__PURE__ */ jsx(plugin.form.Actions, { ...actionProps }, `actions_${plugin.key}`) : null).filter(Boolean));
19557
+ 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
19558
  }
19531
19559
  const titlePropertyKey = getEntityTitlePropertyKey(resolvedCollection, customizationController.propertyConfigs);
19532
19560
  const title = (formex.values && titlePropertyKey ? getValueInPath(formex.values, titlePropertyKey) : void 0) ?? collection.singularName ?? collection.name;
@@ -19623,6 +19651,7 @@ function EntityForm({
19623
19651
  };
19624
19652
  const formRef = useRef(null);
19625
19653
  const formView = /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsxs(Fragment, { children: [
19654
+ pluginBeforeTitle,
19626
19655
  !Builder && /* @__PURE__ */ jsxs("div", { className: "w-full py-2 flex flex-col items-start my-4 lg:my-6", children: [
19627
19656
  /* @__PURE__ */ jsx(Typography, { className: "my-4 flex-grow line-clamp-1 " + (collection.hideIdFromForm ? "mb-6" : ""), variant: "h4", children: title ?? collection.singularName ?? collection.name }),
19628
19657
  !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 +21909,7 @@ function PropertyFieldBindingInternal(t0) {
21880
21909
  index,
21881
21910
  authController
21882
21911
  });
21883
- Component = configProperty.Field;
21912
+ Component = configProperty?.Field;
21884
21913
  }
21885
21914
  }
21886
21915
  }
@@ -24505,13 +24534,18 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
24505
24534
  });
24506
24535
  }, [onCollectionModifiedForUser, fullPath, userConfigPersistence]);
24507
24536
  const onViewModeChange = useCallback((mode) => {
24537
+ analyticsController.onAnalyticsEvent?.("view_mode_changed", {
24538
+ path: fullPath,
24539
+ from: viewMode,
24540
+ to: mode
24541
+ });
24508
24542
  setViewMode(mode);
24509
24543
  if (userConfigPersistence) {
24510
24544
  onCollectionModifiedForUser(fullPath, {
24511
24545
  defaultViewMode: mode
24512
24546
  });
24513
24547
  }
24514
- }, [setViewMode, userConfigPersistence, onCollectionModifiedForUser, fullPath]);
24548
+ }, [setViewMode, userConfigPersistence, onCollectionModifiedForUser, fullPath, analyticsController, viewMode]);
24515
24549
  const createEnabled = canCreateEntity(collection, authController, fullPath, null);
24516
24550
  const uniqueFieldValidator = useCallback(({
24517
24551
  name,
@@ -24565,24 +24599,26 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
24565
24599
  propertyConfigs: customizationController.propertyConfigs,
24566
24600
  authController
24567
24601
  }), [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]);
24602
+ const hasEnumProperty = useMemo(() => {
24603
+ const properties = resolvedCollection.properties;
24604
+ return Object.values(properties).some((prop) => prop && prop.dataType === "string" && prop.enumValues);
24605
+ }, [resolvedCollection.properties]);
24606
+ const enabledViews = useMemo(() => {
24607
+ const configured = collection.enabledViews ?? ["table", "cards", "kanban"];
24608
+ if (!hasEnumProperty) {
24609
+ return configured.filter((v) => v !== "kanban");
24610
+ }
24611
+ return configured;
24612
+ }, [collection.enabledViews, hasEnumProperty]);
24577
24613
  const kanbanPropertyOptions = useMemo(() => {
24578
24614
  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) {
24615
+ const properties_0 = resolvedCollection.properties;
24616
+ for (const [key_0, property_0] of Object.entries(properties_0)) {
24617
+ const prop_0 = property_0;
24618
+ if (prop_0 && prop_0.dataType === "string" && prop_0.enumValues) {
24583
24619
  options.push({
24584
24620
  key: key_0,
24585
- label: prop.name || key_0
24621
+ label: prop_0.name || key_0
24586
24622
  });
24587
24623
  }
24588
24624
  }
@@ -24610,14 +24646,18 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
24610
24646
  }
24611
24647
  }
24612
24648
  }, [kanbanPropertyOptions, selectedKanbanProperty, getSavedKanbanProperty, collection.kanban?.columnProperty]);
24613
- const onKanbanPropertyChange = useCallback((property_2) => {
24614
- setSelectedKanbanProperty(property_2);
24649
+ const onKanbanPropertyChange = useCallback((property_1) => {
24650
+ analyticsController.onAnalyticsEvent?.("kanban_property_changed", {
24651
+ path: fullPath,
24652
+ property: property_1
24653
+ });
24654
+ setSelectedKanbanProperty(property_1);
24615
24655
  if (userConfigPersistence) {
24616
24656
  onCollectionModifiedForUser(fullPath, {
24617
- kanbanColumnProperty: property_2
24657
+ kanbanColumnProperty: property_1
24618
24658
  });
24619
24659
  }
24620
- }, [userConfigPersistence, onCollectionModifiedForUser, fullPath]);
24660
+ }, [userConfigPersistence, onCollectionModifiedForUser, fullPath, analyticsController]);
24621
24661
  const getPropertyFor = useCallback(({
24622
24662
  propertyKey: propertyKey_0,
24623
24663
  entity: entity_2
@@ -24729,15 +24769,15 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
24729
24769
  }, [docsCount, fullPath, breadcrumbs.updateCount]);
24730
24770
  const countFetcher = /* @__PURE__ */ jsx(EntitiesCount, { fullPath, collection, filter: tableController.filterValues, sortBy: tableController.sortBy, onCountChange: setDocsCount });
24731
24771
  const buildAdditionalHeaderWidget = useCallback(({
24732
- property: property_3,
24772
+ property: property_2,
24733
24773
  propertyKey: propertyKey_1,
24734
24774
  onHover
24735
24775
  }) => {
24736
24776
  const collection_4 = collectionRef.current;
24737
24777
  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}`);
24778
+ return /* @__PURE__ */ jsx(Fragment, { children: customizationController.plugins.filter((plugin_0) => plugin_0.collectionView?.HeaderAction).map((plugin_1, i) => {
24779
+ const HeaderAction = plugin_1.collectionView.HeaderAction;
24780
+ return /* @__PURE__ */ jsx(HeaderAction, { onHover, propertyKey: propertyKey_1, property: property_2, fullPath, collection: collection_4, tableController, parentCollectionIds: parentCollectionIds ?? [] }, `plugin_header_action_${i}`);
24741
24781
  }) });
24742
24782
  }, [customizationController.plugins, fullPath, parentCollectionIds]);
24743
24783
  const addColumnComponentInternal = AddColumnComponent ? function() {
@@ -24755,11 +24795,22 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
24755
24795
  parentCollectionIds
24756
24796
  });
24757
24797
  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 });
24798
+ 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 });
24799
+ const pluginErrorView = useMemo(() => {
24800
+ const error = tableController.dataLoadingError;
24801
+ if (!error || !customizationController.plugins) return null;
24802
+ for (const plugin_2 of customizationController.plugins) {
24803
+ if (plugin_2.collectionView?.CollectionError) {
24804
+ const CollectionError = plugin_2.collectionView.CollectionError;
24805
+ return /* @__PURE__ */ jsx(CollectionError, { path: fullPath, collection, parentCollectionIds, error });
24806
+ }
24807
+ }
24808
+ return null;
24809
+ }, [tableController.dataLoadingError, customizationController.plugins, fullPath, collection, parentCollectionIds]);
24759
24810
  return /* @__PURE__ */ jsxs("div", { className: cls("overflow-hidden h-full w-full rounded-md flex flex-col", className), ref: containerRef, children: [
24760
24811
  countFetcher,
24761
24812
  /* @__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: [
24813
+ 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
24814
  /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", children: "So empty..." }),
24764
24815
  /* @__PURE__ */ jsxs(Button, { onClick: onNewClick, className: "mt-4", children: [
24765
24816
  /* @__PURE__ */ jsx(AddIcon, {}),
@@ -26151,10 +26202,10 @@ function useBuildNavigationController(props) {
26151
26202
  navigationGroupMappings
26152
26203
  } = props;
26153
26204
  const navigate = useNavigate();
26154
- const collectionsRef = useRef();
26155
- const viewsRef = useRef();
26156
- const adminViewsRef = useRef();
26157
- const navigationEntriesOrderRef = useRef();
26205
+ const collectionsRef = useRef(void 0);
26206
+ const viewsRef = useRef(void 0);
26207
+ const adminViewsRef = useRef(void 0);
26208
+ const navigationEntriesOrderRef = useRef(void 0);
26158
26209
  const [initialised, setInitialised] = useState(false);
26159
26210
  const [topLevelNavigation, setTopLevelNavigation] = useState(void 0);
26160
26211
  const [navigationLoading, setNavigationLoading] = useState(true);
@@ -26394,7 +26445,9 @@ function useBuildNavigationController(props) {
26394
26445
  const isUrlCollectionPath = useCallback((path_1) => removeInitialAndTrailingSlashes(path_1 + "/").startsWith(removeInitialAndTrailingSlashes(fullCollectionPath) + "/"), [fullCollectionPath]);
26395
26446
  const urlPathToDataPath = useCallback((path_2) => {
26396
26447
  const decodedPath = decodeURIComponent(path_2);
26397
- if (decodedPath.startsWith(fullCollectionPath)) return decodedPath.replace(fullCollectionPath, "");
26448
+ const withoutHash = decodedPath.split("#")[0];
26449
+ const cleanPath_0 = withoutHash.split("?")[0];
26450
+ if (cleanPath_0.startsWith(fullCollectionPath)) return cleanPath_0.replace(fullCollectionPath, "");
26398
26451
  throw Error("Expected path starting with " + fullCollectionPath);
26399
26452
  }, [fullCollectionPath]);
26400
26453
  const resolveIdsFrom = useCallback((path_3) => {
@@ -26459,7 +26512,24 @@ function useBuildNavigationController(props) {
26459
26512
  };
26460
26513
  }
26461
26514
  function encodePath(input) {
26462
- return encodeURIComponent(removeInitialAndTrailingSlashes(input)).replaceAll("%2F", "/").replaceAll("%23", "#");
26515
+ const cleanInput = removeInitialAndTrailingSlashes(input);
26516
+ const [pathPart, rest] = cleanInput.split("?", 2);
26517
+ let encodedPath = encodeURIComponent(pathPart).replaceAll("%2F", "/");
26518
+ let result = encodedPath;
26519
+ if (rest !== void 0) {
26520
+ const [searchPart, hashPart] = rest.split("#", 2);
26521
+ result += `?${searchPart}`;
26522
+ if (hashPart !== void 0) {
26523
+ result += `#${hashPart}`;
26524
+ }
26525
+ } else {
26526
+ const [pathOnly, hashOnly] = cleanInput.split("#", 2);
26527
+ if (hashOnly !== void 0) {
26528
+ encodedPath = encodeURIComponent(pathOnly).replaceAll("%2F", "/");
26529
+ result = `${encodedPath}#${hashOnly}`;
26530
+ }
26531
+ }
26532
+ return result;
26463
26533
  }
26464
26534
  function filterOutNotAllowedCollections(resolvedCollections, authController) {
26465
26535
  return resolvedCollections.filter((c2) => Boolean(c2.path)).filter((c2) => {
@@ -26859,7 +26929,7 @@ function useValidateAuthenticator(t0) {
26859
26929
  t2 = $[2];
26860
26930
  }
26861
26931
  useEffect(t1, t2);
26862
- const checkedUserRef = useRef();
26932
+ const checkedUserRef = useRef(void 0);
26863
26933
  let t3;
26864
26934
  if ($[3] !== authController || $[4] !== authenticator || $[5] !== dataSourceDelegate || $[6] !== disabled || $[7] !== storageSource) {
26865
26935
  t3 = async () => {
@@ -27188,13 +27258,13 @@ function EntitySidePanel(props) {
27188
27258
  status,
27189
27259
  values
27190
27260
  }) => /* @__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: () => {
27261
+ /* @__PURE__ */ jsx(IconButton, { className: "self-center", size: "smallest", onClick: onClose, children: /* @__PURE__ */ jsx(CloseIcon, { size: "smallest" }) }),
27262
+ allowFullScreen && /* @__PURE__ */ jsx(IconButton, { className: "self-center", size: "smallest", onClick: () => {
27193
27263
  const key = status === "new" || status === "copy" ? path + "#new" : path + "/" + entityId;
27194
27264
  saveEntityToMemoryCache(key, values);
27195
- if (entityId) navigate(location.pathname);
27196
- else navigate(location.pathname + "#new");
27197
- }, children: /* @__PURE__ */ jsx(OpenInFullIcon, { size: "small" }) })
27265
+ if (entityId) navigate(location.pathname + location.search);
27266
+ else navigate(location.pathname + location.search + "#new");
27267
+ }, children: /* @__PURE__ */ jsx(OpenInFullIcon, { size: "smallest" }) })
27198
27268
  ] }), onTabChange: ({
27199
27269
  entityId: entityId_0,
27200
27270
  selectedTab,
@@ -27868,7 +27938,7 @@ function EntityEditViewInner({
27868
27938
  const customViewTabsEnd = resolvedEntityViews.filter((view_1) => !view_1.position || view_1.position === "end").map((view_2) => /* @__PURE__ */ jsx(Tab, { className: !view_2.tabComponent ? "text-sm min-w-[120px]" : void 0, value: view_2.key, children: view_2.tabComponent ?? view_2.name }, `entity_detail_collection_tab_${view_2.name}`));
27869
27939
  const shouldShowTopBar = Boolean(barActions) || hasAdditionalViews;
27870
27940
  let result = /* @__PURE__ */ jsxs("div", { className: "relative flex flex-col h-full w-full bg-white dark:bg-surface-900", children: [
27871
- shouldShowTopBar && /* @__PURE__ */ jsxs("div", { className: cls("h-14 items-center overflow-visible overflow-x-scroll w-full no-scrollbar border-b pl-2 pr-2 flex gap-2 bg-surface-50 dark:bg-surface-900", defaultBorderMixin), children: [
27941
+ shouldShowTopBar && /* @__PURE__ */ jsxs("div", { className: cls("h-14 items-center overflow-hidden w-full border-b pl-2 pr-2 flex gap-2 bg-surface-50 dark:bg-surface-900", defaultBorderMixin), children: [
27872
27942
  barActions?.({
27873
27943
  path: fullIdPath ?? path,
27874
27944
  entityId,
@@ -27985,8 +28055,8 @@ const useBuildSideEntityController = (navigation, sideDialogsController, authCon
27985
28055
  const panelsFromUrl = buildSidePanelsFromUrl(entityOrCollectionPath, navigation.collections ?? [], newFlag);
27986
28056
  for (let i = 0; i < panelsFromUrl.length; i++) {
27987
28057
  const props = panelsFromUrl[i];
27988
- if (i === 0) sideDialogsController.replace(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController));
27989
- else sideDialogsController.open(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController));
28058
+ if (i === 0) sideDialogsController.replace(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController, location.search));
28059
+ else sideDialogsController.open(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController, location.search));
27990
28060
  }
27991
28061
  }
27992
28062
  initialised.current = true;
@@ -28003,7 +28073,7 @@ const useBuildSideEntityController = (navigation, sideDialogsController, authCon
28003
28073
  return;
28004
28074
  }
28005
28075
  const lastPanel = panelsFromUrl_0[panelsFromUrl_0.length - 1];
28006
- const panelProps = propsToSidePanel(lastPanel, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController);
28076
+ const panelProps = propsToSidePanel(lastPanel, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController, location.search);
28007
28077
  const lastCurrentPanel = currentPanelKeys.length > 0 ? currentPanelKeys[currentPanelKeys.length - 1] : void 0;
28008
28078
  if (!lastCurrentPanel || lastCurrentPanel !== panelProps.key) {
28009
28079
  sideDialogsController.replace(panelProps);
@@ -28014,7 +28084,7 @@ const useBuildSideEntityController = (navigation, sideDialogsController, authCon
28014
28084
  useEffect(() => {
28015
28085
  const updatedSidePanels = sideDialogsController.sidePanels.map((sidePanelProps) => {
28016
28086
  if (sidePanelProps.additional) {
28017
- return propsToSidePanel(sidePanelProps.additional, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController);
28087
+ return propsToSidePanel(sidePanelProps.additional, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController, location.search);
28018
28088
  }
28019
28089
  return sidePanelProps;
28020
28090
  });
@@ -28034,14 +28104,14 @@ const useBuildSideEntityController = (navigation, sideDialogsController, authCon
28034
28104
  sideDialogsController.open(propsToSidePanel({
28035
28105
  selectedTab: defaultSelectedView,
28036
28106
  ...props_0
28037
- }, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController));
28038
- }, [sideDialogsController, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, authController.user]);
28107
+ }, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController, location.search));
28108
+ }, [sideDialogsController, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, authController.user, location.search]);
28039
28109
  const replace = useCallback((props_1) => {
28040
28110
  if (props_1.copy && !props_1.entityId) {
28041
28111
  throw Error("If you want to copy an entity you need to provide an entityId");
28042
28112
  }
28043
- sideDialogsController.replace(propsToSidePanel(props_1, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController));
28044
- }, [navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, sideDialogsController, smallLayout, authController.user]);
28113
+ sideDialogsController.replace(propsToSidePanel(props_1, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController, location.search));
28114
+ }, [navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, sideDialogsController, smallLayout, authController.user, location.search]);
28045
28115
  return {
28046
28116
  close,
28047
28117
  open,
@@ -28090,9 +28160,9 @@ function buildSidePanelsFromUrl(path, collections, newFlag) {
28090
28160
  }
28091
28161
  return sidePanel ? [sidePanel] : [];
28092
28162
  }
28093
- const propsToSidePanel = (props, buildUrlCollectionPath, resolveIdsFrom, smallLayout, customizationController, authController) => {
28163
+ const propsToSidePanel = (props, buildUrlCollectionPath, resolveIdsFrom, smallLayout, customizationController, authController, locationSearch) => {
28094
28164
  const collectionPath = removeInitialAndTrailingSlashes(props.path);
28095
- const urlPath = props.entityId ? buildUrlCollectionPath(`${collectionPath}/${props.entityId}${props.selectedTab ? "/" + props.selectedTab : ""}#${SIDE_URL_HASH}`) : buildUrlCollectionPath(`${collectionPath}#${NEW_URL_HASH}`);
28165
+ const urlPath = props.entityId ? buildUrlCollectionPath(`${collectionPath}/${props.entityId}${props.selectedTab ? "/" + props.selectedTab : ""}${locationSearch}#${SIDE_URL_HASH}`) : buildUrlCollectionPath(`${collectionPath}${locationSearch}#${NEW_URL_HASH}`);
28096
28166
  const resolvedPanelProps = {
28097
28167
  ...props,
28098
28168
  formProps: props.formProps
@@ -28470,7 +28540,7 @@ function useBuildDataSource({
28470
28540
  const orderProperty = collection_3?.orderProperty;
28471
28541
  if (orderProperty && (status === "new" || status === "copy")) {
28472
28542
  const orderProp = properties?.[orderProperty];
28473
- if (orderProp?.disabled === true) {
28543
+ if (orderProp) {
28474
28544
  const currentValue = updatedValues[orderProperty];
28475
28545
  if (currentValue === void 0 || currentValue === null) {
28476
28546
  try {
@@ -29691,14 +29761,19 @@ function getDefaultFieldId(property) {
29691
29761
  return "custom_array";
29692
29762
  } else if (isPropertyBuilder(of)) {
29693
29763
  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";
29764
+ } else if (of) {
29765
+ const ofProperty = of;
29766
+ if (ofProperty.dataType === "string" && ofProperty.enumValues) {
29767
+ return "multi_select";
29768
+ } else if (ofProperty.dataType === "number" && ofProperty.enumValues) {
29769
+ return "multi_number_select";
29770
+ } else if (ofProperty.dataType === "string" && ofProperty.storage) {
29771
+ return "multi_file_upload";
29772
+ } else if (ofProperty.dataType === "reference") {
29773
+ return "multi_references";
29774
+ } else {
29775
+ return "repeat";
29776
+ }
29702
29777
  } else {
29703
29778
  return "repeat";
29704
29779
  }