@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.umd.js CHANGED
@@ -785,7 +785,7 @@
785
785
  const defaultValues = getDefaultValuesFor(collection.properties);
786
786
  const usedValues = values ?? defaultValues;
787
787
  const usedPreviousValues = previousValues ?? values ?? defaultValues;
788
- const resolvedProperties = Object.entries(collection.properties).map(([key, propertyOrBuilder]) => {
788
+ const resolvedProperties = Object.entries(collection.properties).filter(([, propertyOrBuilder]) => propertyOrBuilder != null).map(([key, propertyOrBuilder]) => {
789
789
  const childResolvedProperty = resolveProperty({
790
790
  propertyKey: key,
791
791
  propertyOrBuilder,
@@ -824,7 +824,7 @@
824
824
  ignoreMissingFields = false,
825
825
  ...props
826
826
  }) {
827
- if (typeof propertyOrBuilder === "object" && "resolved" in propertyOrBuilder) {
827
+ if (propertyOrBuilder !== null && typeof propertyOrBuilder === "object" && "resolved" in propertyOrBuilder) {
828
828
  return propertyOrBuilder;
829
829
  }
830
830
  let resolvedProperty = null;
@@ -3824,6 +3824,8 @@
3824
3824
  return resultCollection;
3825
3825
  }
3826
3826
  function mergePropertyOrBuilder(target, source) {
3827
+ if (!source) return target;
3828
+ if (!target) return source;
3827
3829
  if (isPropertyBuilder(source)) {
3828
3830
  return source;
3829
3831
  } else if (isPropertyBuilder(target)) {
@@ -7577,7 +7579,7 @@
7577
7579
  } else {
7578
7580
  if (property.dataType === "map") {
7579
7581
  if (typeof value === "object") {
7580
- content = /* @__PURE__ */ jsxRuntime.jsx(MapPropertyPreview, { ...props, property });
7582
+ content = /* @__PURE__ */ jsxRuntime.jsx(MapPropertyPreview, { ...props, value, property });
7581
7583
  } else {
7582
7584
  content = buildWrongValueType(propertyKey, property.dataType, value);
7583
7585
  }
@@ -8461,7 +8463,7 @@
8461
8463
  const handleOpenChange = t4;
8462
8464
  let t5;
8463
8465
  if ($[11] !== disabled || $[12] !== enumValues || $[13] !== internalValue || $[14] !== multiple || $[15] !== onChange || $[16] !== renderValue || $[17] !== small || $[18] !== validValue) {
8464
- t5 = multiple ? /* @__PURE__ */ jsxRuntime.jsx(ui.MultiSelect, { inputRef: ref, className: "w-full h-full p-0 bg-transparent", position: "item-aligned", disabled, includeClear: false, useChips: false, value: validValue ? internalValue.map(_temp2$b) : [], onValueChange: onChange, onOpenChange: handleOpenChange, children: enumValues?.map((enumConfig) => /* @__PURE__ */ jsxRuntime.jsx(ui.MultiSelectItem, { value: String(enumConfig.id), children: /* @__PURE__ */ jsxRuntime.jsx(EnumValuesChip, { enumKey: enumConfig.id, enumValues, size: small ? "small" : "medium" }) }, enumConfig.id)) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Select, { inputRef: ref, size: "large", fullWidth: true, className: "w-full h-full p-0 bg-transparent", inputClassName: "focus:ring-0 focus-visible:ring-0 outline-none focus:outline-none focus-visible:outline-none", position: "item-aligned", disabled, padding: false, value: validValue ? internalValue?.toString() : "", onValueChange: onChange, onOpenChange: handleOpenChange, renderValue, children: enumValues?.map((enumConfig_0) => /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: String(enumConfig_0.id), children: /* @__PURE__ */ jsxRuntime.jsx(EnumValuesChip, { enumKey: enumConfig_0.id, enumValues, size: small ? "small" : "medium" }) }, enumConfig_0.id)) });
8466
+ t5 = multiple ? /* @__PURE__ */ jsxRuntime.jsx(ui.MultiSelect, { inputRef: ref, className: "w-full h-full p-0 bg-transparent outline-none", position: "item-aligned", disabled, includeClear: false, useChips: false, value: validValue ? internalValue.map(_temp2$b) : [], onValueChange: onChange, onOpenChange: handleOpenChange, children: enumValues?.map((enumConfig) => /* @__PURE__ */ jsxRuntime.jsx(ui.MultiSelectItem, { value: String(enumConfig.id), children: /* @__PURE__ */ jsxRuntime.jsx(EnumValuesChip, { enumKey: enumConfig.id, enumValues, size: small ? "small" : "medium" }) }, enumConfig.id)) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Select, { inputRef: ref, size: "large", fullWidth: true, className: "w-full h-full p-0 bg-transparent outline-none [&_button]:ring-0 [&_button]:ring-offset-0", inputClassName: "ring-0 ring-offset-0 focus:ring-0 focus-visible:ring-0 outline-none focus:outline-none focus-visible:outline-none focus-visible:ring-offset-0", position: "item-aligned", disabled, padding: false, value: validValue ? internalValue?.toString() : "", onValueChange: onChange, onOpenChange: handleOpenChange, renderValue, children: enumValues?.map((enumConfig_0) => /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: String(enumConfig_0.id), children: /* @__PURE__ */ jsxRuntime.jsx(EnumValuesChip, { enumKey: enumConfig_0.id, enumValues, size: small ? "small" : "medium" }) }, enumConfig_0.id)) });
8465
8467
  $[11] = disabled;
8466
8468
  $[12] = enumValues;
8467
8469
  $[13] = internalValue;
@@ -9021,7 +9023,7 @@
9021
9023
  openPopup(cellRect);
9022
9024
  }
9023
9025
  }, []);
9024
- const iconRef = React.useRef();
9026
+ const iconRef = React.useRef(void 0);
9025
9027
  React.useEffect(() => {
9026
9028
  if (iconRef.current && selected) {
9027
9029
  iconRef.current.focus({
@@ -12169,7 +12171,7 @@
12169
12171
  onColumnResize(params_0);
12170
12172
  }
12171
12173
  }, [columns, onColumnResize]);
12172
- const filterRef = React.useRef();
12174
+ const filterRef = React.useRef(void 0);
12173
12175
  React.useEffect(() => {
12174
12176
  filterRef.current = filterInput;
12175
12177
  }, [filterInput]);
@@ -12281,7 +12283,7 @@
12281
12283
  return tableContent;
12282
12284
  }, equal);
12283
12285
  const SortableCellWrapper = (t0) => {
12284
- const $ = reactCompilerRuntime.c(15);
12286
+ const $ = reactCompilerRuntime.c(17);
12285
12287
  const {
12286
12288
  columnKey,
12287
12289
  width,
@@ -12309,10 +12311,22 @@
12309
12311
  transform,
12310
12312
  transition
12311
12313
  } = sortable.useSortable(t2);
12314
+ let attrsWithoutTabIndex;
12315
+ if ($[3] !== attributes) {
12316
+ const {
12317
+ tabIndex: _tabIndex,
12318
+ ...t32
12319
+ } = attributes;
12320
+ attrsWithoutTabIndex = t32;
12321
+ $[3] = attributes;
12322
+ $[4] = attrsWithoutTabIndex;
12323
+ } else {
12324
+ attrsWithoutTabIndex = $[4];
12325
+ }
12312
12326
  const t3 = transform ? `translateX(${transform.x}px)` : void 0;
12313
12327
  const t4 = isDragging ? void 0 : transition;
12314
12328
  let t5;
12315
- if ($[3] !== t3 || $[4] !== t4 || $[5] !== width) {
12329
+ if ($[5] !== t3 || $[6] !== t4 || $[7] !== width) {
12316
12330
  t5 = {
12317
12331
  transform: t3,
12318
12332
  transition: t4,
@@ -12320,34 +12334,34 @@
12320
12334
  maxWidth: width,
12321
12335
  width
12322
12336
  };
12323
- $[3] = t3;
12324
- $[4] = t4;
12325
- $[5] = width;
12326
- $[6] = t5;
12337
+ $[5] = t3;
12338
+ $[6] = t4;
12339
+ $[7] = width;
12340
+ $[8] = t5;
12327
12341
  } else {
12328
- t5 = $[6];
12342
+ t5 = $[8];
12329
12343
  }
12330
12344
  const style = t5;
12331
12345
  const t6 = frozen && "sticky left-0 z-10 bg-white dark:bg-surface-950";
12332
12346
  let t7;
12333
- if ($[7] !== t6) {
12347
+ if ($[9] !== t6) {
12334
12348
  t7 = ui.cls("flex-shrink-0", t6);
12335
- $[7] = t6;
12336
- $[8] = t7;
12349
+ $[9] = t6;
12350
+ $[10] = t7;
12337
12351
  } else {
12338
- t7 = $[8];
12352
+ t7 = $[10];
12339
12353
  }
12340
12354
  let t8;
12341
- if ($[9] !== attributes || $[10] !== children || $[11] !== setNodeRef || $[12] !== style || $[13] !== t7) {
12342
- t8 = /* @__PURE__ */ jsxRuntime.jsx("div", { ref: setNodeRef, style, className: t7, ...attributes, children });
12343
- $[9] = attributes;
12344
- $[10] = children;
12345
- $[11] = setNodeRef;
12346
- $[12] = style;
12347
- $[13] = t7;
12348
- $[14] = t8;
12355
+ if ($[11] !== attrsWithoutTabIndex || $[12] !== children || $[13] !== setNodeRef || $[14] !== style || $[15] !== t7) {
12356
+ t8 = /* @__PURE__ */ jsxRuntime.jsx("div", { ref: setNodeRef, style, className: t7, ...attrsWithoutTabIndex, children });
12357
+ $[11] = attrsWithoutTabIndex;
12358
+ $[12] = children;
12359
+ $[13] = setNodeRef;
12360
+ $[14] = style;
12361
+ $[15] = t7;
12362
+ $[16] = t8;
12349
12363
  } else {
12350
- t8 = $[14];
12364
+ t8 = $[16];
12351
12365
  }
12352
12366
  return t8;
12353
12367
  };
@@ -13340,12 +13354,29 @@
13340
13354
  }
13341
13355
  return initialSort;
13342
13356
  }, [initialSort, forceFilter]);
13357
+ const location = reactRouterDom.useLocation();
13343
13358
  const {
13344
13359
  filterValues: initialFilterUrl,
13345
13360
  sortBy: initialSortUrl
13346
- } = parseFilterAndSort(window.location.search);
13361
+ } = parseFilterAndSort(location.search);
13347
13362
  const [filterValues_0, setFilterValues] = React.useState(forceFilter ?? (updateUrl ? initialFilterUrl : void 0) ?? initialFilter ?? void 0);
13348
13363
  const [sortBy_0, setSortBy] = React.useState((updateUrl ? initialSortUrl : void 0) ?? initialSortInternal);
13364
+ React.useEffect(() => {
13365
+ if (updateUrl) {
13366
+ const {
13367
+ filterValues: urlFilterValues,
13368
+ sortBy: urlSortBy
13369
+ } = parseFilterAndSort(location.search);
13370
+ if (!forceFilter) {
13371
+ setFilterValues(urlFilterValues);
13372
+ }
13373
+ if (urlSortBy && forceFilter && !checkFilterCombination(forceFilter, urlSortBy)) {
13374
+ console.warn("URL sort is not compatible with the force filter.");
13375
+ } else {
13376
+ setSortBy(urlSortBy);
13377
+ }
13378
+ }
13379
+ }, [location.search, updateUrl, forceFilter, checkFilterCombination]);
13349
13380
  useUpdateUrl(filterValues_0, sortBy_0, searchString, updateUrl);
13350
13381
  const collectionScroll = scrollRestoration?.getCollectionScroll(fullPath, filterValues_0);
13351
13382
  const initialItemCount = collectionScroll?.data.length ?? pageSize;
@@ -16250,7 +16281,7 @@
16250
16281
  size = "m"
16251
16282
  }) {
16252
16283
  const authController = useAuthController();
16253
- useAnalyticsController();
16284
+ const analyticsController = useAnalyticsController();
16254
16285
  useSideEntityController();
16255
16286
  const customizationController = useCustomizationController();
16256
16287
  useNavigationController();
@@ -16277,6 +16308,10 @@
16277
16308
  return;
16278
16309
  }
16279
16310
  if (onClick) {
16311
+ analyticsController.onAnalyticsEvent?.("card_view_entity_click", {
16312
+ path: entity.path,
16313
+ entityId: entity.id
16314
+ });
16280
16315
  onClick(entity);
16281
16316
  }
16282
16317
  };
@@ -17563,7 +17598,7 @@
17563
17598
  return /* @__PURE__ */ jsxRuntime.jsx("div", { style, className: "py-1", "data-is-dragging": isDragging, "data-testid": item.id, onClick: handleClick, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cardClassName, children: [
17564
17599
  usedImageProperty && usedImageValue ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-10 h-10 rounded-md overflow-hidden shrink-0 mr-2", children: /* @__PURE__ */ jsxRuntime.jsx(PropertyPreview, { property: usedImageProperty, propertyKey: imagePropertyKey, size: "small", value: usedImageValue, fill: true }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-10 h-10 rounded-md bg-surface-100 dark:bg-surface-800 shrink-0 mr-2 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(IconForView, { collectionOrView: collection, color: "disabled", size: "small" }) }),
17565
17600
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
17566
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-sm font-medium", children: titleProperty && titleValue ? /* @__PURE__ */ jsxRuntime.jsx(PropertyPreview, { propertyKey: titlePropertyKey, value: titleValue, property: titleProperty, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-surface-500", children: entity.id }) }),
17601
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "line-clamp-2 text-sm font-medium", children: titleProperty && titleValue ? /* @__PURE__ */ jsxRuntime.jsx(PropertyPreview, { propertyKey: titlePropertyKey, value: titleValue, property: titleProperty, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-surface-500", children: entity.id }) }),
17567
17602
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-surface-500 font-mono truncate", children: entity.id })
17568
17603
  ] }),
17569
17604
  selectionEnabled && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-2 shrink-0", onClick: handleCheckboxClick, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Checkbox, { checked: selected ?? false, onCheckedChange: handleSelectionChange, size: "smallest" }) })
@@ -17919,6 +17954,7 @@
17919
17954
  const context = useFireCMSContext();
17920
17955
  const dataSource = useDataSource();
17921
17956
  const sideEntityController = useSideEntityController();
17957
+ const analyticsController = useAnalyticsController();
17922
17958
  const plugins = customizationController.plugins ?? [];
17923
17959
  const [showBackfillDialog, setShowBackfillDialog] = React.useState(false);
17924
17960
  const [backfillLoading, setBackfillLoading] = React.useState(false);
@@ -18034,6 +18070,10 @@
18034
18070
  return plugins.some((plugin) => plugin.collectionView?.onKanbanColumnsReorder);
18035
18071
  }, [plugins]);
18036
18072
  const handleColumnReorder = React.useCallback((newColumns) => {
18073
+ analyticsController.onAnalyticsEvent?.("kanban_column_reorder", {
18074
+ path: fullPath,
18075
+ columnProperty
18076
+ });
18037
18077
  setHasUserReordered(true);
18038
18078
  setLocalColumnsOrder(newColumns);
18039
18079
  plugins.filter((plugin_0) => plugin_0.collectionView?.onKanbanColumnsReorder).forEach((plugin_1) => {
@@ -18045,7 +18085,7 @@
18045
18085
  newColumnsOrder: newColumns
18046
18086
  });
18047
18087
  });
18048
- }, [plugins, fullPath, parentCollectionIds, collection, columnProperty]);
18088
+ }, [plugins, fullPath, parentCollectionIds, collection, columnProperty, analyticsController]);
18049
18089
  const [missingOrderCount, setMissingOrderCount] = React.useState(0);
18050
18090
  const dataSourceRef = React.useRef(dataSource);
18051
18091
  const collectionRef = React.useRef(collection);
@@ -18157,6 +18197,12 @@
18157
18197
  const handleItemsReorder = React.useCallback(async (items_0, moveInfo) => {
18158
18198
  const entity_2 = items_0.find((item_5) => item_5.id === moveInfo?.itemId)?.entity;
18159
18199
  if (!entity_2) return;
18200
+ analyticsController.onAnalyticsEvent?.("kanban_card_moved", {
18201
+ path: fullPath,
18202
+ entityId: entity_2.id,
18203
+ sourceColumn: moveInfo?.sourceColumn,
18204
+ targetColumn: moveInfo?.targetColumn
18205
+ });
18160
18206
  const isColumnChange = moveInfo && moveInfo.sourceColumn !== moveInfo.targetColumn;
18161
18207
  if (!orderProperty && !isColumnChange) return;
18162
18208
  if (isColumnChange) {
@@ -18194,7 +18240,7 @@
18194
18240
  } catch (e_1) {
18195
18241
  console.error("Error saving entity:", e_1);
18196
18242
  }
18197
- }, [collection, columnProperty, orderProperty, context, dataSource, calculateNewOrder, boardDataController]);
18243
+ }, [collection, columnProperty, orderProperty, context, dataSource, calculateNewOrder, boardDataController, analyticsController, fullPath]);
18198
18244
  const handleBackfill = React.useCallback(async () => {
18199
18245
  console.log("handleBackfill called", {
18200
18246
  orderProperty
@@ -18203,6 +18249,9 @@
18203
18249
  console.log("No orderProperty, returning");
18204
18250
  return;
18205
18251
  }
18252
+ analyticsController.onAnalyticsEvent?.("kanban_backfill_order", {
18253
+ path: fullPath
18254
+ });
18206
18255
  setBackfillLoading(true);
18207
18256
  try {
18208
18257
  console.log("Fetching all documents from collection...");
@@ -18256,7 +18305,7 @@
18256
18305
  } finally {
18257
18306
  setBackfillLoading(false);
18258
18307
  }
18259
- }, [orderProperty, fullPath, collection, dataSource, context, boardDataController]);
18308
+ }, [orderProperty, fullPath, collection, dataSource, context, boardDataController, analyticsController]);
18260
18309
  const handleEntityClick = React.useCallback((entity_5) => {
18261
18310
  onEntityClick?.(entity_5);
18262
18311
  }, [onEntityClick]);
@@ -18317,6 +18366,10 @@
18317
18366
  /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "text", onClick: () => setShowBackfillDialog(true), children: "Initialize Order" })
18318
18367
  ] }),
18319
18368
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-auto no-scrollbar", children: /* @__PURE__ */ jsxRuntime.jsx(Board, { data: boardItems, columns, columnLabels, columnColors, assignColumn, allowColumnReorder, onColumnReorder: handleColumnReorder, onItemsReorder: handleItemsReorder, ItemComponent, columnLoadingState, onLoadMoreColumn: (column) => boardDataController.loadMoreColumn(column), onAddItemToColumn: (column_0) => {
18369
+ analyticsController.onAnalyticsEvent?.("kanban_new_entity_in_column", {
18370
+ path: fullPath,
18371
+ column: column_0
18372
+ });
18320
18373
  sideEntityController.open({
18321
18374
  path: fullPath,
18322
18375
  collection,
@@ -18341,13 +18394,13 @@
18341
18394
  ] })
18342
18395
  ] });
18343
18396
  }
18397
+ const ALL_VIEW_MODES = ["table", "cards", "kanban"];
18344
18398
  function ViewModeToggle(t0) {
18345
- const $ = reactCompilerRuntime.c(42);
18399
+ const $ = reactCompilerRuntime.c(36);
18346
18400
  const {
18347
18401
  viewMode: t1,
18348
18402
  onViewModeChange,
18349
- kanbanEnabled: t2,
18350
- hasKanbanConfigPlugin: t3,
18403
+ enabledViews: t2,
18351
18404
  size,
18352
18405
  onSizeChanged,
18353
18406
  open,
@@ -18357,14 +18410,13 @@
18357
18410
  onKanbanPropertyChange
18358
18411
  } = t0;
18359
18412
  const viewMode = t1 === void 0 ? "table" : t1;
18360
- const kanbanEnabled = t2 === void 0 ? false : t2;
18361
- const hasKanbanConfigPlugin = t3 === void 0 ? false : t3;
18413
+ const enabledViews = t2 === void 0 ? ALL_VIEW_MODES : t2;
18362
18414
  if (!onViewModeChange) {
18363
18415
  return null;
18364
18416
  }
18365
- let t4;
18417
+ let t3;
18366
18418
  if ($[0] !== viewMode) {
18367
- t4 = () => {
18419
+ t3 = () => {
18368
18420
  if (viewMode === "kanban") {
18369
18421
  return /* @__PURE__ */ jsxRuntime.jsx(ui.ViewKanbanIcon, { size: "small" });
18370
18422
  }
@@ -18374,14 +18426,14 @@
18374
18426
  return /* @__PURE__ */ jsxRuntime.jsx(ui.ListIcon, { size: "small" });
18375
18427
  };
18376
18428
  $[0] = viewMode;
18377
- $[1] = t4;
18429
+ $[1] = t3;
18378
18430
  } else {
18379
- t4 = $[1];
18431
+ t3 = $[1];
18380
18432
  }
18381
- const getViewModeIcon = t4;
18382
- let t5;
18433
+ const getViewModeIcon = t3;
18434
+ let t4;
18383
18435
  if ($[2] !== viewMode) {
18384
- t5 = () => {
18436
+ t4 = () => {
18385
18437
  if (viewMode === "kanban") {
18386
18438
  return "Board";
18387
18439
  }
@@ -18391,177 +18443,151 @@
18391
18443
  return "List";
18392
18444
  };
18393
18445
  $[2] = viewMode;
18394
- $[3] = t5;
18446
+ $[3] = t4;
18395
18447
  } else {
18396
- t5 = $[3];
18448
+ t4 = $[3];
18397
18449
  }
18398
- const getViewModeName = t5;
18399
- const showKanban = kanbanEnabled || hasKanbanConfigPlugin;
18450
+ const getViewModeName = t4;
18400
18451
  const showSizeSelector = size && onSizeChanged && (viewMode === "table" || viewMode === "cards");
18401
18452
  const showKanbanPropertySelector = viewMode === "kanban" && kanbanPropertyOptions && kanbanPropertyOptions.length > 0 && onKanbanPropertyChange;
18453
+ let t5;
18402
18454
  let t6;
18403
- let t7;
18404
18455
  if ($[4] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
18405
- t7 = {
18406
- value: "table",
18407
- label: "List",
18408
- icon: /* @__PURE__ */ jsxRuntime.jsx(ui.ListIcon, { size: "small" })
18409
- };
18410
- $[4] = t7;
18456
+ t6 = /* @__PURE__ */ jsxRuntime.jsx(ui.ListIcon, { size: "small" });
18457
+ $[4] = t6;
18411
18458
  } else {
18412
- t7 = $[4];
18459
+ t6 = $[4];
18413
18460
  }
18414
- let t8;
18415
- if ($[5] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
18416
- t8 = {
18461
+ let t7;
18462
+ if ($[5] !== enabledViews) {
18463
+ const allOptions = [{
18464
+ value: "table",
18465
+ label: "List",
18466
+ icon: t6
18467
+ }, {
18417
18468
  value: "cards",
18418
18469
  label: "Cards",
18419
18470
  icon: /* @__PURE__ */ jsxRuntime.jsx(ui.AppsIcon, { size: "small" })
18420
- };
18421
- $[5] = t8;
18471
+ }, {
18472
+ value: "kanban",
18473
+ label: "Board",
18474
+ icon: /* @__PURE__ */ jsxRuntime.jsx(ui.ViewKanbanIcon, { size: "small" })
18475
+ }];
18476
+ t7 = allOptions.filter((option) => enabledViews.includes(option.value));
18477
+ $[5] = enabledViews;
18478
+ $[6] = t7;
18422
18479
  } else {
18423
- t8 = $[5];
18480
+ t7 = $[6];
18424
18481
  }
18425
- let options;
18426
- if ($[6] !== hasKanbanConfigPlugin || $[7] !== kanbanEnabled || $[8] !== showKanban) {
18427
- options = [t7, t8];
18428
- if (showKanban) {
18429
- let t92;
18430
- if ($[10] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
18431
- t92 = /* @__PURE__ */ jsxRuntime.jsx(ui.ViewKanbanIcon, { size: "small" });
18432
- $[10] = t92;
18433
- } else {
18434
- t92 = $[10];
18435
- }
18436
- const t102 = !kanbanEnabled && !hasKanbanConfigPlugin;
18437
- let t112;
18438
- if ($[11] !== t102) {
18439
- t112 = {
18440
- value: "kanban",
18441
- label: "Board",
18442
- icon: t92,
18443
- disabled: t102
18444
- };
18445
- $[11] = t102;
18446
- $[12] = t112;
18447
- } else {
18448
- t112 = $[12];
18449
- }
18450
- options.push(t112);
18451
- }
18452
- $[6] = hasKanbanConfigPlugin;
18453
- $[7] = kanbanEnabled;
18454
- $[8] = showKanban;
18455
- $[9] = options;
18482
+ t5 = t7;
18483
+ const viewModeOptions = t5;
18484
+ if (viewModeOptions.length <= 1 && !showSizeSelector) {
18485
+ return null;
18486
+ }
18487
+ let t8;
18488
+ if ($[7] !== getViewModeIcon) {
18489
+ t8 = getViewModeIcon();
18490
+ $[7] = getViewModeIcon;
18491
+ $[8] = t8;
18456
18492
  } else {
18457
- options = $[9];
18493
+ t8 = $[8];
18458
18494
  }
18459
- t6 = options;
18460
- const viewModeOptions = t6;
18461
- let t9;
18462
- if ($[13] !== getViewModeIcon) {
18463
- t9 = getViewModeIcon();
18464
- $[13] = getViewModeIcon;
18465
- $[14] = t9;
18495
+ const t9 = getViewModeName();
18496
+ let t10;
18497
+ if ($[9] !== t9) {
18498
+ t10 = /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 text-sm", children: t9 });
18499
+ $[9] = t9;
18500
+ $[10] = t10;
18466
18501
  } else {
18467
- t9 = $[14];
18502
+ t10 = $[10];
18468
18503
  }
18469
- const t10 = getViewModeName();
18470
18504
  let t11;
18471
- if ($[15] !== t10) {
18472
- t11 = /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 text-sm", children: t10 });
18473
- $[15] = t10;
18474
- $[16] = t11;
18505
+ if ($[11] !== t10 || $[12] !== t8) {
18506
+ t11 = /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", children: [
18507
+ t8,
18508
+ t10
18509
+ ] });
18510
+ $[11] = t10;
18511
+ $[12] = t8;
18512
+ $[13] = t11;
18475
18513
  } else {
18476
- t11 = $[16];
18514
+ t11 = $[13];
18477
18515
  }
18478
18516
  let t12;
18479
- if ($[17] !== t11 || $[18] !== t9) {
18480
- t12 = /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", children: [
18481
- t9,
18482
- t11
18483
- ] });
18484
- $[17] = t11;
18485
- $[18] = t9;
18486
- $[19] = t12;
18517
+ if ($[14] !== onViewModeChange || $[15] !== viewMode || $[16] !== viewModeOptions) {
18518
+ t12 = viewModeOptions.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(ui.ToggleButtonGroup, { value: viewMode, onValueChange: onViewModeChange, options: viewModeOptions });
18519
+ $[14] = onViewModeChange;
18520
+ $[15] = viewMode;
18521
+ $[16] = viewModeOptions;
18522
+ $[17] = t12;
18487
18523
  } else {
18488
- t12 = $[19];
18524
+ t12 = $[17];
18489
18525
  }
18490
18526
  let t13;
18491
- if ($[20] !== onViewModeChange || $[21] !== viewMode || $[22] !== viewModeOptions) {
18492
- t13 = /* @__PURE__ */ jsxRuntime.jsx(ui.ToggleButtonGroup, { value: viewMode, onValueChange: onViewModeChange, options: viewModeOptions });
18493
- $[20] = onViewModeChange;
18494
- $[21] = viewMode;
18495
- $[22] = viewModeOptions;
18496
- $[23] = t13;
18497
- } else {
18498
- t13 = $[23];
18499
- }
18500
- let t14;
18501
- if ($[24] !== onSizeChanged || $[25] !== showSizeSelector || $[26] !== size) {
18502
- t14 = showSizeSelector && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-row items-center justify-between gap-2", children: [
18527
+ if ($[18] !== onSizeChanged || $[19] !== showSizeSelector || $[20] !== size) {
18528
+ t13 = showSizeSelector && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-row items-center justify-between gap-2", children: [
18503
18529
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm text-surface-600 dark:text-surface-300", children: [
18504
18530
  /* @__PURE__ */ jsxRuntime.jsx(ui.ViewColumnIcon, { size: "small" }),
18505
18531
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Size" })
18506
18532
  ] }),
18507
18533
  /* @__PURE__ */ jsxRuntime.jsx(ui.Select, { value: size, size: "small", className: "w-20", onValueChange: (v) => onSizeChanged?.(v), renderValue: _temp$e, children: ["xs", "s", "m", "l", "xl"].map(_temp2$5) })
18508
18534
  ] });
18509
- $[24] = onSizeChanged;
18510
- $[25] = showSizeSelector;
18511
- $[26] = size;
18512
- $[27] = t14;
18535
+ $[18] = onSizeChanged;
18536
+ $[19] = showSizeSelector;
18537
+ $[20] = size;
18538
+ $[21] = t13;
18513
18539
  } else {
18514
- t14 = $[27];
18540
+ t13 = $[21];
18515
18541
  }
18516
- let t15;
18517
- if ($[28] !== kanbanPropertyOptions || $[29] !== onKanbanPropertyChange || $[30] !== selectedKanbanProperty || $[31] !== showKanbanPropertySelector) {
18518
- t15 = showKanbanPropertySelector && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-row items-center justify-between gap-2", children: [
18542
+ let t14;
18543
+ if ($[22] !== kanbanPropertyOptions || $[23] !== onKanbanPropertyChange || $[24] !== selectedKanbanProperty || $[25] !== showKanbanPropertySelector) {
18544
+ t14 = showKanbanPropertySelector && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-row items-center justify-between gap-2", children: [
18519
18545
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm text-surface-600 dark:text-surface-300", children: [
18520
18546
  /* @__PURE__ */ jsxRuntime.jsx(ui.ViewKanbanIcon, { size: "small" }),
18521
18547
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Group by" })
18522
18548
  ] }),
18523
18549
  /* @__PURE__ */ jsxRuntime.jsx(ui.Select, { value: selectedKanbanProperty, size: "small", className: "w-32", onValueChange: (v_1) => onKanbanPropertyChange?.(v_1), renderValue: (v_2) => {
18524
- const option = kanbanPropertyOptions?.find((o) => o.key === v_2);
18525
- return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium truncate", children: option?.label ?? v_2 });
18550
+ const option_0 = kanbanPropertyOptions?.find((o) => o.key === v_2);
18551
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium truncate", children: option_0?.label ?? v_2 });
18526
18552
  }, children: kanbanPropertyOptions?.map(_temp3$3) })
18527
18553
  ] });
18528
- $[28] = kanbanPropertyOptions;
18529
- $[29] = onKanbanPropertyChange;
18530
- $[30] = selectedKanbanProperty;
18531
- $[31] = showKanbanPropertySelector;
18532
- $[32] = t15;
18554
+ $[22] = kanbanPropertyOptions;
18555
+ $[23] = onKanbanPropertyChange;
18556
+ $[24] = selectedKanbanProperty;
18557
+ $[25] = showKanbanPropertySelector;
18558
+ $[26] = t14;
18533
18559
  } else {
18534
- t15 = $[32];
18560
+ t14 = $[26];
18535
18561
  }
18536
- let t16;
18537
- if ($[33] !== t13 || $[34] !== t14 || $[35] !== t15) {
18538
- t16 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-3 flex flex-col gap-3 min-w-[240px]", children: [
18562
+ let t15;
18563
+ if ($[27] !== t12 || $[28] !== t13 || $[29] !== t14) {
18564
+ t15 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-3 flex flex-col gap-3 min-w-[240px]", children: [
18565
+ t12,
18539
18566
  t13,
18540
- t14,
18541
- t15
18567
+ t14
18542
18568
  ] });
18543
- $[33] = t13;
18544
- $[34] = t14;
18545
- $[35] = t15;
18546
- $[36] = t16;
18569
+ $[27] = t12;
18570
+ $[28] = t13;
18571
+ $[29] = t14;
18572
+ $[30] = t15;
18547
18573
  } else {
18548
- t16 = $[36];
18574
+ t15 = $[30];
18549
18575
  }
18550
- let t17;
18551
- if ($[37] !== onOpenChange || $[38] !== open || $[39] !== t12 || $[40] !== t16) {
18552
- t17 = /* @__PURE__ */ jsxRuntime.jsx(ui.Popover, { open, onOpenChange, modal: true, trigger: t12, children: t16 });
18553
- $[37] = onOpenChange;
18554
- $[38] = open;
18555
- $[39] = t12;
18556
- $[40] = t16;
18557
- $[41] = t17;
18576
+ let t16;
18577
+ if ($[31] !== onOpenChange || $[32] !== open || $[33] !== t11 || $[34] !== t15) {
18578
+ t16 = /* @__PURE__ */ jsxRuntime.jsx(ui.Popover, { open, onOpenChange, modal: true, trigger: t11, children: t15 });
18579
+ $[31] = onOpenChange;
18580
+ $[32] = open;
18581
+ $[33] = t11;
18582
+ $[34] = t15;
18583
+ $[35] = t16;
18558
18584
  } else {
18559
- t17 = $[41];
18585
+ t16 = $[35];
18560
18586
  }
18561
- return t17;
18587
+ return t16;
18562
18588
  }
18563
- function _temp3$3(option_0) {
18564
- return /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: option_0.key, children: option_0.label }, option_0.key);
18589
+ function _temp3$3(option_1) {
18590
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: option_1.key, children: option_1.label }, option_1.key);
18565
18591
  }
18566
18592
  function _temp2$5(s) {
18567
18593
  return /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: s, className: "font-medium text-center", children: s.toUpperCase() }, s);
@@ -19508,6 +19534,7 @@
19508
19534
  console.error(error);
19509
19535
  }, [snackbarController]);
19510
19536
  const pluginActions = [];
19537
+ const pluginBeforeTitle = [];
19511
19538
  const plugins = customizationController.plugins;
19512
19539
  const actionsDisabled = disabled || formex$1.isSubmitting || status === "existing" && !formex$1.dirty || Boolean(disabledProp);
19513
19540
  const parentCollectionIds = navigationController.getParentCollectionIds(path);
@@ -19524,6 +19551,7 @@
19524
19551
  disabled: actionsDisabled
19525
19552
  };
19526
19553
  pluginActions.push(...plugins.map((plugin) => plugin.form?.Actions ? /* @__PURE__ */ jsxRuntime.jsx(plugin.form.Actions, { ...actionProps }, `actions_${plugin.key}`) : null).filter(Boolean));
19554
+ pluginBeforeTitle.push(...plugins.map((plugin_0) => plugin_0.form?.BeforeTitle ? /* @__PURE__ */ jsxRuntime.jsx(plugin_0.form.BeforeTitle, { ...actionProps }, `before_title_${plugin_0.key}`) : null).filter(Boolean));
19527
19555
  }
19528
19556
  const titlePropertyKey = getEntityTitlePropertyKey(resolvedCollection, customizationController.propertyConfigs);
19529
19557
  const title = (formex$1.values && titlePropertyKey ? getValueInPath(formex$1.values, titlePropertyKey) : void 0) ?? collection.singularName ?? collection.name;
@@ -19620,6 +19648,7 @@
19620
19648
  };
19621
19649
  const formRef = React.useRef(null);
19622
19650
  const formView = /* @__PURE__ */ jsxRuntime.jsx(ErrorBoundary, { children: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
19651
+ pluginBeforeTitle,
19623
19652
  !Builder && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full py-2 flex flex-col items-start my-4 lg:my-6", children: [
19624
19653
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { className: "my-4 flex-grow line-clamp-1 " + (collection.hideIdFromForm ? "mb-6" : ""), variant: "h4", children: title ?? collection.singularName ?? collection.name }),
19625
19654
  !entity?.values && initialStatus === "existing" && /* @__PURE__ */ jsxRuntime.jsx(ui.Alert, { color: "warning", size: "small", outerClassName: "w-full mb-4 text-xs", children: "This entity does not exist in the database" }),
@@ -21877,7 +21906,7 @@
21877
21906
  index,
21878
21907
  authController
21879
21908
  });
21880
- Component = configProperty.Field;
21909
+ Component = configProperty?.Field;
21881
21910
  }
21882
21911
  }
21883
21912
  }
@@ -24502,13 +24531,18 @@
24502
24531
  });
24503
24532
  }, [onCollectionModifiedForUser, fullPath, userConfigPersistence]);
24504
24533
  const onViewModeChange = React.useCallback((mode) => {
24534
+ analyticsController.onAnalyticsEvent?.("view_mode_changed", {
24535
+ path: fullPath,
24536
+ from: viewMode,
24537
+ to: mode
24538
+ });
24505
24539
  setViewMode(mode);
24506
24540
  if (userConfigPersistence) {
24507
24541
  onCollectionModifiedForUser(fullPath, {
24508
24542
  defaultViewMode: mode
24509
24543
  });
24510
24544
  }
24511
- }, [setViewMode, userConfigPersistence, onCollectionModifiedForUser, fullPath]);
24545
+ }, [setViewMode, userConfigPersistence, onCollectionModifiedForUser, fullPath, analyticsController, viewMode]);
24512
24546
  const createEnabled = canCreateEntity(collection, authController, fullPath, null);
24513
24547
  const uniqueFieldValidator = React.useCallback(({
24514
24548
  name,
@@ -24562,24 +24596,26 @@
24562
24596
  propertyConfigs: customizationController.propertyConfigs,
24563
24597
  authController
24564
24598
  }), [collection, fullPath]);
24565
- const kanbanEnabled = React.useMemo(() => {
24566
- if (!collection.kanban?.columnProperty) return false;
24567
- const property_0 = getPropertyInPath(resolvedCollection.properties, collection.kanban.columnProperty);
24568
- if (!property_0 || !("dataType" in property_0) || property_0.dataType !== "string") return false;
24569
- return Boolean(property_0.enumValues);
24570
- }, [collection.kanban?.columnProperty, resolvedCollection.properties]);
24571
- const hasKanbanConfigPlugin = React.useMemo(() => {
24572
- return customizationController.plugins?.some((plugin_0) => plugin_0.collectionView?.KanbanSetupComponent) ?? false;
24573
- }, [customizationController.plugins]);
24599
+ const hasEnumProperty = React.useMemo(() => {
24600
+ const properties = resolvedCollection.properties;
24601
+ return Object.values(properties).some((prop) => prop && prop.dataType === "string" && prop.enumValues);
24602
+ }, [resolvedCollection.properties]);
24603
+ const enabledViews = React.useMemo(() => {
24604
+ const configured = collection.enabledViews ?? ["table", "cards", "kanban"];
24605
+ if (!hasEnumProperty) {
24606
+ return configured.filter((v) => v !== "kanban");
24607
+ }
24608
+ return configured;
24609
+ }, [collection.enabledViews, hasEnumProperty]);
24574
24610
  const kanbanPropertyOptions = React.useMemo(() => {
24575
24611
  const options = [];
24576
- const properties = resolvedCollection.properties;
24577
- for (const [key_0, property_1] of Object.entries(properties)) {
24578
- const prop = property_1;
24579
- if (prop && prop.dataType === "string" && prop.enumValues) {
24612
+ const properties_0 = resolvedCollection.properties;
24613
+ for (const [key_0, property_0] of Object.entries(properties_0)) {
24614
+ const prop_0 = property_0;
24615
+ if (prop_0 && prop_0.dataType === "string" && prop_0.enumValues) {
24580
24616
  options.push({
24581
24617
  key: key_0,
24582
- label: prop.name || key_0
24618
+ label: prop_0.name || key_0
24583
24619
  });
24584
24620
  }
24585
24621
  }
@@ -24607,14 +24643,18 @@
24607
24643
  }
24608
24644
  }
24609
24645
  }, [kanbanPropertyOptions, selectedKanbanProperty, getSavedKanbanProperty, collection.kanban?.columnProperty]);
24610
- const onKanbanPropertyChange = React.useCallback((property_2) => {
24611
- setSelectedKanbanProperty(property_2);
24646
+ const onKanbanPropertyChange = React.useCallback((property_1) => {
24647
+ analyticsController.onAnalyticsEvent?.("kanban_property_changed", {
24648
+ path: fullPath,
24649
+ property: property_1
24650
+ });
24651
+ setSelectedKanbanProperty(property_1);
24612
24652
  if (userConfigPersistence) {
24613
24653
  onCollectionModifiedForUser(fullPath, {
24614
- kanbanColumnProperty: property_2
24654
+ kanbanColumnProperty: property_1
24615
24655
  });
24616
24656
  }
24617
- }, [userConfigPersistence, onCollectionModifiedForUser, fullPath]);
24657
+ }, [userConfigPersistence, onCollectionModifiedForUser, fullPath, analyticsController]);
24618
24658
  const getPropertyFor = React.useCallback(({
24619
24659
  propertyKey: propertyKey_0,
24620
24660
  entity: entity_2
@@ -24726,15 +24766,15 @@
24726
24766
  }, [docsCount, fullPath, breadcrumbs.updateCount]);
24727
24767
  const countFetcher = /* @__PURE__ */ jsxRuntime.jsx(EntitiesCount, { fullPath, collection, filter: tableController.filterValues, sortBy: tableController.sortBy, onCountChange: setDocsCount });
24728
24768
  const buildAdditionalHeaderWidget = React.useCallback(({
24729
- property: property_3,
24769
+ property: property_2,
24730
24770
  propertyKey: propertyKey_1,
24731
24771
  onHover
24732
24772
  }) => {
24733
24773
  const collection_4 = collectionRef.current;
24734
24774
  if (!customizationController.plugins) return null;
24735
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: customizationController.plugins.filter((plugin_1) => plugin_1.collectionView?.HeaderAction).map((plugin_2, i) => {
24736
- const HeaderAction = plugin_2.collectionView.HeaderAction;
24737
- return /* @__PURE__ */ jsxRuntime.jsx(HeaderAction, { onHover, propertyKey: propertyKey_1, property: property_3, fullPath, collection: collection_4, tableController, parentCollectionIds: parentCollectionIds ?? [] }, `plugin_header_action_${i}`);
24775
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: customizationController.plugins.filter((plugin_0) => plugin_0.collectionView?.HeaderAction).map((plugin_1, i) => {
24776
+ const HeaderAction = plugin_1.collectionView.HeaderAction;
24777
+ return /* @__PURE__ */ jsxRuntime.jsx(HeaderAction, { onHover, propertyKey: propertyKey_1, property: property_2, fullPath, collection: collection_4, tableController, parentCollectionIds: parentCollectionIds ?? [] }, `plugin_header_action_${i}`);
24738
24778
  }) });
24739
24779
  }, [customizationController.plugins, fullPath, parentCollectionIds]);
24740
24780
  const addColumnComponentInternal = AddColumnComponent ? function() {
@@ -24752,11 +24792,22 @@
24752
24792
  parentCollectionIds
24753
24793
  });
24754
24794
  const [viewModePopoverOpen, setViewModePopoverOpen] = React.useState(false);
24755
- const viewModeToggleElement = /* @__PURE__ */ jsxRuntime.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 });
24795
+ const viewModeToggleElement = /* @__PURE__ */ jsxRuntime.jsx(ViewModeToggle, { viewMode, onViewModeChange, enabledViews, size: viewMode === "table" ? tableSize : viewMode === "cards" ? cardSize : void 0, onSizeChanged: viewMode === "table" ? onTableSizeChanged : viewMode === "cards" ? setCardSize : void 0, open: viewModePopoverOpen, onOpenChange: setViewModePopoverOpen, kanbanPropertyOptions, selectedKanbanProperty, onKanbanPropertyChange });
24796
+ const pluginErrorView = React.useMemo(() => {
24797
+ const error = tableController.dataLoadingError;
24798
+ if (!error || !customizationController.plugins) return null;
24799
+ for (const plugin_2 of customizationController.plugins) {
24800
+ if (plugin_2.collectionView?.CollectionError) {
24801
+ const CollectionError = plugin_2.collectionView.CollectionError;
24802
+ return /* @__PURE__ */ jsxRuntime.jsx(CollectionError, { path: fullPath, collection, parentCollectionIds, error });
24803
+ }
24804
+ }
24805
+ return null;
24806
+ }, [tableController.dataLoadingError, customizationController.plugins, fullPath, collection, parentCollectionIds]);
24756
24807
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cls("overflow-hidden h-full w-full rounded-md flex flex-col", className), ref: containerRef, children: [
24757
24808
  countFetcher,
24758
24809
  /* @__PURE__ */ jsxRuntime.jsx(CollectionTableToolbar, { loading: tableController.dataLoading, onTextSearch: textSearchEnabled && textSearchInitialised ? tableController.setSearchString : void 0, onTextSearchClick: textSearchEnabled && !textSearchInitialised ? onTextSearchClick : void 0, textSearchLoading, viewModeToggle: viewModeToggleElement, actionsStart: /* @__PURE__ */ jsxRuntime.jsx(EntityCollectionViewStartActions, { parentCollectionIds: parentCollectionIds ?? [], collection, tableController, path: fullPath, relativePath: collection.path, selectionController: usedSelectionController, collectionEntitiesCount: docsCount, resolvedProperties: resolvedCollection.properties }), actions: /* @__PURE__ */ jsxRuntime.jsx(EntityCollectionViewActions, { parentCollectionIds: parentCollectionIds ?? [], collection, tableController, onMultipleDeleteClick, onNewClick, path: fullPath, relativePath: collection.path, selectionController: usedSelectionController, selectionEnabled, collectionEntitiesCount: docsCount }) }),
24759
- viewMode === "kanban" && (kanbanEnabled || hasKanbanConfigPlugin) ? /* @__PURE__ */ jsxRuntime.jsx(EntityCollectionBoardView, { collection, tableController, fullPath, parentCollectionIds, columnProperty: selectedKanbanProperty, onEntityClick, selectionController: usedSelectionController, selectionEnabled, highlightedEntities: highlightedEntity ? [highlightedEntity] : [], deletedEntities, emptyComponent: canCreateEntities && tableController.filterValues === void 0 && tableController.sortBy === void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center", children: [
24810
+ tableController.dataLoadingError && pluginErrorView ? pluginErrorView : viewMode === "kanban" && enabledViews.includes("kanban") ? /* @__PURE__ */ jsxRuntime.jsx(EntityCollectionBoardView, { collection, tableController, fullPath, parentCollectionIds, columnProperty: selectedKanbanProperty, onEntityClick, selectionController: usedSelectionController, selectionEnabled, highlightedEntities: highlightedEntity ? [highlightedEntity] : [], deletedEntities, emptyComponent: canCreateEntities && tableController.filterValues === void 0 && tableController.sortBy === void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center", children: [
24760
24811
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "subtitle2", children: "So empty..." }),
24761
24812
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { onClick: onNewClick, className: "mt-4", children: [
24762
24813
  /* @__PURE__ */ jsxRuntime.jsx(ui.AddIcon, {}),
@@ -26148,10 +26199,10 @@
26148
26199
  navigationGroupMappings
26149
26200
  } = props;
26150
26201
  const navigate = reactRouterDom.useNavigate();
26151
- const collectionsRef = React.useRef();
26152
- const viewsRef = React.useRef();
26153
- const adminViewsRef = React.useRef();
26154
- const navigationEntriesOrderRef = React.useRef();
26202
+ const collectionsRef = React.useRef(void 0);
26203
+ const viewsRef = React.useRef(void 0);
26204
+ const adminViewsRef = React.useRef(void 0);
26205
+ const navigationEntriesOrderRef = React.useRef(void 0);
26155
26206
  const [initialised, setInitialised] = React.useState(false);
26156
26207
  const [topLevelNavigation, setTopLevelNavigation] = React.useState(void 0);
26157
26208
  const [navigationLoading, setNavigationLoading] = React.useState(true);
@@ -26391,7 +26442,9 @@
26391
26442
  const isUrlCollectionPath = React.useCallback((path_1) => removeInitialAndTrailingSlashes(path_1 + "/").startsWith(removeInitialAndTrailingSlashes(fullCollectionPath) + "/"), [fullCollectionPath]);
26392
26443
  const urlPathToDataPath = React.useCallback((path_2) => {
26393
26444
  const decodedPath = decodeURIComponent(path_2);
26394
- if (decodedPath.startsWith(fullCollectionPath)) return decodedPath.replace(fullCollectionPath, "");
26445
+ const withoutHash = decodedPath.split("#")[0];
26446
+ const cleanPath_0 = withoutHash.split("?")[0];
26447
+ if (cleanPath_0.startsWith(fullCollectionPath)) return cleanPath_0.replace(fullCollectionPath, "");
26395
26448
  throw Error("Expected path starting with " + fullCollectionPath);
26396
26449
  }, [fullCollectionPath]);
26397
26450
  const resolveIdsFrom = React.useCallback((path_3) => {
@@ -26456,7 +26509,24 @@
26456
26509
  };
26457
26510
  }
26458
26511
  function encodePath(input) {
26459
- return encodeURIComponent(removeInitialAndTrailingSlashes(input)).replaceAll("%2F", "/").replaceAll("%23", "#");
26512
+ const cleanInput = removeInitialAndTrailingSlashes(input);
26513
+ const [pathPart, rest] = cleanInput.split("?", 2);
26514
+ let encodedPath = encodeURIComponent(pathPart).replaceAll("%2F", "/");
26515
+ let result = encodedPath;
26516
+ if (rest !== void 0) {
26517
+ const [searchPart, hashPart] = rest.split("#", 2);
26518
+ result += `?${searchPart}`;
26519
+ if (hashPart !== void 0) {
26520
+ result += `#${hashPart}`;
26521
+ }
26522
+ } else {
26523
+ const [pathOnly, hashOnly] = cleanInput.split("#", 2);
26524
+ if (hashOnly !== void 0) {
26525
+ encodedPath = encodeURIComponent(pathOnly).replaceAll("%2F", "/");
26526
+ result = `${encodedPath}#${hashOnly}`;
26527
+ }
26528
+ }
26529
+ return result;
26460
26530
  }
26461
26531
  function filterOutNotAllowedCollections(resolvedCollections, authController) {
26462
26532
  return resolvedCollections.filter((c) => Boolean(c.path)).filter((c) => {
@@ -26856,7 +26926,7 @@
26856
26926
  t2 = $[2];
26857
26927
  }
26858
26928
  React.useEffect(t1, t2);
26859
- const checkedUserRef = React.useRef();
26929
+ const checkedUserRef = React.useRef(void 0);
26860
26930
  let t3;
26861
26931
  if ($[3] !== authController || $[4] !== authenticator || $[5] !== dataSourceDelegate || $[6] !== disabled || $[7] !== storageSource) {
26862
26932
  t3 = async () => {
@@ -27185,13 +27255,13 @@
27185
27255
  status,
27186
27256
  values
27187
27257
  }) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
27188
- /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { className: "self-center", onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(ui.CloseIcon, { size: "small" }) }),
27189
- allowFullScreen && /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { className: "self-center", onClick: () => {
27258
+ /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { className: "self-center", size: "smallest", onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(ui.CloseIcon, { size: "smallest" }) }),
27259
+ allowFullScreen && /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { className: "self-center", size: "smallest", onClick: () => {
27190
27260
  const key = status === "new" || status === "copy" ? path + "#new" : path + "/" + entityId;
27191
27261
  saveEntityToMemoryCache(key, values);
27192
- if (entityId) navigate(location.pathname);
27193
- else navigate(location.pathname + "#new");
27194
- }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.OpenInFullIcon, { size: "small" }) })
27262
+ if (entityId) navigate(location.pathname + location.search);
27263
+ else navigate(location.pathname + location.search + "#new");
27264
+ }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.OpenInFullIcon, { size: "smallest" }) })
27195
27265
  ] }), onTabChange: ({
27196
27266
  entityId: entityId_0,
27197
27267
  selectedTab,
@@ -27865,7 +27935,7 @@
27865
27935
  const customViewTabsEnd = resolvedEntityViews.filter((view_1) => !view_1.position || view_1.position === "end").map((view_2) => /* @__PURE__ */ jsxRuntime.jsx(ui.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}`));
27866
27936
  const shouldShowTopBar = Boolean(barActions) || hasAdditionalViews;
27867
27937
  let result = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-col h-full w-full bg-white dark:bg-surface-900", children: [
27868
- shouldShowTopBar && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.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", ui.defaultBorderMixin), children: [
27938
+ shouldShowTopBar && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.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", ui.defaultBorderMixin), children: [
27869
27939
  barActions?.({
27870
27940
  path: fullIdPath ?? path,
27871
27941
  entityId,
@@ -27982,8 +28052,8 @@
27982
28052
  const panelsFromUrl = buildSidePanelsFromUrl(entityOrCollectionPath, navigation.collections ?? [], newFlag);
27983
28053
  for (let i = 0; i < panelsFromUrl.length; i++) {
27984
28054
  const props = panelsFromUrl[i];
27985
- if (i === 0) sideDialogsController.replace(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController));
27986
- else sideDialogsController.open(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController));
28055
+ if (i === 0) sideDialogsController.replace(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController, location.search));
28056
+ else sideDialogsController.open(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController, location.search));
27987
28057
  }
27988
28058
  }
27989
28059
  initialised.current = true;
@@ -28000,7 +28070,7 @@
28000
28070
  return;
28001
28071
  }
28002
28072
  const lastPanel = panelsFromUrl_0[panelsFromUrl_0.length - 1];
28003
- const panelProps = propsToSidePanel(lastPanel, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController);
28073
+ const panelProps = propsToSidePanel(lastPanel, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController, location.search);
28004
28074
  const lastCurrentPanel = currentPanelKeys.length > 0 ? currentPanelKeys[currentPanelKeys.length - 1] : void 0;
28005
28075
  if (!lastCurrentPanel || lastCurrentPanel !== panelProps.key) {
28006
28076
  sideDialogsController.replace(panelProps);
@@ -28011,7 +28081,7 @@
28011
28081
  React.useEffect(() => {
28012
28082
  const updatedSidePanels = sideDialogsController.sidePanels.map((sidePanelProps) => {
28013
28083
  if (sidePanelProps.additional) {
28014
- return propsToSidePanel(sidePanelProps.additional, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController);
28084
+ return propsToSidePanel(sidePanelProps.additional, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController, location.search);
28015
28085
  }
28016
28086
  return sidePanelProps;
28017
28087
  });
@@ -28031,14 +28101,14 @@
28031
28101
  sideDialogsController.open(propsToSidePanel({
28032
28102
  selectedTab: defaultSelectedView,
28033
28103
  ...props_0
28034
- }, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController));
28035
- }, [sideDialogsController, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, authController.user]);
28104
+ }, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController, location.search));
28105
+ }, [sideDialogsController, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, authController.user, location.search]);
28036
28106
  const replace = React.useCallback((props_1) => {
28037
28107
  if (props_1.copy && !props_1.entityId) {
28038
28108
  throw Error("If you want to copy an entity you need to provide an entityId");
28039
28109
  }
28040
- sideDialogsController.replace(propsToSidePanel(props_1, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController));
28041
- }, [navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, sideDialogsController, smallLayout, authController.user]);
28110
+ sideDialogsController.replace(propsToSidePanel(props_1, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController, authController, location.search));
28111
+ }, [navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, sideDialogsController, smallLayout, authController.user, location.search]);
28042
28112
  return {
28043
28113
  close,
28044
28114
  open,
@@ -28087,9 +28157,9 @@
28087
28157
  }
28088
28158
  return sidePanel ? [sidePanel] : [];
28089
28159
  }
28090
- const propsToSidePanel = (props, buildUrlCollectionPath, resolveIdsFrom, smallLayout, customizationController, authController) => {
28160
+ const propsToSidePanel = (props, buildUrlCollectionPath, resolveIdsFrom, smallLayout, customizationController, authController, locationSearch) => {
28091
28161
  const collectionPath = removeInitialAndTrailingSlashes(props.path);
28092
- const urlPath = props.entityId ? buildUrlCollectionPath(`${collectionPath}/${props.entityId}${props.selectedTab ? "/" + props.selectedTab : ""}#${SIDE_URL_HASH}`) : buildUrlCollectionPath(`${collectionPath}#${NEW_URL_HASH}`);
28162
+ const urlPath = props.entityId ? buildUrlCollectionPath(`${collectionPath}/${props.entityId}${props.selectedTab ? "/" + props.selectedTab : ""}${locationSearch}#${SIDE_URL_HASH}`) : buildUrlCollectionPath(`${collectionPath}${locationSearch}#${NEW_URL_HASH}`);
28093
28163
  const resolvedPanelProps = {
28094
28164
  ...props,
28095
28165
  formProps: props.formProps
@@ -28467,7 +28537,7 @@
28467
28537
  const orderProperty = collection_3?.orderProperty;
28468
28538
  if (orderProperty && (status === "new" || status === "copy")) {
28469
28539
  const orderProp = properties?.[orderProperty];
28470
- if (orderProp?.disabled === true) {
28540
+ if (orderProp) {
28471
28541
  const currentValue = updatedValues[orderProperty];
28472
28542
  if (currentValue === void 0 || currentValue === null) {
28473
28543
  try {
@@ -29688,14 +29758,19 @@
29688
29758
  return "custom_array";
29689
29759
  } else if (isPropertyBuilder(of)) {
29690
29760
  return "repeat";
29691
- } else if (of?.dataType === "string" && of.enumValues) {
29692
- return "multi_select";
29693
- } else if (of?.dataType === "number" && of.enumValues) {
29694
- return "multi_number_select";
29695
- } else if (of?.dataType === "string" && of.storage) {
29696
- return "multi_file_upload";
29697
- } else if (of?.dataType === "reference") {
29698
- return "multi_references";
29761
+ } else if (of) {
29762
+ const ofProperty = of;
29763
+ if (ofProperty.dataType === "string" && ofProperty.enumValues) {
29764
+ return "multi_select";
29765
+ } else if (ofProperty.dataType === "number" && ofProperty.enumValues) {
29766
+ return "multi_number_select";
29767
+ } else if (ofProperty.dataType === "string" && ofProperty.storage) {
29768
+ return "multi_file_upload";
29769
+ } else if (ofProperty.dataType === "reference") {
29770
+ return "multi_references";
29771
+ } else {
29772
+ return "repeat";
29773
+ }
29699
29774
  } else {
29700
29775
  return "repeat";
29701
29776
  }