@rebasepro/admin 0.2.5 → 0.4.0

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 (64) hide show
  1. package/dist/{CollectionEditorDialog-Cn8-tGyL.js → CollectionEditorDialog-Bo86h-d-.js} +3 -3
  2. package/dist/{CollectionEditorDialog-Cn8-tGyL.js.map → CollectionEditorDialog-Bo86h-d-.js.map} +1 -1
  3. package/dist/{CollectionsStudioView-C-Ts1rZt.js → CollectionsStudioView-bsg4AT_Z.js} +4 -4
  4. package/dist/{CollectionsStudioView-C-Ts1rZt.js.map → CollectionsStudioView-bsg4AT_Z.js.map} +1 -1
  5. package/dist/{ExportCollectionAction-BRdKM3DF.js → ExportCollectionAction-Cf-Id5uO.js} +35 -27
  6. package/dist/ExportCollectionAction-Cf-Id5uO.js.map +1 -0
  7. package/dist/{ImportCollectionAction-U-v7lGxO.js → ImportCollectionAction-LN5sreK9.js} +2 -2
  8. package/dist/{ImportCollectionAction-U-v7lGxO.js.map → ImportCollectionAction-LN5sreK9.js.map} +1 -1
  9. package/dist/{PropertyEditView-BDNYkfNf.js → PropertyEditView-jCWCxmCz.js} +2 -2
  10. package/dist/{PropertyEditView-BDNYkfNf.js.map → PropertyEditView-jCWCxmCz.js.map} +1 -1
  11. package/dist/collection_editor_ui.js +3 -3
  12. package/dist/components/CollectionPanel.d.ts +83 -0
  13. package/dist/components/EntityDetailView.d.ts +0 -3
  14. package/dist/components/EntityEditView.d.ts +2 -3
  15. package/dist/components/SelectableTable/SelectableTable.d.ts +2 -2
  16. package/dist/components/SelectableTable/SelectableTableContext.d.ts +1 -1
  17. package/dist/components/SelectableTable/SelectionStore.d.ts +3 -3
  18. package/dist/components/index.d.ts +1 -0
  19. package/dist/editor.js +15 -5
  20. package/dist/editor.js.map +1 -1
  21. package/dist/{index-DJSL_SCr.js → index-BrqSvMG0.js} +3 -3
  22. package/dist/index-BrqSvMG0.js.map +1 -0
  23. package/dist/{index-DHaOV-7A.js → index-Cb0bPnzZ.js} +3 -3
  24. package/dist/index-Cb0bPnzZ.js.map +1 -0
  25. package/dist/{index-XMII4H3d.js → index-z3H8iqsj.js} +2 -2
  26. package/dist/{index-XMII4H3d.js.map → index-z3H8iqsj.js.map} +1 -1
  27. package/dist/index.d.ts +2 -2
  28. package/dist/index.js +142 -4
  29. package/dist/index.js.map +1 -1
  30. package/dist/util/entity_view_constants.d.ts +6 -0
  31. package/dist/util/resolutions.d.ts +1 -2
  32. package/dist/{util-0GYaJqL_.js → util-CvNp6A-r.js} +283 -168
  33. package/dist/util-CvNp6A-r.js.map +1 -0
  34. package/package.json +8 -8
  35. package/src/collection_editor/validateCollectionJson.ts +12 -12
  36. package/src/components/CollectionPanel.tsx +155 -0
  37. package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +65 -35
  38. package/src/components/EntityCollectionView/EntityCollectionListView.tsx +1 -1
  39. package/src/components/EntityCollectionView/EntityCollectionView.tsx +1 -1
  40. package/src/components/EntityCollectionView/hooks/useCollectionInlineEditor.ts +1 -0
  41. package/src/components/EntityCollectionView/useEntityPreviewSlots.ts +69 -18
  42. package/src/components/EntityDetailView.tsx +36 -37
  43. package/src/components/EntityEditView.tsx +108 -51
  44. package/src/components/EntityEditViewFormActions.tsx +4 -4
  45. package/src/components/EntitySidePanel.tsx +47 -14
  46. package/src/components/PropertyCollectionView.tsx +1 -0
  47. package/src/components/SelectableTable/SelectableTable.tsx +24 -22
  48. package/src/components/SelectableTable/SelectableTableContext.tsx +2 -1
  49. package/src/components/SelectableTable/SelectionStore.ts +4 -4
  50. package/src/components/index.ts +2 -0
  51. package/src/data_export/export/BasicExportAction.tsx +11 -9
  52. package/src/data_export/export/ExportCollectionAction.tsx +15 -13
  53. package/src/editor/editor.tsx +20 -4
  54. package/src/form/EntityForm.tsx +3 -3
  55. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +3 -1
  56. package/src/hooks/navigation/useResolvedCollections.ts +2 -10
  57. package/src/hooks/useBuildSideEntityController.tsx +20 -3
  58. package/src/index.ts +4 -2
  59. package/src/util/entity_view_constants.ts +6 -0
  60. package/src/util/resolutions.ts +2 -6
  61. package/dist/ExportCollectionAction-BRdKM3DF.js.map +0 -1
  62. package/dist/index-DHaOV-7A.js.map +0 -1
  63. package/dist/index-DJSL_SCr.js.map +0 -1
  64. package/dist/util-0GYaJqL_.js.map +0 -1
@@ -5,7 +5,7 @@ import * as React from "react";
5
5
  import React__default, { useRef, useEffect, useState, useMemo, lazy, Suspense, useCallback, useSyncExternalStore, useContext, createContext, forwardRef, memo, useLayoutEffect, createElement } from "react";
6
6
  import { useTranslation, useStorageSource, ErrorView, buildEnumLabel, getColorScheme, useAuthController, useCustomizationController, useAnalyticsController, IconForView, useEntityFetch, useModeController, useRebaseContext, usePermissions, createFormexStub, useSlot, resolveComponentRef, getIcon, PluginProviderStack, useUserSelector, UserDisplay, useSnackbarController, ErrorTooltip, useStorageUploadController, useData, useRelationSelector, getRowHeight, getEntityFromCache, useLargeLayout, getColumnKeysForProperty, DEFAULT_PAGE_SIZE as DEFAULT_PAGE_SIZE$1, getEntityFromMemoryCache, saveEntityToMemoryCache, CONTAINER_FULL_WIDTH, ADDITIONAL_TAB_WIDTH, FORM_CONTAINER_WIDTH, useUnsavedChangesDialog, UnsavedChangesDialog, useColumnIds, useDataTableController, saveEntityWithCallbacks, iconsSearch, deleteEntityWithCallbacks, useInternalUserManagementController, ConfirmationDialog, useUserConfigurationPersistence, useScrollRestoration, useBridgeRegistration, useAdminModeController, RebaseLogo, LanguageToggle, useRebaseRegistry, buildCollapsedDefaults, useCollapsedGroups, useBuildLocalConfigurationPersistence, useRebaseClient, CustomizationControllerContext, StudioBridgeRegistryProvider, flattenKeys, removeEntityFromCache, saveEntityToCache, removeEntityFromMemoryCache, getFormFieldKeys } from "@rebasepro/core";
7
7
  import ExcelJS from "exceljs";
8
- import { isPropertyBuilder, enumToObjectEntries, getLabelOrConfigFrom, resolveArrayProperties, getEntityImagePreviewPropertyKey, resolveDefaultSelectedView, getSubcollections, removeInitialAndTrailingSlashes, resolveEnumValues, getReferenceFrom, normalizeToEntityRelation, getRelationFrom, isReadOnly, getLocalChangesBackup, getNavigationEntriesFromPath, CollectionRegistry, getParentReferencesFromPath, canReadCollection, defaultUsersCollection, resolveCollectionPathIds, resolveProperty, isHidden, getArrayResolvedProperties, DEFAULT_ONE_OF_VALUE, getDefaultValueFor, DEFAULT_ONE_OF_TYPE, getDefaultValueFortype, resolveStorageFilenameString, resolveStoragePathString, resolveRelationProperty, getTableName, getDefaultValuesFor } from "@rebasepro/common";
8
+ import { isPropertyBuilder, enumToObjectEntries, getLabelOrConfigFrom, resolveArrayProperties, getEntityImagePreviewPropertyKey, resolveDefaultSelectedView, getSubcollections, removeInitialAndTrailingSlashes, resolveEnumValues, getReferenceFrom, normalizeToEntityRelation, getRelationFrom, isReadOnly, getLocalChangesBackup, getNavigationEntriesFromPath, CollectionRegistry, getParentReferencesFromPath, canReadCollection, resolveCollectionPathIds, resolveProperty, isHidden, getArrayResolvedProperties, DEFAULT_ONE_OF_VALUE, getDefaultValueFor, DEFAULT_ONE_OF_TYPE, getDefaultValueFortype, resolveStorageFilenameString, resolveStoragePathString, resolveRelationProperty, getTableName, getDefaultValuesFor } from "@rebasepro/common";
9
9
  import { EntityRelation, EntityReference, GeoPoint, getDataSourceCapabilities, Vector } from "@rebasepro/types";
10
10
  import { useFormex, setIn, Field, getIn, useCreateFormex, Formex } from "@rebasepro/formex";
11
11
  import { inferTypeFromValue } from "@rebasepro/schema-inference";
@@ -2619,9 +2619,6 @@ function EntityView(t0) {
2619
2619
  }
2620
2620
  return t8;
2621
2621
  }
2622
- const EntityHistoryView$2 = lazy(() => import("./index-XMII4H3d.js").then((m) => ({
2623
- default: m.EntityHistoryView
2624
- })));
2625
2622
  const BUILTIN_ENTITY_VIEWS = {
2626
2623
  "__rebase_history": {
2627
2624
  key: "__rebase_history",
@@ -2629,7 +2626,6 @@ const BUILTIN_ENTITY_VIEWS = {
2629
2626
  tabComponent: React__default.createElement(HistoryIcon, {
2630
2627
  size: 20
2631
2628
  }),
2632
- Builder: EntityHistoryView$2,
2633
2629
  position: "end"
2634
2630
  }
2635
2631
  };
@@ -2709,12 +2705,12 @@ function EntityJsonPreview(t0) {
2709
2705
  }
2710
2706
  return t4;
2711
2707
  }
2712
- const EntityHistoryView$1 = lazy(() => import("./index-XMII4H3d.js").then((m) => ({
2708
+ const MAIN_TAB_VALUE = "__main_##Q$SC^#S6";
2709
+ const JSON_TAB_VALUE = "__json";
2710
+ const HISTORY_TAB_VALUE = "__rebase_history";
2711
+ const EntityHistoryView$1 = lazy(() => import("./index-z3H8iqsj.js").then((m) => ({
2713
2712
  default: m.EntityHistoryView
2714
2713
  })));
2715
- const MAIN_TAB_VALUE$1 = "__main_##Q$SC^#S6";
2716
- const JSON_TAB_VALUE$1 = "__json";
2717
- const HISTORY_TAB_VALUE$1 = "__rebase_history";
2718
2714
  function EntityDetailView(t0) {
2719
2715
  const $ = c(15);
2720
2716
  let entityId;
@@ -2822,13 +2818,22 @@ function EntityDetailViewInner({
2822
2818
  status: "existing",
2823
2819
  entityId
2824
2820
  }), [collection, entityId]);
2825
- const [selectedTab, setSelectedTab] = useState(selectedTabProp ?? defaultSelectedView ?? MAIN_TAB_VALUE$1);
2821
+ const hasAppliedDefault = useRef(false);
2822
+ const [selectedTab, setSelectedTab] = useState(() => {
2823
+ const val = selectedTabProp ?? defaultSelectedView ?? MAIN_TAB_VALUE;
2824
+ hasAppliedDefault.current = true;
2825
+ return val === "edit" ? MAIN_TAB_VALUE : val;
2826
+ });
2826
2827
  useEffect(() => {
2827
- const target = selectedTabProp ?? defaultSelectedView ?? MAIN_TAB_VALUE$1;
2828
+ const val_0 = hasAppliedDefault.current ? selectedTabProp ?? MAIN_TAB_VALUE : selectedTabProp ?? defaultSelectedView ?? MAIN_TAB_VALUE;
2829
+ const target = val_0 === "edit" ? MAIN_TAB_VALUE : val_0;
2830
+ if (!hasAppliedDefault.current) {
2831
+ hasAppliedDefault.current = true;
2832
+ }
2828
2833
  if (target !== selectedTab) {
2829
2834
  setSelectedTab(target);
2830
2835
  }
2831
- }, [selectedTabProp, defaultSelectedView]);
2836
+ }, [selectedTabProp]);
2832
2837
  const subcollections = getSubcollections(collection).filter((c2) => !c2.hideFromNavigation);
2833
2838
  const subcollectionsCount = subcollections?.length ?? 0;
2834
2839
  const customViews = collection.entityViews ?? [];
@@ -2839,7 +2844,7 @@ function EntityDetailViewInner({
2839
2844
  const {
2840
2845
  resolvedEntityViews
2841
2846
  } = resolvedSelectedEntityView(customViews, customizationController, selectedTab);
2842
- const mainViewVisible = selectedTab === MAIN_TAB_VALUE$1;
2847
+ const mainViewVisible = selectedTab === MAIN_TAB_VALUE;
2843
2848
  const mountedTabsRef = useRef(/* @__PURE__ */ new Set());
2844
2849
  if (selectedTab) {
2845
2850
  mountedTabsRef.current.add(selectedTab);
@@ -2880,7 +2885,8 @@ function EntityDetailViewInner({
2880
2885
  disabled: true
2881
2886
  }), [entityId, parentCollectionSlugs, parentEntityIds, path, collection, context, readOnlyFormContext, layout]);
2882
2887
  const pluginActionsTop = useSlot("form.actions.top", formActionTopProps);
2883
- const detailViewConfig = collection.detailView;
2888
+ const formViewConfig = collection.formView;
2889
+ const FormViewBuilder = formViewConfig?.Builder ? resolveComponentRef(formViewConfig.Builder) : null;
2884
2890
  const titlePropertyKey = getEntityTitlePropertyKey(collection, customizationController.propertyConfigs);
2885
2891
  const title = (usedEntity?.values && titlePropertyKey ? getValueInPath(usedEntity.values, titlePropertyKey) : void 0) ?? collection.singularName ?? collection.name;
2886
2892
  const nonActionCustomViews = useMemo(() => resolvedEntityViews.filter((e) => !e.includeActions), [resolvedEntityViews]);
@@ -2897,11 +2903,11 @@ function EntityDetailViewInner({
2897
2903
  }), role: "tabpanel", children: /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(CircularProgressCenter, {}), children: readOnlyFormContext && /* @__PURE__ */ jsx(Builder, { collection, parentCollectionSlugs, parentEntityIds, entity: usedEntity, modifiedValues: usedEntity?.values, formContext: readOnlyFormContext }) }) }) }, `custom_view_${customView.key}`);
2898
2904
  }).filter(Boolean);
2899
2905
  const globalLoading = dataLoading && !usedEntity;
2900
- const jsonTabMounted = mountedTabsRef.current.has(JSON_TAB_VALUE$1);
2901
- const jsonView = selectedTab === JSON_TAB_VALUE$1 || jsonTabMounted ? /* @__PURE__ */ jsx("div", { className: cls("relative flex-1 h-full overflow-auto w-full", {
2902
- "hidden": selectedTab !== JSON_TAB_VALUE$1
2906
+ const jsonTabMounted = mountedTabsRef.current.has(JSON_TAB_VALUE);
2907
+ const jsonView = selectedTab === JSON_TAB_VALUE || jsonTabMounted ? /* @__PURE__ */ jsx("div", { className: cls("relative flex-1 h-full overflow-auto w-full", {
2908
+ "hidden": selectedTab !== JSON_TAB_VALUE
2903
2909
  }), role: "tabpanel", children: /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(EntityJsonPreview, { values: usedEntity?.values ?? {} }) }) }, "json_view") : null;
2904
- const historyView = includeHistoryView && selectedTab === HISTORY_TAB_VALUE$1 ? /* @__PURE__ */ jsx("div", { className: "relative flex-1 h-full overflow-auto w-full", role: "tabpanel", children: /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(CircularProgressCenter, {}), children: /* @__PURE__ */ jsx(EntityHistoryView$1, { collection, entity: usedEntity, formContext: readOnlyFormContext, modifiedValues: usedEntity?.values }) }) }) }, "history_view") : null;
2910
+ const historyView = includeHistoryView && selectedTab === HISTORY_TAB_VALUE ? /* @__PURE__ */ jsx("div", { className: "relative flex-1 h-full overflow-auto w-full", role: "tabpanel", children: /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(CircularProgressCenter, {}), children: /* @__PURE__ */ jsx(EntityHistoryView$1, { collection, entity: usedEntity, formContext: readOnlyFormContext, modifiedValues: usedEntity?.values }) }) }) }, "history_view") : null;
2905
2911
  const subCollectionsViews = subcollections && subcollections.map((subcollection) => {
2906
2912
  const subcollectionId = subcollection.slug;
2907
2913
  const newFullPath = usedEntity ? `${path}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(subcollection.slug)}` : void 0;
@@ -2916,27 +2922,15 @@ function EntityDetailViewInner({
2916
2922
  onTabChange?.({
2917
2923
  path,
2918
2924
  entityId,
2919
- selectedTab: value === MAIN_TAB_VALUE$1 ? void 0 : value,
2925
+ selectedTab: value === MAIN_TAB_VALUE ? void 0 : value,
2920
2926
  collection
2921
2927
  });
2922
2928
  }, [onTabChange, path, entityId, collection]);
2923
2929
  const propertyDetailView = () => {
2924
- if (detailViewConfig?.Builder) {
2925
- const CustomBuilder = resolveComponentRef(detailViewConfig.Builder);
2926
- if (CustomBuilder && usedEntity) {
2927
- return /* @__PURE__ */ jsx(CustomBuilder, { collection, entity: usedEntity, path, onEditClick: onEditClick ?? (() => {
2928
- }) });
2929
- }
2930
+ if (FormViewBuilder && usedEntity) {
2931
+ return /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(CircularProgressCenter, {}), children: /* @__PURE__ */ jsx(FormViewBuilder, { collection, parentCollectionSlugs, parentEntityIds, entity: usedEntity, modifiedValues: usedEntity?.values, formContext: readOnlyFormContext }) }) });
2930
2932
  }
2931
- const HeaderComponent = detailViewConfig?.Header ? resolveComponentRef(detailViewConfig.Header) : null;
2932
- const FooterComponent = detailViewConfig?.Footer ? resolveComponentRef(detailViewConfig.Footer) : null;
2933
- return /* @__PURE__ */ jsxs(Fragment, { children: [
2934
- HeaderComponent && usedEntity && /* @__PURE__ */ jsx(HeaderComponent, { collection, entity: usedEntity, path, onEditClick: onEditClick ?? (() => {
2935
- }) }),
2936
- usedEntity && /* @__PURE__ */ jsx(EntityView, { entity: usedEntity, collection, path }),
2937
- FooterComponent && usedEntity && /* @__PURE__ */ jsx(FooterComponent, { collection, entity: usedEntity, path, onEditClick: onEditClick ?? (() => {
2938
- }) })
2939
- ] });
2933
+ return /* @__PURE__ */ jsx(Fragment, { children: usedEntity && /* @__PURE__ */ jsx(EntityView, { entity: usedEntity, collection, path }) });
2940
2934
  };
2941
2935
  const subcollectionTabs = subcollections && subcollections.map((subcollection_0) => {
2942
2936
  const icon = getIcon(subcollection_0.icon, void 0, void 0, "small");
@@ -2996,9 +2990,9 @@ function EntityDetailViewInner({
2996
2990
  hasAdditionalViews && /* @__PURE__ */ jsx("div", { className: "flex-1 flex justify-end min-w-0 shrink-0", children: /* @__PURE__ */ jsxs(Tabs, { className: "!w-fit max-w-full", value: selectedTab, onValueChange: (value_0) => {
2997
2991
  onSideTabClick(value_0);
2998
2992
  }, children: [
2999
- includeJsonView && /* @__PURE__ */ jsx(Tab, { disabled: !hasAdditionalViews, value: JSON_TAB_VALUE$1, className: "text-sm", children: /* @__PURE__ */ jsx(CodeIcon, { size: iconSize.small }) }),
3000
- includeHistoryView && /* @__PURE__ */ jsx(Tab, { disabled: !hasAdditionalViews, value: HISTORY_TAB_VALUE$1, className: "text-sm", children: /* @__PURE__ */ jsx(HistoryIcon, { size: iconSize.small }) }),
3001
- /* @__PURE__ */ jsx(Tab, { disabled: !hasAdditionalViews, value: MAIN_TAB_VALUE$1, className: "text-sm min-w-[90px]", children: collection.singularName ?? collection.name }),
2993
+ includeJsonView && /* @__PURE__ */ jsx(Tab, { disabled: !hasAdditionalViews, value: JSON_TAB_VALUE, className: "text-sm", children: /* @__PURE__ */ jsx(CodeIcon, { size: iconSize.small }) }),
2994
+ includeHistoryView && /* @__PURE__ */ jsx(Tab, { disabled: !hasAdditionalViews, value: HISTORY_TAB_VALUE, className: "text-sm", children: /* @__PURE__ */ jsx(HistoryIcon, { size: iconSize.small }) }),
2995
+ /* @__PURE__ */ jsx(Tab, { disabled: !hasAdditionalViews, value: MAIN_TAB_VALUE, className: "text-sm min-w-[90px]", children: collection.singularName ?? collection.name }),
3002
2996
  customViewTabsStart,
3003
2997
  customViewTabsEnd,
3004
2998
  subcollectionTabs
@@ -7910,17 +7904,19 @@ const SelectableTable = function SelectableTable2({
7910
7904
  };
7911
7905
  }, [unselect]);
7912
7906
  const onFilterUpdate = useCallback((updatedFilterValues) => {
7913
- setFilterValues?.({
7914
- ...updatedFilterValues,
7915
- ...fixedFilter
7916
- });
7917
- }, [fixedFilter]);
7907
+ if (setFilterValues) {
7908
+ setFilterValues({
7909
+ ...updatedFilterValues,
7910
+ ...fixedFilter
7911
+ });
7912
+ }
7913
+ }, [fixedFilter, setFilterValues]);
7918
7914
  const contextValue = useMemo(() => ({
7919
- setPopupCell,
7920
7915
  select,
7921
7916
  onValueChange,
7922
7917
  size: size ?? "m",
7923
- selectionStore
7918
+ selectionStore,
7919
+ setPopupCell
7924
7920
  }), [setPopupCell, select, onValueChange, size, selectionStore]);
7925
7921
  return /* @__PURE__ */ jsx(SelectableTableContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx("div", { className: "h-full w-full flex flex-col bg-white dark:bg-surface-900", ref, children: /* @__PURE__ */ jsx(
7926
7922
  VirtualTable,
@@ -8329,7 +8325,7 @@ function buildBottomActions({
8329
8325
  const canClose = openEntityMode === "side_panel" || openEntityMode === "dialog";
8330
8326
  return /* @__PURE__ */ jsxs(DialogActions, { className, position: "absolute", children: [
8331
8327
  savingError && /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Typography, { color: "error", children: savingError.message }) }),
8332
- formActions.length > 0 && /* @__PURE__ */ jsx("div", { className: "grow flex overflow-auto no-scrollbar", children: formActions.map((action) => {
8328
+ formActions.length > 0 && /* @__PURE__ */ jsx("div", { className: "grow flex overflow-auto no-scrollbar", children: formActions.map((action, index) => {
8333
8329
  const props = {
8334
8330
  view: "form",
8335
8331
  entity,
@@ -8342,7 +8338,7 @@ function buildBottomActions({
8342
8338
  formContext
8343
8339
  };
8344
8340
  const isEnabled = !action.isEnabled || action.isEnabled(props);
8345
- return /* @__PURE__ */ jsx(EntityActionButton, { action, enabled: isEnabled, props }, action.key);
8341
+ return /* @__PURE__ */ jsx(EntityActionButton, { action, enabled: isEnabled, props }, action.key ?? action.name ?? index);
8346
8342
  }) }),
8347
8343
  pluginActions,
8348
8344
  hasErrors ? /* @__PURE__ */ jsx(ErrorTooltip, { title: "This form has errors", children: /* @__PURE__ */ jsx(AlertCircleIcon, { className: "ml-4 text-red-500", size: iconSize.smallest }) }) : null,
@@ -8394,7 +8390,7 @@ function buildSideActions({
8394
8390
  /* @__PURE__ */ jsx(Button, { fullWidth: true, variant: "text", disabled: disabled || formex.isSubmitting, type: "reset", children: status === "existing" ? t("discard") : t("clear") }),
8395
8391
  collection.defaultEntityAction === "view" && status === "existing" && /* @__PURE__ */ jsx(Button, { fullWidth: true, variant: "text", disabled, onClick: navigateBack, children: t("back_to_detail") ?? "Back to details" }),
8396
8392
  pluginActions,
8397
- formActions.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-row flex-wrap mt-2", children: formActions.map((action) => {
8393
+ formActions.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-row flex-wrap mt-2", children: formActions.map((action, index) => {
8398
8394
  const props = {
8399
8395
  view: "form",
8400
8396
  entity,
@@ -8407,7 +8403,7 @@ function buildSideActions({
8407
8403
  formContext
8408
8404
  };
8409
8405
  const isEnabled = !action.isEnabled || action.isEnabled(props);
8410
- return /* @__PURE__ */ jsx(EntityActionButton, { action, enabled: isEnabled, props }, action.key);
8406
+ return /* @__PURE__ */ jsx(EntityActionButton, { action, enabled: isEnabled, props }, action.key ?? action.name ?? index);
8411
8407
  }) }),
8412
8408
  savingError && /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Typography, { color: "error", children: savingError.message }) })
8413
8409
  ] });
@@ -8492,12 +8488,9 @@ function EntityActionButton(t0) {
8492
8488
  }
8493
8489
  return t5;
8494
8490
  }
8495
- const EntityHistoryView = lazy(() => import("./index-XMII4H3d.js").then((m) => ({
8491
+ const EntityHistoryView = lazy(() => import("./index-z3H8iqsj.js").then((m) => ({
8496
8492
  default: m.EntityHistoryView
8497
8493
  })));
8498
- const MAIN_TAB_VALUE = "__main_##Q$SC^#S6";
8499
- const JSON_TAB_VALUE = "__json";
8500
- const HISTORY_TAB_VALUE = "__rebase_history";
8501
8494
  function EntityEditView(t0) {
8502
8495
  const $ = c(28);
8503
8496
  let entityId;
@@ -8658,13 +8651,22 @@ function EntityEditViewInner({
8658
8651
  status,
8659
8652
  entityId
8660
8653
  }), [collection, status, entityId]);
8661
- const [selectedTab, setSelectedTab] = useState(selectedTabProp === "edit" ? MAIN_TAB_VALUE : selectedTabProp ?? defaultSelectedView ?? MAIN_TAB_VALUE);
8654
+ const hasAppliedDefault = useRef(false);
8655
+ const [selectedTab, setSelectedTab] = useState(() => {
8656
+ const val = selectedTabProp ?? defaultSelectedView ?? MAIN_TAB_VALUE;
8657
+ hasAppliedDefault.current = true;
8658
+ return val === "edit" ? MAIN_TAB_VALUE : val;
8659
+ });
8662
8660
  useEffect(() => {
8663
- const target = selectedTabProp === "edit" ? MAIN_TAB_VALUE : selectedTabProp ?? defaultSelectedView ?? MAIN_TAB_VALUE;
8661
+ const val_0 = hasAppliedDefault.current ? selectedTabProp ?? MAIN_TAB_VALUE : selectedTabProp ?? defaultSelectedView ?? MAIN_TAB_VALUE;
8662
+ const target = val_0 === "edit" ? MAIN_TAB_VALUE : val_0;
8663
+ if (!hasAppliedDefault.current) {
8664
+ hasAppliedDefault.current = true;
8665
+ }
8664
8666
  if (target !== selectedTab) {
8665
8667
  setSelectedTab(target);
8666
8668
  }
8667
- }, [selectedTabProp, defaultSelectedView]);
8669
+ }, [selectedTabProp]);
8668
8670
  const subcollections = getSubcollections(collection).filter((c2) => !c2.hideFromNavigation);
8669
8671
  const subcollectionsCount = subcollections?.length ?? 0;
8670
8672
  const customViews = collection.entityViews ?? [];
@@ -8690,6 +8692,7 @@ function EntityEditViewInner({
8690
8692
  return {
8691
8693
  entityId,
8692
8694
  disabled: false,
8695
+ readOnly: true,
8693
8696
  openEntityMode: layout,
8694
8697
  status,
8695
8698
  values: usedEntity?.values ?? {},
@@ -8753,12 +8756,18 @@ function EntityEditViewInner({
8753
8756
  });
8754
8757
  }
8755
8758
  }, [status, onTabChange, path, entityId, collection]);
8759
+ const formViewConfig = collection.formView;
8760
+ const FormViewBuilder = formViewConfig?.Builder ? resolveComponentRef(formViewConfig.Builder) : null;
8761
+ formViewConfig?.includeActions !== false;
8756
8762
  const entityReadOnlyView = !canEdit && entity ? /* @__PURE__ */ jsx("div", { className: cls("flex-1 flex flex-row w-full overflow-y-auto justify-center", canEdit || !mainViewVisible || selectedSecondaryForm ? "hidden" : ""), children: /* @__PURE__ */ jsxs("div", { className: cls("relative flex flex-col max-w-4xl lg:max-w-3xl xl:max-w-4xl 2xl:max-w-6xl w-full h-fit"), children: [
8757
8763
  /* @__PURE__ */ jsx(Typography, { className: "mt-16 mb-8 mx-8", variant: "h4", children: collection.singularName ?? collection.name }),
8758
- /* @__PURE__ */ jsx(EntityView, { className: "px-8 h-full overflow-auto", entity, path, collection }),
8764
+ FormViewBuilder && readOnlyFormContext ? /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(CircularProgressCenter, {}), children: /* @__PURE__ */ jsx(FormViewBuilder, { collection, parentCollectionSlugs, parentEntityIds, entity: usedEntity, modifiedValues: usedEntity?.values, formContext: readOnlyFormContext }) }) }) : /* @__PURE__ */ jsx(EntityView, { className: "px-8 h-full overflow-auto", entity, path, collection }),
8759
8765
  /* @__PURE__ */ jsx("div", { className: "h-16" })
8760
8766
  ] }) }) : null;
8761
- const entityView = /* @__PURE__ */ jsx(EntityForm, { 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, navigateBack, ...formProps, onEntityChange: (entity_0) => {
8767
+ const entityView = FormViewBuilder ? (
8768
+ // formView.Builder replaces the default form
8769
+ /* @__PURE__ */ jsx("div", { className: cls("relative flex-1 w-full h-full overflow-auto", (!mainViewVisible || !canEdit) && !selectedSecondaryForm ? "hidden" : ""), children: /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(CircularProgressCenter, {}), children: (formContext ?? readOnlyFormContext) && /* @__PURE__ */ jsx(FormViewBuilder, { collection, parentCollectionSlugs, parentEntityIds, entity: usedEntity, modifiedValues: (formContext ?? readOnlyFormContext)?.formex?.values ?? usedEntity?.values, formContext: formContext ?? readOnlyFormContext }) }) }) })
8770
+ ) : /* @__PURE__ */ jsx(EntityForm, { 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, navigateBack, ...formProps, onEntityChange: (entity_0) => {
8762
8771
  setUsedEntity(entity_0);
8763
8772
  formProps?.onEntityChange?.(entity_0);
8764
8773
  }, onStatusChange: (status_0) => {
@@ -8952,7 +8961,6 @@ function EntitySidePanel(props) {
8952
8961
  close
8953
8962
  } = useSideDialogContext();
8954
8963
  const navigate = useNavigate();
8955
- const location = useLocation();
8956
8964
  const sideEntityController = useSideEntityController();
8957
8965
  const collectionRegistryController = useCollectionRegistryController();
8958
8966
  const sideDialogsController = useSideDialogContext();
@@ -8995,6 +9003,26 @@ function EntitySidePanel(props) {
8995
9003
  useEffect(() => {
8996
9004
  setShowEditInPanel(selectedTab === "edit");
8997
9005
  }, [entityId, selectedTab]);
9006
+ const hasCorrectedDefaultView = useRef(false);
9007
+ useEffect(() => {
9008
+ if (hasCorrectedDefaultView.current) return;
9009
+ if (selectedTab) return;
9010
+ if (!entityId || !collection?.defaultSelectedView) return;
9011
+ const effectiveDefault = resolveDefaultSelectedView(collection.defaultSelectedView, {
9012
+ status: "existing",
9013
+ entityId
9014
+ });
9015
+ if (effectiveDefault && effectiveDefault !== "edit") {
9016
+ hasCorrectedDefaultView.current = true;
9017
+ sideEntityController.replace({
9018
+ path,
9019
+ entityId,
9020
+ selectedTab: effectiveDefault,
9021
+ updateUrl: collection.openEntityMode !== "dialog",
9022
+ collection
9023
+ });
9024
+ }
9025
+ }, [selectedTab, entityId, collection, path, sideEntityController]);
8998
9026
  const onValuesModified = useCallback((modified) => {
8999
9027
  setBlockedNavigationMessage(modified ? /* @__PURE__ */ jsxs(Fragment, { children: [
9000
9028
  " You have unsaved changes in this ",
@@ -9028,12 +9056,12 @@ function EntitySidePanel(props) {
9028
9056
  return;
9029
9057
  }
9030
9058
  if (tabEntityId) {
9031
- const collectionPath = removeInitialAndTrailingSlashes(path);
9032
- const tabSuffix = selectedTab_0 ? "/" + selectedTab_0 : "";
9033
- const fullUrl = urlController.buildUrlCollectionPath(`${collectionPath}/${tabEntityId}${tabSuffix}#side`);
9034
- navigate(fullUrl, {
9035
- replace: true,
9036
- state: location.state
9059
+ sideEntityController.replace({
9060
+ path,
9061
+ entityId: tabEntityId,
9062
+ selectedTab: selectedTab_0,
9063
+ updateUrl: true,
9064
+ collection: paramCollection ?? collection
9037
9065
  });
9038
9066
  }
9039
9067
  } }) : /* @__PURE__ */ jsx(EntityEditView, { ...props, layout: collection?.openEntityMode === "dialog" ? "dialog" : "side_panel", collection, parentCollectionSlugs, parentEntityIds, onValuesModified, onSaved: onUpdate, navigateBack: () => setShowEditInPanel(false), barActions: ({
@@ -9059,20 +9087,20 @@ function EntitySidePanel(props) {
9059
9087
  }
9060
9088
  }, children: /* @__PURE__ */ jsx(Maximize2Icon, {}) })
9061
9089
  ] }), onTabChange: ({
9062
- entityId: entityId_0,
9090
+ entityId: tabEntityId_0,
9063
9091
  selectedTab: selectedTab_1,
9064
9092
  collection: paramCollection_0
9065
9093
  }) => {
9066
9094
  if (collection?.openEntityMode === "dialog" || paramCollection_0?.openEntityMode === "dialog") {
9067
9095
  return;
9068
9096
  }
9069
- if (entityId_0) {
9070
- const collectionPath_0 = removeInitialAndTrailingSlashes(path);
9071
- const tabSuffix_0 = selectedTab_1 ? "/" + selectedTab_1 : "";
9072
- const fullUrl_0 = urlController.buildUrlCollectionPath(`${collectionPath_0}/${entityId_0}${tabSuffix_0}#side`);
9073
- navigate(fullUrl_0, {
9074
- replace: true,
9075
- state: location.state
9097
+ if (tabEntityId_0) {
9098
+ sideEntityController.replace({
9099
+ path,
9100
+ entityId: tabEntityId_0,
9101
+ selectedTab: selectedTab_1,
9102
+ updateUrl: true,
9103
+ collection: paramCollection_0 ?? collection
9076
9104
  });
9077
9105
  }
9078
9106
  }, formProps }) }) });
@@ -9084,7 +9112,7 @@ function getEntityViewWidth(props, small, customizationController) {
9084
9112
  const {
9085
9113
  selectedSecondaryForm
9086
9114
  } = resolvedSelectedEntityView(props.collection?.entityViews, customizationController, props.selectedTab);
9087
- const shouldUseSmallLayout = !props.selectedTab || props.selectedTab === JSON_TAB_VALUE || props.selectedTab === HISTORY_TAB_VALUE || Boolean(selectedSecondaryForm);
9115
+ const shouldUseSmallLayout = !props.selectedTab || props.selectedTab === "edit" || props.selectedTab === JSON_TAB_VALUE || props.selectedTab === HISTORY_TAB_VALUE || Boolean(selectedSecondaryForm);
9088
9116
  let resolvedWidth;
9089
9117
  if (props.width) {
9090
9118
  resolvedWidth = typeof props.width === "number" ? `${props.width}px` : props.width;
@@ -9207,8 +9235,8 @@ const useBuildSideEntityController = (collectionRegistryController, urlControlle
9207
9235
  entityId: props_0.entityId
9208
9236
  });
9209
9237
  sideDialogsController.open(propsToSidePanel({
9210
- selectedTab: defaultSelectedView,
9211
- ...props_0
9238
+ ...props_0,
9239
+ selectedTab: props_0.selectedTab ?? defaultSelectedView
9212
9240
  }, urlController.buildUrlCollectionPath, urlController.resolveDatabasePathsFrom, smallLayout, customizationController, authController, location.search));
9213
9241
  }, [sideDialogsController, urlController.buildUrlCollectionPath, urlController.resolveDatabasePathsFrom, smallLayout, authController.user, location.search]);
9214
9242
  const replace = useCallback((props_1) => {
@@ -9242,6 +9270,7 @@ function buildSidePanelsFromUrl(path, collections, newFlag) {
9242
9270
  path: navigationEntry.slug,
9243
9271
  entityId: navigationEntry.entityId,
9244
9272
  copy: false,
9273
+ collection: navigationEntry.parentCollection,
9245
9274
  width: navigationEntry.parentCollection?.sideDialogWidth
9246
9275
  };
9247
9276
  } else if (navigationEntry.type === "custom_view") {
@@ -9254,6 +9283,15 @@ function buildSidePanelsFromUrl(path, collections, newFlag) {
9254
9283
  }
9255
9284
  }
9256
9285
  }
9286
+ if (sidePanel && !sidePanel.selectedTab && sidePanel.collection) {
9287
+ const defaultView = resolveDefaultSelectedView(sidePanel.collection.defaultSelectedView, {
9288
+ status: sidePanel.copy ? "copy" : sidePanel.entityId ? "existing" : "new",
9289
+ entityId: sidePanel.entityId
9290
+ });
9291
+ if (defaultView) {
9292
+ sidePanel.selectedTab = defaultView;
9293
+ }
9294
+ }
9257
9295
  if (newFlag) {
9258
9296
  sidePanel = {
9259
9297
  path: lastCollectionPath,
@@ -9726,11 +9764,7 @@ function useResolvedCollections(props) {
9726
9764
  try {
9727
9765
  const resolved = await resolveCollections(collectionsProp, authControllerRef.current, dataRef.current, pluginsRef.current);
9728
9766
  if (cancelled) return;
9729
- const defaults = [];
9730
- if (userManagementRef.current) {
9731
- defaults.push(defaultUsersCollection);
9732
- }
9733
- const deduped = Array.from(new Map([...defaults, ...resolved].map((c2) => [c2.slug, c2])).values());
9767
+ const deduped = [...resolved];
9734
9768
  const changed = collectionRegistryController.collectionRegistryRef.current.registerMultiple(deduped);
9735
9769
  if (changed) {
9736
9770
  console.debug("Collections have changed", deduped);
@@ -10948,6 +10982,9 @@ function useCollectionInlineEditor(t0) {
10948
10982
  setError,
10949
10983
  data: entity
10950
10984
  } = t32;
10985
+ if (!entity) {
10986
+ return;
10987
+ }
10951
10988
  const updatedValues = setIn({}, propertyKey, value_0);
10952
10989
  const saveProps = {
10953
10990
  path: entity.path ?? path,
@@ -11525,7 +11562,7 @@ function FormLayout(t0) {
11525
11562
  return t2;
11526
11563
  }
11527
11564
  function ReadOnlyFieldBinding(t0) {
11528
- const $ = c(18);
11565
+ const $ = c(23);
11529
11566
  const {
11530
11567
  propertyKey,
11531
11568
  value,
@@ -11535,6 +11572,7 @@ function ReadOnlyFieldBinding(t0) {
11535
11572
  property,
11536
11573
  includeDescription
11537
11574
  } = t0;
11575
+ const skipCardWrapper = property.type === "relation" || property.type === "reference";
11538
11576
  let t1;
11539
11577
  if ($[0] !== minimalistView || $[1] !== property || $[2] !== propertyKey) {
11540
11578
  t1 = !minimalistView && /* @__PURE__ */ jsx(LabelWithIconAndTooltip, { propertyKey, icon: getIconForProperty(property, "small"), required: property.validation?.required, title: property.name ?? propertyKey, className: "h-8 text-text-secondary dark:text-text-secondary-dark ml-3.5" });
@@ -11545,49 +11583,62 @@ function ReadOnlyFieldBinding(t0) {
11545
11583
  } else {
11546
11584
  t1 = $[3];
11547
11585
  }
11548
- let t2;
11549
- if ($[4] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
11550
- t2 = cls(paperMixin, "w-full min-h-14 p-4 md:p-6 overflow-x-scroll no-scrollbar");
11586
+ const t2 = !skipCardWrapper && paperMixin;
11587
+ const t3 = !skipCardWrapper && "p-4 md:p-6";
11588
+ let t4;
11589
+ if ($[4] !== t2 || $[5] !== t3) {
11590
+ t4 = cls(t2, "w-full min-h-14 overflow-x-scroll no-scrollbar", t3);
11551
11591
  $[4] = t2;
11592
+ $[5] = t3;
11593
+ $[6] = t4;
11552
11594
  } else {
11553
- t2 = $[4];
11595
+ t4 = $[6];
11554
11596
  }
11555
- let t3;
11556
- if ($[5] !== property || $[6] !== propertyKey || $[7] !== value) {
11557
- t3 = /* @__PURE__ */ jsx("div", { className: t2, children: /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(PropertyPreview, { propertyKey, value, property, size: "medium" }) }) });
11558
- $[5] = property;
11559
- $[6] = propertyKey;
11560
- $[7] = value;
11561
- $[8] = t3;
11597
+ let t5;
11598
+ if ($[7] !== property || $[8] !== propertyKey || $[9] !== value) {
11599
+ t5 = /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(PropertyPreview, { propertyKey, value, property, size: "medium" }) });
11600
+ $[7] = property;
11601
+ $[8] = propertyKey;
11602
+ $[9] = value;
11603
+ $[10] = t5;
11562
11604
  } else {
11563
- t3 = $[8];
11605
+ t5 = $[10];
11564
11606
  }
11565
- let t4;
11566
- if ($[9] !== error || $[10] !== includeDescription || $[11] !== property || $[12] !== showError) {
11567
- t4 = /* @__PURE__ */ jsx(FieldHelperText, { includeDescription, showError, error, property });
11568
- $[9] = error;
11569
- $[10] = includeDescription;
11570
- $[11] = property;
11571
- $[12] = showError;
11572
- $[13] = t4;
11607
+ let t6;
11608
+ if ($[11] !== t4 || $[12] !== t5) {
11609
+ t6 = /* @__PURE__ */ jsx("div", { className: t4, children: t5 });
11610
+ $[11] = t4;
11611
+ $[12] = t5;
11612
+ $[13] = t6;
11573
11613
  } else {
11574
- t4 = $[13];
11614
+ t6 = $[13];
11575
11615
  }
11576
- let t5;
11577
- if ($[14] !== t1 || $[15] !== t3 || $[16] !== t4) {
11578
- t5 = /* @__PURE__ */ jsxs(Fragment, { children: [
11616
+ let t7;
11617
+ if ($[14] !== error || $[15] !== includeDescription || $[16] !== property || $[17] !== showError) {
11618
+ t7 = /* @__PURE__ */ jsx(FieldHelperText, { includeDescription, showError, error, property });
11619
+ $[14] = error;
11620
+ $[15] = includeDescription;
11621
+ $[16] = property;
11622
+ $[17] = showError;
11623
+ $[18] = t7;
11624
+ } else {
11625
+ t7 = $[18];
11626
+ }
11627
+ let t8;
11628
+ if ($[19] !== t1 || $[20] !== t6 || $[21] !== t7) {
11629
+ t8 = /* @__PURE__ */ jsxs(Fragment, { children: [
11579
11630
  t1,
11580
- t3,
11581
- t4
11631
+ t6,
11632
+ t7
11582
11633
  ] });
11583
- $[14] = t1;
11584
- $[15] = t3;
11585
- $[16] = t4;
11586
- $[17] = t5;
11634
+ $[19] = t1;
11635
+ $[20] = t6;
11636
+ $[21] = t7;
11637
+ $[22] = t8;
11587
11638
  } else {
11588
- t5 = $[17];
11639
+ t8 = $[22];
11589
11640
  }
11590
- return t5;
11641
+ return t8;
11591
11642
  }
11592
11643
  const PropertyFieldBinding = React__default.memo(PropertyFieldBindingInternal, (a, b) => {
11593
11644
  if (a.propertyKey !== b.propertyKey) {
@@ -18555,10 +18606,10 @@ function EditorCollectionAction(t0) {
18555
18606
  }
18556
18607
  return t8;
18557
18608
  }
18558
- const ImportCollectionAction = lazy(() => import("./index-DJSL_SCr.js").then((m) => ({
18609
+ const ImportCollectionAction = lazy(() => import("./index-BrqSvMG0.js").then((m) => ({
18559
18610
  default: m.ImportCollectionAction
18560
18611
  })));
18561
- const ExportCollectionAction = lazy(() => import("./index-DHaOV-7A.js").then((m) => ({
18612
+ const ExportCollectionAction = lazy(() => import("./index-Cb0bPnzZ.js").then((m) => ({
18562
18613
  default: m.ExportCollectionAction
18563
18614
  })));
18564
18615
  function EntityCollectionViewActions(t0) {
@@ -19041,35 +19092,71 @@ function resolveEntitySlots(entity, collection, slotKeys) {
19041
19092
  }
19042
19093
  function resolveRelationDisplayName(relation, prop) {
19043
19094
  const data = "data" in relation ? relation.data : void 0;
19044
- if (!data || !data.values) {
19045
- const id2 = "id" in relation ? relation.id : void 0;
19046
- return id2 !== void 0 ? String(id2) : void 0;
19047
- }
19048
- const values = data.values;
19095
+ let targetCollection;
19049
19096
  try {
19050
- const targetCollection = prop.relation?.target?.();
19097
+ const resolved = prop.relation?.target?.() ?? (typeof prop.target === "function" ? prop.target() : void 0);
19098
+ if (resolved && typeof resolved === "object") {
19099
+ targetCollection = resolved;
19100
+ }
19101
+ } catch {
19102
+ }
19103
+ const extractDisplayName = (values) => {
19051
19104
  if (targetCollection) {
19052
19105
  const targetTitleKey = targetCollection.titleProperty;
19053
19106
  if (targetTitleKey && values[targetTitleKey] !== void 0) {
19054
19107
  return String(values[targetTitleKey]);
19055
19108
  }
19109
+ const isHiddenProp = (p) => {
19110
+ const ui = p.ui;
19111
+ if (ui?.hideFromCollection) return true;
19112
+ if (ui?.disabled?.hidden) return true;
19113
+ return false;
19114
+ };
19115
+ const isDisplayCandidate = (p) => {
19116
+ return p.type === "string" && !p.multiline && !p.markdown && !p.storage && !("isId" in p && p.isId) && !isHiddenProp(p);
19117
+ };
19118
+ const priorityKeys = ["name", "title", "label", "displayName"];
19119
+ for (const pk of priorityKeys) {
19120
+ const p = targetCollection.properties[pk];
19121
+ if (p && isDisplayCandidate(p) && values[pk] !== void 0 && values[pk] !== null) {
19122
+ return String(values[pk]);
19123
+ }
19124
+ }
19056
19125
  for (const [k, p] of Object.entries(targetCollection.properties)) {
19057
19126
  const tp = p;
19058
- if (tp.type === "string" && !tp.multiline && !tp.markdown && !tp.storage && !("isId" in tp && tp.isId)) {
19127
+ if (isDisplayCandidate(tp)) {
19059
19128
  if (values[k] !== void 0 && values[k] !== null) {
19060
19129
  return String(values[k]);
19061
19130
  }
19062
19131
  }
19063
19132
  }
19064
19133
  }
19065
- } catch {
19066
- }
19067
- for (const [, v] of Object.entries(values)) {
19068
- if (typeof v === "string" && v.length > 0 && v.length < 200) {
19069
- return v;
19134
+ for (const [, v] of Object.entries(values)) {
19135
+ if (typeof v === "string" && v.length > 0 && v.length < 200) {
19136
+ return v;
19137
+ }
19070
19138
  }
19139
+ return void 0;
19140
+ };
19141
+ if (data && data.values) {
19142
+ const result = extractDisplayName(data.values);
19143
+ if (result) return result;
19071
19144
  }
19072
19145
  const id = "id" in relation ? relation.id : void 0;
19146
+ if (id !== void 0 && targetCollection) {
19147
+ try {
19148
+ const slug = targetCollection.slug ?? targetCollection.table;
19149
+ if (slug) {
19150
+ const cacheKey = `${slug}/${id}`;
19151
+ const cached = getEntityFromCache(cacheKey);
19152
+ if (cached?.values) {
19153
+ const result = extractDisplayName(cached.values);
19154
+ if (result) return result;
19155
+ }
19156
+ }
19157
+ } catch {
19158
+ }
19159
+ }
19073
19160
  return id !== void 0 ? String(id) : void 0;
19074
19161
  }
19075
19162
  function EntityCard({
@@ -19144,6 +19231,18 @@ function getGridColumnsClass(size) {
19144
19231
  return "grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6";
19145
19232
  }
19146
19233
  }
19234
+ function getScrollParent$1(element) {
19235
+ if (!element) return null;
19236
+ let parent = element.parentElement;
19237
+ while (parent) {
19238
+ const overflowY = window.getComputedStyle(parent).overflowY;
19239
+ if (overflowY === "auto" || overflowY === "scroll") {
19240
+ return parent;
19241
+ }
19242
+ parent = parent.parentElement;
19243
+ }
19244
+ return document.documentElement;
19245
+ }
19147
19246
  function EntityCollectionCardView({
19148
19247
  collection,
19149
19248
  tableController,
@@ -19157,7 +19256,6 @@ function EntityCollectionCardView({
19157
19256
  size = "m"
19158
19257
  }) {
19159
19258
  const containerRef = useRef(null);
19160
- const loadMoreRef = useRef(null);
19161
19259
  const hasRestoredScroll = useRef(false);
19162
19260
  const {
19163
19261
  data,
@@ -19190,36 +19288,48 @@ function EntityCollectionCardView({
19190
19288
  if (!dataLoading) isLoadingMore.current = false;
19191
19289
  }, [dataLoading]);
19192
19290
  useEffect(() => {
19193
- if (!loadMoreRef.current) return;
19194
- const observer = new IntersectionObserver((entries) => {
19291
+ const el = containerRef.current;
19292
+ if (!el) return;
19293
+ const scrollEl = getScrollParent$1(el);
19294
+ if (!scrollEl) return;
19295
+ let rafId = null;
19296
+ const update = () => {
19297
+ rafId = null;
19195
19298
  const {
19196
19299
  paginationEnabled: pe,
19197
19300
  noMoreToLoad: nm,
19198
- dataLoading: dl,
19199
19301
  itemCount: ic,
19200
19302
  pageSize: ps
19201
19303
  } = paginationStateRef.current;
19202
- if (entries[0].isIntersecting && pe && !dl && !nm && !isLoadingMore.current) {
19304
+ if (pe && !nm && !isLoadingMore.current && scrollEl.scrollHeight - scrollEl.scrollTop - scrollEl.clientHeight < 400) {
19203
19305
  isLoadingMore.current = true;
19204
19306
  setItemCount?.((ic ?? ps) + ps);
19205
19307
  }
19206
- }, {
19207
- root: containerRef.current,
19208
- rootMargin: "400px",
19209
- threshold: 0
19308
+ };
19309
+ const onScrollEvent = () => {
19310
+ if (rafId === null) rafId = requestAnimationFrame(update);
19311
+ };
19312
+ scrollEl.addEventListener("scroll", onScrollEvent, {
19313
+ passive: true
19210
19314
  });
19211
- observer.observe(loadMoreRef.current);
19212
- return () => observer.disconnect();
19213
- }, [setItemCount, data.length]);
19315
+ const ro = new ResizeObserver(() => update());
19316
+ ro.observe(scrollEl);
19317
+ update();
19318
+ return () => {
19319
+ scrollEl.removeEventListener("scroll", onScrollEvent);
19320
+ ro.disconnect();
19321
+ if (rafId !== null) cancelAnimationFrame(rafId);
19322
+ };
19323
+ }, [setItemCount]);
19214
19324
  useEffect(() => {
19215
19325
  if (!containerRef.current || !initialScroll || hasRestoredScroll.current || data.length === 0) return;
19326
+ const scrollEl_0 = getScrollParent$1(containerRef.current);
19327
+ if (!scrollEl_0) return;
19216
19328
  let attempts = 0;
19217
19329
  const maxAttempts = 5;
19218
19330
  const tryRestore = () => {
19219
- const el = containerRef.current;
19220
- if (!el) return;
19221
- if (el.scrollHeight >= initialScroll || attempts >= maxAttempts) {
19222
- el.scrollTop = initialScroll;
19331
+ if (scrollEl_0.scrollHeight >= initialScroll || attempts >= maxAttempts) {
19332
+ scrollEl_0.scrollTop = initialScroll;
19223
19333
  hasRestoredScroll.current = true;
19224
19334
  } else {
19225
19335
  attempts++;
@@ -19230,10 +19340,12 @@ function EntityCollectionCardView({
19230
19340
  }, [initialScroll, data.length]);
19231
19341
  const lastScrollOffset = useRef(0);
19232
19342
  useEffect(() => {
19233
- const container = containerRef.current;
19234
- if (!container || !onScroll) return;
19343
+ const el_0 = containerRef.current;
19344
+ if (!el_0 || !onScroll) return;
19345
+ const scrollEl_1 = getScrollParent$1(el_0);
19346
+ if (!scrollEl_1) return;
19235
19347
  const handleScroll = () => {
19236
- const currentOffset = container.scrollTop;
19348
+ const currentOffset = scrollEl_1.scrollTop;
19237
19349
  const direction = currentOffset > lastScrollOffset.current ? "forward" : "backward";
19238
19350
  lastScrollOffset.current = currentOffset;
19239
19351
  onScroll({
@@ -19242,10 +19354,10 @@ function EntityCollectionCardView({
19242
19354
  scrollUpdateWasRequested: false
19243
19355
  });
19244
19356
  };
19245
- container.addEventListener("scroll", handleScroll, {
19357
+ scrollEl_1.addEventListener("scroll", handleScroll, {
19246
19358
  passive: true
19247
19359
  });
19248
- return () => container.removeEventListener("scroll", handleScroll);
19360
+ return () => scrollEl_1.removeEventListener("scroll", handleScroll);
19249
19361
  }, [onScroll]);
19250
19362
  const handleEntityClick = useCallback((entity) => {
19251
19363
  onEntityClick?.(entity);
@@ -19262,12 +19374,12 @@ function EntityCollectionCardView({
19262
19374
  const gridColumnsClass = getGridColumnsClass(size);
19263
19375
  const isInitialLoading = dataLoading && data.length === 0 && !dataLoadingError;
19264
19376
  const isEmpty = !dataLoading && data.length === 0 && !dataLoadingError;
19265
- return /* @__PURE__ */ jsx("div", { ref: containerRef, className: "flex-1 overflow-auto p-4", children: dataLoadingError ? /* @__PURE__ */ jsx("div", { className: "h-full flex items-center justify-center p-8", children: /* @__PURE__ */ jsxs(Typography, { className: "text-red-500", children: [
19377
+ return /* @__PURE__ */ jsx("div", { ref: containerRef, className: "w-full p-4", children: dataLoadingError ? /* @__PURE__ */ jsx("div", { className: "h-full flex items-center justify-center p-8", children: /* @__PURE__ */ jsxs(Typography, { className: "text-red-500", children: [
19266
19378
  "Error loading data: ",
19267
19379
  dataLoadingError.message
19268
- ] }) }) : isInitialLoading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-12 px-8", children: /* @__PURE__ */ jsx(CircularProgress, { size: "small" }) }) : isEmpty ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-12 px-8", children: emptyComponent ?? /* @__PURE__ */ jsx(Typography, { variant: "label", color: "secondary", children: "No entries found" }) }) : /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("div", { className: "max-w-7xl mx-auto", children: [
19380
+ ] }) }) : isInitialLoading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-12 px-8", children: /* @__PURE__ */ jsx(CircularProgress, { size: "small" }) }) : isEmpty ? /* @__PURE__ */ jsx("div", { className: "w-full flex items-center justify-center py-12 px-8", children: emptyComponent ?? /* @__PURE__ */ jsx(Typography, { variant: "label", color: "secondary", children: "No entries found" }) }) : /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("div", { className: "max-w-7xl mx-auto", children: [
19269
19381
  /* @__PURE__ */ jsx("div", { className: cls("grid gap-4", gridColumnsClass), children: data.map((entity_3) => /* @__PURE__ */ jsx(EntityCard, { entity: entity_3, collection, onClick: handleEntityClick, selected: isEntitySelected(entity_3), highlighted: isEntityHighlighted(entity_3), onSelectionChange: handleSelectionChange, selectionEnabled, size }, `${entity_3.path}_${entity_3.id}`)) }),
19270
- /* @__PURE__ */ jsxs("div", { ref: loadMoreRef, className: "flex items-center justify-center py-8", children: [
19382
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center py-8", children: [
19271
19383
  dataLoading && /* @__PURE__ */ jsx(CircularProgress, { size: "small" }),
19272
19384
  !dataLoading && noMoreToLoad && data.length > 0 && /* @__PURE__ */ jsxs(Typography, { variant: "caption", color: "secondary", children: [
19273
19385
  "All ",
@@ -19659,7 +19771,7 @@ function EntityCollectionListView({
19659
19771
  return /* @__PURE__ */ jsx("div", { ref: containerRef, className: cls("w-full", selectedEntityId === void 0 && "rounded-lg overflow-hidden border " + defaultBorderMixin), children: dataLoadingError ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center p-8", children: /* @__PURE__ */ jsxs(Typography, { className: "text-red-500", children: [
19660
19772
  "Error loading data: ",
19661
19773
  dataLoadingError.message
19662
- ] }) }) : isInitialLoading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-12 px-8", children: /* @__PURE__ */ jsx(CircularProgress, { size: "small" }) }) : isEmpty ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-12 px-8", children: emptyComponent ?? /* @__PURE__ */ jsx(Typography, { variant: "label", color: "secondary", children: "No entries found" }) }) : (
19774
+ ] }) }) : isInitialLoading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-12 px-8", children: /* @__PURE__ */ jsx(CircularProgress, { size: "small" }) }) : isEmpty ? /* @__PURE__ */ jsx("div", { className: "w-full flex items-center justify-center py-12 px-8", children: emptyComponent ?? /* @__PURE__ */ jsx(Typography, { variant: "label", color: "secondary", children: "No entries found" }) }) : (
19663
19775
  /* Spacer with total height — no internal scroll.
19664
19776
  The nearest scrollable ancestor provides the scrollbar. */
19665
19777
  /* @__PURE__ */ jsxs("div", { style: {
@@ -24748,7 +24860,7 @@ const EntityCollectionView = React__default.memo(function EntityCollectionView2(
24748
24860
  /* @__PURE__ */ jsx(EntityCollectionListView, { collection, tableController, onEntityClick, selectionController: usedSelectionController, selectionEnabled, highlightedEntities: highlightedEntity ? [highlightedEntity] : [], size: listSize, emptyComponent, selectedEntityId: selectedEntityIdProp, getActionsForEntity, path, openEntityMode }, `list-view-${path}`)
24749
24861
  ] }) : innerView }, `split-list-view-${path}`) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col w-full h-full", children: [
24750
24862
  toolbarNode,
24751
- /* @__PURE__ */ jsx("div", { className: cls("flex-1 flex flex-col", viewMode === "list" && "overflow-y-auto"), children: viewMode === "list" ? /* @__PURE__ */ jsxs("div", { className: cls("flex flex-col w-full", selectedEntityIdProp === void 0 ? "max-w-6xl mx-auto px-3 md:px-4 lg:px-6 py-4" : ""), children: [
24863
+ /* @__PURE__ */ jsx("div", { className: cls("flex-1 flex flex-col", (viewMode === "list" || viewMode === "cards") && "overflow-y-auto"), children: viewMode === "list" ? /* @__PURE__ */ jsxs("div", { className: cls("flex flex-col w-full", selectedEntityIdProp === void 0 ? "max-w-6xl mx-auto px-3 md:px-4 lg:px-6 py-4" : ""), children: [
24752
24864
  /* @__PURE__ */ jsx("div", { className: cls("grid transition-[grid-template-rows,transform,margin] duration-150 ease-out", selectedEntityIdProp === void 0 ? "grid-rows-[1fr] translate-y-0 mt-12 mb-6" : "grid-rows-[0fr] -translate-y-2 mt-0 mb-0"), children: /* @__PURE__ */ jsx("div", { className: "overflow-hidden flex items-center gap-4", children: /* @__PURE__ */ jsx(Typography, { gutterBottom: true, variant: "h4", className: "grow mb-0", component: "h4", children: collection.name }) }) }),
24753
24865
  pluginInsights.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: pluginInsights }),
24754
24866
  innerView
@@ -26926,7 +27038,7 @@ function useLocalCollectionsConfigController(clientOrUrl, baseCollections = [],
26926
27038
  }
26927
27039
  const EMPTY_PLUGINS = [];
26928
27040
  const EMPTY_COLLECTIONS = [];
26929
- const CollectionsStudioView = lazy(() => import("./CollectionsStudioView-C-Ts1rZt.js").then((n) => n.b).then((m) => ({
27041
+ const CollectionsStudioView = lazy(() => import("./CollectionsStudioView-bsg4AT_Z.js").then((n) => n.b).then((m) => ({
26930
27042
  default: m.CollectionsStudioView
26931
27043
  })));
26932
27044
  function RebaseNavigation({
@@ -27164,10 +27276,10 @@ function _temp$3(event) {
27164
27276
  event.preventDefault();
27165
27277
  event.stopPropagation();
27166
27278
  }
27167
- const CollectionEditorDialog = lazy(() => import("./CollectionEditorDialog-Cn8-tGyL.js").then((m) => ({
27279
+ const CollectionEditorDialog = lazy(() => import("./CollectionEditorDialog-Bo86h-d-.js").then((m) => ({
27168
27280
  default: m.CollectionEditorDialog
27169
27281
  })));
27170
- const PropertyFormDialog = lazy(() => import("./PropertyEditView-BDNYkfNf.js").then((n) => n.P).then((m) => ({
27282
+ const PropertyFormDialog = lazy(() => import("./PropertyEditView-jCWCxmCz.js").then((n) => n.P).then((m) => ({
27171
27283
  default: m.PropertyFormDialog
27172
27284
  })));
27173
27285
  function CollectionEditorDialogs() {
@@ -28759,6 +28871,9 @@ const PropertyCollectionView = (t0) => {
28759
28871
  if (value === null || value === void 0) {
28760
28872
  return null;
28761
28873
  }
28874
+ if (baseKey === "" && !properties[key]) {
28875
+ return null;
28876
+ }
28762
28877
  const currentKey_0 = baseKey ? `${baseKey}.${key}` : key;
28763
28878
  return /* @__PURE__ */ jsx(PropertyCollectionView, { data: value, properties, baseKey: currentKey_0, size }, currentKey_0);
28764
28879
  };
@@ -29862,15 +29977,15 @@ function validateProperty(property, path, errors) {
29862
29977
  });
29863
29978
  return;
29864
29979
  }
29865
- if (!property.dataType) {
29980
+ if (!property.type) {
29866
29981
  errors.push({
29867
- path: `${path}.dataType`,
29982
+ path: `${path}.type`,
29868
29983
  message: "Required field is missing"
29869
29984
  });
29870
- } else if (!VALID_DATA_TYPES.includes(property.dataType)) {
29985
+ } else if (!VALID_DATA_TYPES.includes(property.type)) {
29871
29986
  errors.push({
29872
- path: `${path}.dataType`,
29873
- message: `Invalid value "${property.dataType}", expected one of: ${VALID_DATA_TYPES.join(", ")}`
29987
+ path: `${path}.type`,
29988
+ message: `Invalid value "${property.type}", expected one of: ${VALID_DATA_TYPES.join(", ")}`
29874
29989
  });
29875
29990
  }
29876
29991
  if (property.name !== void 0 && typeof property.name !== "string") {
@@ -29879,7 +29994,7 @@ function validateProperty(property, path, errors) {
29879
29994
  message: "Must be a string"
29880
29995
  });
29881
29996
  }
29882
- if (property.dataType === "array") {
29997
+ if (property.type === "array") {
29883
29998
  if (property.of) {
29884
29999
  if (Array.isArray(property.of)) {
29885
30000
  property.of.forEach((ofProp, index) => {
@@ -29900,10 +30015,10 @@ function validateProperty(property, path, errors) {
29900
30015
  }
29901
30016
  }
29902
30017
  }
29903
- if (property.dataType === "map" && property.properties) {
30018
+ if (property.type === "map" && property.properties) {
29904
30019
  validateProperties(property.properties, `${path}.properties`, errors);
29905
30020
  }
29906
- if (property.dataType === "reference") {
30021
+ if (property.type === "reference") {
29907
30022
  if (property.path !== void 0 && typeof property.path !== "string") {
29908
30023
  errors.push({
29909
30024
  path: `${path}.path`,
@@ -29911,7 +30026,7 @@ function validateProperty(property, path, errors) {
29911
30026
  });
29912
30027
  }
29913
30028
  }
29914
- if (property.dataType === "relation") {
30029
+ if (property.type === "relation") {
29915
30030
  if (property.target !== void 0 && typeof property.target !== "string" && typeof property.target !== "function") {
29916
30031
  errors.push({
29917
30032
  path: `${path}.target`,
@@ -29983,7 +30098,7 @@ function validateProperty(property, path, errors) {
29983
30098
  });
29984
30099
  }
29985
30100
  }
29986
- if (property.dataType === "vector") {
30101
+ if (property.type === "vector") {
29987
30102
  if (property.dimensions !== void 0 && (typeof property.dimensions !== "number" || isNaN(property.dimensions) || property.dimensions <= 0)) {
29988
30103
  errors.push({
29989
30104
  path: `${path}.dimensions`,
@@ -29991,7 +30106,7 @@ function validateProperty(property, path, errors) {
29991
30106
  });
29992
30107
  }
29993
30108
  }
29994
- if (property.dataType === "string" && property.storage) {
30109
+ if (property.type === "string" && property.storage) {
29995
30110
  if (typeof property.storage !== "object") {
29996
30111
  errors.push({
29997
30112
  path: `${path}.storage`,
@@ -30387,4 +30502,4 @@ export {
30387
30502
  EntityCollectionTable as y,
30388
30503
  EntityCollectionView as z
30389
30504
  };
30390
- //# sourceMappingURL=util-0GYaJqL_.js.map
30505
+ //# sourceMappingURL=util-CvNp6A-r.js.map