@firecms/core 3.0.0-rc.1 → 3.0.0-rc.3

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 (96) hide show
  1. package/dist/components/HomePage/HomePageDnD.d.ts +2 -1
  2. package/dist/components/PropertyCollectionView.d.ts +23 -0
  3. package/dist/components/UserDisplay.d.ts +7 -0
  4. package/dist/components/VirtualTable/fields/VirtualTableUserSelect.d.ts +12 -0
  5. package/dist/contexts/InternalUserManagementContext.d.ts +3 -0
  6. package/dist/core/EntityEditView.d.ts +10 -4
  7. package/dist/core/FireCMS.d.ts +0 -1
  8. package/dist/core/field_configs.d.ts +1 -1
  9. package/dist/form/EntityForm.d.ts +5 -2
  10. package/dist/form/components/LocalChangesMenu.d.ts +11 -0
  11. package/dist/form/field_bindings/UserSelectFieldBinding.d.ts +12 -0
  12. package/dist/form/index.d.ts +2 -1
  13. package/dist/hooks/index.d.ts +2 -0
  14. package/dist/hooks/useCollapsedGroups.d.ts +9 -0
  15. package/dist/hooks/useInternalUserManagementController.d.ts +12 -0
  16. package/dist/index.es.js +1983 -650
  17. package/dist/index.es.js.map +1 -1
  18. package/dist/index.umd.js +1981 -648
  19. package/dist/index.umd.js.map +1 -1
  20. package/dist/preview/components/UserPreview.d.ts +8 -0
  21. package/dist/preview/index.d.ts +1 -0
  22. package/dist/types/collections.d.ts +13 -0
  23. package/dist/types/entities.d.ts +5 -1
  24. package/dist/types/firecms.d.ts +15 -0
  25. package/dist/types/firecms_context.d.ts +16 -0
  26. package/dist/types/index.d.ts +1 -0
  27. package/dist/types/internal_user_management.d.ts +20 -0
  28. package/dist/types/plugins.d.ts +2 -0
  29. package/dist/types/properties.d.ts +41 -6
  30. package/dist/types/property_config.d.ts +1 -1
  31. package/dist/types/user.d.ts +1 -1
  32. package/dist/util/collections.d.ts +1 -0
  33. package/dist/util/entity_cache.d.ts +6 -1
  34. package/dist/util/make_properties_editable.d.ts +1 -2
  35. package/dist/util/objects.d.ts +1 -0
  36. package/dist/util/useStorageUploadController.d.ts +1 -0
  37. package/package.json +6 -6
  38. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +47 -47
  39. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +12 -0
  40. package/src/components/EntityCollectionView/EntityCollectionView.tsx +6 -1
  41. package/src/components/EntityView.tsx +29 -40
  42. package/src/components/ErrorView.tsx +1 -1
  43. package/src/components/HomePage/DefaultHomePage.tsx +21 -34
  44. package/src/components/HomePage/HomePageDnD.tsx +143 -83
  45. package/src/components/HomePage/RenameGroupDialog.tsx +9 -3
  46. package/src/components/PropertyCollectionView.tsx +329 -0
  47. package/src/components/PropertyConfigBadge.tsx +2 -2
  48. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +2 -1
  49. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +1 -2
  50. package/src/components/UserDisplay.tsx +55 -0
  51. package/src/components/VirtualTable/fields/VirtualTableUserSelect.tsx +99 -0
  52. package/src/components/common/useColumnsIds.tsx +1 -8
  53. package/src/contexts/InternalUserManagementContext.tsx +4 -0
  54. package/src/core/EntityEditView.tsx +27 -14
  55. package/src/core/EntityEditViewFormActions.tsx +33 -18
  56. package/src/core/EntitySidePanel.tsx +9 -3
  57. package/src/core/FireCMS.tsx +22 -13
  58. package/src/core/field_configs.tsx +15 -1
  59. package/src/form/EntityForm.tsx +173 -42
  60. package/src/form/EntityFormActions.tsx +30 -15
  61. package/src/form/PropertyFieldBinding.tsx +4 -0
  62. package/src/form/components/ErrorFocus.tsx +22 -29
  63. package/src/form/components/LocalChangesMenu.tsx +144 -0
  64. package/src/form/field_bindings/UserSelectFieldBinding.tsx +94 -0
  65. package/src/form/index.tsx +5 -1
  66. package/src/hooks/index.tsx +3 -0
  67. package/src/hooks/useBrowserTitleAndIcon.tsx +1 -1
  68. package/src/hooks/useBuildNavigationController.tsx +104 -31
  69. package/src/hooks/useCollapsedGroups.ts +64 -0
  70. package/src/hooks/useFireCMSContext.tsx +6 -2
  71. package/src/hooks/useInternalUserManagementController.tsx +16 -0
  72. package/src/preview/PropertyPreview.tsx +8 -0
  73. package/src/preview/components/ReferencePreview.tsx +4 -2
  74. package/src/preview/components/UserPreview.tsx +27 -0
  75. package/src/preview/index.ts +1 -0
  76. package/src/preview/property_previews/ArrayPropertyPreview.tsx +1 -1
  77. package/src/preview/property_previews/MapPropertyPreview.tsx +2 -2
  78. package/src/preview/property_previews/NumberPropertyPreview.tsx +2 -2
  79. package/src/types/collections.ts +14 -0
  80. package/src/types/entities.ts +7 -1
  81. package/src/types/firecms.tsx +16 -0
  82. package/src/types/firecms_context.tsx +17 -0
  83. package/src/types/index.ts +1 -0
  84. package/src/types/internal_user_management.ts +24 -0
  85. package/src/types/plugins.tsx +3 -0
  86. package/src/types/properties.ts +45 -6
  87. package/src/types/property_config.tsx +1 -0
  88. package/src/types/user.ts +1 -1
  89. package/src/util/collections.ts +8 -0
  90. package/src/util/createFormexStub.tsx +4 -0
  91. package/src/util/entities.ts +1 -1
  92. package/src/util/entity_cache.ts +72 -53
  93. package/src/util/join_collections.ts +3 -3
  94. package/src/util/make_properties_editable.ts +0 -22
  95. package/src/util/objects.ts +40 -2
  96. package/src/util/useStorageUploadController.tsx +71 -34
package/dist/index.es.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { jsx, Fragment, jsxs } from "react/jsx-runtime";
2
2
  import { c } from "react-compiler-runtime";
3
3
  import * as React from "react";
4
- import React__default, { useRef, useEffect, useContext, useCallback, useMemo, useState, createElement, createRef, createContext, forwardRef, useLayoutEffect, useDeferredValue } 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, Markdown, TextareaAutosize, focusedDisabled, MultiSelect, MultiSelectItem, Select, SelectItem, BooleanSwitch, DateTimeField, paperMixin, EditIcon, DoNotDisturbOnIcon, Menu, MenuItem, MoreVertIcon, CircularProgress, SearchBar, Badge, 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, LoadingButton, Alert, CheckIcon, NotesIcon, InfoIcon, fieldBackgroundMixin, RemoveIcon, fieldBackgroundDisabledMixin, fieldBackgroundHoverMixin, ArrowDropDownIcon, FilterListOffIcon, SearchIcon, Avatar, DarkModeIcon, LightModeIcon, BrightnessMediumIcon, LogoutIcon, HandleIcon, KeyboardArrowUpIcon, KeyboardArrowDownIcon, debounce, Sheet, Tab, Tabs, CodeIcon, OpenInFullIcon, ViewStreamIcon, RepeatIcon, BallotIcon, ScheduleIcon, AddLinkIcon, LinkIcon, DriveFolderUploadIcon, UploadFileIcon, FormatListNumberedIcon, NumbersIcon, ListAltIcon, ListIcon, FlagIcon, MailIcon, HttpIcon, FormatQuoteIcon, SubjectIcon, ShortTextIcon, MenuIcon, ChevronLeftIcon } from "@firecms/ui";
4
+ import React__default, { useRef, useEffect, useContext, useCallback, useMemo, useState, createElement, createRef, createContext, forwardRef, 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, LoadingButton, WarningIcon, KeyboardArrowDownIcon, VisibilityIcon, CheckIcon, CancelIcon, Alert, NotesIcon, InfoIcon, fieldBackgroundMixin, RemoveIcon, fieldBackgroundDisabledMixin, fieldBackgroundHoverMixin, ArrowDropDownIcon, FilterListOffIcon, SearchIcon, Avatar, DarkModeIcon, LightModeIcon, BrightnessMediumIcon, LogoutIcon, HandleIcon, KeyboardArrowUpIcon, debounce, Sheet, Tab, Tabs, CodeIcon, OpenInFullIcon, ViewStreamIcon, RepeatIcon, BallotIcon, ScheduleIcon, AddLinkIcon, LinkIcon, DriveFolderUploadIcon, UploadFileIcon, FormatListNumberedIcon, NumbersIcon, PersonIcon, ListAltIcon, ListIcon, 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, useFormex, setIn, useCreateFormex, Formex, Field } from "@firecms/formex";
@@ -14,12 +14,12 @@ import * as locales from "date-fns/locale";
14
14
  import useMeasure from "react-use-measure";
15
15
  import * as yup from "yup";
16
16
  import { FixedSizeList } from "react-window";
17
- import { useSensor, MouseSensor, TouchSensor, KeyboardSensor, useSensors, closestCorners, closestCenter, pointerWithin, getFirstCollision, rectIntersection, useDroppable, useDndMonitor, DndContext, MeasuringStrategy, DragOverlay, PointerSensor } from "@dnd-kit/core";
17
+ import { useSensor, MouseSensor, TouchSensor, KeyboardSensor, useSensors, closestCenter, pointerWithin, closestCorners, getFirstCollision, rectIntersection, useDroppable, useDndMonitor, DndContext, MeasuringStrategy, DragOverlay, PointerSensor } from "@dnd-kit/core";
18
18
  import { useSortable, defaultAnimateLayoutChanges, arrayMove as arrayMove$1, SortableContext, rectSortingStrategy, verticalListSortingStrategy, sortableKeyboardCoordinates, horizontalListSortingStrategy } from "@dnd-kit/sortable";
19
19
  import { CSS } from "@dnd-kit/utilities";
20
20
  import { restrictToVerticalAxis, restrictToWindowEdges } from "@dnd-kit/modifiers";
21
21
  import { useDropzone } from "react-dropzone";
22
- import Resizer from "react-image-file-resizer";
22
+ import Compressor from "compressorjs";
23
23
  import { FireCMSEditor } from "@firecms/editor";
24
24
  import { themes, Highlight } from "prism-react-renderer";
25
25
  import { useLocation as useLocation$1, useBlocker } from "react-router";
@@ -210,9 +210,14 @@ class EntityReference {
210
210
  * to the root of the database).
211
211
  */
212
212
  path;
213
- constructor(id, path) {
213
+ /**
214
+ * Optional database ID where the entity is stored (if multiple databases are used)
215
+ */
216
+ databaseId;
217
+ constructor(id, path, databaseId) {
214
218
  this.id = id;
215
219
  this.path = path;
220
+ this.databaseId = databaseId;
216
221
  }
217
222
  get pathWithId() {
218
223
  return `${this.path}/${this.id}`;
@@ -250,6 +255,13 @@ const pick = (obj, ...args) => ({
250
255
  function isObject(item) {
251
256
  return item && typeof item === "object" && !Array.isArray(item);
252
257
  }
258
+ function isPlainObject(obj) {
259
+ if (typeof obj !== "object" || obj === null || Array.isArray(obj)) {
260
+ return false;
261
+ }
262
+ const proto = Object.getPrototypeOf(obj);
263
+ return proto === Object.prototype;
264
+ }
253
265
  function mergeDeep(target, source, ignoreUndefined = false) {
254
266
  if (!isObject(target)) {
255
267
  return target;
@@ -270,7 +282,28 @@ function mergeDeep(target, source, ignoreUndefined = false) {
270
282
  if (sourceValue instanceof Date) {
271
283
  output[key] = new Date(sourceValue.getTime());
272
284
  } else if (Array.isArray(sourceValue)) {
273
- output[key] = [...sourceValue];
285
+ if (Array.isArray(outputValue)) {
286
+ const newArray = [];
287
+ const maxLength = Math.max(outputValue.length, sourceValue.length);
288
+ for (let i = 0; i < maxLength; i++) {
289
+ const sourceItem = sourceValue[i];
290
+ const targetItem = outputValue[i];
291
+ if (i >= sourceValue.length) {
292
+ newArray[i] = targetItem;
293
+ } else if (i >= outputValue.length) {
294
+ newArray[i] = sourceItem;
295
+ } else if (sourceItem === null) {
296
+ newArray[i] = targetItem;
297
+ } else if (isObject(sourceItem) && isObject(targetItem)) {
298
+ newArray[i] = mergeDeep(targetItem, sourceItem, ignoreUndefined);
299
+ } else {
300
+ newArray[i] = sourceItem;
301
+ }
302
+ }
303
+ output[key] = newArray;
304
+ } else {
305
+ output[key] = [...sourceValue];
306
+ }
274
307
  } else if (isObject(sourceValue)) {
275
308
  if (isObject(outputValue)) {
276
309
  output[key] = mergeDeep(outputValue, sourceValue, ignoreUndefined);
@@ -517,7 +550,7 @@ function sanitizeData(values, properties) {
517
550
  return result;
518
551
  }
519
552
  function getReferenceFrom(entity) {
520
- return new EntityReference(entity.id, entity.path);
553
+ return new EntityReference(entity.id, entity.path, entity.databaseId);
521
554
  }
522
555
  function traverseValuesProperties(inputValues, properties, operation) {
523
556
  const updatedValues = Object.entries(properties).map(([key, property]) => {
@@ -1049,6 +1082,12 @@ const applyPermissionsFunctionIfEmpty = (collections, permissionsBuilder) => {
1049
1082
  };
1050
1083
  });
1051
1084
  };
1085
+ function getLocalChangesBackup(collection) {
1086
+ if (!collection.localChangesBackup) {
1087
+ return "manual_apply";
1088
+ }
1089
+ return collection.localChangesBackup;
1090
+ }
1052
1091
  const kebabCaseRegex = /[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g;
1053
1092
  const toKebabCase = (str) => {
1054
1093
  const regExpMatchArray = str.match(kebabCaseRegex);
@@ -3505,26 +3544,6 @@ function makePropertiesEditable(properties) {
3505
3544
  });
3506
3545
  return properties;
3507
3546
  }
3508
- function makePropertiesNonEditable(properties) {
3509
- return Object.entries(properties).reduce((acc, [key, property]) => {
3510
- if (!isPropertyBuilder(property) && property.dataType === "map" && property.properties) {
3511
- const updated = {
3512
- ...property,
3513
- properties: makePropertiesNonEditable(property.properties)
3514
- };
3515
- acc[key] = updated;
3516
- }
3517
- if (isPropertyBuilder(property)) {
3518
- acc[key] = property;
3519
- } else {
3520
- acc[key] = {
3521
- ...property,
3522
- editable: false
3523
- };
3524
- }
3525
- return acc;
3526
- }, {});
3527
- }
3528
3547
  function applyModifyFunction(modifyCollection, collection, parentPaths) {
3529
3548
  if (modifyCollection) {
3530
3549
  const modified = modifyCollection({
@@ -3606,8 +3625,8 @@ function mergePropertyOrBuilder(target, source) {
3606
3625
  return target;
3607
3626
  } else {
3608
3627
  const mergedProperty = mergeDeep(target, source);
3609
- const targetEditable = Boolean(target.editable);
3610
- const sourceEditable = Boolean(source.editable);
3628
+ const targetEditable = target.editable === void 0 ? true : Boolean(target.editable);
3629
+ const sourceEditable = source.editable === void 0 ? true : Boolean(source.editable);
3611
3630
  if (source.dataType === "map" && source.properties) {
3612
3631
  const targetProperties = "properties" in target ? target.properties : {};
3613
3632
  const sourceProperties = "properties" in source ? source.properties : {};
@@ -4068,6 +4087,10 @@ const AnalyticsContext = React__default.createContext({});
4068
4087
  const useAnalyticsController = () => {
4069
4088
  return useContext(AnalyticsContext);
4070
4089
  };
4090
+ const InternalUserManagementContext = React__default.createContext({});
4091
+ const useInternalUserManagementController = () => {
4092
+ return useContext(InternalUserManagementContext);
4093
+ };
4071
4094
  const useFireCMSContext = () => {
4072
4095
  const authController = useAuthController();
4073
4096
  const sideDialogsController = useSideDialogsController();
@@ -4080,6 +4103,7 @@ const useFireCMSContext = () => {
4080
4103
  const dialogsController = useDialogsController();
4081
4104
  const customizationController = useCustomizationController();
4082
4105
  const analyticsController = useAnalyticsController();
4106
+ const userManagement = useInternalUserManagementController();
4083
4107
  const fireCMSContextRef = React__default.useRef({
4084
4108
  authController,
4085
4109
  sideDialogsController,
@@ -4091,7 +4115,8 @@ const useFireCMSContext = () => {
4091
4115
  userConfigPersistence,
4092
4116
  dialogsController,
4093
4117
  customizationController,
4094
- analyticsController
4118
+ analyticsController,
4119
+ userManagement
4095
4120
  });
4096
4121
  useEffect(() => {
4097
4122
  fireCMSContextRef.current = {
@@ -4105,7 +4130,8 @@ const useFireCMSContext = () => {
4105
4130
  userConfigPersistence,
4106
4131
  dialogsController,
4107
4132
  customizationController,
4108
- analyticsController
4133
+ analyticsController,
4134
+ userManagement
4109
4135
  };
4110
4136
  }, [authController, dialogsController, navigation, sideDialogsController]);
4111
4137
  return fireCMSContextRef.current;
@@ -4166,7 +4192,7 @@ function useCollectionFetch(t0) {
4166
4192
  }
4167
4193
  setDataLoading(false);
4168
4194
  setDataLoadingError(void 0);
4169
- setData(entities.map(_temp$r));
4195
+ setData(entities.map(_temp$t));
4170
4196
  setNoMoreToLoad(!itemCount || entities.length < itemCount);
4171
4197
  };
4172
4198
  const onError = (error) => {
@@ -4199,7 +4225,7 @@ function useCollectionFetch(t0) {
4199
4225
  orderBy: sortByProperty,
4200
4226
  order: currentSort
4201
4227
  }).then(onEntitiesUpdate).catch(onError);
4202
- return _temp2$d;
4228
+ return _temp2$e;
4203
4229
  }
4204
4230
  };
4205
4231
  $[4] = collection;
@@ -4247,9 +4273,9 @@ function useCollectionFetch(t0) {
4247
4273
  }
4248
4274
  return t5;
4249
4275
  }
4250
- function _temp2$d() {
4276
+ function _temp2$e() {
4251
4277
  }
4252
- function _temp$r(e_0) {
4278
+ function _temp$t(e_0) {
4253
4279
  return {
4254
4280
  ...e_0
4255
4281
  };
@@ -4314,7 +4340,7 @@ function useEntityFetch(t0) {
4314
4340
  setEntity(CACHE[`${path}/${entityId}`]);
4315
4341
  setDataLoading(false);
4316
4342
  setDataLoadingError(void 0);
4317
- return _temp$q;
4343
+ return _temp$s;
4318
4344
  } else {
4319
4345
  if (entityId && path && collection) {
4320
4346
  if (dataSource.listenEntity) {
@@ -4333,7 +4359,7 @@ function useEntityFetch(t0) {
4333
4359
  databaseId,
4334
4360
  collection
4335
4361
  }).then(onEntityUpdate).catch(onError);
4336
- return _temp2$c;
4362
+ return _temp2$d;
4337
4363
  }
4338
4364
  } else {
4339
4365
  onEntityUpdate(void 0);
@@ -4380,9 +4406,9 @@ function useEntityFetch(t0) {
4380
4406
  }
4381
4407
  function _temp3$4() {
4382
4408
  }
4383
- function _temp2$c() {
4409
+ function _temp2$d() {
4384
4410
  }
4385
- function _temp$q() {
4411
+ function _temp$s() {
4386
4412
  }
4387
4413
  async function saveEntityWithCallbacks({
4388
4414
  collection,
@@ -4762,6 +4788,48 @@ function checkLargeLayout(breakpoint = "lg") {
4762
4788
  if (typeof window === "undefined") return false;
4763
4789
  return window.matchMedia(`(min-width: ${breakpoints[breakpoint] + 1}px)`).matches;
4764
4790
  }
4791
+ function useCollapsedGroups(groupNames) {
4792
+ const [collapsedGroups, setCollapsedGroups] = useState(() => {
4793
+ try {
4794
+ const stored = localStorage.getItem("firecms-collapsed-groups");
4795
+ return stored ? JSON.parse(stored) : {};
4796
+ } catch {
4797
+ return {};
4798
+ }
4799
+ });
4800
+ useEffect(() => {
4801
+ try {
4802
+ localStorage.setItem("firecms-collapsed-groups", JSON.stringify(collapsedGroups));
4803
+ } catch {
4804
+ }
4805
+ }, [collapsedGroups]);
4806
+ useEffect(() => {
4807
+ if (groupNames.length === 0) return;
4808
+ const currentGroupNames = new Set(groupNames);
4809
+ setCollapsedGroups((prev) => {
4810
+ const cleaned = Object.fromEntries(Object.entries(prev).filter(([groupName]) => currentGroupNames.has(groupName)));
4811
+ const prevKeys = Object.keys(prev);
4812
+ const cleanedKeys = Object.keys(cleaned);
4813
+ if (prevKeys.length === cleanedKeys.length && prevKeys.every((key) => cleanedKeys.includes(key))) {
4814
+ return prev;
4815
+ }
4816
+ return cleaned;
4817
+ });
4818
+ }, [groupNames]);
4819
+ const isGroupCollapsed = useCallback((name) => {
4820
+ return !!collapsedGroups[name];
4821
+ }, [collapsedGroups]);
4822
+ const toggleGroupCollapsed = useCallback((name_0) => {
4823
+ setCollapsedGroups((prev_0) => ({
4824
+ ...prev_0,
4825
+ [name_0]: !prev_0[name_0]
4826
+ }));
4827
+ }, []);
4828
+ return {
4829
+ isGroupCollapsed,
4830
+ toggleGroupCollapsed
4831
+ };
4832
+ }
4765
4833
  function ErrorTooltip(props) {
4766
4834
  const $ = c(2);
4767
4835
  let t0;
@@ -4782,6 +4850,7 @@ function ErrorView(t0) {
4782
4850
  tooltip
4783
4851
  } = t0;
4784
4852
  const component = error instanceof Error ? error.message : error;
4853
+ console.warn("ErrorView", JSON.stringify(error));
4785
4854
  let t1;
4786
4855
  if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
4787
4856
  t1 = /* @__PURE__ */ jsx(ErrorIcon, { className: "mx-2", size: "small", color: "error" });
@@ -4966,7 +5035,7 @@ function ImagePreview(t0) {
4966
5035
  }
4967
5036
  let t9;
4968
5037
  if ($[16] !== url) {
4969
- t9 = /* @__PURE__ */ jsx(Tooltip, { title: "Open image in new tab", side: "bottom", children: /* @__PURE__ */ jsx(IconButton, { className: "invisible group-hover:visible", variant: "filled", component: "a", href: url, rel: "noopener noreferrer", target: "_blank", size: "smallest", onClick: _temp$p, children: t8 }) });
5038
+ t9 = /* @__PURE__ */ jsx(Tooltip, { title: "Open image in new tab", side: "bottom", children: /* @__PURE__ */ jsx(IconButton, { className: "invisible group-hover:visible", variant: "filled", component: "a", href: url, rel: "noopener noreferrer", target: "_blank", size: "smallest", onClick: _temp$r, children: t8 }) });
4970
5039
  $[16] = url;
4971
5040
  $[17] = t9;
4972
5041
  } else {
@@ -5000,7 +5069,7 @@ function ImagePreview(t0) {
5000
5069
  }
5001
5070
  return t11;
5002
5071
  }
5003
- function _temp$p(e_0) {
5072
+ function _temp$r(e_0) {
5004
5073
  return e_0.stopPropagation();
5005
5074
  }
5006
5075
  function UrlComponentPreview(t0) {
@@ -5033,7 +5102,7 @@ function UrlComponentPreview(t0) {
5033
5102
  }
5034
5103
  let t3;
5035
5104
  if ($[2] !== url) {
5036
- t3 = /* @__PURE__ */ jsxs("a", { className: "flex gap-4 break-words items-center font-medium text-primary visited:text-primary dark:visited:text-primary dark:text-primary", href: url, rel: "noopener noreferrer", onMouseDown: _temp$o, target: "_blank", children: [
5105
+ t3 = /* @__PURE__ */ jsxs("a", { className: "flex gap-4 break-words items-center font-medium text-primary visited:text-primary dark:visited:text-primary dark:text-primary", href: url, rel: "noopener noreferrer", onMouseDown: _temp$q, target: "_blank", children: [
5037
5106
  t2,
5038
5107
  url
5039
5108
  ] });
@@ -5136,7 +5205,7 @@ function UrlComponentPreview(t0) {
5136
5205
  }
5137
5206
  let t7;
5138
5207
  if ($[24] !== t4 || $[25] !== t6 || $[26] !== url) {
5139
- t7 = /* @__PURE__ */ jsxs("a", { href: url, rel: "noopener noreferrer", target: "_blank", onClick: _temp2$b, className: "flex flex-col items-center justify-center", style: t4, children: [
5208
+ t7 = /* @__PURE__ */ jsxs("a", { href: url, rel: "noopener noreferrer", target: "_blank", onClick: _temp2$c, className: "flex flex-col items-center justify-center", style: t4, children: [
5140
5209
  t5,
5141
5210
  t6
5142
5211
  ] });
@@ -5161,10 +5230,10 @@ function UrlComponentPreview(t0) {
5161
5230
  }
5162
5231
  }
5163
5232
  }
5164
- function _temp2$b(e_0) {
5233
+ function _temp2$c(e_0) {
5165
5234
  return e_0.stopPropagation();
5166
5235
  }
5167
- function _temp$o(e) {
5236
+ function _temp$q(e) {
5168
5237
  e.preventDefault();
5169
5238
  }
5170
5239
  function VideoPreview(t0) {
@@ -5298,7 +5367,7 @@ function SkeletonPropertyComponent(t0) {
5298
5367
  if (Array.isArray(arrayProperty.of)) {
5299
5368
  let t1;
5300
5369
  if ($[6] !== arrayProperty.of) {
5301
- t1 = arrayProperty.of.map(_temp$n);
5370
+ t1 = arrayProperty.of.map(_temp$p);
5302
5371
  $[6] = arrayProperty.of;
5303
5372
  $[7] = t1;
5304
5373
  } else {
@@ -5436,7 +5505,7 @@ function SkeletonPropertyComponent(t0) {
5436
5505
  }
5437
5506
  return content || null;
5438
5507
  }
5439
- function _temp$n(p, i) {
5508
+ function _temp$p(p, i) {
5440
5509
  return renderGenericArrayCell(p, i);
5441
5510
  }
5442
5511
  function renderMap(property, size) {
@@ -5795,7 +5864,7 @@ function ArrayPropertyPreview(t0) {
5795
5864
  }
5796
5865
  let t3;
5797
5866
  if ($[11] !== t2) {
5798
- t3 = /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: t2 });
5867
+ t3 = /* @__PURE__ */ jsx("div", { className: "w-full flex flex-col gap-2", children: t2 });
5799
5868
  $[11] = t2;
5800
5869
  $[12] = t3;
5801
5870
  } else {
@@ -6007,7 +6076,7 @@ const ReferencePreview = function ReferencePreview2(props) {
6007
6076
  }
6008
6077
  let t0;
6009
6078
  if ($[8] !== props) {
6010
- t0 = /* @__PURE__ */ jsx(ReferencePreviewInternal, { ...props });
6079
+ t0 = /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(ReferencePreviewInternal, { ...props }) });
6011
6080
  $[8] = props;
6012
6081
  $[9] = t0;
6013
6082
  } else {
@@ -6583,7 +6652,7 @@ function MapPropertyPreview(t0) {
6583
6652
  const isArrayOrMap = childProperty.dataType === "map" || childProperty === "array";
6584
6653
  return /* @__PURE__ */ jsxs("div", { className: cls(defaultBorderMixin, "last:border-b-0 border-b"), children: [
6585
6654
  /* @__PURE__ */ jsxs("div", { className: "flex flex-row pt-0.5 pb-0.5 gap-2", children: [
6586
- /* @__PURE__ */ jsx("div", { className: "min-w-[140px] w-[25%] py-1", children: /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "font-mono break-words", color: "secondary", children: childProperty.name }) }),
6655
+ /* @__PURE__ */ jsx("div", { className: "min-w-[140px] w-[25%] py-1", children: /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "break-words font-semibold", color: "secondary", children: childProperty.name }) }),
6587
6656
  /* @__PURE__ */ jsx("div", { className: "flex-grow max-w-[75%]", children: /* @__PURE__ */ jsx(ErrorBoundary, { children: !isArrayOrMap && /* @__PURE__ */ jsx(PropertyPreview, { propertyKey: key_0, value: value[key_0], property: childProperty, size }) }) })
6588
6657
  ] }),
6589
6658
  isArrayOrMap && /* @__PURE__ */ jsx("div", { className: cls(defaultBorderMixin, "border-l pl-4 ml-2 my-2"), children: /* @__PURE__ */ jsx(PropertyPreview, { propertyKey: key_0, value: value[key_0], property: childProperty, size }) })
@@ -6619,7 +6688,7 @@ function KeyValuePreview(t0) {
6619
6688
  }
6620
6689
  let t1;
6621
6690
  if ($[1] !== value) {
6622
- t1 = Object.entries(value).map(_temp$m);
6691
+ t1 = Object.entries(value).map(_temp$o);
6623
6692
  $[1] = value;
6624
6693
  $[2] = t1;
6625
6694
  } else {
@@ -6635,11 +6704,11 @@ function KeyValuePreview(t0) {
6635
6704
  }
6636
6705
  return t2;
6637
6706
  }
6638
- function _temp$m(t0) {
6707
+ function _temp$o(t0) {
6639
6708
  const [key, childValue] = t0;
6640
6709
  return /* @__PURE__ */ jsxs("div", { className: cls(defaultBorderMixin, "last:border-b-0 border-b"), children: [
6641
6710
  /* @__PURE__ */ jsxs("div", { className: "flex flex-row pt-0.5 pb-0.5 gap-2", children: [
6642
- /* @__PURE__ */ jsx("div", { className: "min-w-[140px] w-[25%] py-1", children: /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "font-mono break-words", color: "secondary", children: key }) }, `table-cell-title-${key}-${key}`),
6711
+ /* @__PURE__ */ jsx("div", { className: "min-w-[140px] w-[25%] py-1", children: /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "font-semibold break-words", color: "secondary", children: key }) }, `table-cell-title-${key}-${key}`),
6643
6712
  /* @__PURE__ */ jsx("div", { className: "flex-grow max-w-[75%]", children: childValue && typeof childValue !== "object" && /* @__PURE__ */ jsx(Typography, { children: /* @__PURE__ */ jsx(ErrorBoundary, { children: childValue.toString() }) }) })
6644
6713
  ] }),
6645
6714
  typeof childValue === "object" && /* @__PURE__ */ jsx("div", { className: cls(defaultBorderMixin, "border-l pl-4"), children: /* @__PURE__ */ jsx(KeyValuePreview, { value: childValue }) })
@@ -6716,7 +6785,7 @@ function BooleanPreview(t0) {
6716
6785
  return t3;
6717
6786
  }
6718
6787
  function NumberPropertyPreview(t0) {
6719
- const $ = c(10);
6788
+ const $ = c(12);
6720
6789
  const {
6721
6790
  value,
6722
6791
  property,
@@ -6734,39 +6803,178 @@ function NumberPropertyPreview(t0) {
6734
6803
  }
6735
6804
  const enumValues = t1;
6736
6805
  if (!enumValues) {
6737
- let t22;
6738
- if ($[2] !== value) {
6739
- t22 = /* @__PURE__ */ jsx(Fragment, { children: value });
6740
- $[2] = value;
6741
- $[3] = t22;
6806
+ const t22 = size === "small" ? "text-sm" : "";
6807
+ let t32;
6808
+ if ($[2] !== t22 || $[3] !== value) {
6809
+ t32 = /* @__PURE__ */ jsx("span", { className: t22, children: value });
6810
+ $[2] = t22;
6811
+ $[3] = value;
6812
+ $[4] = t32;
6742
6813
  } else {
6743
- t22 = $[3];
6814
+ t32 = $[4];
6744
6815
  }
6745
- return t22;
6816
+ return t32;
6746
6817
  }
6747
6818
  const t2 = size !== "medium" ? "small" : "medium";
6748
6819
  let t3;
6749
- if ($[4] !== enumKey || $[5] !== enumValues || $[6] !== t2) {
6820
+ if ($[5] !== enumKey || $[6] !== enumValues || $[7] !== t2) {
6750
6821
  t3 = /* @__PURE__ */ jsx(EnumValuesChip, { enumKey, enumValues, size: t2 });
6751
- $[4] = enumKey;
6752
- $[5] = enumValues;
6753
- $[6] = t2;
6754
- $[7] = t3;
6822
+ $[5] = enumKey;
6823
+ $[6] = enumValues;
6824
+ $[7] = t2;
6825
+ $[8] = t3;
6755
6826
  } else {
6756
- t3 = $[7];
6827
+ t3 = $[8];
6757
6828
  }
6758
6829
  return t3;
6759
6830
  } else {
6760
- let t1;
6761
- if ($[8] !== value) {
6762
- t1 = /* @__PURE__ */ jsx(Fragment, { children: value });
6763
- $[8] = value;
6831
+ const t1 = size === "small" ? "text-sm" : "";
6832
+ let t2;
6833
+ if ($[9] !== t1 || $[10] !== value) {
6834
+ t2 = /* @__PURE__ */ jsx("span", { className: t1, children: value });
6764
6835
  $[9] = t1;
6836
+ $[10] = value;
6837
+ $[11] = t2;
6838
+ } else {
6839
+ t2 = $[11];
6840
+ }
6841
+ return t2;
6842
+ }
6843
+ }
6844
+ function UserDisplay(t0) {
6845
+ const $ = c(18);
6846
+ const {
6847
+ user
6848
+ } = t0;
6849
+ if (!user) {
6850
+ let t12;
6851
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
6852
+ t12 = /* @__PURE__ */ jsx(EmptyValue, {});
6853
+ $[0] = t12;
6854
+ } else {
6855
+ t12 = $[0];
6856
+ }
6857
+ return t12;
6858
+ }
6859
+ let t1;
6860
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
6861
+ t1 = cls("inline-flex items-center gap-4 px-2 py-1 rounded-xl", "bg-surface-accent-100 dark:bg-surface-accent-800", "border", defaultBorderMixin);
6862
+ $[1] = t1;
6863
+ } else {
6864
+ t1 = $[1];
6865
+ }
6866
+ let t2;
6867
+ if ($[2] !== user.displayName || $[3] !== user.email || $[4] !== user.photoURL) {
6868
+ t2 = user.photoURL ? /* @__PURE__ */ jsx("img", { src: user.photoURL, alt: user.displayName || user.email || "User", className: cls("rounded-full object-cover", "w-6 h-6") }) : /* @__PURE__ */ jsx(AccountCircleIcon, { className: cls("text-text-secondary dark:text-text-secondary-dark", "w-6 h-6") });
6869
+ $[2] = user.displayName;
6870
+ $[3] = user.email;
6871
+ $[4] = user.photoURL;
6872
+ $[5] = t2;
6873
+ } else {
6874
+ t2 = $[5];
6875
+ }
6876
+ let t3;
6877
+ if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
6878
+ t3 = cls("font-regular truncate", "text-sm");
6879
+ $[6] = t3;
6880
+ } else {
6881
+ t3 = $[6];
6882
+ }
6883
+ const t4 = user.displayName || user.email || "-";
6884
+ let t5;
6885
+ if ($[7] !== t4) {
6886
+ t5 = /* @__PURE__ */ jsx("span", { className: t3, children: t4 });
6887
+ $[7] = t4;
6888
+ $[8] = t5;
6889
+ } else {
6890
+ t5 = $[8];
6891
+ }
6892
+ let t6;
6893
+ if ($[9] !== user.displayName || $[10] !== user.email) {
6894
+ t6 = user.displayName && user.email && /* @__PURE__ */ jsx("span", { className: cls("text-text-secondary dark:text-text-secondary-dark truncate", "text-xs"), children: user.email });
6895
+ $[9] = user.displayName;
6896
+ $[10] = user.email;
6897
+ $[11] = t6;
6898
+ } else {
6899
+ t6 = $[11];
6900
+ }
6901
+ let t7;
6902
+ if ($[12] !== t5 || $[13] !== t6) {
6903
+ t7 = /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0", children: [
6904
+ t5,
6905
+ t6
6906
+ ] });
6907
+ $[12] = t5;
6908
+ $[13] = t6;
6909
+ $[14] = t7;
6910
+ } else {
6911
+ t7 = $[14];
6912
+ }
6913
+ let t8;
6914
+ if ($[15] !== t2 || $[16] !== t7) {
6915
+ t8 = /* @__PURE__ */ jsxs("div", { className: t1, children: [
6916
+ t2,
6917
+ t7
6918
+ ] });
6919
+ $[15] = t2;
6920
+ $[16] = t7;
6921
+ $[17] = t8;
6922
+ } else {
6923
+ t8 = $[17];
6924
+ }
6925
+ return t8;
6926
+ }
6927
+ function UserPreview(t0) {
6928
+ const $ = c(8);
6929
+ const {
6930
+ value
6931
+ } = t0;
6932
+ const {
6933
+ getUser
6934
+ } = useInternalUserManagementController();
6935
+ if (!value) {
6936
+ let t12;
6937
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
6938
+ t12 = /* @__PURE__ */ jsx(EmptyValue, {});
6939
+ $[0] = t12;
6940
+ } else {
6941
+ t12 = $[0];
6942
+ }
6943
+ return t12;
6944
+ }
6945
+ let t1;
6946
+ if ($[1] !== getUser || $[2] !== value) {
6947
+ t1 = getUser(value);
6948
+ $[1] = getUser;
6949
+ $[2] = value;
6950
+ $[3] = t1;
6951
+ } else {
6952
+ t1 = $[3];
6953
+ }
6954
+ const user = t1;
6955
+ if (!user) {
6956
+ let t22;
6957
+ if ($[4] !== value) {
6958
+ t22 = /* @__PURE__ */ jsxs(Typography, { variant: "caption", color: "secondary", children: [
6959
+ "User not found: ",
6960
+ value
6961
+ ] });
6962
+ $[4] = value;
6963
+ $[5] = t22;
6765
6964
  } else {
6766
- t1 = $[9];
6965
+ t22 = $[5];
6767
6966
  }
6768
- return t1;
6967
+ return t22;
6769
6968
  }
6969
+ let t2;
6970
+ if ($[6] !== user) {
6971
+ t2 = /* @__PURE__ */ jsx(UserDisplay, { user });
6972
+ $[6] = user;
6973
+ $[7] = t2;
6974
+ } else {
6975
+ t2 = $[7];
6976
+ }
6977
+ return t2;
6770
6978
  }
6771
6979
  const PropertyPreview = React__default.memo(function PropertyPreview2(props) {
6772
6980
  const $ = c(31);
@@ -6868,21 +7076,25 @@ const PropertyPreview = React__default.memo(function PropertyPreview2(props) {
6868
7076
  }
6869
7077
  content = t02;
6870
7078
  } else {
6871
- if (stringProperty.reference) {
6872
- if (typeof stringProperty.reference.path === "string") {
6873
- content = /* @__PURE__ */ jsx(ReferencePreview, { disabled: !stringProperty.reference.path, previewProperties: stringProperty.reference.previewProperties, includeId: stringProperty.reference.includeId, includeEntityLink: stringProperty.reference.includeEntityLink, size: props.size, reference: new EntityReference(value, stringProperty.reference.path) });
6874
- } else {
6875
- let t02;
6876
- if ($[23] === Symbol.for("react.memo_cache_sentinel")) {
6877
- t02 = /* @__PURE__ */ jsx(EmptyValue, {});
6878
- $[23] = t02;
7079
+ if (stringProperty.userSelect) {
7080
+ content = /* @__PURE__ */ jsx(UserPreview, { value, property: stringProperty, propertyKey, size: props.size });
7081
+ } else {
7082
+ if (stringProperty.reference) {
7083
+ if (typeof stringProperty.reference.path === "string") {
7084
+ content = /* @__PURE__ */ jsx(ReferencePreview, { disabled: !stringProperty.reference.path, previewProperties: stringProperty.reference.previewProperties, includeId: stringProperty.reference.includeId, includeEntityLink: stringProperty.reference.includeEntityLink, size: props.size, reference: new EntityReference(value, stringProperty.reference.path) });
6879
7085
  } else {
6880
- t02 = $[23];
7086
+ let t02;
7087
+ if ($[23] === Symbol.for("react.memo_cache_sentinel")) {
7088
+ t02 = /* @__PURE__ */ jsx(EmptyValue, {});
7089
+ $[23] = t02;
7090
+ } else {
7091
+ t02 = $[23];
7092
+ }
7093
+ content = t02;
6881
7094
  }
6882
- content = t02;
7095
+ } else {
7096
+ content = /* @__PURE__ */ jsx(StringPropertyPreview, { ...props, property: stringProperty, value });
6883
7097
  }
6884
- } else {
6885
- content = /* @__PURE__ */ jsx(StringPropertyPreview, { ...props, property: stringProperty, value });
6886
7098
  }
6887
7099
  }
6888
7100
  }
@@ -7175,98 +7387,467 @@ const AsyncPreviewComponent = React.memo(function AsyncPreviewComponentInternal(
7175
7387
  }
7176
7388
  return t3;
7177
7389
  });
7178
- function EntityView({
7179
- entity,
7180
- collection,
7181
- path,
7182
- className
7183
- }) {
7184
- const authController = useAuthController();
7185
- const customizationController = useCustomizationController();
7186
- const resolvedCollection = useMemo(() => resolveCollection({
7187
- collection,
7188
- path,
7189
- entityId: entity.id,
7190
- values: entity.values,
7191
- propertyConfigs: customizationController.propertyConfigs,
7192
- authController
7193
- }), [collection, path, entity, customizationController.propertyConfigs]);
7194
- const properties = resolvedCollection.properties;
7195
- return /* @__PURE__ */ jsx("div", { className: "w-full " + className, children: /* @__PURE__ */ jsxs("div", { className: "w-full mb-4", children: [
7196
- /* @__PURE__ */ jsxs("div", { className: cls(defaultBorderMixin, "flex justify-between py-2 border-b last:border-b-0"), children: [
7197
- /* @__PURE__ */ jsx("div", { className: "flex items-center w-1/4", children: /* @__PURE__ */ jsx("span", { className: "pl-2 text-sm text-surface-600", children: "Id" }) }),
7198
- /* @__PURE__ */ jsxs("div", { className: "flex-grow p-2 ml-2 w-3/4 text-surface-900 dark:text-white min-h-[56px] flex items-center", children: [
7199
- /* @__PURE__ */ jsx("span", { className: "flex-grow mr-2", children: entity.id }),
7200
- customizationController?.entityLinkBuilder && /* @__PURE__ */ jsx("a", { href: customizationController.entityLinkBuilder({
7201
- entity
7202
- }), rel: "noopener noreferrer", target: "_blank", children: /* @__PURE__ */ jsx(IconButton, { children: /* @__PURE__ */ jsx(OpenInNewIcon, { size: "small" }) }) })
7203
- ] })
7204
- ] }),
7205
- Object.entries(properties).map(([key, property]) => {
7206
- const value = entity.values?.[key];
7207
- return /* @__PURE__ */ jsxs("div", { className: cls(defaultBorderMixin, "flex justify-between py-2 border-b last:border-b-0"), children: [
7208
- /* @__PURE__ */ jsx("div", { className: "flex items-center w-1/4", children: /* @__PURE__ */ jsx("span", { className: "pl-2 text-sm text-surface-600", children: property.name }) }),
7209
- /* @__PURE__ */ jsx("div", { className: "flex-grow p-2 ml-2 w-3/4 text-surface-900 dark:text-white min-h-[56px] flex items-center", children: /* @__PURE__ */ jsx(
7210
- PropertyPreview,
7211
- {
7212
- propertyKey: key,
7213
- value,
7214
- property,
7215
- size: "medium"
7216
- }
7217
- ) })
7218
- ] }, `reference_previews_${key}`);
7219
- })
7220
- ] }) });
7390
+ function buildPropertyLabelAndGetProperty(properties, key) {
7391
+ if (!key) return {
7392
+ label: "",
7393
+ property: void 0
7394
+ };
7395
+ const segments = [];
7396
+ const re = /([^[.\]]+)|\[(\d+)\]/g;
7397
+ let m;
7398
+ while ((m = re.exec(key)) !== null) {
7399
+ if (m[1] !== void 0) segments.push(m[1]);
7400
+ else if (m[2] !== void 0) segments.push(Number(m[2]));
7401
+ }
7402
+ let currentProps = properties;
7403
+ let currentProp;
7404
+ let lastLabel = "";
7405
+ const getArrayOfProp = (p) => {
7406
+ if (!p || p.dataType !== "array") return void 0;
7407
+ return Array.isArray(p.of) ? p.of[0] : p.of;
7408
+ };
7409
+ for (const seg of segments) {
7410
+ if (typeof seg === "number") {
7411
+ lastLabel = `[${seg}]`;
7412
+ if (currentProp?.dataType === "array") {
7413
+ currentProp = getArrayOfProp(currentProp);
7414
+ if (currentProp?.dataType === "map" && currentProp.properties) {
7415
+ currentProps = currentProp.properties;
7416
+ } else {
7417
+ currentProps = void 0;
7418
+ }
7419
+ } else {
7420
+ currentProp = void 0;
7421
+ currentProps = void 0;
7422
+ }
7423
+ continue;
7424
+ }
7425
+ if (currentProps && currentProps[seg]) {
7426
+ const nextProp = currentProps[seg];
7427
+ currentProp = nextProp;
7428
+ lastLabel = nextProp.name || String(seg);
7429
+ if (nextProp.dataType === "map" && nextProp.properties) {
7430
+ currentProps = nextProp.properties;
7431
+ } else if (nextProp.dataType === "array") {
7432
+ currentProps = void 0;
7433
+ } else {
7434
+ currentProps = void 0;
7435
+ }
7436
+ } else {
7437
+ currentProp = void 0;
7438
+ currentProps = void 0;
7439
+ lastLabel = String(seg);
7440
+ }
7441
+ }
7442
+ return {
7443
+ label: lastLabel,
7444
+ property: currentProp
7445
+ };
7221
7446
  }
7222
- function VirtualTableInput(props) {
7223
- const $ = c(22);
7224
- const ref = React__default.useRef(null);
7447
+ const pathEndsWithIndex = (p) => /\[\d+\]$/.test(p);
7448
+ const PropertyCollectionView = (t0) => {
7449
+ const $ = c(89);
7225
7450
  const {
7226
- value,
7227
- multiline,
7228
- updateValue,
7229
- focused
7230
- } = props;
7231
- const prevValue = useRef(value);
7232
- const [internalValue, setInternalValue] = useState(value);
7233
- const focusedState = useRef(false);
7234
- let t0;
7235
- if ($[0] !== internalValue || $[1] !== value) {
7236
- t0 = () => {
7237
- if (prevValue.current !== value && value !== internalValue) {
7238
- setInternalValue(value);
7451
+ data,
7452
+ properties,
7453
+ baseKey: t1,
7454
+ suppressHeader: t2,
7455
+ size: t3
7456
+ } = t0;
7457
+ const baseKey = t1 === void 0 ? "" : t1;
7458
+ const suppressHeader = t2 === void 0 ? false : t2;
7459
+ const size = t3 === void 0 ? "small" : t3;
7460
+ const isTopLevel = !!baseKey && !baseKey.includes(".") && !baseKey.includes("[");
7461
+ if (Array.isArray(data)) {
7462
+ let t4;
7463
+ if ($[0] !== baseKey || $[1] !== properties) {
7464
+ t4 = baseKey ? buildPropertyLabelAndGetProperty(properties, baseKey) : {
7465
+ label: "",
7466
+ property: void 0
7467
+ };
7468
+ $[0] = baseKey;
7469
+ $[1] = properties;
7470
+ $[2] = t4;
7471
+ } else {
7472
+ t4 = $[2];
7473
+ }
7474
+ const {
7475
+ label: arrayLabel,
7476
+ property
7477
+ } = t4;
7478
+ const ofProp = property?.dataType === "array" ? Array.isArray(property.of) ? property.of[0] : property.of : void 0;
7479
+ const isArrayOfMaps = ofProp?.dataType === "map";
7480
+ const isArrayOfPrimitives = property?.dataType === "array" && ofProp && ofProp.dataType !== "map";
7481
+ if (baseKey && property && isArrayOfPrimitives) {
7482
+ const t52 = `grid grid-cols-12 gap-x-4 ${isTopLevel ? "py-4" : "py-2"} items-start ${isTopLevel ? `border-b ${defaultBorderMixin} last:border-b-0` : ""}`;
7483
+ let t62;
7484
+ if ($[3] !== arrayLabel) {
7485
+ t62 = /* @__PURE__ */ jsx("div", { className: "col-span-4 pr-2", children: /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", component: "span", className: "break-words", children: arrayLabel }) });
7486
+ $[3] = arrayLabel;
7487
+ $[4] = t62;
7488
+ } else {
7489
+ t62 = $[4];
7239
7490
  }
7240
- prevValue.current = value;
7241
- };
7242
- $[0] = internalValue;
7243
- $[1] = value;
7244
- $[2] = t0;
7245
- } else {
7246
- t0 = $[2];
7247
- }
7248
- let t1;
7249
- if ($[3] !== value) {
7250
- t1 = [value];
7251
- $[3] = value;
7252
- $[4] = t1;
7253
- } else {
7254
- t1 = $[4];
7255
- }
7256
- useEffect(t0, t1);
7257
- let t2;
7258
- if ($[5] !== internalValue || $[6] !== updateValue || $[7] !== value) {
7259
- t2 = () => {
7260
- const emptyInitialValue = !value;
7261
- if (emptyInitialValue && !internalValue) {
7262
- return;
7491
+ let t72;
7492
+ if ($[5] !== baseKey || $[6] !== data || $[7] !== property || $[8] !== size) {
7493
+ t72 = /* @__PURE__ */ jsx("div", { className: "col-span-8", children: /* @__PURE__ */ jsx(PropertyPreview, { propertyKey: baseKey, value: data, property, size }) });
7494
+ $[5] = baseKey;
7495
+ $[6] = data;
7496
+ $[7] = property;
7497
+ $[8] = size;
7498
+ $[9] = t72;
7499
+ } else {
7500
+ t72 = $[9];
7263
7501
  }
7264
- if (internalValue !== value) {
7265
- prevValue.current = internalValue;
7266
- updateValue(internalValue);
7502
+ let t82;
7503
+ if ($[10] !== t52 || $[11] !== t62 || $[12] !== t72) {
7504
+ t82 = /* @__PURE__ */ jsxs("div", { className: t52, children: [
7505
+ t62,
7506
+ t72
7507
+ ] });
7508
+ $[10] = t52;
7509
+ $[11] = t62;
7510
+ $[12] = t72;
7511
+ $[13] = t82;
7512
+ } else {
7513
+ t82 = $[13];
7267
7514
  }
7268
- };
7269
- $[5] = internalValue;
7515
+ return t82;
7516
+ }
7517
+ const t5 = `${isTopLevel ? "py-4" : "py-1"} ${isTopLevel ? `border-b ${defaultBorderMixin} last:border-b-0` : ""}`;
7518
+ let t6;
7519
+ if ($[14] !== arrayLabel || $[15] !== baseKey || $[16] !== suppressHeader) {
7520
+ t6 = baseKey && arrayLabel && !suppressHeader && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", component: "span", children: arrayLabel });
7521
+ $[14] = arrayLabel;
7522
+ $[15] = baseKey;
7523
+ $[16] = suppressHeader;
7524
+ $[17] = t6;
7525
+ } else {
7526
+ t6 = $[17];
7527
+ }
7528
+ const t7 = baseKey ? `pl-4 mt-1 border-l ${defaultBorderMixin}` : "";
7529
+ let t8;
7530
+ if ($[18] !== baseKey || $[19] !== data || $[20] !== isArrayOfMaps || $[21] !== ofProp || $[22] !== properties || $[23] !== size) {
7531
+ let t92;
7532
+ if ($[25] !== baseKey || $[26] !== isArrayOfMaps || $[27] !== ofProp || $[28] !== properties || $[29] !== size) {
7533
+ t92 = (item, index) => {
7534
+ if (item === null || item === void 0) {
7535
+ return null;
7536
+ }
7537
+ const currentKey = baseKey ? `${baseKey}[${index}]` : `[${index}]`;
7538
+ const itemHeader = isArrayOfMaps && ofProp?.name ? `${ofProp.name} [${index}]` : `[${index}]`;
7539
+ return /* @__PURE__ */ jsxs("div", { className: "py-1", children: [
7540
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", component: "span", children: itemHeader }),
7541
+ /* @__PURE__ */ jsx("div", { className: `pl-4 mt-1 border-l ${defaultBorderMixin}`, children: /* @__PURE__ */ jsx(PropertyCollectionView, { data: item, properties, baseKey: currentKey, suppressHeader: true, size }) })
7542
+ ] }, currentKey);
7543
+ };
7544
+ $[25] = baseKey;
7545
+ $[26] = isArrayOfMaps;
7546
+ $[27] = ofProp;
7547
+ $[28] = properties;
7548
+ $[29] = size;
7549
+ $[30] = t92;
7550
+ } else {
7551
+ t92 = $[30];
7552
+ }
7553
+ t8 = data.map(t92);
7554
+ $[18] = baseKey;
7555
+ $[19] = data;
7556
+ $[20] = isArrayOfMaps;
7557
+ $[21] = ofProp;
7558
+ $[22] = properties;
7559
+ $[23] = size;
7560
+ $[24] = t8;
7561
+ } else {
7562
+ t8 = $[24];
7563
+ }
7564
+ let t9;
7565
+ if ($[31] !== t7 || $[32] !== t8) {
7566
+ t9 = /* @__PURE__ */ jsx("div", { className: t7, children: t8 });
7567
+ $[31] = t7;
7568
+ $[32] = t8;
7569
+ $[33] = t9;
7570
+ } else {
7571
+ t9 = $[33];
7572
+ }
7573
+ let t10;
7574
+ if ($[34] !== t5 || $[35] !== t6 || $[36] !== t9) {
7575
+ t10 = /* @__PURE__ */ jsxs("div", { className: t5, children: [
7576
+ t6,
7577
+ t9
7578
+ ] });
7579
+ $[34] = t5;
7580
+ $[35] = t6;
7581
+ $[36] = t9;
7582
+ $[37] = t10;
7583
+ } else {
7584
+ t10 = $[37];
7585
+ }
7586
+ return t10;
7587
+ }
7588
+ if (typeof data === "object" && data !== null) {
7589
+ let t4;
7590
+ if ($[38] !== baseKey || $[39] !== properties) {
7591
+ t4 = baseKey ? buildPropertyLabelAndGetProperty(properties, baseKey) : {
7592
+ label: "",
7593
+ property: void 0
7594
+ };
7595
+ $[38] = baseKey;
7596
+ $[39] = properties;
7597
+ $[40] = t4;
7598
+ } else {
7599
+ t4 = $[40];
7600
+ }
7601
+ const {
7602
+ label,
7603
+ property: property_0
7604
+ } = t4;
7605
+ if (baseKey && (!property_0 || property_0.dataType !== "map" || !property_0.properties)) {
7606
+ if (!property_0) {
7607
+ return null;
7608
+ }
7609
+ const t52 = `grid grid-cols-12 gap-x-4 ${isTopLevel ? "py-4" : "py-2"} items-start ${isTopLevel ? `border-b ${defaultBorderMixin} last:border-b-0` : ""}`;
7610
+ let t62;
7611
+ if ($[41] !== label) {
7612
+ t62 = /* @__PURE__ */ jsx("div", { className: "col-span-4 pr-2", children: /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", component: "span", className: "break-words", children: label }) });
7613
+ $[41] = label;
7614
+ $[42] = t62;
7615
+ } else {
7616
+ t62 = $[42];
7617
+ }
7618
+ let t72;
7619
+ if ($[43] !== baseKey || $[44] !== data || $[45] !== property_0 || $[46] !== size) {
7620
+ t72 = /* @__PURE__ */ jsx("div", { className: "col-span-8", children: /* @__PURE__ */ jsx(PropertyPreview, { propertyKey: baseKey, value: data, property: property_0, size }) });
7621
+ $[43] = baseKey;
7622
+ $[44] = data;
7623
+ $[45] = property_0;
7624
+ $[46] = size;
7625
+ $[47] = t72;
7626
+ } else {
7627
+ t72 = $[47];
7628
+ }
7629
+ let t82;
7630
+ if ($[48] !== t52 || $[49] !== t62 || $[50] !== t72) {
7631
+ t82 = /* @__PURE__ */ jsxs("div", { className: t52, children: [
7632
+ t62,
7633
+ t72
7634
+ ] });
7635
+ $[48] = t52;
7636
+ $[49] = t62;
7637
+ $[50] = t72;
7638
+ $[51] = t82;
7639
+ } else {
7640
+ t82 = $[51];
7641
+ }
7642
+ return t82;
7643
+ }
7644
+ let t5;
7645
+ if ($[52] !== baseKey || $[53] !== property_0 || $[54] !== suppressHeader) {
7646
+ t5 = baseKey && !suppressHeader && property_0?.dataType === "map" && (property_0.name || !pathEndsWithIndex(baseKey));
7647
+ $[52] = baseKey;
7648
+ $[53] = property_0;
7649
+ $[54] = suppressHeader;
7650
+ $[55] = t5;
7651
+ } else {
7652
+ t5 = $[55];
7653
+ }
7654
+ const showMapHeader = t5;
7655
+ const headerText = property_0?.name || label;
7656
+ const t6 = `${isTopLevel ? "py-4" : "py-1"} ${isTopLevel ? `border-b ${defaultBorderMixin} last:border-b-0` : ""}`;
7657
+ let t7;
7658
+ if ($[56] !== headerText || $[57] !== showMapHeader) {
7659
+ t7 = showMapHeader && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", component: "span", children: headerText });
7660
+ $[56] = headerText;
7661
+ $[57] = showMapHeader;
7662
+ $[58] = t7;
7663
+ } else {
7664
+ t7 = $[58];
7665
+ }
7666
+ const t8 = baseKey ? `pl-4 mt-1 border-l ${defaultBorderMixin}` : "";
7667
+ let t9;
7668
+ if ($[59] !== baseKey || $[60] !== data || $[61] !== properties || $[62] !== size) {
7669
+ let t102;
7670
+ if ($[64] !== baseKey || $[65] !== properties || $[66] !== size) {
7671
+ t102 = (t112) => {
7672
+ const [key, value] = t112;
7673
+ if (value === null || value === void 0) {
7674
+ return null;
7675
+ }
7676
+ const currentKey_0 = baseKey ? `${baseKey}.${key}` : key;
7677
+ return /* @__PURE__ */ jsx(PropertyCollectionView, { data: value, properties, baseKey: currentKey_0, size }, currentKey_0);
7678
+ };
7679
+ $[64] = baseKey;
7680
+ $[65] = properties;
7681
+ $[66] = size;
7682
+ $[67] = t102;
7683
+ } else {
7684
+ t102 = $[67];
7685
+ }
7686
+ t9 = Object.entries(data).map(t102);
7687
+ $[59] = baseKey;
7688
+ $[60] = data;
7689
+ $[61] = properties;
7690
+ $[62] = size;
7691
+ $[63] = t9;
7692
+ } else {
7693
+ t9 = $[63];
7694
+ }
7695
+ let t10;
7696
+ if ($[68] !== t8 || $[69] !== t9) {
7697
+ t10 = /* @__PURE__ */ jsx("div", { className: t8, children: t9 });
7698
+ $[68] = t8;
7699
+ $[69] = t9;
7700
+ $[70] = t10;
7701
+ } else {
7702
+ t10 = $[70];
7703
+ }
7704
+ let t11;
7705
+ if ($[71] !== t10 || $[72] !== t6 || $[73] !== t7) {
7706
+ t11 = /* @__PURE__ */ jsxs("div", { className: t6, children: [
7707
+ t7,
7708
+ t10
7709
+ ] });
7710
+ $[71] = t10;
7711
+ $[72] = t6;
7712
+ $[73] = t7;
7713
+ $[74] = t11;
7714
+ } else {
7715
+ t11 = $[74];
7716
+ }
7717
+ return t11;
7718
+ }
7719
+ if (baseKey) {
7720
+ let t4;
7721
+ if ($[75] !== baseKey || $[76] !== properties) {
7722
+ t4 = buildPropertyLabelAndGetProperty(properties, baseKey);
7723
+ $[75] = baseKey;
7724
+ $[76] = properties;
7725
+ $[77] = t4;
7726
+ } else {
7727
+ t4 = $[77];
7728
+ }
7729
+ const {
7730
+ label: label_0,
7731
+ property: property_1
7732
+ } = t4;
7733
+ if (!property_1) {
7734
+ return null;
7735
+ }
7736
+ const t5 = `grid grid-cols-12 gap-x-4 ${isTopLevel ? "py-4" : "py-2"} items-start ${isTopLevel ? `border-b ${defaultBorderMixin} last:border-b-0` : ""}`;
7737
+ let t6;
7738
+ if ($[78] !== label_0) {
7739
+ t6 = /* @__PURE__ */ jsx("div", { className: "col-span-4 pr-2", children: /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", component: "span", className: "break-words", children: label_0 }) });
7740
+ $[78] = label_0;
7741
+ $[79] = t6;
7742
+ } else {
7743
+ t6 = $[79];
7744
+ }
7745
+ let t7;
7746
+ if ($[80] !== baseKey || $[81] !== data || $[82] !== property_1 || $[83] !== size) {
7747
+ t7 = /* @__PURE__ */ jsx("div", { className: "col-span-8", children: /* @__PURE__ */ jsx(PropertyPreview, { propertyKey: baseKey, value: data, property: property_1, size }) });
7748
+ $[80] = baseKey;
7749
+ $[81] = data;
7750
+ $[82] = property_1;
7751
+ $[83] = size;
7752
+ $[84] = t7;
7753
+ } else {
7754
+ t7 = $[84];
7755
+ }
7756
+ let t8;
7757
+ if ($[85] !== t5 || $[86] !== t6 || $[87] !== t7) {
7758
+ t8 = /* @__PURE__ */ jsxs("div", { className: t5, children: [
7759
+ t6,
7760
+ t7
7761
+ ] });
7762
+ $[85] = t5;
7763
+ $[86] = t6;
7764
+ $[87] = t7;
7765
+ $[88] = t8;
7766
+ } else {
7767
+ t8 = $[88];
7768
+ }
7769
+ return t8;
7770
+ }
7771
+ return null;
7772
+ };
7773
+ function EntityView({
7774
+ entity,
7775
+ collection,
7776
+ path,
7777
+ className
7778
+ }) {
7779
+ const authController = useAuthController();
7780
+ const customizationController = useCustomizationController();
7781
+ const resolvedCollection = useMemo(() => resolveCollection({
7782
+ collection,
7783
+ path,
7784
+ entityId: entity.id,
7785
+ values: entity.values,
7786
+ propertyConfigs: customizationController.propertyConfigs,
7787
+ authController
7788
+ }), [collection, path, entity, customizationController.propertyConfigs]);
7789
+ const properties = resolvedCollection.properties;
7790
+ return /* @__PURE__ */ jsx("div", { className: "w-full " + className, children: /* @__PURE__ */ jsxs("div", { className: "w-full mb-4 p-4", children: [
7791
+ /* @__PURE__ */ jsxs("div", { className: `grid grid-cols-12 gap-x-4 py-4 items-start border-b ${defaultBorderMixin}`, children: [
7792
+ /* @__PURE__ */ jsx("div", { className: "col-span-4 pr-2", children: /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", component: "span", className: "break-words", children: "Id" }) }),
7793
+ /* @__PURE__ */ jsx("div", { className: "col-span-8", children: /* @__PURE__ */ jsxs("div", { className: "flex-grow text-surface-900 dark:text-white flex items-center", children: [
7794
+ /* @__PURE__ */ jsx("span", { className: "flex-grow mr-2", children: entity.id }),
7795
+ customizationController?.entityLinkBuilder && /* @__PURE__ */ jsx("a", { href: customizationController.entityLinkBuilder({
7796
+ entity
7797
+ }), rel: "noopener noreferrer", target: "_blank", children: /* @__PURE__ */ jsx(IconButton, { children: /* @__PURE__ */ jsx(OpenInNewIcon, { size: "small" }) }) })
7798
+ ] }) })
7799
+ ] }),
7800
+ /* @__PURE__ */ jsx(PropertyCollectionView, { data: entity.values, properties, size: "medium" })
7801
+ ] }) });
7802
+ }
7803
+ function VirtualTableInput(props) {
7804
+ const $ = c(22);
7805
+ const ref = React__default.useRef(null);
7806
+ const {
7807
+ value,
7808
+ multiline,
7809
+ updateValue,
7810
+ focused
7811
+ } = props;
7812
+ const prevValue = useRef(value);
7813
+ const [internalValue, setInternalValue] = useState(value);
7814
+ const focusedState = useRef(false);
7815
+ let t0;
7816
+ if ($[0] !== internalValue || $[1] !== value) {
7817
+ t0 = () => {
7818
+ if (prevValue.current !== value && value !== internalValue) {
7819
+ setInternalValue(value);
7820
+ }
7821
+ prevValue.current = value;
7822
+ };
7823
+ $[0] = internalValue;
7824
+ $[1] = value;
7825
+ $[2] = t0;
7826
+ } else {
7827
+ t0 = $[2];
7828
+ }
7829
+ let t1;
7830
+ if ($[3] !== value) {
7831
+ t1 = [value];
7832
+ $[3] = value;
7833
+ $[4] = t1;
7834
+ } else {
7835
+ t1 = $[4];
7836
+ }
7837
+ useEffect(t0, t1);
7838
+ let t2;
7839
+ if ($[5] !== internalValue || $[6] !== updateValue || $[7] !== value) {
7840
+ t2 = () => {
7841
+ const emptyInitialValue = !value;
7842
+ if (emptyInitialValue && !internalValue) {
7843
+ return;
7844
+ }
7845
+ if (internalValue !== value) {
7846
+ prevValue.current = internalValue;
7847
+ updateValue(internalValue);
7848
+ }
7849
+ };
7850
+ $[5] = internalValue;
7270
7851
  $[6] = updateValue;
7271
7852
  $[7] = value;
7272
7853
  $[8] = t2;
@@ -7403,7 +7984,7 @@ function VirtualTableSelect(props) {
7403
7984
  console.trace("onChange");
7404
7985
  if (valueType === "number") {
7405
7986
  if (multiple) {
7406
- const newValue = updatedValue.map(_temp$l);
7987
+ const newValue = updatedValue.map(_temp$n);
7407
7988
  updateValue(newValue);
7408
7989
  } else {
7409
7990
  updateValue(parseFloat(updatedValue));
@@ -7440,7 +8021,7 @@ function VirtualTableSelect(props) {
7440
8021
  const renderValue = t3;
7441
8022
  let t4;
7442
8023
  if ($[10] !== disabled || $[11] !== enumValues || $[12] !== internalValue || $[13] !== multiple || $[14] !== onChange || $[15] !== renderValue || $[16] !== small || $[17] !== validValue) {
7443
- t4 = 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$a) : [], onValueChange: onChange, 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", position: "item-aligned", disabled, padding: false, value: validValue ? internalValue?.toString() : "", onValueChange: onChange, 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)) });
8024
+ t4 = 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, 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", position: "item-aligned", disabled, padding: false, value: validValue ? internalValue?.toString() : "", onValueChange: onChange, 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)) });
7444
8025
  $[10] = disabled;
7445
8026
  $[11] = enumValues;
7446
8027
  $[12] = internalValue;
@@ -7455,10 +8036,10 @@ function VirtualTableSelect(props) {
7455
8036
  }
7456
8037
  return t4;
7457
8038
  }
7458
- function _temp2$a(v_0) {
8039
+ function _temp2$b(v_0) {
7459
8040
  return v_0.toString();
7460
8041
  }
7461
- function _temp$l(v) {
8042
+ function _temp$n(v) {
7462
8043
  return parseFloat(v);
7463
8044
  }
7464
8045
  function VirtualTableNumberInput(props) {
@@ -7589,6 +8170,89 @@ function VirtualTableDateField(props) {
7589
8170
  }
7590
8171
  return t4;
7591
8172
  }
8173
+ function VirtualTableUserSelect(props) {
8174
+ const $ = c(15);
8175
+ const {
8176
+ internalValue,
8177
+ disabled,
8178
+ focused,
8179
+ updateValue,
8180
+ multiple
8181
+ } = props;
8182
+ const {
8183
+ users,
8184
+ getUser
8185
+ } = useInternalUserManagementController();
8186
+ const validValue = Array.isArray(internalValue) && multiple || !Array.isArray(internalValue) && !multiple;
8187
+ const ref = React__default.useRef(null);
8188
+ let t0;
8189
+ let t1;
8190
+ if ($[0] !== focused) {
8191
+ t0 = () => {
8192
+ if (ref.current && focused) {
8193
+ ref.current?.focus({
8194
+ preventScroll: true
8195
+ });
8196
+ }
8197
+ };
8198
+ t1 = [focused, ref];
8199
+ $[0] = focused;
8200
+ $[1] = t0;
8201
+ $[2] = t1;
8202
+ } else {
8203
+ t0 = $[1];
8204
+ t1 = $[2];
8205
+ }
8206
+ useEffect(t0, t1);
8207
+ let t2;
8208
+ if ($[3] !== updateValue) {
8209
+ t2 = (updatedValue) => {
8210
+ if (!updatedValue) {
8211
+ updateValue(null);
8212
+ } else {
8213
+ updateValue(updatedValue);
8214
+ }
8215
+ };
8216
+ $[3] = updateValue;
8217
+ $[4] = t2;
8218
+ } else {
8219
+ t2 = $[4];
8220
+ }
8221
+ const onChange = t2;
8222
+ let t3;
8223
+ if ($[5] !== getUser) {
8224
+ t3 = (userId) => {
8225
+ const user = getUser(userId);
8226
+ return /* @__PURE__ */ jsx(UserDisplay, { user });
8227
+ };
8228
+ $[5] = getUser;
8229
+ $[6] = t3;
8230
+ } else {
8231
+ t3 = $[6];
8232
+ }
8233
+ const renderValue = t3;
8234
+ let t4;
8235
+ if ($[7] !== disabled || $[8] !== internalValue || $[9] !== multiple || $[10] !== onChange || $[11] !== renderValue || $[12] !== users || $[13] !== validValue) {
8236
+ t4 = 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 : [], onValueChange: onChange, children: users?.map(_temp$m) }) : /* @__PURE__ */ jsx(Select, { inputRef: ref, size: "large", fullWidth: true, className: "w-full h-full p-0 bg-transparent", position: "item-aligned", disabled, padding: false, value: validValue ? internalValue : "", onValueChange: onChange, renderValue, children: users?.map(_temp2$a) });
8237
+ $[7] = disabled;
8238
+ $[8] = internalValue;
8239
+ $[9] = multiple;
8240
+ $[10] = onChange;
8241
+ $[11] = renderValue;
8242
+ $[12] = users;
8243
+ $[13] = validValue;
8244
+ $[14] = t4;
8245
+ } else {
8246
+ t4 = $[14];
8247
+ }
8248
+ return t4;
8249
+ }
8250
+ function _temp2$a(user_1) {
8251
+ return /* @__PURE__ */ jsx(SelectItem, { value: user_1.uid, children: /* @__PURE__ */ jsx(UserDisplay, { user: user_1 }) }, user_1.uid);
8252
+ }
8253
+ function _temp$m(user_0) {
8254
+ return /* @__PURE__ */ jsx(MultiSelectItem, { value: user_0.uid, children: /* @__PURE__ */ jsx(UserDisplay, { user: user_0 }) }, user_0.uid);
8255
+ }
7592
8256
  class ErrorBoundary extends React__default.Component {
7593
8257
  constructor(props) {
7594
8258
  super(props);
@@ -7636,7 +8300,8 @@ function useStorageUploadController({
7636
8300
  const processFile = storage?.processFile;
7637
8301
  const metadata = storage?.metadata;
7638
8302
  const size = multipleFilesSupported ? "medium" : "large";
7639
- const compression = storage?.imageCompression;
8303
+ const imageResize = storage?.imageResize;
8304
+ const legacyCompression = storage?.imageCompression;
7640
8305
  const internalInitialValue = getInternalInitialValue(multipleFilesSupported, value, metadata, size);
7641
8306
  const [initialValue, setInitialValue] = useState(value);
7642
8307
  const [internalValue, setInternalValue] = useState(internalInitialValue);
@@ -7708,6 +8373,11 @@ function useStorageUploadController({
7708
8373
  onChange(fieldValue ? fieldValue[0] : null);
7709
8374
  }
7710
8375
  }, [internalValue, multipleFilesSupported, onChange, storage, storageSource]);
8376
+ const onFileUploadError = useCallback((entry_0) => {
8377
+ console.debug("onFileUploadError", entry_0);
8378
+ const newValue_0 = internalValue.filter((item) => item.id !== entry_0.id);
8379
+ setInternalValue(newValue_0);
8380
+ }, [internalValue]);
7711
8381
  const onFilesAdded = useCallback(async (acceptedFiles) => {
7712
8382
  if (!acceptedFiles.length || disabled) return;
7713
8383
  if (processFile) {
@@ -7726,8 +8396,8 @@ function useStorageUploadController({
7726
8396
  let newInternalValue;
7727
8397
  if (multipleFilesSupported) {
7728
8398
  newInternalValue = [...internalValue, ...await Promise.all(acceptedFiles.map(async (file_2) => {
7729
- if (compression && compressionFormat(file_2)) {
7730
- file_2 = await resizeAndCompressImage(file_2, compression);
8399
+ if ((imageResize || legacyCompression) && isImageFile(file_2)) {
8400
+ file_2 = await resizeImage(file_2, imageResize, legacyCompression);
7731
8401
  }
7732
8402
  return {
7733
8403
  id: getRandomId$2(),
@@ -7739,8 +8409,8 @@ function useStorageUploadController({
7739
8409
  }))];
7740
8410
  } else {
7741
8411
  let file_3 = acceptedFiles[0];
7742
- if (compression && compressionFormat(file_3)) {
7743
- file_3 = await resizeAndCompressImage(file_3, compression);
8412
+ if ((imageResize || legacyCompression) && isImageFile(file_3)) {
8413
+ file_3 = await resizeImage(file_3, imageResize, legacyCompression);
7744
8414
  }
7745
8415
  newInternalValue = [{
7746
8416
  id: getRandomId$2(),
@@ -7752,7 +8422,7 @@ function useStorageUploadController({
7752
8422
  }
7753
8423
  newInternalValue = removeDuplicates(newInternalValue);
7754
8424
  setInternalValue(newInternalValue);
7755
- }, [disabled, fileNameBuilder, internalValue, metadata, multipleFilesSupported, size]);
8425
+ }, [disabled, fileNameBuilder, internalValue, metadata, multipleFilesSupported, size, imageResize, legacyCompression]);
7756
8426
  return {
7757
8427
  internalValue,
7758
8428
  setInternalValue,
@@ -7760,6 +8430,7 @@ function useStorageUploadController({
7760
8430
  fileNameBuilder,
7761
8431
  storagePathBuilder,
7762
8432
  onFileUploadComplete,
8433
+ onFileUploadError,
7763
8434
  onFilesAdded,
7764
8435
  multipleFilesSupported
7765
8436
  };
@@ -7790,22 +8461,42 @@ function removeDuplicates(items) {
7790
8461
  function getRandomId$2() {
7791
8462
  return Math.floor(Math.random() * Math.floor(Number.MAX_SAFE_INTEGER));
7792
8463
  }
7793
- const supportedTypes = {
7794
- "image/jpeg": "JPEG",
7795
- "image/png": "PNG",
7796
- "image/webp": "WEBP"
7797
- };
7798
- const compressionFormat = (file) => supportedTypes[file.type] ? supportedTypes[file.type] : null;
7799
- const defaultQuality = 100;
7800
- const resizeAndCompressImage = (file, compression) => new Promise((resolve) => {
7801
- const inputQuality = compression.quality === void 0 ? defaultQuality : compression.quality;
7802
- const quality = inputQuality >= 0 ? inputQuality <= 100 ? inputQuality : 100 : 100;
7803
- const format2 = compressionFormat(file);
7804
- if (!format2) {
7805
- throw Error("resizeAndCompressImage: Unsupported image format");
7806
- }
7807
- Resizer.imageFileResizer(file, compression.maxWidth || Number.MAX_VALUE, compression.maxHeight || Number.MAX_VALUE, format2, quality, 0, (file2) => resolve(file2), "file");
7808
- });
8464
+ function isImageFile(file) {
8465
+ return file.type === "image/jpeg" || file.type === "image/png" || file.type === "image/webp";
8466
+ }
8467
+ async function resizeImage(file, imageResize, legacyCompression) {
8468
+ const maxWidth = imageResize?.maxWidth ?? legacyCompression?.maxWidth;
8469
+ const maxHeight = imageResize?.maxHeight ?? legacyCompression?.maxHeight;
8470
+ const quality = (imageResize?.quality ?? legacyCompression?.quality ?? 80) / 100;
8471
+ const mode = imageResize?.mode ?? "contain";
8472
+ let mimeType = file.type;
8473
+ if (imageResize?.format && imageResize.format !== "original") {
8474
+ mimeType = `image/${imageResize.format}`;
8475
+ }
8476
+ return new Promise((resolve, reject) => {
8477
+ new Compressor(file, {
8478
+ quality,
8479
+ maxWidth,
8480
+ maxHeight,
8481
+ mimeType,
8482
+ // Use cover mode if specified (crops to fit)
8483
+ // Otherwise use contain mode (scales to fit)
8484
+ ...mode === "cover" || mode === void 0 ? {
8485
+ width: maxWidth,
8486
+ height: maxHeight,
8487
+ resize: "cover"
8488
+ } : {},
8489
+ success: (result) => {
8490
+ const compressedFile = new File([result], file.name, {
8491
+ type: result.type,
8492
+ lastModified: Date.now()
8493
+ });
8494
+ resolve(compressedFile);
8495
+ },
8496
+ error: reject
8497
+ });
8498
+ });
8499
+ }
7809
8500
  function StorageUploadProgress({
7810
8501
  storagePath,
7811
8502
  entry,
@@ -8017,7 +8708,7 @@ function StorageUpload$1(t0) {
8017
8708
  const snackbarContext = useSnackbarController();
8018
8709
  let t1;
8019
8710
  if ($[0] !== storage.acceptedFiles) {
8020
- t1 = storage.acceptedFiles ? storage.acceptedFiles.map(_temp$k).reduce(_temp2$9, {}) : void 0;
8711
+ t1 = storage.acceptedFiles ? storage.acceptedFiles.map(_temp$l).reduce(_temp2$9, {}) : void 0;
8021
8712
  $[0] = storage.acceptedFiles;
8022
8713
  $[1] = t1;
8023
8714
  } else {
@@ -8246,7 +8937,7 @@ function _temp2$9(a, b) {
8246
8937
  ...b
8247
8938
  };
8248
8939
  }
8249
- function _temp$k(e) {
8940
+ function _temp$l(e) {
8250
8941
  return {
8251
8942
  [e]: []
8252
8943
  };
@@ -8353,7 +9044,7 @@ const TableReferenceFieldInternal = React__default.memo(function TableReferenceF
8353
9044
  let t1;
8354
9045
  if ($[2] !== updateValue) {
8355
9046
  t1 = (entities) => {
8356
- updateValue(entities.map(_temp$j));
9047
+ updateValue(entities.map(_temp$k));
8357
9048
  };
8358
9049
  $[2] = updateValue;
8359
9050
  $[3] = t1;
@@ -8514,7 +9205,7 @@ const TableReferenceFieldInternal = React__default.memo(function TableReferenceF
8514
9205
  }
8515
9206
  return t10;
8516
9207
  }, equal);
8517
- function _temp$j(e) {
9208
+ function _temp$k(e) {
8518
9209
  return getReferenceFrom(e);
8519
9210
  }
8520
9211
  function _temp2$8(ref) {
@@ -9376,6 +10067,9 @@ const PropertyTableCell = React__default.memo(function PropertyTableCell2({
9376
10067
  if (stringProperty_0.enumValues) {
9377
10068
  innerComponent = /* @__PURE__ */ jsx(VirtualTableSelect, { name: propertyKey, multiple: false, focused: selected, disabled, valueType: "string", small: getPreviewSizeFrom(size) !== "medium", enumValues: stringProperty_0.enumValues, error: validationError ?? error, internalValue, updateValue });
9378
10069
  fullHeight = true;
10070
+ } else if (stringProperty_0.userSelect) {
10071
+ innerComponent = /* @__PURE__ */ jsx(VirtualTableUserSelect, { name: propertyKey, multiple: false, focused: selected, disabled, small: getPreviewSizeFrom(size) !== "medium", error: validationError ?? error, internalValue, updateValue });
10072
+ fullHeight = true;
9379
10073
  } else if (stringProperty_0.markdown || !stringProperty_0.storage || !stringProperty_0.reference) {
9380
10074
  const multiline = Boolean(stringProperty_0.multiline) || Boolean(stringProperty_0.markdown);
9381
10075
  innerComponent = /* @__PURE__ */ jsx(VirtualTableInput, { error: validationError ?? error, disabled, multiline, focused: selected, value: internalValue, updateValue });
@@ -9440,7 +10134,8 @@ function customReplacer(key) {
9440
10134
  return {
9441
10135
  __type: "EntityReference",
9442
10136
  id: value.id,
9443
- path: value.path
10137
+ path: value.path,
10138
+ databaseId: value.databaseId
9444
10139
  };
9445
10140
  }
9446
10141
  if (value instanceof GeoPoint) {
@@ -9464,7 +10159,7 @@ function customReviver(key, value) {
9464
10159
  case "Date":
9465
10160
  return new Date(value.value);
9466
10161
  case "EntityReference":
9467
- return new EntityReference(value.id, value.path);
10162
+ return new EntityReference(value.id, value.path, value.databaseId);
9468
10163
  case "GeoPoint":
9469
10164
  return new GeoPoint(value.latitude, value.longitude);
9470
10165
  case "Vector":
@@ -9475,50 +10170,41 @@ function customReviver(key, value) {
9475
10170
  }
9476
10171
  return value;
9477
10172
  }
9478
- if (isLocalStorageAvailable) {
9479
- try {
9480
- for (let i = 0; i < localStorage.length; i++) {
9481
- const fullKey = localStorage.key(i);
9482
- if (fullKey && fullKey.startsWith(LOCAL_STORAGE_PREFIX)) {
9483
- const path = fullKey.substring(LOCAL_STORAGE_PREFIX.length);
9484
- const entityString = localStorage.getItem(fullKey);
9485
- if (entityString) {
9486
- try {
9487
- const entity = JSON.parse(entityString, customReviver);
9488
- entityCache.set(path, entity);
9489
- } catch (parseError) {
9490
- console.error(`Failed to parse entity for path "${path}" from localStorage:`, parseError);
9491
- }
9492
- }
9493
- }
9494
- }
9495
- } catch (error) {
9496
- console.error("Error accessing localStorage during initialization:", error);
9497
- }
9498
- }
9499
10173
  function saveEntityToCache(path, data) {
9500
- entityCache.set(path, data);
9501
10174
  if (isLocalStorageAvailable) {
9502
10175
  try {
9503
10176
  const key = LOCAL_STORAGE_PREFIX + path;
9504
10177
  const entityString = JSON.stringify(data, customReplacer);
10178
+ console.log("Saving entity to localStorage:", {
10179
+ key,
10180
+ entityString
10181
+ });
9505
10182
  localStorage.setItem(key, entityString);
9506
10183
  } catch (error) {
9507
10184
  console.error(`Failed to save entity for path "${path}" to localStorage:`, error);
9508
10185
  }
9509
10186
  }
9510
10187
  }
10188
+ function removeEntityFromMemoryCache(path) {
10189
+ entityCache.delete(path);
10190
+ }
10191
+ function saveEntityToMemoryCache(path, data) {
10192
+ entityCache.set(path, data);
10193
+ }
10194
+ function getEntityFromMemoryCache(path) {
10195
+ return entityCache.get(path);
10196
+ }
9511
10197
  function getEntityFromCache(path) {
9512
- if (entityCache.has(path)) {
9513
- return entityCache.get(path);
9514
- }
9515
10198
  if (isLocalStorageAvailable) {
9516
10199
  try {
9517
10200
  const key = LOCAL_STORAGE_PREFIX + path;
9518
10201
  const entityString = localStorage.getItem(key);
9519
10202
  if (entityString) {
9520
10203
  const entity = JSON.parse(entityString, customReviver);
9521
- entityCache.set(path, entity);
10204
+ console.log("Loaded entity from localStorage:", {
10205
+ key,
10206
+ entity
10207
+ });
9522
10208
  return entity;
9523
10209
  }
9524
10210
  } catch (error) {
@@ -9527,12 +10213,7 @@ function getEntityFromCache(path) {
9527
10213
  }
9528
10214
  return void 0;
9529
10215
  }
9530
- function hasEntityInCache(path) {
9531
- return entityCache.has(path);
9532
- }
9533
10216
  function removeEntityFromCache(path) {
9534
- console.debug("Removing entity from cache", path);
9535
- entityCache.delete(path);
9536
10217
  if (isLocalStorageAvailable) {
9537
10218
  try {
9538
10219
  const key = LOCAL_STORAGE_PREFIX + path;
@@ -9542,6 +10223,26 @@ function removeEntityFromCache(path) {
9542
10223
  }
9543
10224
  }
9544
10225
  }
10226
+ function flattenKeys(obj, prefix = "", result = []) {
10227
+ if (isObject(obj) || Array.isArray(obj)) {
10228
+ const plainObject = isPlainObject(obj);
10229
+ if (!plainObject && prefix) {
10230
+ result.push(prefix);
10231
+ } else {
10232
+ for (const key in obj) {
10233
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
10234
+ const newKey = prefix ? Array.isArray(obj) ? `${prefix}[${key}]` : `${prefix}.${key}` : key;
10235
+ if (isObject(obj[key]) || Array.isArray(obj[key])) {
10236
+ flattenKeys(obj[key], newKey, result);
10237
+ } else {
10238
+ result.push(newKey);
10239
+ }
10240
+ }
10241
+ }
10242
+ }
10243
+ }
10244
+ return result;
10245
+ }
9545
10246
  const EntityCollectionRowActions = function EntityCollectionRowActions2({
9546
10247
  entity,
9547
10248
  collection,
@@ -9569,7 +10270,9 @@ const EntityCollectionRowActions = function EntityCollectionRowActions2({
9569
10270
  const hasCollapsedActions = actions.some((a) => a.collapsed || a.collapsed === void 0);
9570
10271
  const collapsedActions = actions.filter((a_0) => a_0.collapsed || a_0.collapsed === void 0);
9571
10272
  const uncollapsedActions = actions.filter((a_1) => a_1.collapsed === false);
9572
- const hasDraft = hasEntityInCache(fullPath + "/" + entity.id);
10273
+ const enableLocalChangesBackup = collection ? getLocalChangesBackup(collection) : false;
10274
+ const hasDraft = enableLocalChangesBackup ? getEntityFromCache(fullPath + "/" + entity.id) : false;
10275
+ const iconSize = largeLayout && (size === "m" || size === "l" || size == "xl") ? "medium" : "small";
9573
10276
  return /* @__PURE__ */ jsxs("div", { className: cls("h-full flex items-center justify-center flex-col bg-surface-50 dark:bg-surface-900 bg-opacity-90 dark:bg-opacity-90 z-10", frozen ? "sticky left-0" : ""), onClick: useCallback((event) => {
9574
10277
  event.stopPropagation();
9575
10278
  }, []), style: {
@@ -9579,23 +10282,31 @@ const EntityCollectionRowActions = function EntityCollectionRowActions2({
9579
10282
  contain: "strict"
9580
10283
  }, children: [
9581
10284
  (hasActions || selectionEnabled) && /* @__PURE__ */ jsxs("div", { className: "w-34 flex justify-center", children: [
9582
- uncollapsedActions.map((action, index) => /* @__PURE__ */ jsx(Tooltip, { title: action.name, asChild: true, children: /* @__PURE__ */ jsx(IconButton, { onClick: (event_0) => {
9583
- event_0.stopPropagation();
9584
- action.onClick({
9585
- view: "collection",
9586
- entity,
9587
- fullPath,
9588
- fullIdPath,
9589
- collection,
9590
- context,
9591
- selectionController,
9592
- highlightEntity,
9593
- unhighlightEntity,
9594
- onCollectionChange,
9595
- openEntityMode: openEntityMode ?? collection?.openEntityMode
9596
- });
9597
- }, size: largeLayout ? "medium" : "small", children: action.icon }) }, index)),
9598
- hasCollapsedActions && /* @__PURE__ */ jsx(Menu, { trigger: /* @__PURE__ */ jsx(IconButton, { size: largeLayout ? "medium" : "small", children: /* @__PURE__ */ jsx(MoreVertIcon, {}) }), children: collapsedActions.map((action_0, index_0) => /* @__PURE__ */ jsxs(MenuItem, { onClick: (e) => {
10285
+ uncollapsedActions.map((action, index) => {
10286
+ const isEditAction = action.key === "edit";
10287
+ const tooltip = isEditAction && hasDraft ? "Local unsaved changes" : action.name;
10288
+ let iconButton = /* @__PURE__ */ jsx(IconButton, { onClick: (event_0) => {
10289
+ event_0.stopPropagation();
10290
+ action.onClick({
10291
+ view: "collection",
10292
+ entity,
10293
+ fullPath,
10294
+ fullIdPath,
10295
+ collection,
10296
+ context,
10297
+ selectionController,
10298
+ highlightEntity,
10299
+ unhighlightEntity,
10300
+ onCollectionChange,
10301
+ openEntityMode: openEntityMode ?? collection?.openEntityMode
10302
+ });
10303
+ }, size: iconSize, children: action.icon });
10304
+ if (isEditAction && hasDraft) {
10305
+ iconButton = /* @__PURE__ */ jsx(Badge, { color: "warning", children: iconButton });
10306
+ }
10307
+ return /* @__PURE__ */ jsx(Tooltip, { title: tooltip, asChild: true, children: iconButton }, index);
10308
+ }),
10309
+ hasCollapsedActions && /* @__PURE__ */ jsx(Menu, { trigger: /* @__PURE__ */ jsx(IconButton, { size: iconSize, children: /* @__PURE__ */ jsx(MoreVertIcon, {}) }), children: collapsedActions.map((action_0, index_0) => /* @__PURE__ */ jsxs(MenuItem, { onClick: (e) => {
9599
10310
  e.stopPropagation();
9600
10311
  action_0.onClick({
9601
10312
  view: "collection",
@@ -9614,14 +10325,11 @@ const EntityCollectionRowActions = function EntityCollectionRowActions2({
9614
10325
  action_0.icon,
9615
10326
  action_0.name
9616
10327
  ] }, index_0)) }),
9617
- selectionEnabled && /* @__PURE__ */ jsx(Tooltip, { title: `Select ${entity.id}`, children: /* @__PURE__ */ jsx(Checkbox, { size: largeLayout ? "medium" : "small", checked: Boolean(isSelected), onCheckedChange }) })
10328
+ selectionEnabled && /* @__PURE__ */ jsx(Tooltip, { title: `Select ${entity.id}`, children: /* @__PURE__ */ jsx(Checkbox, { size: iconSize, checked: Boolean(isSelected), onCheckedChange }) })
9618
10329
  ] }),
9619
- !hideId && size !== "xs" && /* @__PURE__ */ jsxs("div", { className: "w-[138px] overflow-hidden truncate font-mono text-xs text-text-secondary dark:text-text-secondary-dark max-w-full text-ellipsis px-2 align-center justify-center flex items-center gap-1", onClick: (event_1) => {
10330
+ !hideId && size !== "xs" && /* @__PURE__ */ jsx("div", { className: "w-[138px] overflow-hidden truncate font-mono text-xs text-text-secondary dark:text-text-secondary-dark max-w-full text-ellipsis px-2 align-center justify-center flex items-center gap-1", onClick: (event_1) => {
9620
10331
  event_1.stopPropagation();
9621
- }, children: [
9622
- hasDraft && /* @__PURE__ */ jsx(Tooltip, { title: "Local unsaved changes", className: "inline", children: /* @__PURE__ */ jsx(Chip, { colorScheme: "orangeDarker", className: "p-0.5", children: /* @__PURE__ */ jsx(EditIcon, { size: 12 }) }) }),
9623
- /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate text-center", children: entity ? entity.id : /* @__PURE__ */ jsx(Skeleton, {}) })
9624
- ] })
10332
+ }, children: /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate text-center", children: entity ? entity.id : /* @__PURE__ */ jsx(Skeleton, {}) }) })
9625
10333
  ] });
9626
10334
  };
9627
10335
  function CollectionTableToolbar(t0) {
@@ -9676,7 +10384,7 @@ function CollectionTableToolbar(t0) {
9676
10384
  }
9677
10385
  let t6;
9678
10386
  if ($[6] !== t3 || $[7] !== t4) {
9679
- t6 = /* @__PURE__ */ jsx(Tooltip, { title: "Table row size", side: "right", sideOffset: 4, children: /* @__PURE__ */ jsx(Select, { value: t3, className: "w-16 ml-2", size: "small", onValueChange: t4, renderValue: _temp$i, children: t5 }) });
10387
+ t6 = /* @__PURE__ */ jsx(Tooltip, { title: "Table row size", side: "right", sideOffset: 4, children: /* @__PURE__ */ jsx(Select, { value: t3, className: "w-16 ml-2", size: "small", onValueChange: t4, renderValue: _temp$j, children: t5 }) });
9680
10388
  $[6] = t3;
9681
10389
  $[7] = t4;
9682
10390
  $[8] = t6;
@@ -9763,7 +10471,7 @@ function CollectionTableToolbar(t0) {
9763
10471
  function _temp2$7(size_0) {
9764
10472
  return /* @__PURE__ */ jsx(SelectItem, { value: size_0, className: "w-12 font-medium text-center", children: size_0.toUpperCase() }, size_0);
9765
10473
  }
9766
- function _temp$i(v_0) {
10474
+ function _temp$j(v_0) {
9767
10475
  return /* @__PURE__ */ jsx("div", { className: "font-medium", children: v_0.toUpperCase() });
9768
10476
  }
9769
10477
  function getTableCellAlignment(property) {
@@ -9835,21 +10543,15 @@ function useColumnIds(collection, includeSubcollections) {
9835
10543
  let t0;
9836
10544
  bb0: {
9837
10545
  if (collection.propertiesOrder) {
9838
- let propertyColumnConfigs;
10546
+ let t12;
9839
10547
  if ($[0] !== collection) {
9840
- propertyColumnConfigs = hideAndExpandKeys(collection, collection.propertiesOrder);
9841
- if (collection.collectionGroup) {
9842
- propertyColumnConfigs.push({
9843
- key: COLLECTION_GROUP_PARENT_ID,
9844
- disabled: true
9845
- });
9846
- }
10548
+ t12 = hideAndExpandKeys(collection, collection.propertiesOrder);
9847
10549
  $[0] = collection;
9848
- $[1] = propertyColumnConfigs;
10550
+ $[1] = t12;
9849
10551
  } else {
9850
- propertyColumnConfigs = $[1];
10552
+ t12 = $[1];
9851
10553
  }
9852
- t0 = propertyColumnConfigs;
10554
+ t0 = t12;
9853
10555
  break bb0;
9854
10556
  }
9855
10557
  let t1;
@@ -10883,7 +11585,7 @@ const SafeLinkRenderer = (t0) => {
10883
11585
  let t1;
10884
11586
  if ($[0] !== text) {
10885
11587
  const urlRegex = /https?:\/\/[^\s]+/g;
10886
- t1 = text.replace(urlRegex, _temp$h);
11588
+ t1 = text.replace(urlRegex, _temp$i);
10887
11589
  $[0] = text;
10888
11590
  $[1] = t1;
10889
11591
  } else {
@@ -10902,7 +11604,7 @@ const SafeLinkRenderer = (t0) => {
10902
11604
  }
10903
11605
  return t2;
10904
11606
  };
10905
- function _temp$h(url) {
11607
+ function _temp$i(url) {
10906
11608
  return `<a href="${url}" class="underline" target="_blank">Link</a><br/>`;
10907
11609
  }
10908
11610
  const operationLabels$2 = {
@@ -11110,7 +11812,7 @@ function StringNumberFilterField(t0) {
11110
11812
  }
11111
11813
  let t6;
11112
11814
  if ($[16] !== operation || $[17] !== t4 || $[18] !== t5) {
11113
- t6 = /* @__PURE__ */ jsx("div", { className: "w-[80px]", children: /* @__PURE__ */ jsx(Select, { value: operation, fullWidth: true, position: "item-aligned", onValueChange: t4, renderValue: _temp$g, children: t5 }) });
11815
+ t6 = /* @__PURE__ */ jsx("div", { className: "w-[80px]", children: /* @__PURE__ */ jsx(Select, { value: operation, fullWidth: true, position: "item-aligned", onValueChange: t4, renderValue: _temp$h, children: t5 }) });
11114
11816
  $[16] = operation;
11115
11817
  $[17] = t4;
11116
11818
  $[18] = t5;
@@ -11123,7 +11825,7 @@ function StringNumberFilterField(t0) {
11123
11825
  t7 = !enumValues && /* @__PURE__ */ jsx(TextField, { type: dataType === "number" ? "number" : void 0, value: internalValue !== void 0 && internalValue != null ? String(internalValue) : "", onChange: (evt) => {
11124
11826
  const val_0 = dataType === "number" ? parseFloat(evt.target.value) : evt.target.value;
11125
11827
  updateFilter(operation, val_0);
11126
- }, endAdornment: internalValue && /* @__PURE__ */ jsx(IconButton, { onClick: (e) => updateFilter(operation, void 0), children: /* @__PURE__ */ jsx(CloseIcon, {}) }) });
11828
+ }, endAdornment: internalValue !== void 0 && internalValue != null && /* @__PURE__ */ jsx(IconButton, { onClick: (e) => updateFilter(operation, void 0), children: /* @__PURE__ */ jsx(CloseIcon, {}) }) });
11127
11829
  $[20] = dataType;
11128
11830
  $[21] = enumValues;
11129
11831
  $[22] = internalValue;
@@ -11139,7 +11841,7 @@ function StringNumberFilterField(t0) {
11139
11841
  if (value_1 !== "") {
11140
11842
  updateFilter(operation, dataType === "number" ? parseInt(value_1) : value_1);
11141
11843
  }
11142
- }, endAdornment: internalValue && /* @__PURE__ */ jsx(IconButton, { className: "absolute right-2 top-3", onClick: (e_0) => updateFilter(operation, void 0), children: /* @__PURE__ */ jsx(CloseIcon, {}) }), renderValue: (enumKey) => {
11844
+ }, endAdornment: internalValue && /* @__PURE__ */ jsx(IconButton, { onClick: (e_0) => updateFilter(operation, void 0), children: /* @__PURE__ */ jsx(CloseIcon, {}) }), renderValue: (enumKey) => {
11143
11845
  if (enumKey === null) {
11144
11846
  return "Filter for null values";
11145
11847
  }
@@ -11234,7 +11936,7 @@ function _temp3$3(e_1) {
11234
11936
  function _temp2$6(op_1) {
11235
11937
  return /* @__PURE__ */ jsx(SelectItem, { value: op_1, children: operationLabels$1[op_1] }, op_1);
11236
11938
  }
11237
- function _temp$g(op_0) {
11939
+ function _temp$h(op_0) {
11238
11940
  return operationLabels$1[op_0];
11239
11941
  }
11240
11942
  function BooleanFilterField(t0) {
@@ -11296,7 +11998,7 @@ const operationLabels = {
11296
11998
  };
11297
11999
  const multipleSelectOperations = ["array-contains-any", "in"];
11298
12000
  function DateTimeFilterField(t0) {
11299
- const $ = c(38);
12001
+ const $ = c(39);
11300
12002
  const {
11301
12003
  isArray,
11302
12004
  mode,
@@ -11337,7 +12039,7 @@ function DateTimeFilterField(t0) {
11337
12039
  newValue = newOpIsArray ? val ? [val] : [] : "";
11338
12040
  }
11339
12041
  setOperation(op);
11340
- setInternalValue(newValue === null ? void 0 : newValue);
12042
+ setInternalValue(newValue);
11341
12043
  const hasNewValue = newValue !== null && Array.isArray(newValue) ? newValue.length > 0 : newValue !== void 0;
11342
12044
  if (op && hasNewValue) {
11343
12045
  setValue([op, newValue]);
@@ -11373,7 +12075,7 @@ function DateTimeFilterField(t0) {
11373
12075
  }
11374
12076
  let t6;
11375
12077
  if ($[13] !== operation || $[14] !== t4 || $[15] !== t5) {
11376
- t6 = /* @__PURE__ */ jsx("div", { className: "w-[80px]", children: /* @__PURE__ */ jsx(Select, { value: operation, size: "large", fullWidth: true, onValueChange: t4, renderValue: _temp$f, children: t5 }) });
12078
+ t6 = /* @__PURE__ */ jsx("div", { className: "w-[80px]", children: /* @__PURE__ */ jsx(Select, { value: operation, size: "large", fullWidth: true, onValueChange: t4, renderValue: _temp$g, children: t5 }) });
11377
12079
  $[13] = operation;
11378
12080
  $[14] = t4;
11379
12081
  $[15] = t5;
@@ -11381,88 +12083,90 @@ function DateTimeFilterField(t0) {
11381
12083
  } else {
11382
12084
  t6 = $[16];
11383
12085
  }
11384
- const t7 = internalValue ?? void 0;
11385
- let t8;
12086
+ const t7 = internalValue === null;
12087
+ const t8 = internalValue ?? void 0;
12088
+ let t9;
11386
12089
  if ($[17] !== operation || $[18] !== updateFilter) {
11387
- t8 = (dateValue) => {
12090
+ t9 = (dateValue) => {
11388
12091
  updateFilter(operation, dateValue === null ? void 0 : dateValue);
11389
12092
  };
11390
12093
  $[17] = operation;
11391
12094
  $[18] = updateFilter;
11392
- $[19] = t8;
12095
+ $[19] = t9;
11393
12096
  } else {
11394
- t8 = $[19];
12097
+ t9 = $[19];
11395
12098
  }
11396
- let t9;
11397
- if ($[20] !== locale || $[21] !== mode || $[22] !== t7 || $[23] !== t8) {
11398
- t9 = /* @__PURE__ */ jsx(DateTimeField, { mode, size: "large", locale, value: t7, onChange: t8, clearable: true });
12099
+ let t10;
12100
+ if ($[20] !== locale || $[21] !== mode || $[22] !== t7 || $[23] !== t8 || $[24] !== t9) {
12101
+ t10 = /* @__PURE__ */ jsx(DateTimeField, { mode, size: "large", locale, disabled: t7, value: t8, onChange: t9, clearable: true });
11399
12102
  $[20] = locale;
11400
12103
  $[21] = mode;
11401
12104
  $[22] = t7;
11402
12105
  $[23] = t8;
11403
12106
  $[24] = t9;
12107
+ $[25] = t10;
11404
12108
  } else {
11405
- t9 = $[24];
12109
+ t10 = $[25];
11406
12110
  }
11407
- const t10 = internalValue === null;
11408
- let t11;
11409
- if ($[25] !== internalValue || $[26] !== operation || $[27] !== updateFilter) {
11410
- t11 = (checked) => {
12111
+ const t11 = internalValue === null;
12112
+ let t12;
12113
+ if ($[26] !== internalValue || $[27] !== operation || $[28] !== updateFilter) {
12114
+ t12 = (checked) => {
11411
12115
  if (internalValue !== null) {
11412
12116
  updateFilter(operation, null);
11413
12117
  } else {
11414
12118
  updateFilter(operation, void 0);
11415
12119
  }
11416
12120
  };
11417
- $[25] = internalValue;
11418
- $[26] = operation;
11419
- $[27] = updateFilter;
11420
- $[28] = t11;
12121
+ $[26] = internalValue;
12122
+ $[27] = operation;
12123
+ $[28] = updateFilter;
12124
+ $[29] = t12;
11421
12125
  } else {
11422
- t11 = $[28];
12126
+ t12 = $[29];
11423
12127
  }
11424
- let t12;
11425
- if ($[29] !== t10 || $[30] !== t11) {
11426
- t12 = /* @__PURE__ */ jsxs(Label, { className: "border cursor-pointer rounded-md p-2 flex items-center gap-2 [&:has(:checked)]:bg-surface-100 dark:[&:has(:checked)]:bg-surface-800", htmlFor: "null-filter", children: [
11427
- /* @__PURE__ */ jsx(Checkbox, { id: "null-filter", checked: t10, size: "small", onCheckedChange: t11 }),
12128
+ let t13;
12129
+ if ($[30] !== t11 || $[31] !== t12) {
12130
+ t13 = /* @__PURE__ */ jsxs(Label, { className: "border cursor-pointer rounded-md p-2 flex items-center gap-2 [&:has(:checked)]:bg-surface-100 dark:[&:has(:checked)]:bg-surface-800", htmlFor: "null-filter", children: [
12131
+ /* @__PURE__ */ jsx(Checkbox, { id: "null-filter", checked: t11, size: "small", onCheckedChange: t12 }),
11428
12132
  "Filter for null values"
11429
12133
  ] });
11430
- $[29] = t10;
11431
12134
  $[30] = t11;
11432
12135
  $[31] = t12;
12136
+ $[32] = t13;
11433
12137
  } else {
11434
- t12 = $[31];
12138
+ t13 = $[32];
11435
12139
  }
11436
- let t13;
11437
- if ($[32] !== t12 || $[33] !== t9) {
11438
- t13 = /* @__PURE__ */ jsxs("div", { className: "flex-grow ml-2 flex flex-col gap-2", children: [
11439
- t9,
11440
- t12
12140
+ let t14;
12141
+ if ($[33] !== t10 || $[34] !== t13) {
12142
+ t14 = /* @__PURE__ */ jsxs("div", { className: "flex-grow ml-2 flex flex-col gap-2", children: [
12143
+ t10,
12144
+ t13
11441
12145
  ] });
11442
- $[32] = t12;
11443
- $[33] = t9;
12146
+ $[33] = t10;
11444
12147
  $[34] = t13;
12148
+ $[35] = t14;
11445
12149
  } else {
11446
- t13 = $[34];
12150
+ t14 = $[35];
11447
12151
  }
11448
- let t14;
11449
- if ($[35] !== t13 || $[36] !== t6) {
11450
- t14 = /* @__PURE__ */ jsxs("div", { className: "flex w-[440px]", children: [
12152
+ let t15;
12153
+ if ($[36] !== t14 || $[37] !== t6) {
12154
+ t15 = /* @__PURE__ */ jsxs("div", { className: "flex w-[440px]", children: [
11451
12155
  t6,
11452
- t13
12156
+ t14
11453
12157
  ] });
11454
- $[35] = t13;
11455
- $[36] = t6;
11456
- $[37] = t14;
12158
+ $[36] = t14;
12159
+ $[37] = t6;
12160
+ $[38] = t15;
11457
12161
  } else {
11458
- t14 = $[37];
12162
+ t15 = $[38];
11459
12163
  }
11460
- return t14;
12164
+ return t15;
11461
12165
  }
11462
12166
  function _temp2$5(op_1) {
11463
12167
  return /* @__PURE__ */ jsx(SelectItem, { value: op_1, children: operationLabels[op_1] }, op_1);
11464
12168
  }
11465
- function _temp$f(op_0) {
12169
+ function _temp$g(op_0) {
11466
12170
  return operationLabels[op_0];
11467
12171
  }
11468
12172
  const SelectableTable = function SelectableTable2({
@@ -12166,7 +12870,7 @@ function useTableSearchHelper(t0) {
12166
12870
  const searchBlocked = t12;
12167
12871
  let t2;
12168
12872
  if ($[15] !== customizationController.plugins || $[16] !== dataSource?.initTextSearch) {
12169
- t2 = Boolean(dataSource?.initTextSearch) || customizationController.plugins?.find(_temp$e);
12873
+ t2 = Boolean(dataSource?.initTextSearch) || customizationController.plugins?.find(_temp$f);
12170
12874
  $[15] = customizationController.plugins;
12171
12875
  $[16] = dataSource?.initTextSearch;
12172
12876
  $[17] = t2;
@@ -12258,7 +12962,7 @@ function useTableSearchHelper(t0) {
12258
12962
  }
12259
12963
  return t1;
12260
12964
  }
12261
- function _temp$e(p_0) {
12965
+ function _temp$f(p_0) {
12262
12966
  return Boolean(p_0.collectionView?.onTextSearchClick);
12263
12967
  }
12264
12968
  function DeleteEntityDialog({
@@ -12851,7 +13555,7 @@ function FavouritesView(t0) {
12851
13555
  T0 = Collapse;
12852
13556
  t4 = favouriteCollections.length > 0;
12853
13557
  t2 = "flex flex-row flex-wrap gap-2 pb-2 min-h-[32px]";
12854
- t3 = favouriteCollections.map(_temp$d);
13558
+ t3 = favouriteCollections.map(_temp$e);
12855
13559
  $[2] = navigationController;
12856
13560
  $[3] = t1;
12857
13561
  $[4] = T0;
@@ -12885,7 +13589,7 @@ function FavouritesView(t0) {
12885
13589
  }
12886
13590
  return t6;
12887
13591
  }
12888
- function _temp$d(entry_0) {
13592
+ function _temp$e(entry_0) {
12889
13593
  return /* @__PURE__ */ jsx(NavigationChip, { entry: entry_0 }, entry_0.path);
12890
13594
  }
12891
13595
  const scrollsMap = {};
@@ -13102,7 +13806,7 @@ const NavigationCard = React__default.memo(function NavigationCard2(t0) {
13102
13806
  }
13103
13807
  let t4;
13104
13808
  if ($[4] !== actions) {
13105
- t4 = /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", onClick: _temp$c, children: actions });
13809
+ t4 = /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", onClick: _temp$d, children: actions });
13106
13810
  $[4] = actions;
13107
13811
  $[5] = t4;
13108
13812
  } else {
@@ -13189,7 +13893,7 @@ const NavigationCard = React__default.memo(function NavigationCard2(t0) {
13189
13893
  }
13190
13894
  return t12;
13191
13895
  });
13192
- function _temp$c(event) {
13896
+ function _temp$d(event) {
13193
13897
  event.preventDefault();
13194
13898
  event.stopPropagation();
13195
13899
  }
@@ -13602,14 +14306,16 @@ function SortableNavigationGroup(t0) {
13602
14306
  return t5;
13603
14307
  }
13604
14308
  function useHomePageDnd({
13605
- items: dndItems,
13606
- setItems: setDndItems,
14309
+ items,
14310
+ setItems,
13607
14311
  disabled,
13608
14312
  onCardMovedBetweenGroups,
13609
14313
  onGroupMoved,
13610
14314
  onNewGroupDrop,
13611
14315
  onPersist
13612
14316
  }) {
14317
+ const dndItems = items;
14318
+ const setDndItems = setItems;
13613
14319
  const [activeId, setActiveId] = useState(null);
13614
14320
  const [activeIsGroup, setActiveIsGroup] = useState(false);
13615
14321
  const [currentDraggingGroupId, setCurrentDraggingGroupId] = useState(null);
@@ -13617,6 +14323,9 @@ function useHomePageDnd({
13617
14323
  const [isDraggingCardOnly, setIsDraggingCardOnly] = useState(false);
13618
14324
  const [dialogOpenForGroup, setDialogOpenForGroup] = useState(null);
13619
14325
  const [isHoveringNewGroupDropZone, setIsHoveringNewGroupDropZone] = useState(false);
14326
+ const [pendingNewGroupName, setPendingNewGroupName] = useState(null);
14327
+ const [stateBeforeNewGroup, setStateBeforeNewGroup] = useState(null);
14328
+ const preDragItemsRef = useRef(null);
13620
14329
  const interimItemsRef = useRef(null);
13621
14330
  useEffect(() => {
13622
14331
  interimItemsRef.current = dndItems;
@@ -13651,32 +14360,6 @@ function useHomePageDnd({
13651
14360
  if (activeIsGroup) {
13652
14361
  const groups = args.droppableContainers.filter((c2) => dndItems.some((g_2) => g_2.name === c2.id));
13653
14362
  if (!groups.length) return [];
13654
- if (groups.length > 0) {
13655
- const firstGroup = groups[0];
13656
- const firstGroupRect = firstGroup.rect.current;
13657
- const {
13658
- x,
13659
- y
13660
- } = args.pointerCoordinates || {
13661
- x: 0,
13662
- y: 0
13663
- };
13664
- if (firstGroupRect && y < firstGroupRect.top + 20) {
13665
- return [{
13666
- id: firstGroup.id,
13667
- data: {
13668
- insertBefore: true
13669
- }
13670
- }];
13671
- }
13672
- }
13673
- const cornersResult = closestCorners({
13674
- ...args,
13675
- droppableContainers: groups
13676
- });
13677
- if (cornersResult.length) {
13678
- return cornersResult;
13679
- }
13680
14363
  return closestCenter({
13681
14364
  ...args,
13682
14365
  droppableContainers: groups
@@ -13734,6 +14417,7 @@ function useHomePageDnd({
13734
14417
  }) => {
13735
14418
  setDndKitActiveNode(active);
13736
14419
  if (disabled) return;
14420
+ preDragItemsRef.current = cloneItemsForDnd(dndItems);
13737
14421
  const isGroup = dndItems.some((g_7) => g_7.name === active.id);
13738
14422
  if (!active.data.current) active.data.current = {};
13739
14423
  active.data.current.type = isGroup ? "group" : "item";
@@ -13757,18 +14441,30 @@ function useHomePageDnd({
13757
14441
  if (!activeCont) return;
13758
14442
  if (overCont && activeCont !== overCont) {
13759
14443
  recentlyMovedToNewContainer.current = true;
13760
- const newState = cloneItemsForDnd(dndItems);
13761
- const srcIdx = newState.findIndex((g_8) => g_8.name === activeCont);
13762
- const tgtIdx = newState.findIndex((g_9) => g_9.name === overCont);
13763
- if (srcIdx === -1 || tgtIdx === -1) return;
13764
- const src = newState[srcIdx];
13765
- const tgt = newState[tgtIdx];
13766
- const idxInSrc = src.entries.findIndex((e_2) => e_2.url === activeIdNow);
13767
- if (idxInSrc === -1) return;
13768
- const [moved] = src.entries.splice(idxInSrc, 1);
13769
- tgt.entries.push(moved);
13770
- interimItemsRef.current = newState;
13771
- setDndItems(newState);
14444
+ lastOverId.current = overIdNow;
14445
+ setDndItems((current) => {
14446
+ const newState = cloneItemsForDnd(current);
14447
+ const srcIdx = newState.findIndex((g_8) => g_8.name === activeCont);
14448
+ const tgtIdx = newState.findIndex((g_9) => g_9.name === overCont);
14449
+ if (srcIdx === -1 || tgtIdx === -1) return current;
14450
+ const src = newState[srcIdx];
14451
+ const tgt = newState[tgtIdx];
14452
+ const idxInSrc = src.entries.findIndex((e_2) => e_2.url === activeIdNow);
14453
+ if (idxInSrc === -1) return current;
14454
+ const [moved] = src.entries.splice(idxInSrc, 1);
14455
+ const overIsContainer_0 = overIdNow === overCont;
14456
+ if (overIsContainer_0) {
14457
+ tgt.entries.push(moved);
14458
+ } else {
14459
+ const overIdx = tgt.entries.findIndex((e_3) => e_3.url === overIdNow);
14460
+ if (overIdx !== -1) {
14461
+ tgt.entries.splice(overIdx, 0, moved);
14462
+ } else {
14463
+ tgt.entries.push(moved);
14464
+ }
14465
+ }
14466
+ return newState;
14467
+ });
13772
14468
  } else if (activeCont === overCont) {
13773
14469
  recentlyMovedToNewContainer.current = false;
13774
14470
  }
@@ -13784,75 +14480,112 @@ function useHomePageDnd({
13784
14480
  const activeIdNow_0 = active_1.id;
13785
14481
  const overIdNow_0 = over_0.id;
13786
14482
  if (activeIsGroup) {
13787
- const insertBefore = over_0.data?.current?.insertBefore;
13788
- if (insertBefore && activeIdNow_0 !== overIdNow_0) {
14483
+ if (activeIdNow_0 !== overIdNow_0 && dndItems.some((g_12) => g_12.name === overIdNow_0)) {
13789
14484
  const from = dndItems.findIndex((g_10) => g_10.name === activeIdNow_0);
13790
- if (from !== -1 && from !== 0) {
13791
- const newState_0 = arrayMove$1(dndItems, from, 0);
14485
+ const to = dndItems.findIndex((g_11) => g_11.name === overIdNow_0);
14486
+ if (from !== -1 && to !== -1) {
14487
+ const newState_0 = arrayMove$1(dndItems, from, to);
13792
14488
  setDndItems(newState_0);
13793
14489
  onPersist?.(newState_0);
13794
- onGroupMoved?.(activeIdNow_0, from, 0);
13795
- }
13796
- } else if (activeIdNow_0 !== overIdNow_0 && dndItems.some((g_13) => g_13.name === overIdNow_0)) {
13797
- const from_0 = dndItems.findIndex((g_11) => g_11.name === activeIdNow_0);
13798
- const to = dndItems.findIndex((g_12) => g_12.name === overIdNow_0);
13799
- if (from_0 !== -1 && to !== -1) {
13800
- const newState_1 = arrayMove$1(dndItems, from_0, to);
13801
- setDndItems(newState_1);
13802
- onPersist?.(newState_1);
13803
- onGroupMoved?.(activeIdNow_0, from_0, to);
14490
+ onGroupMoved?.(activeIdNow_0, from, to);
13804
14491
  }
13805
14492
  }
13806
14493
  } else {
13807
- const activeCont_0 = findDndContainer(activeIdNow_0);
14494
+ const findContainerInState = (id_0, state) => {
14495
+ const group_0 = state.find((g_13) => g_13.name === id_0);
14496
+ if (group_0) return group_0.name;
14497
+ for (const g_14 of state) {
14498
+ if (g_14.entries.some((e_4) => e_4.url === id_0)) return g_14.name;
14499
+ }
14500
+ return void 0;
14501
+ };
14502
+ const sourceState = preDragItemsRef.current || dndItems;
14503
+ const activeCont_0 = findContainerInState(activeIdNow_0, sourceState);
14504
+ findDndContainer(overIdNow_0);
13808
14505
  if (overIdNow_0 === "new-group-drop-zone") {
13809
14506
  if (activeCont_0) {
13810
- const newState_2 = cloneItemsForDnd(dndItems);
13811
- const srcIdx_0 = newState_2.findIndex((g_14) => g_14.name === activeCont_0);
14507
+ setStateBeforeNewGroup(cloneItemsForDnd(dndItems));
14508
+ const newState_1 = cloneItemsForDnd(dndItems);
14509
+ const srcIdx_0 = newState_1.findIndex((g_15) => g_15.name === activeCont_0);
13812
14510
  if (srcIdx_0 !== -1) {
13813
- const src_0 = newState_2[srcIdx_0];
13814
- const idxInSrc_0 = src_0.entries.findIndex((e_3) => e_3.url === activeIdNow_0);
14511
+ const src_0 = newState_1[srcIdx_0];
14512
+ const idxInSrc_0 = src_0.entries.findIndex((e_5) => e_5.url === activeIdNow_0);
13815
14513
  if (idxInSrc_0 !== -1) {
13816
14514
  const [dragged] = src_0.entries.splice(idxInSrc_0, 1);
13817
- if (src_0.entries.length === 0) newState_2.splice(srcIdx_0, 1);
14515
+ if (src_0.entries.length === 0) newState_1.splice(srcIdx_0, 1);
13818
14516
  let tentative = "New Group";
13819
14517
  let counter = 1;
13820
- while (newState_2.some((g_15) => g_15.name === tentative)) tentative = `New Group ${counter++}`;
13821
- newState_2.push({
14518
+ while (newState_1.some((g_16) => g_16.name === tentative)) tentative = `New Group ${counter++}`;
14519
+ newState_1.push({
13822
14520
  name: tentative,
13823
14521
  entries: [dragged]
13824
14522
  });
13825
- setDndItems(newState_2);
13826
- onPersist?.(newState_2);
14523
+ setDndItems(newState_1);
14524
+ setPendingNewGroupName(tentative);
13827
14525
  setDialogOpenForGroup(tentative);
13828
14526
  onNewGroupDrop?.();
13829
14527
  }
13830
14528
  }
13831
14529
  }
13832
14530
  } else {
13833
- const overCont_0 = findDndContainer(overIdNow_0);
13834
- if (activeCont_0 === overCont_0) {
13835
- const grpIdx = dndItems.findIndex((g_16) => g_16.name === activeCont_0);
14531
+ const overCont_1 = findDndContainer(overIdNow_0);
14532
+ if (activeCont_0 === overCont_1) {
14533
+ const grpIdx = dndItems.findIndex((g_17) => g_17.name === activeCont_0);
13836
14534
  if (grpIdx !== -1) {
13837
- const group_0 = dndItems[grpIdx];
13838
- const oldIdx = group_0.entries.findIndex((e_4) => e_4.url === activeIdNow_0);
13839
- let newIdx = group_0.entries.findIndex((e_5) => e_5.url === overIdNow_0);
13840
- if (newIdx === -1 && overIdNow_0 === activeCont_0) newIdx = group_0.entries.length - 1;
14535
+ const group_1 = dndItems[grpIdx];
14536
+ const oldIdx = group_1.entries.findIndex((e_6) => e_6.url === activeIdNow_0);
14537
+ let newIdx = group_1.entries.findIndex((e_7) => e_7.url === overIdNow_0);
14538
+ if (newIdx === -1 && overIdNow_0 === activeCont_0) newIdx = group_1.entries.length - 1;
13841
14539
  if (oldIdx !== -1 && newIdx !== -1 && oldIdx !== newIdx) {
13842
- const reordered = arrayMove$1(group_0.entries, oldIdx, newIdx);
13843
- const newState_3 = [...dndItems];
13844
- newState_3[grpIdx] = {
13845
- ...group_0,
14540
+ const reordered = arrayMove$1(group_1.entries, oldIdx, newIdx);
14541
+ const newState_2 = [...dndItems];
14542
+ newState_2[grpIdx] = {
14543
+ ...group_1,
13846
14544
  entries: reordered
13847
14545
  };
13848
- setDndItems(newState_3);
13849
- onPersist?.(newState_3);
14546
+ setDndItems(newState_2);
14547
+ onPersist?.(newState_2);
14548
+ }
14549
+ }
14550
+ } else if (overCont_1 && activeCont_0 !== overCont_1) {
14551
+ const finalState = cloneItemsForDnd(sourceState);
14552
+ const finalOverId = lastOverId.current || overIdNow_0;
14553
+ const cleanOverCont = findContainerInState(finalOverId, sourceState) || overCont_1;
14554
+ const srcIdx_1 = finalState.findIndex((g_18) => g_18.name === activeCont_0);
14555
+ const tgtIdx_0 = finalState.findIndex((g_19) => g_19.name === cleanOverCont);
14556
+ if (srcIdx_1 !== -1 && tgtIdx_0 !== -1) {
14557
+ const src_1 = finalState[srcIdx_1];
14558
+ const tgt_0 = finalState[tgtIdx_0];
14559
+ const idxInSrc_1 = src_1.entries.findIndex((e_8) => e_8.url === activeIdNow_0);
14560
+ if (idxInSrc_1 !== -1) {
14561
+ const [moved_0] = src_1.entries.splice(idxInSrc_1, 1);
14562
+ const overIsContainer_1 = finalOverId === cleanOverCont;
14563
+ if (overIsContainer_1) {
14564
+ tgt_0.entries.push(moved_0);
14565
+ } else {
14566
+ const overIdx_0 = tgt_0.entries.findIndex((e_9) => e_9.url === finalOverId);
14567
+ if (overIdx_0 !== -1) {
14568
+ tgt_0.entries.splice(overIdx_0, 0, moved_0);
14569
+ } else {
14570
+ tgt_0.entries.push(moved_0);
14571
+ }
14572
+ }
14573
+ if (src_1.entries.length === 0) {
14574
+ finalState.splice(srcIdx_1, 1);
14575
+ }
14576
+ setDndItems(finalState);
14577
+ onPersist?.(finalState);
14578
+ onCardMovedBetweenGroups?.(moved_0);
13850
14579
  }
13851
14580
  }
13852
- } else if (recentlyMovedToNewContainer.current && interimItemsRef.current) {
13853
- onPersist?.(interimItemsRef.current);
14581
+ } else if (recentlyMovedToNewContainer.current) {
14582
+ console.error("Move between containers detected but conditions not met", {
14583
+ activeCont: activeCont_0,
14584
+ overCont: overCont_1,
14585
+ activeIdNow: activeIdNow_0,
14586
+ overIdNow: overIdNow_0
14587
+ });
13854
14588
  }
13855
- onCardMovedBetweenGroups?.(dndItems.flatMap((g_17) => g_17.entries).find((e_6) => e_6.url === activeIdNow_0));
13856
14589
  }
13857
14590
  }
13858
14591
  resetDragState();
@@ -13865,15 +14598,13 @@ function useHomePageDnd({
13865
14598
  setIsDraggingCardOnly(false);
13866
14599
  recentlyMovedToNewContainer.current = false;
13867
14600
  };
13868
- const handleDragCancel = () => {
13869
- resetDragState();
13870
- };
14601
+ const handleDragCancel = () => resetDragState();
13871
14602
  const handleRenameGroup = (oldName, newName) => {
13872
- setDndItems((current) => {
13873
- const idx = current.findIndex((g_18) => g_18.name === oldName);
13874
- if (idx === -1) return current;
13875
- if (current.some((g_19) => g_19.name === newName && g_19.name !== oldName)) return current;
13876
- const updated = [...current];
14603
+ setDndItems((current_0) => {
14604
+ const idx = current_0.findIndex((g_20) => g_20.name === oldName);
14605
+ if (idx === -1) return current_0;
14606
+ if (current_0.some((g_21) => g_21.name === newName && g_21.name !== oldName)) return current_0;
14607
+ const updated = [...current_0];
13877
14608
  updated[idx] = {
13878
14609
  ...updated[idx],
13879
14610
  name: newName
@@ -13881,9 +14612,20 @@ function useHomePageDnd({
13881
14612
  onPersist?.(updated);
13882
14613
  return updated;
13883
14614
  });
14615
+ setPendingNewGroupName(null);
14616
+ setStateBeforeNewGroup(null);
14617
+ setDialogOpenForGroup(null);
13884
14618
  };
13885
- const activeItemForOverlay = disabled || !activeId || activeIsGroup ? null : dndItems.flatMap((g_20) => g_20.entries).find((e_7) => e_7.url === activeId) || null;
13886
- const activeGroupData = disabled || !activeId || !activeIsGroup ? null : dndItems.find((g_21) => g_21.name === activeId) || null;
14619
+ const handleDialogClose = () => {
14620
+ if (pendingNewGroupName && dialogOpenForGroup === pendingNewGroupName && stateBeforeNewGroup) {
14621
+ setDndItems(stateBeforeNewGroup);
14622
+ }
14623
+ setPendingNewGroupName(null);
14624
+ setStateBeforeNewGroup(null);
14625
+ setDialogOpenForGroup(null);
14626
+ };
14627
+ const activeItemForOverlay = disabled || !activeId || activeIsGroup ? null : dndItems.flatMap((g_22) => g_22.entries).find((e_10) => e_10.url === activeId) || null;
14628
+ const activeGroupData = disabled || !activeId || !activeIsGroup ? null : dndItems.find((g_23) => g_23.name === activeId) || null;
13887
14629
  return {
13888
14630
  sensors,
13889
14631
  collisionDetection,
@@ -13901,6 +14643,7 @@ function useHomePageDnd({
13901
14643
  dialogOpenForGroup,
13902
14644
  setDialogOpenForGroup,
13903
14645
  handleRenameGroup,
14646
+ handleDialogClose,
13904
14647
  isHoveringNewGroupDropZone,
13905
14648
  setIsHoveringNewGroupDropZone
13906
14649
  };
@@ -14001,7 +14744,7 @@ function NewGroupDropZone(t0) {
14001
14744
  return t8;
14002
14745
  }
14003
14746
  function RenameGroupDialog(t0) {
14004
- const $ = c(41);
14747
+ const $ = c(40);
14005
14748
  const {
14006
14749
  open,
14007
14750
  initialName,
@@ -14193,19 +14936,18 @@ function RenameGroupDialog(t0) {
14193
14936
  t15 = $[35];
14194
14937
  }
14195
14938
  let t16;
14196
- if ($[36] !== onClose || $[37] !== open || $[38] !== t11 || $[39] !== t15) {
14197
- t16 = /* @__PURE__ */ jsxs(Dialog, { open, onOpenChange: onClose, children: [
14939
+ if ($[36] !== open || $[37] !== t11 || $[38] !== t15) {
14940
+ t16 = /* @__PURE__ */ jsxs(Dialog, { open, children: [
14198
14941
  t6,
14199
14942
  t11,
14200
14943
  t15
14201
14944
  ] });
14202
- $[36] = onClose;
14203
- $[37] = open;
14204
- $[38] = t11;
14205
- $[39] = t15;
14206
- $[40] = t16;
14945
+ $[36] = open;
14946
+ $[37] = t11;
14947
+ $[38] = t15;
14948
+ $[39] = t16;
14207
14949
  } else {
14208
- t16 = $[40];
14950
+ t16 = $[39];
14209
14951
  }
14210
14952
  return t16;
14211
14953
  }
@@ -14279,7 +15021,7 @@ function DefaultHomePage({
14279
15021
  entries: []
14280
15022
  });
14281
15023
  }
14282
- allProcessed = allProcessed.filter((g_4) => g_4.entries.length || groupOrderFromNavController.includes(g_4.name) || g_4.name === DEFAULT_GROUP_NAME && hasPluginAdditionalCards);
15024
+ allProcessed = allProcessed.filter((g_4) => g_4.entries.length || g_4.name === DEFAULT_GROUP_NAME && hasPluginAdditionalCards);
14283
15025
  }
14284
15026
  const admin = allProcessed.find((g_5) => g_5.name === ADMIN_GROUP_NAME);
14285
15027
  return {
@@ -14305,16 +15047,11 @@ function DefaultHomePage({
14305
15047
  }] : draggable;
14306
15048
  onNavigationEntriesUpdate(all);
14307
15049
  };
14308
- const [collapsedGroups, setCollapsedGroups] = useState({});
14309
- const isGroupCollapsed = useCallback((name_0) => {
14310
- return !!collapsedGroups[name_0];
14311
- }, [collapsedGroups]);
14312
- const toggleGroupCollapsed = useCallback((name_1) => {
14313
- setCollapsedGroups((prev) => ({
14314
- ...prev,
14315
- [name_1]: !prev[name_1]
14316
- }));
14317
- }, []);
15050
+ const groupNames = useMemo(() => [...items.map((item) => item.name), ...adminGroupData ? [adminGroupData.name] : []], [items, adminGroupData]);
15051
+ const {
15052
+ isGroupCollapsed,
15053
+ toggleGroupCollapsed
15054
+ } = useCollapsedGroups(groupNames);
14318
15055
  const {
14319
15056
  sensors,
14320
15057
  collisionDetection,
@@ -14332,6 +15069,7 @@ function DefaultHomePage({
14332
15069
  dialogOpenForGroup,
14333
15070
  setDialogOpenForGroup,
14334
15071
  handleRenameGroup,
15072
+ handleDialogClose,
14335
15073
  isHoveringNewGroupDropZone,
14336
15074
  setIsHoveringNewGroupDropZone
14337
15075
  } = useHomePageDnd({
@@ -14339,22 +15077,12 @@ function DefaultHomePage({
14339
15077
  setItems: updateItems,
14340
15078
  disabled: !allowDragAndDrop || performingSearch,
14341
15079
  onPersist: persistNavigationGroups,
14342
- // ——► persistence here
14343
15080
  onGroupMoved: (g_8) => context.analyticsController?.onAnalyticsEvent?.("home_move_group", {
14344
15081
  name: g_8
14345
15082
  }),
14346
- onCardMovedBetweenGroups: (card) => {
14347
- let targetGroup = items.find((group) => group.entries.some((entry) => entry.url === card.url));
14348
- if (!targetGroup && adminGroupData?.entries.some((entry_0) => entry_0.url === card.url)) {
14349
- targetGroup = adminGroupData;
14350
- }
14351
- if (targetGroup && isGroupCollapsed(targetGroup.name)) {
14352
- toggleGroupCollapsed(targetGroup.name);
14353
- }
14354
- context.analyticsController?.onAnalyticsEvent?.("home_move_card", {
14355
- id: card.id
14356
- });
14357
- },
15083
+ onCardMovedBetweenGroups: (card) => context.analyticsController?.onAnalyticsEvent?.("home_move_card", {
15084
+ id: card.id
15085
+ }),
14358
15086
  onNewGroupDrop: () => context.analyticsController?.onAnalyticsEvent?.("home_drop_new_group")
14359
15087
  });
14360
15088
  const {
@@ -14394,7 +15122,7 @@ function DefaultHomePage({
14394
15122
  frequency: 500
14395
15123
  }
14396
15124
  }, onDragStart, onDragOver, onDragEnd, onDragCancel, modifiers: dndModifiers, children: [
14397
- /* @__PURE__ */ jsx(SortableContext, { items: containers, strategy: verticalListSortingStrategy, children: items.map((groupData) => {
15125
+ /* @__PURE__ */ jsx(SortableContext, { items: containers, strategy: verticalListSortingStrategy, children: items.map((groupData, groupIndex) => {
14398
15126
  const groupKey = groupData.name;
14399
15127
  const entriesInGroup = groupData.entries;
14400
15128
  const AdditionalCards = [];
@@ -14405,22 +15133,22 @@ function DefaultHomePage({
14405
15133
  group: groupKey === DEFAULT_GROUP_NAME ? void 0 : groupKey,
14406
15134
  context
14407
15135
  };
14408
- if (entriesInGroup.length === 0 && (AdditionalCards.length === 0 || performingSearch) && !groupOrderFromNavController.includes(groupKey)) return null;
15136
+ if (entriesInGroup.length === 0 && (AdditionalCards.length === 0 || performingSearch)) return null;
14409
15137
  return /* @__PURE__ */ jsx(SortableNavigationGroup, { groupName: groupKey, disabled: dndDisabled, children: /* @__PURE__ */ jsx(NavigationGroup, { group: groupKey === DEFAULT_GROUP_NAME ? void 0 : groupKey, minimised: draggingGroupId === groupKey && !isDraggingCardOnly, isPotentialCardDropTarget: isDraggingCardOnly, dndDisabled, onEditGroup: () => {
14410
15138
  if (dndDisabled) return;
14411
15139
  setDialogOpenForGroup(groupKey);
14412
15140
  }, collapsed: isGroupCollapsed(groupKey), onToggleCollapsed: () => toggleGroupCollapsed(groupKey), children: /* @__PURE__ */ jsx(NavigationGroupDroppable, { id: groupKey, itemIds: entriesInGroup.map((e_4) => e_4.url), isPotentialCardDropTarget: isDraggingCardOnly, children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 ", children: [
14413
- entriesInGroup.map((entry_1) => /* @__PURE__ */ jsx(SortableNavigationCard, { entry: entry_1, onClick: () => {
15141
+ entriesInGroup.map((entry) => /* @__PURE__ */ jsx(SortableNavigationCard, { entry, onClick: () => {
14414
15142
  let event = "unmapped_event";
14415
- if (entry_1.type === "collection") event = "home_navigate_to_collection";
14416
- else if (entry_1.type === "view") event = "home_navigate_to_view";
14417
- else if (entry_1.type === "admin") event = "home_navigate_to_admin_view";
15143
+ if (entry.type === "collection") event = "home_navigate_to_collection";
15144
+ else if (entry.type === "view") event = "home_navigate_to_view";
15145
+ else if (entry.type === "admin") event = "home_navigate_to_admin_view";
14418
15146
  context.analyticsController?.onAnalyticsEvent?.(event, {
14419
- path: entry_1.path
15147
+ path: entry.path
14420
15148
  });
14421
- } }, entry_1.url)),
15149
+ } }, entry.url)),
14422
15150
  !performingSearch && groupKey.toLowerCase() !== ADMIN_GROUP_NAME.toLowerCase() && AdditionalCards.map((C, i_1) => /* @__PURE__ */ jsx(C, { ...actionProps }, `extra_${groupKey}_${i_1}`))
14423
- ] }) }) }) }, groupKey);
15151
+ ] }) }) }) }, `group-${groupIndex}`);
14424
15152
  }) }, JSON.stringify(containers)),
14425
15153
  /* @__PURE__ */ jsx(NewGroupDropZone, { disabled: dndDisabled, setIsHovering: setIsHoveringNewGroupDropZone }),
14426
15154
  /* @__PURE__ */ jsx(DragOverlay, { adjustScale: false, dropAnimation, children: activeGroupData && draggingGroupId === activeGroupData.name ? /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-transparent", style: {
@@ -14428,22 +15156,21 @@ function DefaultHomePage({
14428
15156
  margin: 0
14429
15157
  }, children: /* @__PURE__ */ jsx(NavigationGroup, { group: activeGroupData.name === DEFAULT_GROUP_NAME ? void 0 : activeGroupData.name, isPreview: false, minimised: true }) }) : activeItemForOverlay ? /* @__PURE__ */ jsx(NavigationCardBinding, { ...activeItemForOverlay, shrink: isHoveringNewGroupDropZone }) : null })
14430
15158
  ] }),
14431
- !performingSearch && adminGroupData && /* @__PURE__ */ jsx(NavigationGroup, { group: adminGroupData.name, collapsed: isGroupCollapsed(adminGroupData.name), onToggleCollapsed: () => toggleGroupCollapsed(adminGroupData.name), children: /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 ", children: adminGroupData.entries.map((entry_2) => /* @__PURE__ */ jsx(NavigationCardBinding, { ...entry_2, onClick: () => {
15159
+ !performingSearch && adminGroupData && /* @__PURE__ */ jsx(NavigationGroup, { group: adminGroupData.name, collapsed: isGroupCollapsed(adminGroupData.name), onToggleCollapsed: () => toggleGroupCollapsed(adminGroupData.name), children: /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 ", children: adminGroupData.entries.map((entry_0) => /* @__PURE__ */ jsx(NavigationCardBinding, { ...entry_0, onClick: () => {
14432
15160
  let event_0 = "unmapped_event";
14433
- if (entry_2.type === "collection") event_0 = "home_navigate_to_collection";
14434
- else if (entry_2.type === "view") event_0 = "home_navigate_to_view";
14435
- else if (entry_2.type === "admin") event_0 = "home_navigate_to_admin_view";
15161
+ if (entry_0.type === "collection") event_0 = "home_navigate_to_collection";
15162
+ else if (entry_0.type === "view") event_0 = "home_navigate_to_view";
15163
+ else if (entry_0.type === "admin") event_0 = "home_navigate_to_admin_view";
14436
15164
  context.analyticsController?.onAnalyticsEvent?.(event_0, {
14437
- path: entry_2.path
15165
+ path: entry_0.path
14438
15166
  });
14439
- } }, entry_2.url)) }) }),
15167
+ } }, entry_0.url)) }) }),
14440
15168
  additionalPluginSections,
14441
15169
  additionalPluginChildrenEnd,
14442
15170
  additionalChildrenEnd
14443
15171
  ] }),
14444
- dialogOpenForGroup && /* @__PURE__ */ jsx(RenameGroupDialog, { open: true, initialName: dialogOpenForGroup, existingGroupNames: items.map((g_9) => g_9.name).filter((n) => n !== dialogOpenForGroup), onClose: () => setDialogOpenForGroup(null), onRename: (newName) => {
15172
+ dialogOpenForGroup && /* @__PURE__ */ jsx(RenameGroupDialog, { open: true, initialName: dialogOpenForGroup, existingGroupNames: items.map((g_9) => g_9.name).filter((n) => n !== dialogOpenForGroup), onClose: handleDialogClose, onRename: (newName) => {
14445
15173
  handleRenameGroup(dialogOpenForGroup, newName);
14446
- setDialogOpenForGroup(null);
14447
15174
  } })
14448
15175
  ] });
14449
15176
  }
@@ -14766,61 +15493,60 @@ function CustomIdField({
14766
15493
  ] });
14767
15494
  }
14768
15495
  const ErrorFocus = (t0) => {
14769
- const $ = c(6);
15496
+ const $ = c(10);
14770
15497
  const {
14771
15498
  containerRef
14772
15499
  } = t0;
14773
15500
  const {
14774
- isSubmitting,
14775
15501
  isValidating,
14776
- errors
15502
+ errors,
15503
+ version
14777
15504
  } = useFormex();
15505
+ const prevVersion = useRef(version);
14778
15506
  let t1;
14779
- let t2;
14780
- if ($[0] !== containerRef || $[1] !== errors || $[2] !== isSubmitting || $[3] !== isValidating) {
15507
+ if ($[0] !== containerRef?.current || $[1] !== errors || $[2] !== isValidating || $[3] !== version) {
14781
15508
  t1 = () => {
15509
+ if (version === prevVersion.current) {
15510
+ return;
15511
+ }
14782
15512
  const keys = Object.keys(errors);
14783
- if (keys.length > 0 && isSubmitting && !isValidating) {
15513
+ if (!isValidating && keys.length > 0) {
14784
15514
  const errorElement = containerRef?.current?.querySelector(`#form_field_${keys[0]}`);
14785
- if (errorElement && containerRef?.current) {
14786
- const scrollableParent = getScrollableParent(containerRef.current);
14787
- if (scrollableParent) {
14788
- const top = errorElement.getBoundingClientRect().top;
14789
- scrollableParent.scrollTo({
14790
- top: scrollableParent.scrollTop + top - 196,
14791
- behavior: "smooth"
14792
- });
14793
- }
15515
+ if (errorElement) {
15516
+ errorElement.scrollIntoView({
15517
+ behavior: "smooth",
15518
+ block: "center"
15519
+ });
14794
15520
  const input = errorElement.querySelector("input");
14795
15521
  if (input) {
14796
15522
  input.focus();
14797
15523
  }
14798
15524
  }
15525
+ prevVersion.current = version;
14799
15526
  }
14800
15527
  };
14801
- t2 = [isSubmitting, isValidating, errors, containerRef];
14802
- $[0] = containerRef;
15528
+ $[0] = containerRef?.current;
14803
15529
  $[1] = errors;
14804
- $[2] = isSubmitting;
14805
- $[3] = isValidating;
15530
+ $[2] = isValidating;
15531
+ $[3] = version;
14806
15532
  $[4] = t1;
14807
- $[5] = t2;
14808
15533
  } else {
14809
15534
  t1 = $[4];
14810
- t2 = $[5];
15535
+ }
15536
+ let t2;
15537
+ if ($[5] !== containerRef || $[6] !== errors || $[7] !== isValidating || $[8] !== version) {
15538
+ t2 = [isValidating, errors, containerRef, version];
15539
+ $[5] = containerRef;
15540
+ $[6] = errors;
15541
+ $[7] = isValidating;
15542
+ $[8] = version;
15543
+ $[9] = t2;
15544
+ } else {
15545
+ t2 = $[9];
14811
15546
  }
14812
15547
  useEffect(t1, t2);
14813
15548
  return null;
14814
15549
  };
14815
- const isScrollable = (ele) => {
14816
- const hasScrollableContent = ele && ele.scrollHeight > ele.clientHeight;
14817
- const overflowYStyle = ele ? window.getComputedStyle(ele).overflowY : null;
14818
- const isOverflowHidden = overflowYStyle && overflowYStyle.indexOf("hidden") !== -1;
14819
- return hasScrollableContent && !isOverflowHidden;
14820
- };
14821
- const getScrollableParent = (ele) => {
14822
- return !ele || ele === document.body ? document.body : isScrollable(ele) ? ele : getScrollableParent(ele.parentNode);
14823
- };
14824
15550
  function EntityFormActions(t0) {
14825
15551
  const $ = c(16);
14826
15552
  const {
@@ -14841,7 +15567,7 @@ function EntityFormActions(t0) {
14841
15567
  const context = useFireCMSContext();
14842
15568
  const sideEntityController = useSideEntityController();
14843
15569
  let t1;
14844
- if ($[0] !== collection || $[1] !== context || $[2] !== disabled || $[3] !== entity || $[4] !== formContext || $[5] !== formex.isSubmitting || $[6] !== fullIdPath || $[7] !== fullPath || $[8] !== layout || $[9] !== navigateBack || $[10] !== openEntityMode || $[11] !== pluginActions || $[12] !== savingError || $[13] !== sideEntityController || $[14] !== status) {
15570
+ if ($[0] !== collection || $[1] !== context || $[2] !== disabled || $[3] !== entity || $[4] !== formContext || $[5] !== formex || $[6] !== fullIdPath || $[7] !== fullPath || $[8] !== layout || $[9] !== navigateBack || $[10] !== openEntityMode || $[11] !== pluginActions || $[12] !== savingError || $[13] !== sideEntityController || $[14] !== status) {
14845
15571
  t1 = layout === "bottom" ? buildBottomActions$1({
14846
15572
  fullPath,
14847
15573
  fullIdPath,
@@ -14850,13 +15576,13 @@ function EntityFormActions(t0) {
14850
15576
  collection,
14851
15577
  context,
14852
15578
  sideEntityController,
14853
- isSubmitting: formex.isSubmitting,
14854
15579
  disabled,
14855
15580
  status,
14856
15581
  pluginActions,
14857
15582
  openEntityMode,
14858
15583
  navigateBack,
14859
- formContext
15584
+ formContext,
15585
+ formex
14860
15586
  }) : buildSideActions$1({
14861
15587
  fullPath,
14862
15588
  fullIdPath,
@@ -14865,18 +15591,18 @@ function EntityFormActions(t0) {
14865
15591
  collection,
14866
15592
  context,
14867
15593
  sideEntityController,
14868
- isSubmitting: formex.isSubmitting,
14869
15594
  disabled,
14870
15595
  status,
14871
15596
  pluginActions,
14872
- openEntityMode
15597
+ openEntityMode,
15598
+ formex
14873
15599
  });
14874
15600
  $[0] = collection;
14875
15601
  $[1] = context;
14876
15602
  $[2] = disabled;
14877
15603
  $[3] = entity;
14878
15604
  $[4] = formContext;
14879
- $[5] = formex.isSubmitting;
15605
+ $[5] = formex;
14880
15606
  $[6] = fullIdPath;
14881
15607
  $[7] = fullPath;
14882
15608
  $[8] = layout;
@@ -14901,14 +15627,15 @@ function buildBottomActions$1({
14901
15627
  collection,
14902
15628
  context,
14903
15629
  sideEntityController,
14904
- isSubmitting,
14905
15630
  disabled,
14906
15631
  status,
14907
15632
  pluginActions,
14908
15633
  openEntityMode,
14909
15634
  navigateBack,
14910
- formContext
15635
+ formContext,
15636
+ formex
14911
15637
  }) {
15638
+ const hasErrors = Object.keys(formex.errors).length > 0 && formex.submitCount > 0;
14912
15639
  return /* @__PURE__ */ jsxs(DialogActions, { position: "absolute", children: [
14913
15640
  savingError && /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Typography, { color: "error", children: savingError.message }) }),
14914
15641
  entity && (formActions ?? []).length > 0 && /* @__PURE__ */ jsx("div", { className: "flex-grow flex overflow-auto no-scrollbar", children: (formActions ?? []).map((action) => /* @__PURE__ */ jsx(IconButton, { color: "primary", onClick: (event) => {
@@ -14927,39 +15654,361 @@ function buildBottomActions$1({
14927
15654
  });
14928
15655
  }, children: action.icon }, action.name)) }),
14929
15656
  pluginActions,
14930
- /* @__PURE__ */ jsx(Button, { variant: "text", disabled: disabled || isSubmitting, color: "primary", type: "reset", children: status === "existing" ? "Discard" : "Clear" }),
14931
- /* @__PURE__ */ jsxs(Button, { variant: "filled", color: "primary", type: "submit", disabled: disabled || isSubmitting, children: [
15657
+ /* @__PURE__ */ jsx(Button, { variant: "text", disabled: disabled || formex.isSubmitting, color: "primary", type: "reset", children: status === "existing" ? "Discard" : "Clear" }),
15658
+ /* @__PURE__ */ jsxs(Button, { variant: "filled", color: "primary", type: "submit", disabled: disabled || formex.isSubmitting, startIcon: hasErrors ? /* @__PURE__ */ jsx(ErrorIcon, {}) : void 0, children: [
14932
15659
  status === "existing" && "Save",
14933
15660
  status === "copy" && "Create copy",
14934
15661
  status === "new" && "Create"
14935
15662
  ] })
14936
15663
  ] });
14937
15664
  }
14938
- function buildSideActions$1({
14939
- savingError,
14940
- entity,
14941
- formActions,
14942
- fullPath,
14943
- fullIdPath,
14944
- openEntityMode,
14945
- collection,
14946
- context,
14947
- sideEntityController,
14948
- isSubmitting,
14949
- disabled,
14950
- status,
14951
- pluginActions
14952
- }) {
14953
- return /* @__PURE__ */ jsxs("div", { className: cls("overflow-auto h-full flex flex-col gap-2 w-80 2xl:w-96 px-4 py-16 sticky top-0 border-l", defaultBorderMixin), children: [
14954
- /* @__PURE__ */ jsxs(LoadingButton, { fullWidth: true, variant: "filled", color: "primary", type: "submit", size: "large", disabled: disabled || isSubmitting, children: [
14955
- status === "existing" && "Save",
14956
- status === "copy" && "Create copy",
14957
- status === "new" && "Create"
14958
- ] }),
14959
- /* @__PURE__ */ jsx(Button, { fullWidth: true, variant: "text", disabled: disabled || isSubmitting, type: "reset", children: status === "existing" ? "Discard" : "Clear" }),
14960
- pluginActions,
14961
- savingError && /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Typography, { color: "error", children: savingError.message }) })
14962
- ] });
15665
+ function buildSideActions$1({
15666
+ savingError,
15667
+ entity,
15668
+ formActions,
15669
+ fullPath,
15670
+ fullIdPath,
15671
+ openEntityMode,
15672
+ collection,
15673
+ context,
15674
+ sideEntityController,
15675
+ disabled,
15676
+ status,
15677
+ pluginActions,
15678
+ formex
15679
+ }) {
15680
+ const hasErrors = Object.keys(formex.errors).length > 0 && formex.submitCount > 0;
15681
+ return /* @__PURE__ */ jsxs("div", { className: cls("overflow-auto h-full flex flex-col gap-2 w-80 2xl:w-96 px-4 py-16 sticky top-0 border-l", defaultBorderMixin), children: [
15682
+ /* @__PURE__ */ jsxs(LoadingButton, { fullWidth: true, variant: "filled", color: "primary", type: "submit", size: "large", startIcon: hasErrors ? /* @__PURE__ */ jsx(ErrorIcon, {}) : void 0, disabled: disabled || formex.isSubmitting, children: [
15683
+ status === "existing" && "Save",
15684
+ status === "copy" && "Create copy",
15685
+ status === "new" && "Create"
15686
+ ] }),
15687
+ /* @__PURE__ */ jsx(Button, { fullWidth: true, variant: "text", disabled: disabled || formex.isSubmitting, type: "reset", children: status === "existing" ? "Discard" : "Clear" }),
15688
+ pluginActions,
15689
+ savingError && /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Typography, { color: "error", children: savingError.message }) })
15690
+ ] });
15691
+ }
15692
+ function LocalChangesMenu(t0) {
15693
+ const $ = c(42);
15694
+ const {
15695
+ localChangesData,
15696
+ formex,
15697
+ onClearLocalChanges,
15698
+ cacheKey,
15699
+ properties
15700
+ } = t0;
15701
+ const snackbarController = useSnackbarController();
15702
+ const [previewDialogOpen, setPreviewDialogOpen] = useState(false);
15703
+ const [open, setOpen] = useState(false);
15704
+ let t1;
15705
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
15706
+ t1 = () => setOpen(true);
15707
+ $[0] = t1;
15708
+ } else {
15709
+ t1 = $[0];
15710
+ }
15711
+ const handleOpenMenu = t1;
15712
+ let t2;
15713
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
15714
+ t2 = () => setOpen(false);
15715
+ $[1] = t2;
15716
+ } else {
15717
+ t2 = $[1];
15718
+ }
15719
+ const handleCloseMenu = t2;
15720
+ let t3;
15721
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
15722
+ t3 = () => {
15723
+ setPreviewDialogOpen(true);
15724
+ handleCloseMenu();
15725
+ };
15726
+ $[2] = t3;
15727
+ } else {
15728
+ t3 = $[2];
15729
+ }
15730
+ const handlePreview = t3;
15731
+ let t4;
15732
+ if ($[3] !== formex || $[4] !== localChangesData || $[5] !== onClearLocalChanges || $[6] !== snackbarController) {
15733
+ t4 = () => {
15734
+ const mergedValues = mergeDeep(formex.values, localChangesData);
15735
+ const touched = {
15736
+ ...formex.touched
15737
+ };
15738
+ const previewKeys = flattenKeys(localChangesData);
15739
+ previewKeys.forEach((key) => {
15740
+ touched[key] = true;
15741
+ });
15742
+ formex.setTouched(touched);
15743
+ formex.setValues(mergedValues);
15744
+ snackbarController.open({
15745
+ type: "info",
15746
+ message: "Local changes applied to the form"
15747
+ });
15748
+ handleCloseMenu();
15749
+ onClearLocalChanges?.();
15750
+ };
15751
+ $[3] = formex;
15752
+ $[4] = localChangesData;
15753
+ $[5] = onClearLocalChanges;
15754
+ $[6] = snackbarController;
15755
+ $[7] = t4;
15756
+ } else {
15757
+ t4 = $[7];
15758
+ }
15759
+ const handleApply = t4;
15760
+ let t5;
15761
+ if ($[8] !== cacheKey || $[9] !== onClearLocalChanges || $[10] !== snackbarController) {
15762
+ t5 = () => {
15763
+ removeEntityFromCache(cacheKey);
15764
+ snackbarController.open({
15765
+ type: "info",
15766
+ message: "Local changes discarded"
15767
+ });
15768
+ handleCloseMenu();
15769
+ onClearLocalChanges?.();
15770
+ };
15771
+ $[8] = cacheKey;
15772
+ $[9] = onClearLocalChanges;
15773
+ $[10] = snackbarController;
15774
+ $[11] = t5;
15775
+ } else {
15776
+ t5 = $[11];
15777
+ }
15778
+ const handleDiscard = t5;
15779
+ let t6;
15780
+ if ($[12] === Symbol.for("react.memo_cache_sentinel")) {
15781
+ t6 = /* @__PURE__ */ jsx(WarningIcon, { size: "smallest", className: "mr-1 text-yellow-600 dark:text-yellow-400" });
15782
+ $[12] = t6;
15783
+ } else {
15784
+ t6 = $[12];
15785
+ }
15786
+ let t7;
15787
+ if ($[13] === Symbol.for("react.memo_cache_sentinel")) {
15788
+ t7 = /* @__PURE__ */ jsxs(Button, { size: "small", className: "font-semibold text-xs rounded-full px-4 py-1 bg-yellow-200 dark:bg-yellow-900 hover:bg-yellow-300 dark:hover:bg-yellow-800 text-yellow-800 dark:text-yellow-200", onClick: handleOpenMenu, children: [
15789
+ t6,
15790
+ "Unsaved Local changes",
15791
+ /* @__PURE__ */ jsx(KeyboardArrowDownIcon, { size: "smallest" })
15792
+ ] });
15793
+ $[13] = t7;
15794
+ } else {
15795
+ t7 = $[13];
15796
+ }
15797
+ let t8;
15798
+ if ($[14] === Symbol.for("react.memo_cache_sentinel")) {
15799
+ t8 = /* @__PURE__ */ jsx("div", { className: "max-w-xs px-4 py-4 text-sm text-gray-700 dark:text-gray-300", children: "This document was edited locally and has unsaved changes. These local changes will be lost if you don't apply them." });
15800
+ $[14] = t8;
15801
+ } else {
15802
+ t8 = $[14];
15803
+ }
15804
+ let t9;
15805
+ if ($[15] === Symbol.for("react.memo_cache_sentinel")) {
15806
+ t9 = /* @__PURE__ */ jsxs(MenuItem, { dense: true, onClick: handlePreview, children: [
15807
+ /* @__PURE__ */ jsx(VisibilityIcon, { size: "small" }),
15808
+ "Preview Changes"
15809
+ ] });
15810
+ $[15] = t9;
15811
+ } else {
15812
+ t9 = $[15];
15813
+ }
15814
+ let t10;
15815
+ if ($[16] === Symbol.for("react.memo_cache_sentinel")) {
15816
+ t10 = /* @__PURE__ */ jsx(CheckIcon, { size: "small" });
15817
+ $[16] = t10;
15818
+ } else {
15819
+ t10 = $[16];
15820
+ }
15821
+ let t11;
15822
+ if ($[17] !== handleApply) {
15823
+ t11 = /* @__PURE__ */ jsxs(MenuItem, { dense: true, onClick: handleApply, children: [
15824
+ t10,
15825
+ "Apply Changes"
15826
+ ] });
15827
+ $[17] = handleApply;
15828
+ $[18] = t11;
15829
+ } else {
15830
+ t11 = $[18];
15831
+ }
15832
+ let t12;
15833
+ if ($[19] === Symbol.for("react.memo_cache_sentinel")) {
15834
+ t12 = /* @__PURE__ */ jsx(CancelIcon, { size: "small" });
15835
+ $[19] = t12;
15836
+ } else {
15837
+ t12 = $[19];
15838
+ }
15839
+ let t13;
15840
+ if ($[20] !== handleDiscard) {
15841
+ t13 = /* @__PURE__ */ jsxs(MenuItem, { dense: true, onClick: handleDiscard, children: [
15842
+ t12,
15843
+ "Discard Local Changes"
15844
+ ] });
15845
+ $[20] = handleDiscard;
15846
+ $[21] = t13;
15847
+ } else {
15848
+ t13 = $[21];
15849
+ }
15850
+ let t14;
15851
+ if ($[22] !== open || $[23] !== t11 || $[24] !== t13) {
15852
+ t14 = /* @__PURE__ */ jsxs(Menu, { trigger: t7, open, onOpenChange: setOpen, children: [
15853
+ t8,
15854
+ t9,
15855
+ t11,
15856
+ t13
15857
+ ] });
15858
+ $[22] = open;
15859
+ $[23] = t11;
15860
+ $[24] = t13;
15861
+ $[25] = t14;
15862
+ } else {
15863
+ t14 = $[25];
15864
+ }
15865
+ let t15;
15866
+ if ($[26] === Symbol.for("react.memo_cache_sentinel")) {
15867
+ t15 = /* @__PURE__ */ jsx(DialogTitle, { variant: "h6", children: "Preview Local Changes" });
15868
+ $[26] = t15;
15869
+ } else {
15870
+ t15 = $[26];
15871
+ }
15872
+ let t16;
15873
+ if ($[27] === Symbol.for("react.memo_cache_sentinel")) {
15874
+ t16 = /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "mb-4", children: "These are the local changes that will be applied to the form." });
15875
+ $[27] = t16;
15876
+ } else {
15877
+ t16 = $[27];
15878
+ }
15879
+ let t17;
15880
+ if ($[28] === Symbol.for("react.memo_cache_sentinel")) {
15881
+ t17 = {
15882
+ maxHeight: 520,
15883
+ overflow: "auto"
15884
+ };
15885
+ $[28] = t17;
15886
+ } else {
15887
+ t17 = $[28];
15888
+ }
15889
+ const t18 = properties;
15890
+ let t19;
15891
+ if ($[29] !== localChangesData || $[30] !== t18) {
15892
+ t19 = /* @__PURE__ */ jsxs(DialogContent, { className: "my-4", children: [
15893
+ t16,
15894
+ /* @__PURE__ */ jsx("div", { className: `border rounded-lg ${defaultBorderMixin}`, style: t17, children: /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx(PropertyCollectionView, { data: localChangesData, properties: t18 }) }) })
15895
+ ] });
15896
+ $[29] = localChangesData;
15897
+ $[30] = t18;
15898
+ $[31] = t19;
15899
+ } else {
15900
+ t19 = $[31];
15901
+ }
15902
+ let t20;
15903
+ if ($[32] === Symbol.for("react.memo_cache_sentinel")) {
15904
+ t20 = /* @__PURE__ */ jsx(Button, { onClick: () => setPreviewDialogOpen(false), children: "Close" });
15905
+ $[32] = t20;
15906
+ } else {
15907
+ t20 = $[32];
15908
+ }
15909
+ let t21;
15910
+ if ($[33] !== handleApply) {
15911
+ t21 = /* @__PURE__ */ jsxs(DialogActions, { children: [
15912
+ t20,
15913
+ /* @__PURE__ */ jsx(Button, { variant: "filled", onClick: () => {
15914
+ handleApply();
15915
+ setPreviewDialogOpen(false);
15916
+ }, children: "Apply changes" })
15917
+ ] });
15918
+ $[33] = handleApply;
15919
+ $[34] = t21;
15920
+ } else {
15921
+ t21 = $[34];
15922
+ }
15923
+ let t22;
15924
+ if ($[35] !== previewDialogOpen || $[36] !== t19 || $[37] !== t21) {
15925
+ t22 = /* @__PURE__ */ jsxs(Dialog, { open: previewDialogOpen, onOpenChange: setPreviewDialogOpen, maxWidth: "4xl", children: [
15926
+ t15,
15927
+ t19,
15928
+ t21
15929
+ ] });
15930
+ $[35] = previewDialogOpen;
15931
+ $[36] = t19;
15932
+ $[37] = t21;
15933
+ $[38] = t22;
15934
+ } else {
15935
+ t22 = $[38];
15936
+ }
15937
+ let t23;
15938
+ if ($[39] !== t14 || $[40] !== t22) {
15939
+ t23 = /* @__PURE__ */ jsxs(Fragment, { children: [
15940
+ t14,
15941
+ t22
15942
+ ] });
15943
+ $[39] = t14;
15944
+ $[40] = t22;
15945
+ $[41] = t23;
15946
+ } else {
15947
+ t23 = $[41];
15948
+ }
15949
+ return t23;
15950
+ }
15951
+ function extractTouchedValues(values, touched) {
15952
+ let acc = {};
15953
+ if (!touched || typeof touched !== "object") {
15954
+ return acc;
15955
+ }
15956
+ Object.entries(touched).forEach(([key, value]) => {
15957
+ if (value) {
15958
+ acc = setIn(acc, key, getIn(values, key));
15959
+ }
15960
+ });
15961
+ return acc;
15962
+ }
15963
+ function getChanges(source, comparison) {
15964
+ const changes = {};
15965
+ if (!source) {
15966
+ return {};
15967
+ }
15968
+ if (!comparison) {
15969
+ return source;
15970
+ }
15971
+ const allKeys = Array.from(/* @__PURE__ */ new Set([...Object.keys(source), ...Object.keys(comparison)]));
15972
+ for (const key of allKeys) {
15973
+ const sourceValue = source[key];
15974
+ const comparisonValue = comparison[key];
15975
+ if (equal(sourceValue, comparisonValue)) {
15976
+ continue;
15977
+ }
15978
+ const sourceHasKey = source && typeof source === "object" && Object.prototype.hasOwnProperty.call(source, key);
15979
+ const comparisonHasKey = comparison && typeof comparison === "object" && Object.prototype.hasOwnProperty.call(comparison, key);
15980
+ if (comparisonHasKey && !sourceHasKey) {
15981
+ changes[key] = void 0;
15982
+ } else if (Array.isArray(sourceValue)) {
15983
+ const comparisonArray = Array.isArray(comparisonValue) ? comparisonValue : [];
15984
+ if (sourceValue.length < comparisonArray.length) {
15985
+ changes[key] = sourceValue;
15986
+ continue;
15987
+ }
15988
+ const changedArray = sourceValue.map((item, index) => {
15989
+ const comparisonItem = comparisonArray[index];
15990
+ if (equal(item, comparisonItem)) {
15991
+ return null;
15992
+ }
15993
+ if (isObject(item) && item && isObject(comparisonItem) && comparisonItem) {
15994
+ const nestedChanges = getChanges(item, comparisonItem);
15995
+ return Object.keys(nestedChanges).length > 0 ? nestedChanges : item;
15996
+ }
15997
+ return item;
15998
+ });
15999
+ if (changedArray.some((item) => item !== null) || sourceValue.length > comparisonArray.length) {
16000
+ changes[key] = changedArray;
16001
+ }
16002
+ } else if (isObject(sourceValue) && sourceValue && isObject(comparisonValue) && comparisonValue) {
16003
+ const nestedChanges = getChanges(sourceValue, comparisonValue);
16004
+ if (Object.keys(nestedChanges).length > 0) {
16005
+ changes[key] = nestedChanges;
16006
+ }
16007
+ } else {
16008
+ changes[key] = sourceValue;
16009
+ }
16010
+ }
16011
+ return changes;
14963
16012
  }
14964
16013
  function EntityForm({
14965
16014
  path,
@@ -15018,7 +16067,7 @@ function EntityForm({
15018
16067
  const customizationController = useCustomizationController();
15019
16068
  const context = useFireCMSContext();
15020
16069
  const analyticsController = useAnalyticsController();
15021
- const [underlyingChanges, setUnderlyingChanges] = useState({});
16070
+ const [underlyingChanges] = useState({});
15022
16071
  const [customIdLoading, setCustomIdLoading] = useState(false);
15023
16072
  const mustSetCustomId = (status === "new" || status === "copy") && Boolean(collection.customId) && collection.customId !== "optional";
15024
16073
  const initialEntityId = useMemo(() => {
@@ -15036,6 +16085,12 @@ function EntityForm({
15036
16085
  const [entityIdError, setEntityIdError] = useState(false);
15037
16086
  const [savingError, setSavingError] = useState();
15038
16087
  const autoSave = collection.formAutoSave && !collection.customId;
16088
+ const baseInitialValues = useMemo(() => getInitialEntityValues(authController, collection, path, status, entity, customizationController.propertyConfigs), [authController, collection, path, status, entity, customizationController.propertyConfigs]);
16089
+ const localChangesDataRaw = useMemo(() => entityId ? getEntityFromCache(path + "/" + entityId) : getEntityFromCache(path + "#new"), [entityId, path]);
16090
+ const [localChangesCleared, setLocalChangesCleared] = useState(false);
16091
+ const localChangesBackup = getLocalChangesBackup(collection);
16092
+ const autoApplyLocalChanges = localChangesBackup === "auto_apply";
16093
+ const manualApplyLocalChanges = localChangesBackup === "manual_apply";
15039
16094
  const onSubmit = (values, formexController) => {
15040
16095
  if (mustSetCustomId && !entityId) {
15041
16096
  console.error("Missing custom Id");
@@ -15066,16 +16121,40 @@ function EntityForm({
15066
16121
  formexController.setSubmitting(false);
15067
16122
  });
15068
16123
  };
16124
+ const [initialValues_0, initialDirty_0] = useMemo(() => {
16125
+ const initialValuesWithLocalChanges = autoApplyLocalChanges && localChangesDataRaw ? mergeDeep(baseInitialValues, localChangesDataRaw) : baseInitialValues;
16126
+ const initialValues = initialDirtyValues ? mergeDeep(initialValuesWithLocalChanges, initialDirtyValues) : initialValuesWithLocalChanges;
16127
+ const initialDirty = Boolean(initialDirtyValues) && initialDirtyValues && Object.keys(initialDirtyValues).length > 0;
16128
+ return [initialValues, initialDirty];
16129
+ }, [autoApplyLocalChanges, localChangesDataRaw, baseInitialValues, initialDirtyValues]);
16130
+ const localChangesData = useMemo(() => {
16131
+ if (!localChangesDataRaw) {
16132
+ return void 0;
16133
+ }
16134
+ return getChanges(localChangesDataRaw, initialValues_0);
16135
+ }, [localChangesDataRaw, initialValues_0]);
16136
+ const hasLocalChanges = !localChangesCleared && localChangesData && Object.keys(localChangesData).length > 0;
15069
16137
  const formex = formexProp ?? useCreateFormex({
15070
- initialValues: initialDirtyValues ?? getInitialEntityValues(authController, collection, path, status, entity, customizationController.propertyConfigs),
15071
- initialDirty: Boolean(initialDirtyValues),
16138
+ initialValues: initialValues_0,
16139
+ initialDirty: initialDirty_0,
16140
+ initialTouched: initialDirtyValues ? flattenKeys(initialDirtyValues).reduce((previousValue, currentValue) => ({
16141
+ ...previousValue,
16142
+ [currentValue]: true
16143
+ }), {}) : {},
15072
16144
  onSubmit,
15073
16145
  onReset: () => {
15074
16146
  clearDirtyCache();
15075
- onValuesModified?.(false);
16147
+ onValuesModified?.(false, initialValues_0);
15076
16148
  },
15077
- validation: (values_0) => {
15078
- return validationSchema?.validate(values_0, {
16149
+ onValuesChangeDeferred: (values_0, controller) => {
16150
+ const key = status === "new" || status === "copy" ? path + "#new" : path + "/" + entityId;
16151
+ if (controller.dirty) {
16152
+ const touchedValues = extractTouchedValues(values_0, controller.touched);
16153
+ saveEntityToCache(key, touchedValues);
16154
+ }
16155
+ },
16156
+ validation: (values_1) => {
16157
+ return validationSchema?.validate(values_1, {
15079
16158
  abortEarly: false
15080
16159
  }).then(() => {
15081
16160
  return {};
@@ -15124,14 +16203,16 @@ function EntityForm({
15124
16203
  }, [snackbarController]);
15125
16204
  function clearDirtyCache() {
15126
16205
  if (status === "new" || status === "copy") {
16206
+ removeEntityFromMemoryCache(path + "#new");
15127
16207
  removeEntityFromCache(path + "#new");
15128
16208
  } else {
16209
+ removeEntityFromMemoryCache(path + "/" + entityId);
15129
16210
  removeEntityFromCache(path + "/" + entityId);
15130
16211
  }
15131
16212
  }
15132
16213
  const onSaveSuccess = (updatedEntity) => {
15133
16214
  clearDirtyCache();
15134
- onValuesModified?.(false);
16215
+ onValuesModified?.(false, updatedEntity.values);
15135
16216
  if (!autoSave) snackbarController.open({
15136
16217
  type: "success",
15137
16218
  message: `${collection.singularName ?? collection.name}: Saved correctly`
@@ -15158,7 +16239,7 @@ function EntityForm({
15158
16239
  console.error(e_3);
15159
16240
  }, [entityId, path, snackbarController]);
15160
16241
  const saveEntity = ({
15161
- values: values_1,
16242
+ values: values_2,
15162
16243
  previousValues,
15163
16244
  entityId: entityId_0,
15164
16245
  collection: collection_0,
@@ -15167,7 +16248,7 @@ function EntityForm({
15167
16248
  return saveEntityWithCallbacks({
15168
16249
  path: path_0,
15169
16250
  entityId: entityId_0,
15170
- values: values_1,
16251
+ values: values_2,
15171
16252
  previousValues,
15172
16253
  collection: collection_0,
15173
16254
  status,
@@ -15183,34 +16264,34 @@ function EntityForm({
15183
16264
  collection: collection_1,
15184
16265
  path: path_1,
15185
16266
  entityId: entityId_1,
15186
- values: values_2,
16267
+ values: values_3,
15187
16268
  previousValues: previousValues_0,
15188
16269
  autoSave: autoSave_0
15189
16270
  }) => {
15190
16271
  if (!status) return;
15191
16272
  if (autoSave_0) {
15192
- setValuesToBeSaved(values_2);
16273
+ setValuesToBeSaved(values_3);
15193
16274
  } else {
15194
16275
  return saveEntity({
15195
16276
  collection: collection_1,
15196
16277
  path: path_1,
15197
16278
  entityId: entityId_1,
15198
- values: values_2,
16279
+ values: values_3,
15199
16280
  previousValues: previousValues_0
15200
16281
  });
15201
16282
  }
15202
16283
  };
15203
16284
  const lastSavedValues = useRef(entity?.values);
15204
- const save = (values_3) => {
15205
- lastSavedValues.current = values_3;
16285
+ const save = (values_4) => {
16286
+ lastSavedValues.current = values_4;
15206
16287
  return onSaveEntityRequest({
15207
16288
  collection: resolvedCollection,
15208
16289
  path,
15209
16290
  entityId,
15210
- values: values_3,
16291
+ values: values_4,
15211
16292
  previousValues: entity?.values,
15212
16293
  autoSave: autoSave ?? false
15213
- }).then((res) => {
16294
+ }).then(() => {
15214
16295
  const eventName = status === "new" ? "new_entity_saved" : status === "copy" ? "entity_copied" : status === "existing" ? "entity_edited" : "unmapped_event";
15215
16296
  analyticsController.onAnalyticsEvent?.(eventName, {
15216
16297
  path
@@ -15244,7 +16325,8 @@ function EntityForm({
15244
16325
  type: "error",
15245
16326
  message: "Error updating id, check the console"
15246
16327
  });
15247
- }, []);
16328
+ console.error(error);
16329
+ }, [snackbarController]);
15248
16330
  const pluginActions = [];
15249
16331
  const plugins = customizationController.plugins;
15250
16332
  const actionsDisabled = disabled || formex.isSubmitting || status === "existing" && !formex.dirty || Boolean(disabledProp);
@@ -15290,23 +16372,15 @@ function EntityForm({
15290
16372
  }, [doOnIdUpdate]);
15291
16373
  useEffect(() => {
15292
16374
  if (!autoSave) {
15293
- onValuesModified?.(modified);
16375
+ onValuesModified?.(modified, formex.values);
15294
16376
  }
15295
16377
  }, [formex.dirty]);
15296
- const deferredValues = useDeferredValue(formex.values);
15297
16378
  const modified = formex.dirty;
15298
16379
  const uniqueFieldValidator = useCallback(({
15299
16380
  name,
15300
- value,
15301
- property
16381
+ value
15302
16382
  }) => dataSource.checkUniqueField(path, name, value, entityId, collection), [dataSource, path, entityId]);
15303
16383
  const validationSchema = useMemo(() => entityId ? getYupEntitySchema(entityId, resolvedCollection.properties, uniqueFieldValidator) : void 0, [entityId, resolvedCollection.properties, uniqueFieldValidator]);
15304
- useEffect(() => {
15305
- const key = status === "new" || status === "copy" ? path + "#new" : path + "/" + entityId;
15306
- if (modified) {
15307
- saveEntityToCache(key, deferredValues);
15308
- }
15309
- }, [deferredValues, modified, path, entityId, status]);
15310
16384
  useOnAutoSave(autoSave, formex, lastSavedValues, save);
15311
16385
  useEffect(() => {
15312
16386
  if (!autoSave && !formex.isSubmitting && underlyingChanges && entity) {
@@ -15325,18 +16399,18 @@ function EntityForm({
15325
16399
  return /* @__PURE__ */ jsx(Builder, { collection, entity, modifiedValues: formex.values, formContext });
15326
16400
  }
15327
16401
  return /* @__PURE__ */ jsx(FormLayout, { children: formFieldKeys.map((key_1) => {
15328
- const property_0 = resolvedCollection.properties[key_1];
15329
- if (property_0) {
16402
+ const property = resolvedCollection.properties[key_1];
16403
+ if (property) {
15330
16404
  const underlyingValueHasChanged = !!underlyingChanges && Object.keys(underlyingChanges).includes(key_1) && formex.touched[key_1];
15331
- const disabled_0 = disabledProp || !autoSave && formex.isSubmitting || isReadOnly(property_0) || Boolean(property_0.disabled);
15332
- const hidden = isHidden(property_0);
16405
+ const disabled_0 = disabledProp || !autoSave && formex.isSubmitting || isReadOnly(property) || Boolean(property.disabled);
16406
+ const hidden = isHidden(property);
15333
16407
  if (hidden) return null;
15334
- const widthPercentage = property_0.widthPercentage ?? 100;
16408
+ const widthPercentage = property.widthPercentage ?? 100;
15335
16409
  const cmsFormFieldProps = {
15336
16410
  propertyKey: key_1,
15337
16411
  disabled: disabled_0,
15338
- property: property_0,
15339
- includeDescription: property_0.description || property_0.longDescription,
16412
+ property,
16413
+ includeDescription: property.description || property.longDescription,
15340
16414
  underlyingValueHasChanged: underlyingValueHasChanged && !autoSave,
15341
16415
  context: formContext,
15342
16416
  partOfArray: false,
@@ -15392,10 +16466,13 @@ function EntityForm({
15392
16466
  }
15393
16467
  const dialogActions = /* @__PURE__ */ jsx(EntityFormActionsComponent, { collection: resolvedCollection, path, fullPath: path, fullIdPath, entity, layout: forceActionsAtTheBottom ? "bottom" : "side", savingError, formex, disabled: actionsDisabled, status, pluginActions: pluginActions ?? [], openEntityMode, showDefaultActions, navigateBack, formContext });
15394
16468
  return /* @__PURE__ */ jsx(Formex, { value: formex, children: /* @__PURE__ */ jsxs("form", { onSubmit: formex.handleSubmit, onReset: () => formex.resetForm({
15395
- values: getInitialEntityValues(authController, collection, path, status, entity, customizationController.propertyConfigs)
16469
+ values: baseInitialValues
15396
16470
  }), noValidate: true, className: cls("flex-1 flex flex-row w-full overflow-y-auto justify-center", className), children: [
15397
16471
  /* @__PURE__ */ jsx("div", { id: `form_${path}`, className: cls("relative flex flex-row max-w-4xl lg:max-w-3xl xl:max-w-4xl 2xl:max-w-6xl w-full h-fit"), children: /* @__PURE__ */ jsxs("div", { className: cls("flex flex-col w-full pt-12 pb-16 px-4 sm:px-8 md:px-10"), children: [
15398
- formex.dirty ? /* @__PURE__ */ jsx(Tooltip, { title: "Local unsaved changes", className: "self-end sticky top-4 z-10", children: /* @__PURE__ */ jsx(Chip, { size: "small", colorScheme: "orangeDarker", children: /* @__PURE__ */ jsx(EditIcon, { size: "smallest" }) }) }) : /* @__PURE__ */ jsx(Tooltip, { title: "In sync with the database", className: "self-end sticky top-4 z-10", children: /* @__PURE__ */ jsx(Chip, { size: "small", children: /* @__PURE__ */ jsx(CheckIcon, { size: "smallest" }) }) }),
16472
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-row gap-4 self-end sticky top-4 z-10", children: [
16473
+ manualApplyLocalChanges && hasLocalChanges && /* @__PURE__ */ jsx(LocalChangesMenu, { cacheKey: status === "new" || status === "copy" ? path + "#new" : path + "/" + entityId, properties: resolvedCollection.properties, localChangesData, formex, onClearLocalChanges: () => setLocalChangesCleared(true) }),
16474
+ formex.dirty ? /* @__PURE__ */ jsx(Tooltip, { title: "There are local unsaved changes", children: /* @__PURE__ */ jsx(Chip, { size: "small", className: "py-1", colorScheme: "orangeDarker", children: /* @__PURE__ */ jsx(EditIcon, { size: "smallest" }) }) }) : /* @__PURE__ */ jsx(Tooltip, { title: "The current form is in sync with the database", children: /* @__PURE__ */ jsx(Chip, { size: "small", className: "py-1", children: /* @__PURE__ */ jsx(CheckIcon, { size: "smallest" }) }) })
16475
+ ] }),
15399
16476
  formView
15400
16477
  ] }) }),
15401
16478
  dialogActions
@@ -16115,7 +17192,7 @@ function StorageItemPreview(t0) {
16115
17192
  }
16116
17193
  let t5;
16117
17194
  if ($[14] !== placeholder) {
16118
- t5 = placeholder && /* @__PURE__ */ jsx("div", { onClick: _temp$b, className: "flex flex-col items-center justify-center w-full h-full", children: /* @__PURE__ */ jsx(DescriptionIcon, { className: "text-surface-700 dark:text-surface-300" }) });
17195
+ t5 = placeholder && /* @__PURE__ */ jsx("div", { onClick: _temp$c, className: "flex flex-col items-center justify-center w-full h-full", children: /* @__PURE__ */ jsx(DescriptionIcon, { className: "text-surface-700 dark:text-surface-300" }) });
16119
17196
  $[14] = placeholder;
16120
17197
  $[15] = t5;
16121
17198
  } else {
@@ -16138,7 +17215,7 @@ function StorageItemPreview(t0) {
16138
17215
  }
16139
17216
  return t6;
16140
17217
  }
16141
- function _temp$b(e) {
17218
+ function _temp$c(e) {
16142
17219
  return e.stopPropagation();
16143
17220
  }
16144
17221
  const dropZoneClasses = "box-border relative pt-[2px] items-center border border-transparent min-h-[254px] outline-none rounded-md duration-200 ease-[cubic-bezier(0.4,0,0.2,1)] focus:border-primary-solid";
@@ -16356,7 +17433,7 @@ function SortableStorageItem(t0) {
16356
17433
  t4 = $[7];
16357
17434
  }
16358
17435
  const style = t4;
16359
- const getImageSizeNumber = _temp$a;
17436
+ const getImageSizeNumber = _temp$b;
16360
17437
  let child;
16361
17438
  if (entry.storagePathOrDownloadUrl) {
16362
17439
  const t52 = `storage_preview_${entry.storagePathOrDownloadUrl}`;
@@ -16431,7 +17508,7 @@ function SortableStorageItem(t0) {
16431
17508
  }
16432
17509
  return t6;
16433
17510
  }
16434
- function _temp$a(previewSize) {
17511
+ function _temp$b(previewSize) {
16435
17512
  switch (previewSize) {
16436
17513
  case "small": {
16437
17514
  return 40;
@@ -17576,6 +18653,13 @@ function PropertyFieldBindingInternal(t0) {
17576
18653
  } = t0;
17577
18654
  const authController = useAuthController();
17578
18655
  const customizationController = useCustomizationController();
18656
+ if (propertyKey === "created_by") {
18657
+ console.log("Rendering field for created_by", {
18658
+ propertyKey,
18659
+ property,
18660
+ context
18661
+ });
18662
+ }
17579
18663
  let t1;
17580
18664
  if ($[0] !== authController || $[1] !== autoFocus || $[2] !== context || $[3] !== customizationController.propertyConfigs || $[4] !== disabledProp || $[5] !== includeDescription || $[6] !== index || $[7] !== minimalistView || $[8] !== onPropertyChange || $[9] !== partOfArray || $[10] !== property || $[11] !== propertyKey || $[12] !== size || $[13] !== underlyingValueHasChanged) {
17581
18665
  t1 = (fieldProps) => {
@@ -17887,7 +18971,7 @@ function MapFieldBinding(t0) {
17887
18971
  } else {
17888
18972
  t42 = $[20];
17889
18973
  }
17890
- t3 = Object.entries(mapProperties).filter(_temp$9).map(t42);
18974
+ t3 = Object.entries(mapProperties).filter(_temp$a).map(t42);
17891
18975
  $[6] = autoFocus;
17892
18976
  $[7] = context;
17893
18977
  $[8] = disabled;
@@ -17957,7 +19041,7 @@ function MapFieldBinding(t0) {
17957
19041
  }
17958
19042
  return t10;
17959
19043
  }
17960
- function _temp$9(t0) {
19044
+ function _temp$a(t0) {
17961
19045
  const [, property_0] = t0;
17962
19046
  return !isHidden(property_0);
17963
19047
  }
@@ -19027,7 +20111,7 @@ function BlockEntry(t0) {
19027
20111
  const property = t4;
19028
20112
  let t5;
19029
20113
  if ($[9] !== properties) {
19030
- t5 = Object.entries(properties).map(_temp$8);
20114
+ t5 = Object.entries(properties).map(_temp$9);
19031
20115
  $[9] = properties;
19032
20116
  $[10] = t5;
19033
20117
  } else {
@@ -19118,7 +20202,7 @@ function BlockEntry(t0) {
19118
20202
  }
19119
20203
  return t11;
19120
20204
  }
19121
- function _temp$8(t0) {
20205
+ function _temp$9(t0) {
19122
20206
  const [key, property_0] = t0;
19123
20207
  return {
19124
20208
  id: key,
@@ -20055,6 +21139,11 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
20055
21139
  console.error("Save failure");
20056
21140
  console.error(e_0);
20057
21141
  setError(e_0);
21142
+ },
21143
+ onPreSaveHookError: (e_1) => {
21144
+ console.error("Pre-save hook error");
21145
+ console.error(e_1);
21146
+ setError(e_1);
20058
21147
  }
20059
21148
  });
20060
21149
  };
@@ -20152,7 +21241,7 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
20152
21241
  width: width_0,
20153
21242
  frozen
20154
21243
  }) => {
20155
- const isSelected = Boolean(usedSelectionController.selectedEntities.find((e_1) => e_1.id == entity_6.id && e_1.path == entity_6.path));
21244
+ const isSelected = Boolean(usedSelectionController.selectedEntities.find((e_2) => e_2.id == entity_6.id && e_2.path == entity_6.path));
20156
21245
  const customEntityActions_0 = (collection.entityActions ?? []).map((action) => resolveEntityAction(action, customizationController.entityActions)).filter(Boolean);
20157
21246
  const actions_0 = getActionsForEntity({
20158
21247
  entity: entity_6,
@@ -20161,9 +21250,9 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
20161
21250
  return /* @__PURE__ */ jsx(EntityCollectionRowActions, { entity: entity_6, width: width_0, frozen, isSelected, selectionEnabled, size: size_0, highlightEntity: setHighlightedEntity, unhighlightEntity: unselectNavigatedEntity, collection, fullPath, fullIdPath, actions: actions_0, hideId: collection?.hideIdFromCollection, onCollectionChange: updateLastDeleteTimestamp, selectionController: usedSelectionController, openEntityMode });
20162
21251
  }, [updateLastDeleteTimestamp, usedSelectionController]);
20163
21252
  const title = /* @__PURE__ */ jsx(Popover, { open: popOverOpen, onOpenChange: setPopOverOpen, enabled: Boolean(collection.description), trigger: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start", children: [
20164
- /* @__PURE__ */ jsx(Typography, { variant: "subtitle1", className: `leading-none truncate max-w-[160px] lg:max-w-[240px] ${collection.description ? "cursor-pointer" : "cursor-auto"}`, onClick: collection.description ? (e_2) => {
21253
+ /* @__PURE__ */ jsx(Typography, { variant: "subtitle1", className: `leading-none truncate max-w-[160px] lg:max-w-[240px] ${collection.description ? "cursor-pointer" : "cursor-auto"}`, onClick: collection.description ? (e_3) => {
20165
21254
  setPopOverOpen(true);
20166
- e_2.stopPropagation();
21255
+ e_3.stopPropagation();
20167
21256
  } : void 0, children: `${collection.name}` }),
20168
21257
  /* @__PURE__ */ jsx(EntitiesCount, { fullPath, collection, filter: tableController.filterValues, sortBy: tableController.sortBy, onCountChange: setDocsCount })
20169
21258
  ] }), children: collection.description && /* @__PURE__ */ jsx("div", { className: "m-4 text-surface-900 dark:text-white", children: /* @__PURE__ */ jsx(Markdown, { source: collection.description }) }) });
@@ -20198,7 +21287,7 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
20198
21287
  /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", children: "So empty..." }),
20199
21288
  /* @__PURE__ */ jsxs(Button, { color: "primary", variant: "outlined", onClick: onNewClick, className: "mt-4", children: [
20200
21289
  /* @__PURE__ */ jsx(AddIcon, {}),
20201
- "Create your first entity"
21290
+ "Create your first entry"
20202
21291
  ] })
20203
21292
  ] }) : /* @__PURE__ */ jsx(Typography, { variant: "label", children: "No results with the applied filter/sort" }), hoverRow, inlineEditing: checkInlineEditing(), AdditionalHeaderWidget: buildAdditionalHeaderWidget, AddColumnComponent: addColumnComponentInternal, getIdColumnWidth, additionalIDHeaderWidget: /* @__PURE__ */ jsx(EntityIdHeaderWidget, { path: fullPath, fullIdPath: fullIdPath ?? fullPath, collection }), openEntityMode }, `collection_table_${fullPath}`),
20204
21293
  popupCell && /* @__PURE__ */ jsx(PopupFormField, { open: Boolean(popupCell), onClose: onPopupClose, cellRect: popupCell?.cellRect, propertyKey: popupCell?.propertyKey, collection, entityId: popupCell.entityId, tableKey: tableKey.current, customFieldValidator: uniqueFieldValidator, path: resolvedFullPath, onCellValueChange: onValueChange, container: containerRef.current }, `popup_form_${popupCell?.propertyKey}_${popupCell?.entityId}`),
@@ -20440,7 +21529,7 @@ function PropertyConfigBadge(t0) {
20440
21529
  propertyConfig,
20441
21530
  disabled
20442
21531
  } = t0;
20443
- const classes = "h-8 w-8 p-1 rounded-full shadow text-white " + (disabled ? "bg-surface-400 dark:bg-surface-600" : "");
21532
+ const classes = "h-8 w-8 flex items-center justify-center rounded-full shadow text-white " + (disabled ? "bg-surface-400 dark:bg-surface-600" : "");
20444
21533
  let t1;
20445
21534
  if ($[0] !== classes || $[1] !== disabled || $[2] !== propertyConfig) {
20446
21535
  const defaultPropertyConfig = typeof propertyConfig?.property === "object" ? getDefaultFieldConfig(propertyConfig.property) : void 0;
@@ -20455,7 +21544,7 @@ function PropertyConfigBadge(t0) {
20455
21544
  } else {
20456
21545
  t3 = $[5];
20457
21546
  }
20458
- t1 = /* @__PURE__ */ jsx("div", { className: classes, style: t3, children: propertyConfig?.Icon ? getIconForWidget(propertyConfig, "medium") : getIconForWidget(defaultPropertyConfig, "medium") });
21547
+ t1 = /* @__PURE__ */ jsx("div", { className: classes, style: t3, children: propertyConfig?.Icon ? getIconForWidget(propertyConfig, "small") : getIconForWidget(defaultPropertyConfig, "small") });
20459
21548
  $[0] = classes;
20460
21549
  $[1] = disabled;
20461
21550
  $[2] = propertyConfig;
@@ -20775,7 +21864,7 @@ const DefaultAppBar = function DefaultAppBar2(t0) {
20775
21864
  }
20776
21865
  let t7;
20777
21866
  if ($[18] !== breadcrumbs.breadcrumbs) {
20778
- t7 = (breadcrumbs.breadcrumbs ?? []).length > 0 && /* @__PURE__ */ jsx("div", { className: "mr-8 hidden lg:block", children: /* @__PURE__ */ jsx("div", { className: "flex flex-row gap-2", children: breadcrumbs.breadcrumbs.map(_temp$7) }) });
21867
+ t7 = (breadcrumbs.breadcrumbs ?? []).length > 0 && /* @__PURE__ */ jsx("div", { className: "mr-8 hidden lg:block", children: /* @__PURE__ */ jsx("div", { className: "flex flex-row gap-2", children: breadcrumbs.breadcrumbs.map(_temp$8) }) });
20779
21868
  $[18] = breadcrumbs.breadcrumbs;
20780
21869
  $[19] = t7;
20781
21870
  } else {
@@ -20887,7 +21976,7 @@ const DefaultAppBar = function DefaultAppBar2(t0) {
20887
21976
  }
20888
21977
  return t14;
20889
21978
  };
20890
- function _temp$7(breadcrumb, index) {
21979
+ function _temp$8(breadcrumb, index) {
20891
21980
  return /* @__PURE__ */ jsxs(React__default.Fragment, { children: [
20892
21981
  /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: "/" }),
20893
21982
  /* @__PURE__ */ jsx(Link, { className: "visited:text-inherit visited:dark:text-inherit block", to: breadcrumb.url, children: /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: breadcrumb.title }) }, index)
@@ -21321,7 +22410,7 @@ function SearchIconsView(t0) {
21321
22410
  } else {
21322
22411
  const searchResult = iconsSearch.search(value);
21323
22412
  const limited = searchResult.slice(0, 50);
21324
- setKeys(limited.map(_temp$6));
22413
+ setKeys(limited.map(_temp$7));
21325
22414
  }
21326
22415
  }, UPDATE_SEARCH_INDEX_WAIT_MS);
21327
22416
  $[0] = t3;
@@ -21388,7 +22477,7 @@ function SearchIconsView(t0) {
21388
22477
  }
21389
22478
  return t8;
21390
22479
  }
21391
- function _temp$6(e) {
22480
+ function _temp$7(e) {
21392
22481
  return e.item.key;
21393
22482
  }
21394
22483
  function FieldCaption(t0) {
@@ -21472,7 +22561,7 @@ function useReferenceDialog(referenceDialogProps) {
21472
22561
  }
21473
22562
  return t2;
21474
22563
  }
21475
- const fireCMSLogo = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAuDSURBVHgB7Z1fTFvXHcd/GDAk2RaHpmmTjMUVaE3bEJyHRO221OYp6VQJ8zaqSpg+beokHKnStIcKo0rrSyXgIdWeipFa8YjR+tA8YbKHTclDvJCp05QoZGuTaVsTp9vCf9j9XueCjX3te+17f+dc+3yki7EhIvbve35/zu+cc5u2NajOWHq4RenbW/R4eZsy97cou5x7Lbu8/fTnxW85sK9Ju4zH3BXsIAoe8lHvcR+FtAuv1RtNXheAYeyFO5uU+XpLv9wCAgjpYmiicFczRbqbPS8KzwkAozi1uKkbHI/GqBYFBBHp9lH/qRZdEF7DEwIwjD59fUMf4aKNbkawo0kXwdBZ74hBagGkb2/S3K0NSl4TP9LtAjEkLvgprHmHYIePZEVKAcDwY1fW9cd6IHauhUYvtEopBKkEkLy2oRl+rWSWXg/IKAQpBFDvht+LTEIQKoB6c/V2kUEIQgSAhA6Gn1hYp0bHSBaHNDGIgF0AqcUNGp5Z81xW7zYoG6cG/ezegE0AMDgMDwEoSoNZRXiDkTCfN2ARAGL88MxqwyR5tcKZG7gugMmrGxSfXSWFPZAbzL/b7roIXBMAXP6l1Jpe4imqZyLa5mpIcEUAcPUDn6y42plrJBIX/XpIcAPHBQDj911eVvHeYeLhVhqP+slpHBWAMr67IDmcGmwjJ3FMAMr4PER7WvT5AqcWojiSYirj84F5FCTXTlGzAJTx+UFlhXkVJ6hJAMr44oAInPAEVQsAdT5KPWV8caCZhqZaLVQtAPxhVeeLJ/FFbf2VqgSgWrlygSYblsdXg+0yEKP+zEfL5FUCLVkKND/Ofa894lpa+4H+fGn1BHkVLE9H78BueWhLAF5K+mDo0L5F7bpJvQdu6t8H/X/TXy9HdiNAmeUeym4epIVvz2vfn6b0f86TF6hmttCWAFB6yNzcgXFjHZ9R/6HPdYNXMrZVIIr0f39Cc4/e1B7PS+0p4AXs7EmwLAAna0+niQY+p5HnLlPku78nDlLZN2n632/rj7KBNvKN9/ZZDgWWBCCj68foHjnyMcW1y6mRbhd4grH7v6bkN2+TTNgJBZYEIJvrx2hPHP1QmOH3IqMQrIaCigLAqH/hgyckA3DxU8GfU7DtHslI5slpGrgzI0WOgFBw9/39FX+v4jwAXL9oMNLHO39F8y++Ia3xQWj/Tbrb8wqNHvsNiQYDd3Khstcu6wFkSPxg8Pkf/lRqw5cCpePw0m+FegMkgnffL58QlvUA2K4lkmjgd3TjpR97zvgA4Uq0cNGvmawwY2sqAIx+kVk/Er3Z7kFpEr1qgPFvvPwjvUwVxcTVjbKbcEwFIHL0I4ZOaDG/HsBU82z3z2jo8KckgkpeoKQARI5+GD8hQRLlNEmtehElgnJeoKQAcBSLCOrV+AYQAddsZT4w/rTJPE6RANDtE7FdGx9MPRvfAOFARGKYulXapkUCmLzK3+fHB4IJnkYAOQGqA6MlzQUGdamBXSQAnMbFjRfr/FrAex0XkOTOlVg5VCAAJH/c+/YR9xvJ+AYxLSGMa6UuJ8nrxaetFQgAR7JxAsM3Qtw3A+LnDAUw/t51nL78H3K7/9muQWpkYHzuvsHeamBHAAvMmX/smU/15kmjE2dcyAL2VgM+sx+4zeixD0mRg9MLwNPnVwM7AuCs/TH6GzHxMwMegNML5FcDugCQGHBO/Y489zEpChlhrAgy93dtvSMALqB0FfuLQceQqyKAtzfKQV0AOHufi6HDn5GiNJzzAsagf+oB+AQQ+Q5/M8QrhBnzgD8VCoAn/sP9q+TPHM7PZ8cDcMZ/5f4rw7V6CDfTAr57D/kEgH16ivJwlYNG1cfmAZDhquy/Mlx5AKoAbCn3cXX/lPGtgYHClQfgfoq+pUdKALLBFSpRCfiyTBt/sDdfYY1gG99n5VtiSgJ7lQewDNdg0XMAYoJ7DZyXOci0GQb5n4+rCaQEYB0uD6AngcSEl7d41TNsN6cJ/LVT+9pJCgs08X1ObALIpvspsLFCCgscDBK9TCywhYBsSzsp5MPn1LnzCm+iCYBYWPIHSGENrs8K5wixhYB77UoAVuH8rHxctyrNNqscwCqZA88TB7C9L3iIJwfIHDhKCmtkm3ni8gmEAK4cIP29ICmskdnP4wFQALCFgKW2gCoFLQD3z/U56UkgvnDBpWwvs8DkKTH6dQ/Qe9z60eK1MvfMSVKUJ9XxEnEQOpbz/LoH4JoMSh4+Qwpz4Pq5cqXQ8ZzNfbknTKUg4xv0IqlDfB4y/PQk8ZwAjvHlASoMmDN9hM9DGsm//tXOLUZqBWFAVQPFoEpKMyaAhtfXv4YZBQDjTx59lRSFjHVGiItI1669dQFAEaxe4FmVDOaD0c/5mUS6d3O+ne8iXWx9If0NKy+wC+foB/ke31fqRQ4S3+9TuQDxj36U/flV364H0ATAuThE5QI5uEd/9FThQC/w+7Gz/F6Aq/UpI8lnQ+z50NC51oLnBQLo72FbI7rDcPcANSJw/WOdfcTJXvcPCp4hDBhThFygQXQp+AY1GnD9EAEn8ddbi14rSv2jp/i9wISWC3DOgokGI19EKdzfUxziiwQwEm4lESuF4ycuNkQ+kOo4qeU+EeImdraFSq39KHoFxudOBgGqgoEXB9ndIicId8NdYnKeoXOlPXvJ2R8RySCA8fteGa5LEeA9DZwcFDL3geTPbKa3pADwy5Fufi8A6lEEGPlnTv9C2HsavWB+J3Gf+T9qJVHUkwgQ8/FeRM16YvTHzpl7dFMBiPQCAMbHqJk+EiKvMnn0NT2vETnlXW70g7I3j8YRcmc+En/38MRXaRr9+zx5BRgcyR5Gv0is3EK+rADApdlV/c6TogmuZmn+z1P6o8ykDwZ148sQvm68t6/icr+KAsA5Mi98sMx+NzEz4g/+SCMP/iCdEGBwzGiKHvUGqPun3mqr+HsVBQAmFtbpUkrsreTzgfETX83T0D8zJJpcV/M1mnj+VWna23D98++2k5VNP5YEAPourwi5pWw5IAR4hP6HX7J7BBkNbzA12FY288/HsgBwmhgSQllCwV5i/8pQ/6MvKfrNX8gtYGi4+GltHl/W5e1Y7zf/S+uCtCwAIFsoKAXOIYp8u0RRTQy9//sHhbSrFtCfwHYt7NjBhI7Mq5jsuH4DWwIAA5+sUmpRfFVgFQgi9EQTwpMHFFzJ0sHNlZLhAobFGQaPtQtb2WF4nNThpWVrdly/gW0BIAQgFHDeZUxRGczcJi76bf8720uB0S2cfaed1OFS8oBavxrjg6rWguMPjker+4MKZ0Hcn32ncr1vRtWbARBrRDaMFDlvbDfp20tNu0HgduKvi1k7oEDS56daT3ipeTvQ+ECb6WoThXsg4486sHDHkf1gSe0/I7J13Ggg9MYcGnSObQhEIqI8gfsg+a424y+F7XmASsRmVmn6mncmirxENRM9lXBcACDxxRqNXVknhTPk5l7cCbOu+GzDRSkR1E6uzm937RwnVzyAAXoGwzNr0nYQZQdGx8h38zBPVwUA0DPou6x6B3YZ0eZXJgaqn+GziusCMJBlbaHsIN5jgifKtDmHTQAgqVUHY1fWlDcwAYs5pt7yE9f5zYBVAADGH9OqhOR15Q0MMOoxuRMP8/dW2AVggAQRq4sa3Rtg9e74gF9Ye12YAAwaNSzA3Y9ebBU+hS5cAADGT15bp2ktLNS7EGQxvIEUAjCoZyHIZngDqQSQT72EBlkNbyCtAAywGQXNpdStTc/MKOJGXOiMxgUdt2MH6QWQDyqHucVNKcUAo0d7mvXTVby0NsJTAsgHnmFOE0Tm621K3+HfsqYfsK2593C3Tzc85+SNk3hWAPnAG+AsA1wLt7e0vEG7Hm075iUwumFgnKGIeyzhtG2vGnwvdSEAMwxh4BHJ5OOngjBLLI07qJ3QjIv7KaIbZ9xdq175P/vCeAzHXKL0AAAAAElFTkSuQmCC";
22564
+ const fireCMSLogo = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAYAAACOEfKtAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAa9SURBVHgB7Z1NbBNHFMf/a7uBEgMOHy2pSlnUql+oEG7lgNgcqZAgR9RKSU5tT9mcqp6SXNoj5tBzHAmk3ggSUo/Ziko9skXqoVIlJm3Von4IhzhAIIk7b9ab+COJvZ63610nP8netWx5Z//73syb2Zm3BjqJXc4BixaQMgHjDFCWW5iVb83aH5eL8jdC7lS2a/Ny3wGyLvJGER3CQJRsCHZBfrqCBpHaRkCJuXYb2O9EKWg0AtpKtDF5gnJr5BA+BSVm/sAsQiY8AZW1PSHR7IhE2wwhX1NAWlrlywIhwC9gPISrR8iyFJDvnQIzvALapRH5PgG+uo0bAbLIfLYAJngEtJ+awOq03LOQCAxZN6bGOdw6BV3GyV1X7iEx4hFlGQGs3qt4jBbtW6Cq65bIXW0km7x06XG0SXsCei57S+4NoDtwZUs91I5LBxfQE28O8W0o2kVIEQeDihhMwO4Vz0cEFbF1AbtfPB8RRMTWBNw54vmIVkVsMYxRDYaJnYOpztl+1LQn1VxAu3QN3dPaBkGe80sTzX60vQt7geY0IsDcMw8r+wPO9N6H2TOPXHpBbn9DcfWgehHu09OYf/YGnNJ5uE9OIyJkjyWb3+rLrQVU9R71MMIbELD238XlvjsYOXQTuUywIbziSg6zC5cw8+/HcBbPI0RkwdJnt6oPtxFw6ZbX5eFn5PANDB+5qQTkQCyfwNSfX6Lw3ycICTkclh3c7IvNBQzJdUmwide+YhOunpCFHN1sFGcrAR+AsdUl95zo/xr2q98gCkhAEpIEZUQAL6Qr99XUNY2tsL3EOp5HjcPc2x9FJh5BVQQdk47NiAlkGgZOai2QOWD2xWM+kZah1nvwl+84W2xpfS9OVlthnQWuWugS8QgKhebeuYiBfffBRK7eCutduGng2ApxEM+HX0RjrPrThoD2Y7b7tHERz4dEvPXmVbXl+DvvNq1HlQWmLoMBClPiJJ4PlWn65KfgIbVuhV4jojrNLz2CJlTIBx+cQpwZ+vVbzBYvQZP1xqRigWkLDEybnyHuXDv+BYcrS4PrsWinIqC++17J3Qmth8EJeQlPTErTVDbqQAuajEUYKOsyfPgm9DGU0Rkc9V8S6r56KMDWH8V50SctMKM9WErumzSGj9yAPj0WubAFTXhcIlp4LnrZTFVmhbYNtWiMXaXI4Cm3cUYKmNIa80mieD76UYOyQGgN2SdZQLrnovsXJKAJDRgK0TE4upzaFpjLsHTQO8JB/R6JmYEuyz3A4gEkkuW90EVfwLvyZtXffUgkB03gfWihP0N1h0MCCmhQTOu7QadY0C97UdsCxd64rGQIjtijXXahbYHuvn4kFbf3GDQhC1zTCobcfdqF6Bhur+7FN8gCUy40KGb2wjlgImmQ++pf/LV5skABTb6ncCBhMF10Rwq46kCT/LFzSBozr5yFPituqjJNQUCDpLkxuS9DeUXVXbnybWgydXwQSWHquAUGHHrzBXSgCV3RJFghWV/hKIf7GsroKgKqelB7mfzoW0OIO0zWJ3nu0LsnoKoH9a2Qru64eRFxpXB0gMn6UPCnuFV35a6DgXz/h7F0Zd6La6y3GXUTLEt0f1i7g2guFzH387TaxgESb/DUKEffV/0d8tmT/oe6wYQyixUyF1gLCrGG3r3KWZaavAt1Aq7QghIWs4mDiCQelYGxvy5UBpAqagX0GhMWK1RHq4jIMOrR1rHPnv6cebCjPFO/4KZxmYM3V4ZyIJhgZPIPBxO/zyEKrvefw+TrlrJARmrqPp9IF9qE3biQ1VEsGlIUEGChDWGXyFwshMDIPy7G/voRA0sPwQFVEddl+MQU422CMYt876a9hCaLDVfJlUNrBQaePIQthbywIAJbJbnnjAyMZw+9F3LcSVnjMm0sNiTsEq2JuIYIIDHNZ0VYjx/gxPMicivPar4nweZ7cmoUmSwuwpHw0e0yHTVf8m8v5uvXRuwcZESS379tXpwW7sqtTELlVdlxuM3EI5oLqGLDNFWgAjsHUTnnpuymPWlE8Kc98dlNvNNAMAGJ3dRPNQSf2qEOkKYbIN3UsLjtiEcEt8BquiLEocGT7GS7mX/1BCS8fjMF2wmbZaTyUk9tlxOmFfQFJLwcM1JE4wqSgSNddpQjBSiPgD67SWiZsBcn5V8PIzZCkrvSTTPprsxZzsMRkPDCHQsdtcjwhPMJT8BqvHwM8pUaRuiQaCkHWKOBAAchE42APusPI1Bi0gMJTPAgvPk9NDmgGx9GsBVK0NIA1Mg3rdlTCx9z3rYha5zY2NLjMMo/eXMboxWsnv8Br15XnnLWoGsAAAAASUVORK5CYII=";
21476
22565
  function useBrowserTitleAndIcon(name, logo) {
21477
22566
  const $ = c(4);
21478
22567
  let t0;
@@ -21577,22 +22666,9 @@ function useBuildNavigationController(props) {
21577
22666
  const buildUrlCollectionPath = useCallback((path_0) => `${removeInitialAndTrailingSlashes(baseCollectionPath)}/${encodePath(path_0)}`, [baseCollectionPath]);
21578
22667
  const allPluginGroups = plugins?.flatMap((plugin) => plugin.homePage?.navigationEntries ? plugin.homePage.navigationEntries.map((e) => e.name) : []) ?? [];
21579
22668
  const pluginGroups = [...new Set(allPluginGroups)];
21580
- const onNavigationEntriesOrderUpdate = useCallback((entries) => {
21581
- if (!plugins) {
21582
- return;
21583
- }
21584
- const filteredEntries = entries.filter((entry) => entry.entries.length > 0);
21585
- if (plugins.some((plugin_1) => plugin_1.homePage?.onNavigationEntriesUpdate)) {
21586
- plugins.forEach((plugin_0) => {
21587
- if (plugin_0.homePage?.onNavigationEntriesUpdate) {
21588
- plugin_0.homePage.onNavigationEntriesUpdate(filteredEntries);
21589
- }
21590
- });
21591
- }
21592
- }, [plugins]);
21593
- const computeTopNavigation = useCallback((collections, views, adminViews, viewsOrder_0) => {
22669
+ const computeTopNavigation = useCallback((collections, views, adminViews, viewsOrder_0, navigationGroupMappingsOverride, onNavigationEntriesUpdateCallback) => {
21594
22670
  const finalNavigationGroupMappings = computeNavigationGroups({
21595
- navigationGroupMappings,
22671
+ navigationGroupMappings: navigationGroupMappingsOverride ?? navigationGroupMappings,
21596
22672
  collections,
21597
22673
  views,
21598
22674
  plugins
@@ -21624,7 +22700,7 @@ function useBuildNavigationController(props) {
21624
22700
  return acc;
21625
22701
  }, []), ...(views ?? []).reduce((acc_0, view) => {
21626
22702
  if (view.hideFromNavigation) return acc_0;
21627
- const pathKey_0 = Array.isArray(view.path) ? view.path[0] : view.path;
22703
+ const pathKey_0 = view.path;
21628
22704
  let groupName_0 = getGroup(view);
21629
22705
  if (finalNavigationGroupMappings) {
21630
22706
  for (const pluginGroupDef_0 of finalNavigationGroupMappings) {
@@ -21647,7 +22723,7 @@ function useBuildNavigationController(props) {
21647
22723
  return acc_0;
21648
22724
  }, []), ...(adminViews ?? []).reduce((acc_1, view_0) => {
21649
22725
  if (view_0.hideFromNavigation) return acc_1;
21650
- const pathKey_1 = Array.isArray(view_0.path) ? view_0.path[0] : view_0.path;
22726
+ const pathKey_1 = view_0.path;
21651
22727
  const groupName_1 = NAVIGATION_ADMIN_GROUP_NAME;
21652
22728
  acc_1.push({
21653
22729
  id: `admin:${pathKey_1}`,
@@ -21681,21 +22757,43 @@ function useBuildNavigationController(props) {
21681
22757
  });
21682
22758
  }
21683
22759
  const collectedGroupsFromEntries = navigationEntries.map((e_0) => e_0.group).filter(Boolean);
21684
- const allDefinedGroups = [...pluginGroups ?? [], ...collectedGroupsFromEntries];
21685
- const uniqueGroups = [...new Set(allDefinedGroups)].sort((a_1, b_1) => groupOrderValue(a_1) - groupOrderValue(b_1));
22760
+ const groupsFromMappings = finalNavigationGroupMappings.map((g_0) => g_0.name);
22761
+ const additionalGroups = collectedGroupsFromEntries.filter((g_1) => !groupsFromMappings.includes(g_1));
22762
+ const allDefinedGroups = [...pluginGroups ?? [], ...groupsFromMappings, ...additionalGroups];
22763
+ const uniqueGroupsArray = [...new Set(allDefinedGroups)];
22764
+ const adminGroups = uniqueGroupsArray.filter((g_2) => g_2 === NAVIGATION_ADMIN_GROUP_NAME);
22765
+ const nonAdminGroups = uniqueGroupsArray.filter((g_3) => g_3 !== NAVIGATION_ADMIN_GROUP_NAME);
22766
+ const uniqueGroups = [...nonAdminGroups, ...adminGroups];
21686
22767
  return {
21687
- allowDragAndDrop: plugins?.some((plugin_2) => plugin_2.homePage?.allowDragAndDrop) ?? false,
22768
+ allowDragAndDrop: plugins?.some((plugin_0) => plugin_0.homePage?.allowDragAndDrop) ?? false,
21688
22769
  navigationEntries,
21689
22770
  groups: uniqueGroups,
21690
- onNavigationEntriesUpdate: onNavigationEntriesOrderUpdate
22771
+ onNavigationEntriesUpdate: onNavigationEntriesUpdateCallback
21691
22772
  };
21692
- }, [navigationGroupMappings, buildCMSUrlPath, buildUrlCollectionPath, pluginGroups, onNavigationEntriesOrderUpdate]);
22773
+ }, [navigationGroupMappings, buildCMSUrlPath, buildUrlCollectionPath, pluginGroups]);
22774
+ const onNavigationEntriesOrderUpdate = useCallback((entries) => {
22775
+ if (!plugins) {
22776
+ return;
22777
+ }
22778
+ const filteredEntries = entries.filter((entry) => entry.entries.length > 0);
22779
+ if (collectionsRef.current && viewsRef.current) {
22780
+ const updatedNav = computeTopNavigation(collectionsRef.current, viewsRef.current, adminViewsRef.current ?? [], viewsOrder, filteredEntries, onNavigationEntriesOrderUpdate);
22781
+ setTopLevelNavigation(updatedNav);
22782
+ }
22783
+ if (plugins.some((plugin_2) => plugin_2.homePage?.onNavigationEntriesUpdate)) {
22784
+ plugins.forEach((plugin_1) => {
22785
+ if (plugin_1.homePage?.onNavigationEntriesUpdate) {
22786
+ plugin_1.homePage.onNavigationEntriesUpdate(filteredEntries);
22787
+ }
22788
+ });
22789
+ }
22790
+ }, [plugins, computeTopNavigation, viewsOrder]);
21693
22791
  const refreshNavigation = useCallback(async () => {
21694
22792
  if (disabled || authController.initialLoading) return;
21695
22793
  console.debug("Refreshing navigation");
21696
22794
  try {
21697
22795
  const [resolvedCollections = [], resolvedViews, resolvedAdminViews = []] = await Promise.all([resolveCollections(collectionsProp, collectionPermissions, authController, dataSourceDelegate, plugins), resolveCMSViews(viewsProp, authController, dataSourceDelegate), resolveCMSViews(adminViewsProp, authController, dataSourceDelegate)]);
21698
- const computedTopLevelNav = computeTopNavigation(resolvedCollections, resolvedViews, resolvedAdminViews, viewsOrder);
22796
+ const computedTopLevelNav = computeTopNavigation(resolvedCollections, resolvedViews, resolvedAdminViews, viewsOrder, void 0, onNavigationEntriesOrderUpdate);
21699
22797
  let shouldUpdateTopLevelNav = false;
21700
22798
  if (!areCollectionListsEqual(collectionsRef.current ?? [], resolvedCollections)) {
21701
22799
  collectionsRef.current = resolvedCollections;
@@ -21791,7 +22889,8 @@ function useBuildNavigationController(props) {
21791
22889
  }, []);
21792
22890
  const isUrlCollectionPath = useCallback((path_1) => removeInitialAndTrailingSlashes(path_1 + "/").startsWith(removeInitialAndTrailingSlashes(fullCollectionPath) + "/"), [fullCollectionPath]);
21793
22891
  const urlPathToDataPath = useCallback((path_2) => {
21794
- if (path_2.startsWith(fullCollectionPath)) return path_2.replace(fullCollectionPath, "");
22892
+ const decodedPath = decodeURIComponent(path_2);
22893
+ if (decodedPath.startsWith(fullCollectionPath)) return decodedPath.replace(fullCollectionPath, "");
21795
22894
  throw Error("Expected path starting with " + fullCollectionPath);
21796
22895
  }, [fullCollectionPath]);
21797
22896
  const resolveIdsFrom = useCallback((path_3) => {
@@ -21979,6 +23078,42 @@ function computeNavigationGroups({
21979
23078
  }
21980
23079
  return acc;
21981
23080
  }, [...result ?? []]) : result;
23081
+ const assignedEntries = /* @__PURE__ */ new Set();
23082
+ if (result) {
23083
+ result.forEach((group) => {
23084
+ group.entries.forEach((entry) => assignedEntries.add(entry));
23085
+ });
23086
+ }
23087
+ const unassignedGroupMap = {};
23088
+ (collections ?? []).forEach((collection) => {
23089
+ const entry = collection.id ?? collection.path;
23090
+ if (!assignedEntries.has(entry)) {
23091
+ const groupName = getGroup(collection);
23092
+ if (!unassignedGroupMap[groupName]) unassignedGroupMap[groupName] = [];
23093
+ unassignedGroupMap[groupName].push(entry);
23094
+ }
23095
+ });
23096
+ (views ?? []).forEach((view) => {
23097
+ const entry = view.path;
23098
+ if (!assignedEntries.has(entry)) {
23099
+ const groupName = getGroup(view);
23100
+ if (!unassignedGroupMap[groupName]) unassignedGroupMap[groupName] = [];
23101
+ unassignedGroupMap[groupName].push(entry);
23102
+ }
23103
+ });
23104
+ Object.entries(unassignedGroupMap).forEach(([groupName, entries]) => {
23105
+ if (result) {
23106
+ const existingGroup = result.find((g) => g.name === groupName);
23107
+ if (existingGroup) {
23108
+ existingGroup.entries.push(...entries);
23109
+ } else {
23110
+ result.push({
23111
+ name: groupName,
23112
+ entries
23113
+ });
23114
+ }
23115
+ }
23116
+ });
21982
23117
  if (!result) {
21983
23118
  result = [];
21984
23119
  const groupMap = {};
@@ -21990,7 +23125,7 @@ function computeNavigationGroups({
21990
23125
  });
21991
23126
  (views ?? []).forEach((view) => {
21992
23127
  const name = getGroup(view);
21993
- const entry = Array.isArray(view.path) ? view.path[0] : view.path;
23128
+ const entry = view.path;
21994
23129
  if (!groupMap[name]) groupMap[name] = [];
21995
23130
  groupMap[name].push(entry);
21996
23131
  });
@@ -22014,7 +23149,7 @@ function useBuildLocalConfigurationPersistence() {
22014
23149
  t0 = $[0];
22015
23150
  }
22016
23151
  const configCache = useRef(t0);
22017
- const getCollectionFromStorage = _temp$5;
23152
+ const getCollectionFromStorage = _temp$6;
22018
23153
  let t1;
22019
23154
  if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
22020
23155
  t1 = (path) => {
@@ -22137,7 +23272,7 @@ function useBuildLocalConfigurationPersistence() {
22137
23272
  }
22138
23273
  return t11;
22139
23274
  }
22140
- function _temp$5(storageKey) {
23275
+ function _temp$6(storageKey) {
22141
23276
  const item = localStorage.getItem(storageKey);
22142
23277
  return item ? JSON.parse(item) : {};
22143
23278
  }
@@ -22597,14 +23732,14 @@ function EntityEditViewFormActions({
22597
23732
  collection,
22598
23733
  context,
22599
23734
  sideEntityController,
22600
- isSubmitting: formex.isSubmitting,
22601
23735
  disabled,
22602
23736
  status,
22603
23737
  sideDialogContext,
22604
23738
  pluginActions,
22605
23739
  openEntityMode,
22606
23740
  navigateBack,
22607
- formContext
23741
+ formContext,
23742
+ formex
22608
23743
  }) : buildSideActions({
22609
23744
  savingError,
22610
23745
  entity,
@@ -22612,14 +23747,14 @@ function EntityEditViewFormActions({
22612
23747
  collection,
22613
23748
  context,
22614
23749
  sideEntityController,
22615
- isSubmitting: formex.isSubmitting,
22616
23750
  sideDialogContext,
22617
23751
  disabled,
22618
23752
  status,
22619
23753
  pluginActions,
22620
23754
  openEntityMode,
22621
23755
  navigateBack,
22622
- formContext
23756
+ formContext,
23757
+ formex
22623
23758
  });
22624
23759
  }
22625
23760
  function buildBottomActions({
@@ -22629,15 +23764,16 @@ function buildBottomActions({
22629
23764
  collection,
22630
23765
  context,
22631
23766
  sideEntityController,
22632
- isSubmitting,
22633
23767
  disabled,
22634
23768
  status,
22635
23769
  sideDialogContext,
22636
23770
  pluginActions,
22637
23771
  openEntityMode,
22638
23772
  navigateBack,
22639
- formContext
23773
+ formContext,
23774
+ formex
22640
23775
  }) {
23776
+ const hasErrors = Object.keys(formex.errors).length > 0 && formex.submitCount > 0;
22641
23777
  const canClose = openEntityMode === "side_panel";
22642
23778
  return /* @__PURE__ */ jsxs(DialogActions, { position: "absolute", children: [
22643
23779
  savingError && /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Typography, { color: "error", children: savingError.message }) }),
@@ -22657,15 +23793,16 @@ function buildBottomActions({
22657
23793
  return /* @__PURE__ */ jsx(EntityActionButton, { action, enabled: isEnabled, props }, action.key);
22658
23794
  }) }),
22659
23795
  pluginActions,
22660
- /* @__PURE__ */ jsx(Button, { variant: "text", color: "primary", disabled: disabled || isSubmitting, type: "reset", children: status === "existing" ? "Discard" : "Clear" }),
22661
- /* @__PURE__ */ jsxs(Button, { variant: canClose ? "text" : "filled", color: "primary", type: "submit", disabled: disabled || isSubmitting, onClick: () => {
23796
+ hasErrors ? /* @__PURE__ */ jsx(ErrorTooltip, { title: "This form has errors", children: /* @__PURE__ */ jsx(ErrorIcon, { className: "ml-4", color: "error", size: "smallest" }) }) : null,
23797
+ /* @__PURE__ */ jsx(Button, { variant: "text", color: "primary", disabled: disabled || formex.isSubmitting, type: "reset", children: status === "existing" ? "Discard" : "Clear" }),
23798
+ /* @__PURE__ */ jsxs(Button, { variant: canClose ? "text" : "filled", color: "primary", type: "submit", disabled: disabled || formex.isSubmitting, onClick: () => {
22662
23799
  sideDialogContext.setPendingClose(false);
22663
23800
  }, children: [
22664
23801
  status === "existing" && "Save",
22665
23802
  status === "copy" && "Create copy",
22666
23803
  status === "new" && "Create"
22667
23804
  ] }),
22668
- canClose && /* @__PURE__ */ jsxs(LoadingButton, { variant: "filled", color: "primary", type: "submit", loading: isSubmitting, disabled, onClick: () => {
23805
+ canClose && /* @__PURE__ */ jsxs(LoadingButton, { variant: "filled", color: "primary", type: "submit", loading: formex.isSubmitting, disabled, onClick: () => {
22669
23806
  sideDialogContext.setPendingClose?.(true);
22670
23807
  }, children: [
22671
23808
  status === "existing" && "Save and close",
@@ -22681,24 +23818,25 @@ function buildSideActions({
22681
23818
  collection,
22682
23819
  context,
22683
23820
  sideEntityController,
22684
- isSubmitting,
22685
23821
  disabled,
22686
23822
  status,
22687
23823
  sideDialogContext,
22688
23824
  pluginActions,
22689
23825
  openEntityMode,
22690
23826
  navigateBack,
22691
- formContext
23827
+ formContext,
23828
+ formex
22692
23829
  }) {
23830
+ const hasErrors = Object.keys(formex.errors).length > 0 && formex.submitCount > 0;
22693
23831
  return /* @__PURE__ */ jsxs("div", { className: cls("overflow-auto h-full flex flex-col gap-2 w-80 2xl:w-96 px-4 py-16 sticky top-0 border-l", defaultBorderMixin), children: [
22694
- /* @__PURE__ */ jsxs(LoadingButton, { fullWidth: true, variant: "filled", color: "primary", type: "submit", size: "large", disabled: disabled || isSubmitting, onClick: () => {
23832
+ /* @__PURE__ */ jsxs(LoadingButton, { fullWidth: true, variant: "filled", color: "primary", type: "submit", size: "large", startIcon: hasErrors ? /* @__PURE__ */ jsx(ErrorIcon, {}) : void 0, disabled: disabled || formex.isSubmitting, onClick: () => {
22695
23833
  sideDialogContext.setPendingClose?.(false);
22696
23834
  }, children: [
22697
23835
  status === "existing" && "Save",
22698
23836
  status === "copy" && "Create copy",
22699
23837
  status === "new" && "Create"
22700
23838
  ] }),
22701
- /* @__PURE__ */ jsx(Button, { fullWidth: true, variant: "text", disabled: disabled || isSubmitting, type: "reset", children: status === "existing" ? "Discard" : "Clear" }),
23839
+ /* @__PURE__ */ jsx(Button, { fullWidth: true, variant: "text", disabled: disabled || formex.isSubmitting, type: "reset", children: status === "existing" ? "Discard" : "Clear" }),
22702
23840
  pluginActions,
22703
23841
  formActions.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-row flex-wrap mt-2", children: formActions.map((action) => {
22704
23842
  const props = {
@@ -22853,6 +23991,7 @@ function EntityJsonPreview(t0) {
22853
23991
  function createFormexStub(values) {
22854
23992
  const errorMessage = "You are in a read-only context. You cannot modify the formex controller.";
22855
23993
  return {
23994
+ debugId: "",
22856
23995
  values,
22857
23996
  initialValues: values,
22858
23997
  touched: {},
@@ -22867,6 +24006,9 @@ function createFormexStub(values) {
22867
24006
  setValues: () => {
22868
24007
  throw new Error(errorMessage);
22869
24008
  },
24009
+ setTouched(touched) {
24010
+ throw new Error(errorMessage);
24011
+ },
22870
24012
  setFieldValue: () => {
22871
24013
  throw new Error(errorMessage);
22872
24014
  },
@@ -22926,7 +24068,7 @@ function EntityEditView({
22926
24068
  databaseId: props.databaseId,
22927
24069
  useCache: false
22928
24070
  });
22929
- const cachedValues = entityId ? getEntityFromCache(props.path + "/" + entityId) : getEntityFromCache(props.path + "#new");
24071
+ const initialDirtyValues = entityId ? getEntityFromMemoryCache(props.path + "/" + entityId) : getEntityFromMemoryCache(props.path + "#new");
22930
24072
  const authController = useAuthController();
22931
24073
  const initialStatus = props.copy ? "copy" : entityId ? "existing" : "new";
22932
24074
  const [status, setStatus] = useState(initialStatus);
@@ -22937,13 +24079,13 @@ function EntityEditView({
22937
24079
  return entity ? canEditEntity(props.collection, authController, props.path, entity ?? null) : void 0;
22938
24080
  }
22939
24081
  }, [authController, entity, status]);
22940
- if (dataLoading && !cachedValues || (!entity || canEdit === void 0) && (status === "existing" || status === "copy")) {
24082
+ if (dataLoading && !initialDirtyValues || (!entity || canEdit === void 0) && (status === "existing" || status === "copy")) {
22941
24083
  return /* @__PURE__ */ jsx(CircularProgressCenter, {});
22942
24084
  }
22943
- if (entityId && !entity && !cachedValues) {
24085
+ if (entityId && !entity && !initialDirtyValues) {
22944
24086
  console.error(`Entity with id ${entityId} not found in collection ${props.path}`);
22945
24087
  }
22946
- return /* @__PURE__ */ jsx(EntityEditViewInner, { ...props, entityId, entity, cachedDirtyValues: cachedValues, dataLoading, status, setStatus, canEdit });
24088
+ return /* @__PURE__ */ jsx(EntityEditViewInner, { ...props, entityId, entity, initialDirtyValues, dataLoading, status, setStatus, canEdit });
22947
24089
  }
22948
24090
  function EntityEditViewInner({
22949
24091
  path,
@@ -22956,7 +24098,7 @@ function EntityEditViewInner({
22956
24098
  onSaved,
22957
24099
  onTabChange,
22958
24100
  entity,
22959
- cachedDirtyValues,
24101
+ initialDirtyValues,
22960
24102
  dataLoading,
22961
24103
  layout = "side_panel",
22962
24104
  barActions,
@@ -23084,7 +24226,8 @@ function EntityEditViewInner({
23084
24226
  /* @__PURE__ */ jsx(EntityView, { className: "px-8 h-full overflow-auto", entity, path, collection }),
23085
24227
  /* @__PURE__ */ jsx("div", { className: "h-16" })
23086
24228
  ] }) }) : null;
23087
- const entityView = /* @__PURE__ */ jsx(EntityForm, { fullIdPath, collection, path, entityId: entityId ?? usedEntity?.id, onValuesModified, entity, initialDirtyValues: cachedDirtyValues, openEntityMode: layout, forceActionsAtTheBottom: actionsAtTheBottom, initialStatus: status, className: cls((!mainViewVisible || !canEdit) && !selectedSecondaryForm ? "hidden" : "", formProps?.className), EntityFormActionsComponent: EntityEditViewFormActions, disabled: !canEdit, ...formProps, onEntityChange: (entity_0) => {
24229
+ const entityView = /* @__PURE__ */ jsx(EntityForm, { fullIdPath, collection, path, entityId: entityId ?? usedEntity?.id, onValuesModified, entity, initialDirtyValues, openEntityMode: layout, forceActionsAtTheBottom: actionsAtTheBottom, initialStatus: status, className: cls((!mainViewVisible || !canEdit) && !selectedSecondaryForm ? "hidden" : "", formProps?.className), EntityFormActionsComponent: EntityEditViewFormActions, disabled: !canEdit, ...formProps, onEntityChange: (entity_0) => {
24230
+ console.log("333 EntityEditView onEntityChange:", entity_0);
23088
24231
  setUsedEntity(entity_0);
23089
24232
  formProps?.onEntityChange?.(entity_0);
23090
24233
  }, onStatusChange: (status_0) => {
@@ -23107,7 +24250,12 @@ function EntityEditViewInner({
23107
24250
  const shouldShowTopBar = Boolean(barActions) || hasAdditionalViews;
23108
24251
  let result = /* @__PURE__ */ jsxs("div", { className: "relative flex flex-col h-full w-full bg-white dark:bg-surface-900", children: [
23109
24252
  shouldShowTopBar && /* @__PURE__ */ jsxs("div", { className: cls("h-14 items-center flex overflow-visible overflow-x-scroll w-full no-scrollbar h-14 border-b pl-2 pr-2 pt-1 flex bg-surface-50 dark:bg-surface-900", defaultBorderMixin), children: [
23110
- barActions,
24253
+ barActions?.({
24254
+ path: fullIdPath ?? path,
24255
+ entityId,
24256
+ values: formContext?.values ?? usedEntity?.values ?? {},
24257
+ status
24258
+ }),
23111
24259
  /* @__PURE__ */ jsx("div", { className: "flex-grow" }),
23112
24260
  pluginActionsTop,
23113
24261
  globalLoading && /* @__PURE__ */ jsx("div", { className: "self-center", children: /* @__PURE__ */ jsx(CircularProgress, { size: "small" }) }),
@@ -23210,9 +24358,14 @@ function EntitySidePanel(props) {
23210
24358
  if (!props || !collection) {
23211
24359
  return /* @__PURE__ */ jsx("div", { className: "w-full" });
23212
24360
  }
23213
- return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(EntityEditView, { ...props, fullIdPath, layout: "side_panel", collection, parentCollectionIds, onValuesModified, onSaved: onUpdate, barActions: /* @__PURE__ */ jsxs(Fragment, { children: [
24361
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(EntityEditView, { ...props, fullIdPath, layout: "side_panel", collection, parentCollectionIds, onValuesModified, onSaved: onUpdate, barActions: ({
24362
+ status,
24363
+ values
24364
+ }) => /* @__PURE__ */ jsxs(Fragment, { children: [
23214
24365
  /* @__PURE__ */ jsx(IconButton, { className: "self-center", onClick: onClose, children: /* @__PURE__ */ jsx(CloseIcon, { size: "small" }) }),
23215
24366
  allowFullScreen && /* @__PURE__ */ jsx(IconButton, { className: "self-center", onClick: () => {
24367
+ const key = status === "new" || status === "copy" ? path + "#new" : path + "/" + entityId;
24368
+ saveEntityToMemoryCache(key, values);
23216
24369
  if (entityId) navigate(location.pathname);
23217
24370
  else navigate(location.pathname + "#new");
23218
24371
  }, children: /* @__PURE__ */ jsx(OpenInFullIcon, { size: "small" }) })
@@ -23472,7 +24625,7 @@ function useBuildSideDialogsController() {
23472
24625
  t3 = () => {
23473
24626
  const state = location.state;
23474
24627
  const panelKeys = state?.panels ?? [];
23475
- const newPanels_0 = panelKeys.map((key) => routesStore.current[key]).filter(_temp$4);
24628
+ const newPanels_0 = panelKeys.map((key) => routesStore.current[key]).filter(_temp$5);
23476
24629
  if (!equal(sidePanelsRef.current.map(_temp2$3), newPanels_0.map(_temp3$1))) {
23477
24630
  updateSidePanels(newPanels_0);
23478
24631
  }
@@ -23620,7 +24773,7 @@ function _temp3$1(p_1) {
23620
24773
  function _temp2$3(p_0) {
23621
24774
  return p_0.key;
23622
24775
  }
23623
- function _temp$4(p) {
24776
+ function _temp$5(p) {
23624
24777
  return Boolean(p);
23625
24778
  }
23626
24779
  function useBuildDataSource({
@@ -23915,7 +25068,7 @@ function useProjectLog(t0) {
23915
25068
  const dataSourceKey = dataSourceDelegate.key;
23916
25069
  let t1;
23917
25070
  if ($[0] !== plugins) {
23918
- t1 = plugins?.map(_temp$3);
25071
+ t1 = plugins?.map(_temp$4);
23919
25072
  $[0] = plugins;
23920
25073
  $[1] = t1;
23921
25074
  } else {
@@ -23951,7 +25104,7 @@ function useProjectLog(t0) {
23951
25104
  useEffect(t2, t3);
23952
25105
  return accessResponse;
23953
25106
  }
23954
- function _temp$3(plugin) {
25107
+ function _temp$4(plugin) {
23955
25108
  return plugin.key;
23956
25109
  }
23957
25110
  function FireCMS(props) {
@@ -23964,22 +25117,27 @@ function FireCMS(props) {
23964
25117
  authController,
23965
25118
  storageSource,
23966
25119
  dataSourceDelegate,
23967
- plugins: pluginsProp,
25120
+ plugins: _pluginsProp,
23968
25121
  onAnalyticsEvent,
23969
25122
  propertyConfigs,
23970
25123
  entityViews,
23971
25124
  entityActions,
23972
25125
  components,
23973
25126
  navigationController,
23974
- apiKey
25127
+ apiKey,
25128
+ userManagement: _userManagement
23975
25129
  } = props;
23976
- if (pluginsProp) {
25130
+ if (_pluginsProp) {
23977
25131
  console.warn("The `plugins` prop is deprecated in the FireCMS component. You should pass your plugins to `useBuildNavigationController` instead.");
23978
25132
  }
23979
- const plugins = navigationController.plugins ?? pluginsProp;
25133
+ const plugins = navigationController.plugins ?? _pluginsProp;
25134
+ const userManagement = plugins?.find((p) => p.userManagement)?.userManagement ?? _userManagement ?? {
25135
+ users: [],
25136
+ getUser: (uid) => null
25137
+ };
23980
25138
  const sideDialogsController = useBuildSideDialogsController();
23981
25139
  const sideEntityController = useBuildSideEntityController(navigationController, sideDialogsController, authController);
23982
- const pluginsLoading = plugins?.some((p) => p.loading) ?? false;
25140
+ const pluginsLoading = plugins?.some((p_0) => p_0.loading) ?? false;
23983
25141
  const loading = authController.initialLoading || navigationController.loading || pluginsLoading;
23984
25142
  const customizationController = {
23985
25143
  dateTimeFormat,
@@ -24026,7 +25184,7 @@ function FireCMS(props) {
24026
25184
  accessResponse?.message && /* @__PURE__ */ jsx(Typography, { children: accessResponse?.message })
24027
25185
  ] });
24028
25186
  }
24029
- return /* @__PURE__ */ jsx(AnalyticsContext.Provider, { value: analyticsController, children: /* @__PURE__ */ jsx(CustomizationControllerContext.Provider, { value: customizationController, children: /* @__PURE__ */ jsx(UserConfigurationPersistenceContext.Provider, { value: userConfigPersistence, children: /* @__PURE__ */ jsx(StorageSourceContext.Provider, { value: storageSource, children: /* @__PURE__ */ jsx(DataSourceContext.Provider, { value: dataSource, children: /* @__PURE__ */ jsx(AuthControllerContext.Provider, { value: authController, children: /* @__PURE__ */ jsx(SideDialogsControllerContext.Provider, { value: sideDialogsController, children: /* @__PURE__ */ jsx(SideEntityControllerContext.Provider, { value: sideEntityController, children: /* @__PURE__ */ jsx(NavigationContext.Provider, { value: navigationController, children: /* @__PURE__ */ jsx(DialogsProvider, { children: /* @__PURE__ */ jsx(BreadcrumbsProvider, { children: /* @__PURE__ */ jsx(FireCMSInternal, { loading, children }) }) }) }) }) }) }) }) }) }) }) });
25187
+ return /* @__PURE__ */ jsx(AnalyticsContext.Provider, { value: analyticsController, children: /* @__PURE__ */ jsx(CustomizationControllerContext.Provider, { value: customizationController, children: /* @__PURE__ */ jsx(UserConfigurationPersistenceContext.Provider, { value: userConfigPersistence, children: /* @__PURE__ */ jsx(StorageSourceContext.Provider, { value: storageSource, children: /* @__PURE__ */ jsx(DataSourceContext.Provider, { value: dataSource, children: /* @__PURE__ */ jsx(AuthControllerContext.Provider, { value: authController, children: /* @__PURE__ */ jsx(SideDialogsControllerContext.Provider, { value: sideDialogsController, children: /* @__PURE__ */ jsx(SideEntityControllerContext.Provider, { value: sideEntityController, children: /* @__PURE__ */ jsx(NavigationContext.Provider, { value: navigationController, children: /* @__PURE__ */ jsx(InternalUserManagementContext.Provider, { value: userManagement, children: /* @__PURE__ */ jsx(DialogsProvider, { children: /* @__PURE__ */ jsx(BreadcrumbsProvider, { children: /* @__PURE__ */ jsx(FireCMSInternal, { loading, children }) }) }) }) }) }) }) }) }) }) }) }) });
24030
25188
  }
24031
25189
  function FireCMSInternal(t0) {
24032
25190
  const $ = c(7);
@@ -24196,7 +25354,7 @@ function DefaultDrawer(t0) {
24196
25354
  } = navigation.topLevelNavigation;
24197
25355
  let t1;
24198
25356
  if ($[0] !== adminMenuOpen || $[1] !== analyticsController || $[2] !== className || $[3] !== closeDrawer || $[4] !== drawerOpen || $[5] !== groups || $[6] !== largeLayout || $[7] !== logo || $[8] !== navigate || $[9] !== navigationEntries || $[10] !== style || $[11] !== tooltipsOpen) {
24199
- const adminViews = navigationEntries.filter(_temp$2) ?? [];
25357
+ const adminViews = navigationEntries.filter(_temp$3) ?? [];
24200
25358
  let t2;
24201
25359
  let t3;
24202
25360
  let t4;
@@ -24349,7 +25507,7 @@ function DefaultDrawer(t0) {
24349
25507
  function _temp2$2(g) {
24350
25508
  return g !== "Admin";
24351
25509
  }
24352
- function _temp$2(e) {
25510
+ function _temp$3(e) {
24353
25511
  return e.type === "admin";
24354
25512
  }
24355
25513
  function DrawerLogo(t0) {
@@ -24409,6 +25567,165 @@ function DrawerLogo(t0) {
24409
25567
  }
24410
25568
  return t6;
24411
25569
  }
25570
+ function UserSelectFieldBinding(t0) {
25571
+ const $ = c(43);
25572
+ const {
25573
+ propertyKey,
25574
+ value,
25575
+ setValue,
25576
+ error,
25577
+ showError,
25578
+ disabled,
25579
+ property,
25580
+ includeDescription,
25581
+ size: t1
25582
+ } = t0;
25583
+ const size = t1 === void 0 ? "large" : t1;
25584
+ const {
25585
+ users,
25586
+ getUser
25587
+ } = useInternalUserManagementController();
25588
+ let t2;
25589
+ if ($[0] !== setValue) {
25590
+ t2 = (e) => {
25591
+ e.stopPropagation();
25592
+ e.preventDefault();
25593
+ setValue(null);
25594
+ };
25595
+ $[0] = setValue;
25596
+ $[1] = t2;
25597
+ } else {
25598
+ t2 = $[1];
25599
+ }
25600
+ const handleClearClick = t2;
25601
+ let t3;
25602
+ if ($[2] !== value) {
25603
+ t3 = value !== void 0 && value != null ? value.toString() : "";
25604
+ $[2] = value;
25605
+ $[3] = t3;
25606
+ } else {
25607
+ t3 = $[3];
25608
+ }
25609
+ let t4;
25610
+ if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
25611
+ t4 = cls("w-full");
25612
+ $[4] = t4;
25613
+ } else {
25614
+ t4 = $[4];
25615
+ }
25616
+ let t5;
25617
+ if ($[5] !== property) {
25618
+ t5 = getIconForProperty(property, "small");
25619
+ $[5] = property;
25620
+ $[6] = t5;
25621
+ } else {
25622
+ t5 = $[6];
25623
+ }
25624
+ const t6 = property.validation?.required;
25625
+ let t7;
25626
+ if ($[7] !== property.name || $[8] !== t5 || $[9] !== t6) {
25627
+ t7 = /* @__PURE__ */ jsx(LabelWithIcon, { icon: t5, required: t6, title: property.name, className: "h-8 text-text-secondary dark:text-text-secondary-dark ml-3.5 my-0" });
25628
+ $[7] = property.name;
25629
+ $[8] = t5;
25630
+ $[9] = t6;
25631
+ $[10] = t7;
25632
+ } else {
25633
+ t7 = $[10];
25634
+ }
25635
+ let t8;
25636
+ if ($[11] !== propertyKey || $[12] !== t7) {
25637
+ t8 = /* @__PURE__ */ jsx(PropertyIdCopyTooltip, { propertyKey, children: t7 });
25638
+ $[11] = propertyKey;
25639
+ $[12] = t7;
25640
+ $[13] = t8;
25641
+ } else {
25642
+ t8 = $[13];
25643
+ }
25644
+ let t9;
25645
+ if ($[14] !== disabled || $[15] !== handleClearClick || $[16] !== property.clearable || $[17] !== value) {
25646
+ t9 = property.clearable && !disabled && value && /* @__PURE__ */ jsx(IconButton, { size: "small", onClick: handleClearClick, children: /* @__PURE__ */ jsx(CloseIcon, { size: "small" }) });
25647
+ $[14] = disabled;
25648
+ $[15] = handleClearClick;
25649
+ $[16] = property.clearable;
25650
+ $[17] = value;
25651
+ $[18] = t9;
25652
+ } else {
25653
+ t9 = $[18];
25654
+ }
25655
+ let t10;
25656
+ if ($[19] !== setValue) {
25657
+ t10 = (updatedValue) => {
25658
+ const newValue = updatedValue || null;
25659
+ return setValue(newValue);
25660
+ };
25661
+ $[19] = setValue;
25662
+ $[20] = t10;
25663
+ } else {
25664
+ t10 = $[20];
25665
+ }
25666
+ let t11;
25667
+ if ($[21] !== getUser) {
25668
+ t11 = (userId) => {
25669
+ const user = getUser(userId);
25670
+ return /* @__PURE__ */ jsx(UserDisplay, { user });
25671
+ };
25672
+ $[21] = getUser;
25673
+ $[22] = t11;
25674
+ } else {
25675
+ t11 = $[22];
25676
+ }
25677
+ let t12;
25678
+ if ($[23] !== users) {
25679
+ t12 = users && users.map(_temp$2);
25680
+ $[23] = users;
25681
+ $[24] = t12;
25682
+ } else {
25683
+ t12 = $[24];
25684
+ }
25685
+ let t13;
25686
+ if ($[25] !== disabled || $[26] !== size || $[27] !== t10 || $[28] !== t11 || $[29] !== t12 || $[30] !== t3 || $[31] !== t8 || $[32] !== t9) {
25687
+ t13 = /* @__PURE__ */ jsx(Select, { value: t3, disabled, size, fullWidth: true, position: "item-aligned", inputClassName: t4, label: t8, endAdornment: t9, onValueChange: t10, renderValue: t11, children: t12 });
25688
+ $[25] = disabled;
25689
+ $[26] = size;
25690
+ $[27] = t10;
25691
+ $[28] = t11;
25692
+ $[29] = t12;
25693
+ $[30] = t3;
25694
+ $[31] = t8;
25695
+ $[32] = t9;
25696
+ $[33] = t13;
25697
+ } else {
25698
+ t13 = $[33];
25699
+ }
25700
+ let t14;
25701
+ if ($[34] !== disabled || $[35] !== error || $[36] !== includeDescription || $[37] !== property || $[38] !== showError) {
25702
+ t14 = /* @__PURE__ */ jsx(FieldHelperText, { includeDescription, showError, error, disabled, property });
25703
+ $[34] = disabled;
25704
+ $[35] = error;
25705
+ $[36] = includeDescription;
25706
+ $[37] = property;
25707
+ $[38] = showError;
25708
+ $[39] = t14;
25709
+ } else {
25710
+ t14 = $[39];
25711
+ }
25712
+ let t15;
25713
+ if ($[40] !== t13 || $[41] !== t14) {
25714
+ t15 = /* @__PURE__ */ jsxs(Fragment, { children: [
25715
+ t13,
25716
+ t14
25717
+ ] });
25718
+ $[40] = t13;
25719
+ $[41] = t14;
25720
+ $[42] = t15;
25721
+ } else {
25722
+ t15 = $[42];
25723
+ }
25724
+ return t15;
25725
+ }
25726
+ function _temp$2(user_0) {
25727
+ return /* @__PURE__ */ jsx(SelectItem, { value: user_0.uid, children: /* @__PURE__ */ jsx(UserDisplay, { user: user_0 }) }, user_0.uid);
25728
+ }
24412
25729
  function isDefaultFieldConfigId(id) {
24413
25730
  return Object.keys(DEFAULT_FIELD_CONFIGS).includes(id);
24414
25731
  }
@@ -24510,6 +25827,16 @@ const DEFAULT_FIELD_CONFIGS = {
24510
25827
  Field: MultiSelectFieldBinding
24511
25828
  }
24512
25829
  },
25830
+ user_select: {
25831
+ key: "user_select",
25832
+ name: "User select",
25833
+ description: "Select a user from the user management system. Store the user ID.",
25834
+ Icon: PersonIcon,
25835
+ property: {
25836
+ dataType: "string",
25837
+ Field: UserSelectFieldBinding
25838
+ }
25839
+ },
24513
25840
  number_input: {
24514
25841
  key: "number_input",
24515
25842
  name: "Number input",
@@ -24724,6 +26051,8 @@ function getDefaultFieldId(property) {
24724
26051
  return "email";
24725
26052
  } else if (property.enumValues) {
24726
26053
  return "select";
26054
+ } else if (property.userSelect) {
26055
+ return "user_select";
24727
26056
  } else if (property.reference) {
24728
26057
  return "reference_as_string";
24729
26058
  } else {
@@ -25763,6 +27092,7 @@ export {
25763
27092
  SwitchFieldBinding,
25764
27093
  TextFieldBinding,
25765
27094
  UrlComponentPreview,
27095
+ UserPreview,
25766
27096
  Vector,
25767
27097
  VirtualTable,
25768
27098
  addInitialSlash,
@@ -25816,6 +27146,7 @@ export {
25816
27146
  getIdIcon,
25817
27147
  getLabelOrConfigFrom,
25818
27148
  getLastSegment,
27149
+ getLocalChangesBackup,
25819
27150
  getPropertiesWithPropertiesOrder,
25820
27151
  getPropertyInPath,
25821
27152
  getRandomId,
@@ -25830,13 +27161,13 @@ export {
25830
27161
  isEnumValueDisabled,
25831
27162
  isHidden,
25832
27163
  isObject,
27164
+ isPlainObject,
25833
27165
  isPropertyBuilder,
25834
27166
  isReadOnly,
25835
27167
  isReferenceProperty,
25836
27168
  isValidRegExp,
25837
27169
  joinCollectionLists,
25838
27170
  makePropertiesEditable,
25839
- makePropertiesNonEditable,
25840
27171
  mergeCallbacks,
25841
27172
  mergeCollection,
25842
27173
  mergeDeep,
@@ -25897,6 +27228,7 @@ export {
25897
27228
  useBuildNavigationController,
25898
27229
  useClearRestoreValue,
25899
27230
  useClipboard,
27231
+ useCollapsedGroups,
25900
27232
  useCollectionFetch,
25901
27233
  useColumnIds,
25902
27234
  useCustomizationController,
@@ -25907,6 +27239,7 @@ export {
25907
27239
  useDialogsController,
25908
27240
  useEntityFetch,
25909
27241
  useFireCMSContext,
27242
+ useInternalUserManagementController,
25910
27243
  useLargeLayout,
25911
27244
  useModeController,
25912
27245
  useNavigationController,