@burojs/ui-shadcn 0.5.0 → 0.6.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 (133) hide show
  1. package/dist/candidates-gate-Bb70LPAy.js +135 -0
  2. package/dist/candidates-gate-Bb70LPAy.js.map +1 -0
  3. package/dist/candidates-gate-D33jXLHO.cjs +153 -0
  4. package/dist/candidates-gate-D33jXLHO.cjs.map +1 -0
  5. package/dist/candidates-relation-picker-B116Bmqi.js +31 -0
  6. package/dist/candidates-relation-picker-B116Bmqi.js.map +1 -0
  7. package/dist/candidates-relation-picker-Cy0rTxvI.cjs +31 -0
  8. package/dist/candidates-relation-picker-Cy0rTxvI.cjs.map +1 -0
  9. package/dist/{check-confirm-dialog-BRByTFpg.cjs → check-confirm-dialog--gPFnEeg.cjs} +27 -14
  10. package/dist/check-confirm-dialog--gPFnEeg.cjs.map +1 -0
  11. package/dist/{check-confirm-dialog-CkaVTPT9.js → check-confirm-dialog-bRT8lt0d.js} +28 -15
  12. package/dist/check-confirm-dialog-bRT8lt0d.js.map +1 -0
  13. package/dist/{filter-builder-DOnaXNfP.js → filter-builder-Bhn-dhZV.js} +30 -14
  14. package/dist/filter-builder-Bhn-dhZV.js.map +1 -0
  15. package/dist/{filter-builder-B3mZFL-K.cjs → filter-builder-nXqtM_h4.cjs} +39 -11
  16. package/dist/filter-builder-nXqtM_h4.cjs.map +1 -0
  17. package/dist/{flow-runtime-B6zOHYqI.cjs → flow-runtime-D3avVH0I.cjs} +3 -3
  18. package/dist/{flow-runtime-B6zOHYqI.cjs.map → flow-runtime-D3avVH0I.cjs.map} +1 -1
  19. package/dist/{flow-runtime-D8h99FSg.js → flow-runtime-s6lkRPKF.js} +3 -3
  20. package/dist/{flow-runtime-D8h99FSg.js.map → flow-runtime-s6lkRPKF.js.map} +1 -1
  21. package/dist/{flow-screen-CmbARSqg.js → flow-screen-CCvgDI9G.js} +11 -8
  22. package/dist/flow-screen-CCvgDI9G.js.map +1 -0
  23. package/dist/{flow-screen-CX05b3G9.cjs → flow-screen-Ci_Sik4Y.cjs} +10 -7
  24. package/dist/flow-screen-Ci_Sik4Y.cjs.map +1 -0
  25. package/dist/index.cjs +577 -56
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +181 -103
  28. package/dist/index.d.ts +181 -103
  29. package/dist/index.js +567 -45
  30. package/dist/index.js.map +1 -1
  31. package/dist/{inline-flow-host-C3H2UpSA.js → inline-flow-host-B6FI0ctQ.js} +3 -3
  32. package/dist/{inline-flow-host-C3H2UpSA.js.map → inline-flow-host-B6FI0ctQ.js.map} +1 -1
  33. package/dist/{inline-flow-host-B7U1OJUe.cjs → inline-flow-host-DV1et3c6.cjs} +3 -3
  34. package/dist/{inline-flow-host-B7U1OJUe.cjs.map → inline-flow-host-DV1et3c6.cjs.map} +1 -1
  35. package/dist/label-66W1qbke.js.map +1 -1
  36. package/dist/label-w6JYf2cF.cjs.map +1 -1
  37. package/dist/markdown/index.d.cts +2 -3
  38. package/dist/markdown/index.d.ts +2 -3
  39. package/dist/{page-flow-route-CQ7HsbBm.cjs → page-flow-route-hdnULWqd.cjs} +6 -6
  40. package/dist/{page-flow-route-CQ7HsbBm.cjs.map → page-flow-route-hdnULWqd.cjs.map} +1 -1
  41. package/dist/{page-flow-route-CyXSvXSE.js → page-flow-route-i3ZfJ1sd.js} +6 -6
  42. package/dist/{page-flow-route-CyXSvXSE.js.map → page-flow-route-i3ZfJ1sd.js.map} +1 -1
  43. package/dist/{place-node-SIp4XYQH.cjs → place-node-C5SmIAYU.cjs} +441 -135
  44. package/dist/place-node-C5SmIAYU.cjs.map +1 -0
  45. package/dist/{place-node--GdsP688.js → place-node-NraNYKPx.js} +420 -138
  46. package/dist/place-node-NraNYKPx.js.map +1 -0
  47. package/dist/{related-list-cards-B6x9HQQp.js → related-list-cards-BWZ9GfOG.js} +3 -3
  48. package/dist/{related-list-cards-B6x9HQQp.js.map → related-list-cards-BWZ9GfOG.js.map} +1 -1
  49. package/dist/{related-list-cards-nxuODlIA.cjs → related-list-cards-CFq3meUn.cjs} +3 -3
  50. package/dist/{related-list-cards-nxuODlIA.cjs.map → related-list-cards-CFq3meUn.cjs.map} +1 -1
  51. package/dist/{related-list-timeline-BYJKEbmA.cjs → related-list-timeline-CCzl71aA.cjs} +2 -2
  52. package/dist/{related-list-timeline-BYJKEbmA.cjs.map → related-list-timeline-CCzl71aA.cjs.map} +1 -1
  53. package/dist/{related-list-timeline-DEdfd-rr.js → related-list-timeline-yrPsjA3F.js} +2 -2
  54. package/dist/{related-list-timeline-DEdfd-rr.js.map → related-list-timeline-yrPsjA3F.js.map} +1 -1
  55. package/dist/{related-rows-zh5f_4QR.cjs → related-rows-ea43qhhy.cjs} +10 -11
  56. package/dist/related-rows-ea43qhhy.cjs.map +1 -0
  57. package/dist/{related-rows-B4levHcR.js → related-rows-o0_t-Yce.js} +7 -8
  58. package/dist/related-rows-o0_t-Yce.js.map +1 -0
  59. package/dist/{relation-create-BOaUe12G.cjs → relation-create-IA40t1hi.cjs} +10 -8
  60. package/dist/relation-create-IA40t1hi.cjs.map +1 -0
  61. package/dist/{relation-create-Bg-eEJLs.js → relation-create-h6F9B4C4.js} +10 -8
  62. package/dist/relation-create-h6F9B4C4.js.map +1 -0
  63. package/dist/{relation-many-picker-B-NCEUgX.cjs → relation-many-picker-C8zFEjwd.cjs} +14 -12
  64. package/dist/relation-many-picker-C8zFEjwd.cjs.map +1 -0
  65. package/dist/{relation-many-picker-gdAOD-qK.js → relation-many-picker-bvkjkv-k.js} +13 -11
  66. package/dist/relation-many-picker-bvkjkv-k.js.map +1 -0
  67. package/dist/{relation-picker-BAY77ivO.js → relation-picker-Z0ZJJ5uS.js} +68 -37
  68. package/dist/relation-picker-Z0ZJJ5uS.js.map +1 -0
  69. package/dist/{relation-picker-dialog-M0pQaWlp.cjs → relation-picker-dialog-0IzkjmiA.cjs} +17 -13
  70. package/dist/relation-picker-dialog-0IzkjmiA.cjs.map +1 -0
  71. package/dist/{relation-picker-dialog-hA9rYrZB.js → relation-picker-dialog-B6nIiJBf.js} +18 -14
  72. package/dist/relation-picker-dialog-B6nIiJBf.js.map +1 -0
  73. package/dist/{relation-picker-Da_uhFvA.cjs → relation-picker-gag0qSR5.cjs} +74 -37
  74. package/dist/relation-picker-gag0qSR5.cjs.map +1 -0
  75. package/dist/{resource-page-router-T4vS5gbJ.js → resource-page-router-3RUf9d1j.js} +44 -38
  76. package/dist/resource-page-router-3RUf9d1j.js.map +1 -0
  77. package/dist/{resource-page-router-OSQyRA5b.cjs → resource-page-router-PXfMW9nh.cjs} +42 -36
  78. package/dist/resource-page-router-PXfMW9nh.cjs.map +1 -0
  79. package/dist/{search-access-CURsWn-U.js → search-access-CPPmfuvy.js} +4 -19
  80. package/dist/search-access-CPPmfuvy.js.map +1 -0
  81. package/dist/{search-access-B7G5oR8n.cjs → search-access-Dugvttlg.cjs} +3 -24
  82. package/dist/search-access-Dugvttlg.cjs.map +1 -0
  83. package/dist/{toaster-CfCRLgR-.js → toaster-C02XbB9r.js} +30 -59
  84. package/dist/toaster-C02XbB9r.js.map +1 -0
  85. package/dist/{toaster-C7CiYA4Z.cjs → toaster-Cr51X7bz.cjs} +30 -83
  86. package/dist/toaster-Cr51X7bz.cjs.map +1 -0
  87. package/dist/{use-dialog-filter-state-BDcgS5Oz.js → use-dialog-filter-state-C--oMAZG.js} +2 -2
  88. package/dist/{use-dialog-filter-state-BDcgS5Oz.js.map → use-dialog-filter-state-C--oMAZG.js.map} +1 -1
  89. package/dist/{use-dialog-filter-state-BBCC0OEK.cjs → use-dialog-filter-state-Dhe8PcB5.cjs} +2 -2
  90. package/dist/{use-dialog-filter-state-BBCC0OEK.cjs.map → use-dialog-filter-state-Dhe8PcB5.cjs.map} +1 -1
  91. package/dist/use-theme-DFlpXils.cjs.map +1 -1
  92. package/dist/use-theme-dnE3Od3I.js.map +1 -1
  93. package/package.json +9 -9
  94. package/dist/candidates-gate-CX2PBu6l.js +0 -63
  95. package/dist/candidates-gate-CX2PBu6l.js.map +0 -1
  96. package/dist/candidates-gate-DiFI52r7.cjs +0 -70
  97. package/dist/candidates-gate-DiFI52r7.cjs.map +0 -1
  98. package/dist/candidates-relation-picker-CBsVcnPR.js +0 -82
  99. package/dist/candidates-relation-picker-CBsVcnPR.js.map +0 -1
  100. package/dist/candidates-relation-picker-Dd_GVLlu.cjs +0 -84
  101. package/dist/candidates-relation-picker-Dd_GVLlu.cjs.map +0 -1
  102. package/dist/check-confirm-dialog-BRByTFpg.cjs.map +0 -1
  103. package/dist/check-confirm-dialog-CkaVTPT9.js.map +0 -1
  104. package/dist/filter-builder-B3mZFL-K.cjs.map +0 -1
  105. package/dist/filter-builder-DOnaXNfP.js.map +0 -1
  106. package/dist/flow-screen-CX05b3G9.cjs.map +0 -1
  107. package/dist/flow-screen-CmbARSqg.js.map +0 -1
  108. package/dist/lazy-relation-picker-dialog-2oxnA6IR.js +0 -14
  109. package/dist/lazy-relation-picker-dialog-2oxnA6IR.js.map +0 -1
  110. package/dist/lazy-relation-picker-dialog-BfAGKzUG.cjs +0 -19
  111. package/dist/lazy-relation-picker-dialog-BfAGKzUG.cjs.map +0 -1
  112. package/dist/peek-filter-CnqHwTMU.cjs +0 -51
  113. package/dist/peek-filter-CnqHwTMU.cjs.map +0 -1
  114. package/dist/peek-filter-ErLfO153.js +0 -28
  115. package/dist/peek-filter-ErLfO153.js.map +0 -1
  116. package/dist/place-node--GdsP688.js.map +0 -1
  117. package/dist/place-node-SIp4XYQH.cjs.map +0 -1
  118. package/dist/related-rows-B4levHcR.js.map +0 -1
  119. package/dist/related-rows-zh5f_4QR.cjs.map +0 -1
  120. package/dist/relation-create-BOaUe12G.cjs.map +0 -1
  121. package/dist/relation-create-Bg-eEJLs.js.map +0 -1
  122. package/dist/relation-many-picker-B-NCEUgX.cjs.map +0 -1
  123. package/dist/relation-many-picker-gdAOD-qK.js.map +0 -1
  124. package/dist/relation-picker-BAY77ivO.js.map +0 -1
  125. package/dist/relation-picker-Da_uhFvA.cjs.map +0 -1
  126. package/dist/relation-picker-dialog-M0pQaWlp.cjs.map +0 -1
  127. package/dist/relation-picker-dialog-hA9rYrZB.js.map +0 -1
  128. package/dist/resource-page-router-OSQyRA5b.cjs.map +0 -1
  129. package/dist/resource-page-router-T4vS5gbJ.js.map +0 -1
  130. package/dist/search-access-B7G5oR8n.cjs.map +0 -1
  131. package/dist/search-access-CURsWn-U.js.map +0 -1
  132. package/dist/toaster-C7CiYA4Z.cjs.map +0 -1
  133. package/dist/toaster-CfCRLgR-.js.map +0 -1
@@ -1,15 +1,15 @@
1
1
  import { l as cn } from "./use-theme-dnE3Od3I.js";
2
- import { d as useLinkComponent, f as Popover, g as PopoverTrigger, h as PopoverContent, n as toast, r as toFriendlyError } from "./toaster-CfCRLgR-.js";
3
- import { C as loadFailedText, D as preloadFlowRuntime, F as DropdownMenuGroup, I as DropdownMenuItem, K as DropdownMenuTrigger, L as DropdownMenuLabel, M as DropdownMenu, O as useLoaded, P as DropdownMenuContent, S as loadBulkSummary, T as loadInlineFlowHost, V as DropdownMenuSeparator, Z as DocInfo, _ as FlowBoundary, b as RuntimeBulkFlowRunner, c as useListSlot, d as useToBrowserHref, f as FlowActionButton, g as ActionInner, h as useFlowChrome, k as Icon, m as text, n as ActionButton, o as canonicalResourceName, p as FlowMenuItem, r as DisabledAction, t as CheckConfirmDialog, x as RuntimeFlowRunner, y as RuntimeAppFlowRunner } from "./check-confirm-dialog-CkaVTPT9.js";
2
+ import { d as PopoverTrigger, i as toFriendlyError, n as toast, o as useLinkComponent, r as friendlyStringsFrom, s as Popover, u as PopoverContent } from "./toaster-C02XbB9r.js";
3
+ import { C as loadFailedText, D as preloadFlowRuntime, F as DropdownMenuGroup, I as DropdownMenuItem, K as DropdownMenuTrigger, L as DropdownMenuLabel, M as DropdownMenu, O as useLoaded, P as DropdownMenuContent, S as loadBulkSummary, T as loadInlineFlowHost, V as DropdownMenuSeparator, Z as DocInfo, _ as FlowBoundary, b as RuntimeBulkFlowRunner, c as useListSlot, d as useToBrowserHref, f as FlowActionButton, g as ActionInner, h as useFlowChrome, k as Icon, m as text, n as ActionButton, o as canonicalResourceName, p as FlowMenuItem, r as DisabledAction, t as CheckConfirmDialog, x as RuntimeFlowRunner, y as RuntimeAppFlowRunner } from "./check-confirm-dialog-bRT8lt0d.js";
4
4
  import { t as Button } from "./button-MWVeZaqj.js";
5
5
  import { t as Input } from "./input-CUPStzZO.js";
6
6
  import { a as DialogFooter, i as DialogDescription, o as DialogHeader, r as DialogContent, s as DialogTitle, t as Dialog } from "./dialog-B_rt9S1c.js";
7
- import { m as ClaimedQuickLink, s as relationLinkClassName } from "./search-access-CURsWn-U.js";
7
+ import { o as relationLinkClassName, p as ClaimedQuickLink } from "./search-access-CPPmfuvy.js";
8
8
  import { t as Skeleton } from "./skeleton-U2noefj5.js";
9
+ import { C as TableHeader, S as TableHead, T as Badge, _ as SelectValue, c as Select, d as SelectItem, g as SelectTrigger, l as SelectContent, t as FilterBuilder, v as Table$1, w as TableRow, x as TableCell, y as TableBody } from "./filter-builder-Bhn-dhZV.js";
9
10
  import { t as Label } from "./label-66W1qbke.js";
10
- import { C as TableHeader, S as TableHead, T as Badge, _ as SelectValue, c as Select, d as SelectItem, g as SelectTrigger, l as SelectContent, t as FilterBuilder, v as Table$1, w as TableRow, x as TableCell, y as TableBody } from "./filter-builder-DOnaXNfP.js";
11
- import { BULK_EACH_LIMIT, FORM_SLOT, LAYOUT_SIZES, builtinFrames, canonicalEntityNodeKey, compileFlow, compiledScreenFor, composeListFilter, dtoFields, enumFallbackKey, enumNamespaceOf, facts, fieldOptionKey, fieldSensitivity, formatEntityRef, grantedPlacementKeys, hasRecordPage, humanizeKey, i18nPrefixToRef, i18nPrefixToRef as i18nPrefixToRef$1, inlineFlow, isBuiltinItemAction, isDataError, isScreenFailure, planItemActions, projectDto, recordEntries, relatedList, relatedRecord, resolveActionDensity, resolveActionSurfaceMode, resolveContentSlot, resolveEnumLabel, resolveFieldLabel, resolveFieldSlot, resolveNavLabel, resolveResourceLabel, resolveStaticAvailability, resourceKey, validatePlacementProps } from "@burojs/core";
12
- import { DismissGuardScope, FlowRowBatchContext, LOCAL_USER_SCOPE_ID, QUICK_ANCHOR_ATTRIBUTE, ResourceListProvider, RouteSourceContext, ScreenStateProvider, implementFrame, policyRecordOf, policyRowsOf, resolveRoute, resolveValidationMessage, resourceFlowsOn, useApp, useApplicationSnapshot, useAvailability, useCapability, useCapabilityResolver, useComponent, useCtx, useCurrentUserId, useCustomQuery, useDataRuntime, useDismissGuard, useEntryGate, useEnumValues, useExportRuns, useFieldAccess, useFieldImplementation, useFieldMeta, useFieldMetaSources, useFlowRowBatch, useFlowRowResolver, useFormController, useFrameImplementations, useFramePiece, useFrameT, useI18nCaps, useItemActions, useListAccess, useLocale, useNavigationBlocker, useOne, useOptionalDataRuntime, useOptionalRecordFrame, useOptionalRouterAdapter, useOptionalT, usePageFlowGate, usePageScreen, usePlacement, useProjectedRecord, useProjectedTitle, usePublishDocVariant, useQuick, useQuickEntry, useQuickOpener, useRecordFrame, useRecordTitle, useResource, useResourceExport, useResourceList, useResourceListContext, useRouteNavigate, useScreenState, useSearchParamsWriter, useT, useTestIds, useViewRow } from "@burojs/react";
11
+ import { BULK_EACH_LIMIT, FORM_SLOT, LAYOUT_SIZES, builtinFrames, canonicalEntityNodeKey, compileFlow, compiledScreenFor, composeListFilter, declaredField, declaredText, dtoFields, enumFallbackKey, enumFallbackText, enumNamespaceOf, enumValueText, exportFormatFieldKey, exportFormatLabelKey, exportFormatOptionKey, facts, fieldOptionText, fieldSensitivity, formatEntityRef, grantedPlacementKeys, hasRecordPage, humanizeKey, i18nPrefixToRef, i18nPrefixToRef as i18nPrefixToRef$1, inlineFlow, isBuiltinItemAction, isDataError, isLinkField, isRelationField, isScreenFailure, linkOf, normalizeEntityRef, planItemActions, projectDto, recordEntries, relatedList, relatedRecord, resolveActionDensity, resolveActionSurfaceMode, resolveContentSlot, resolveEnumLabel, resolveFieldLabel, resolveFieldOptionLabel, resolveFieldSlot, resolveNavLabel, resolveResourceLabel, resolveStaticAvailability, resolveTextSlot, resourceKey, resourceShowHref, savedViewKey, validatePlacementProps, whereEntryToFilter } from "@burojs/core";
12
+ import { DismissGuardScope, FlowRowBatchContext, LOCAL_USER_SCOPE_ID, QUICK_ANCHOR_ATTRIBUTE, ResourceListProvider, RouteSourceContext, ScreenStateProvider, implementFrame, policyRecordOf, policyRowsOf, resolveColumnField, resolveRoute, resolveValidationMessage, resourceFlowsOn, useApp, useApplicationSnapshot, useAvailability, useAvailabilityResolver, useCapability, useCapabilityResolver, useComponent, useCtx, useCurrentUserId, useCustomQuery, useDataRuntime, useDismissGuard, useEntryGate, useEnumValues, useExportRuns, useFieldAccess, useFieldImplementation, useFieldMeta, useFieldMetaSources, useFlowRowBatch, useFlowRowResolver, useFormController, useFrameImplementations, useFramePiece, useFrameT, useI18nCaps, useItemActions, useListAccess, useLocale, useNavigationBlocker, useOne, useOptionalDataRuntime, useOptionalRecordFrame, useOptionalRouterAdapter, useOptionalT, usePageFlowGate, usePageScreen, usePathAccess, usePlacement, useProjectedRecord, useProjectedTitle, usePublishDocVariant, useQuick, useQuickEntry, useQuickOpener, useRecordFrame, useRecordTitle, useResource, useResourceExport, useResourceList, useResourceListContext, useRouteNavigate, useScreenState, useSearchParamsWriter, useT, useTestIds, useViewRow } from "@burojs/react";
13
13
  import { IconAlertCircle, IconAlertTriangle, IconArrowDown, IconArrowLeft, IconArrowRight, IconArrowUp, IconBookmark, IconCheck, IconChevronLeft, IconChevronRight, IconChevronsLeft, IconChevronsRight, IconColumns3, IconCopy, IconDots, IconDownload, IconEyeOff, IconFilterX, IconInbox, IconLoader2, IconLock, IconMinus, IconPencil, IconPinned, IconPinnedOff, IconPlus, IconRefresh, IconSelector, IconSettings2, IconTrash, IconX } from "@tabler/icons-react";
14
14
  import * as React from "react";
15
15
  import { Component, Fragment, Suspense, createContext, createElement, lazy, memo, useCallback, useContext, useEffect, useId, useMemo, useRef, useState, useSyncExternalStore } from "react";
@@ -188,8 +188,7 @@ const SEMANTIC_KEYS = Object.freeze([
188
188
  "empty",
189
189
  "default",
190
190
  "constraints",
191
- "label",
192
- "description",
191
+ "texts",
193
192
  "options",
194
193
  "items",
195
194
  "properties",
@@ -283,6 +282,7 @@ function lowerLegacyField(field) {
283
282
  const format = ownString(field, "format") ?? mapping?.format ?? kind;
284
283
  const items = type === "array" ? projectFieldDeclaration(ownData(field, "items").value) ?? mapping?.items ?? STRING_ITEM : void 0;
285
284
  const meta = ownData(field, "meta");
285
+ const texts = ownData(field, "texts");
286
286
  const required = ownData(field, "required");
287
287
  const nullable = ownData(field, "nullable");
288
288
  const opts = ownData(field, "opts").value;
@@ -295,6 +295,7 @@ function lowerLegacyField(field) {
295
295
  ...format === void 0 ? {} : { format },
296
296
  ...items === void 0 ? {} : { items },
297
297
  ...meta.present && meta.value !== void 0 ? { meta: meta.value } : {},
298
+ ...texts.present && texts.value !== void 0 ? { texts: texts.value } : {},
298
299
  ...requiredValue === true ? { required: true } : {},
299
300
  ...nullableValue === true ? { nullable: true } : {}
300
301
  });
@@ -309,13 +310,8 @@ function lowerLegacyFieldSource(field) {
309
310
  });
310
311
  }
311
312
  function fieldDescription(field) {
312
- const source = field;
313
- for (const value of [
314
- source?.declaration?.description,
315
- source?.description,
316
- source?.opts?.description,
317
- source?.meta?.description
318
- ]) if (typeof value === "string" && value !== "") return value;
313
+ const declaration = field?.declaration;
314
+ return declaredText("field", declaration, "description") ?? declaredText("field", field, "description");
319
315
  }
320
316
  //#endregion
321
317
  //#region src/fields/resolved-field.tsx
@@ -639,7 +635,7 @@ function MisconfiguredLeaf({ node }) {
639
635
  });
640
636
  const state = useFieldMeta(field, resolved.implementation, sources);
641
637
  useFieldMetaDiagnostic(state, binding.resource, name, field, surface);
642
- const label = resolveFieldLabel(caps, name, typeof binding.field.label === "string" ? binding.field.label : void 0);
638
+ const label = resolveFieldLabel(caps, name, declaredText("field", binding.field, "label"));
643
639
  const testId = leafIds === "record" ? tid.formField(resource, mode, name) : `${leafIds.prefix}:field:${name}`;
644
640
  return jsxs("div", {
645
641
  ...leafAttributes("md", void 0),
@@ -664,8 +660,7 @@ function RecordLeaf({ node }) {
664
660
  const weight = compiled.nodes[node.index]?.options.weight;
665
661
  const caps = useI18nCaps(resource);
666
662
  const tid = useTestIds();
667
- const declared = binding.field;
668
- const label = resolveFieldLabel(caps, name, typeof declared.label === "string" ? declared.label : void 0);
663
+ const label = resolveFieldLabel(caps, name, declaredText("field", binding.field, "label"));
669
664
  const attributes = leafAttributes(size, weight);
670
665
  const t = useOptionalT();
671
666
  if (node.restricted === true) {
@@ -925,7 +920,7 @@ function DeclarativeLeaf({ node, prefix, inputIds }) {
925
920
  if (byId !== null && element.ownerDocument.activeElement === byId) return;
926
921
  element.querySelector(FOCUSABLE)?.focus();
927
922
  });
928
- const label = resolveFieldLabel(caps, name, binding.field.label);
923
+ const label = resolveFieldLabel(caps, name, declaredText("field", binding.field, "label"));
929
924
  const hint = resolveFieldSlot(caps, name, "description", fieldDescription(binding.field));
930
925
  const info = jsx(DocInfo, {
931
926
  address: `${docScope}/fields/${name}`,
@@ -1086,7 +1081,7 @@ function FactsView({ props }) {
1086
1081
  const pairs = shown.map((field) => {
1087
1082
  const value = data[field.name];
1088
1083
  const label = resolveContentSlot(caps, [`queries.${queryId}.fields.${field.name}.label`, `queries.${queryId}.fields.${field.name}`], {
1089
- ...typeof field.label === "string" ? { default: field.label } : {},
1084
+ ...declaredText("field", field, "label") === void 0 ? {} : { default: declaredText("field", field, "label") },
1090
1085
  humanize: () => humanizeKey(field.name)
1091
1086
  });
1092
1087
  const body = value === null || value === void 0 ? jsx("span", {
@@ -1357,11 +1352,11 @@ function PageInlineFlow({ flow }) {
1357
1352
  "data-buro-flow-state": "pending"
1358
1353
  });
1359
1354
  const appAction = "appAction" in target ? app.registry.appActions.get(target.appAction) : void 0;
1360
- const label = appAction === void 0 ? void 0 : resolveNavLabel(caps, `appActions.${"appAction" in target ? target.appAction : ""}`, appAction.label);
1355
+ const label = appAction === void 0 ? void 0 : resolveNavLabel(caps, `appActions.${"appAction" in target ? target.appAction : ""}`, declaredText("flow", appAction, "label"));
1361
1356
  const button = "appAction" in target ? jsx(AppFlowButton, {
1362
1357
  action: {
1363
1358
  name: target.appAction,
1364
- label: appAction?.label ?? target.appAction,
1359
+ label: declaredText("flow", appAction, "label") ?? target.appAction,
1365
1360
  ...appAction?.icon === void 0 ? {} : { icon: appAction.icon },
1366
1361
  ...answer.state === "disabled" ? { disabledReason: answer.reason ?? "" } : {}
1367
1362
  },
@@ -1579,7 +1574,7 @@ function EnumBadge({ enumName, value, testid, className, presentation }) {
1579
1574
  if (entry) {
1580
1575
  const body = jsx(BadgeBody, {
1581
1576
  icon: entry.icon,
1582
- label: resolveEnumLabel(caps, ns, value, entry.label)
1577
+ label: resolveEnumLabel(caps, ns, value, enumValueText(def, value) ?? entry.label)
1583
1578
  });
1584
1579
  if (presentation === "plain") return jsx("span", {
1585
1580
  "data-testid": id,
@@ -1595,15 +1590,16 @@ function EnumBadge({ enumName, value, testid, className, presentation }) {
1595
1590
  children: body
1596
1591
  });
1597
1592
  }
1598
- if (def.fallback) {
1599
- const fallbackLabel = resolveContentSlot(caps, [enumFallbackKey(ns)], { default: def.fallback.label }) ?? value;
1593
+ const declaredFallback = enumFallbackText(def);
1594
+ if (def?.fallback !== void 0 || declaredFallback !== void 0) {
1595
+ const fallbackLabel = resolveContentSlot(caps, [enumFallbackKey(ns)], { default: declaredFallback }) ?? value;
1600
1596
  if (presentation === "plain") return jsx("span", {
1601
1597
  "data-testid": `${id}:fallback`,
1602
1598
  className,
1603
1599
  children: fallbackLabel
1604
1600
  });
1605
1601
  return jsx(Badge, {
1606
- variant: def.fallback.color ?? "outline",
1602
+ variant: def?.fallback?.color ?? "outline",
1607
1603
  className,
1608
1604
  "data-testid": `${id}:fallback`,
1609
1605
  children: fallbackLabel
@@ -2210,15 +2206,7 @@ function nodeAttributes(node, kind = node.kind, tone) {
2210
2206
  }
2211
2207
  function useNodeText() {
2212
2208
  const caps = useI18nCaps();
2213
- return (slot) => {
2214
- if (slot === void 0) return void 0;
2215
- if (caps.has(slot.key)) return caps.t(slot.key);
2216
- if (slot.entry !== void 0 && caps.has(slot.entry)) {
2217
- const entry = caps.t(slot.entry);
2218
- if (typeof entry === "string" && entry !== slot.entry) return entry;
2219
- }
2220
- return slot.default;
2221
- };
2209
+ return (slot) => slot === void 0 ? void 0 : resolveTextSlot(caps, slot);
2222
2210
  }
2223
2211
  function NodeInfo({ node, name }) {
2224
2212
  const { resource } = useScreenTree();
@@ -2820,69 +2808,103 @@ function ColumnHeaderMenu({ label, sortDirection, sortable, onSort, pinned, onPi
2820
2808
  sortable && onSort && jsxs(DropdownMenuGroup, { children: [
2821
2809
  jsx(DropdownMenuLabel, {
2822
2810
  className: "text-xs font-medium text-muted-foreground",
2823
- children: tr("columnMenu.sortSection", "Сортировка")
2811
+ children: tr("columnMenu.sortSection", "Sort")
2824
2812
  }),
2825
2813
  jsxs(DropdownMenuItem, {
2826
2814
  onClick: () => onSort("asc"),
2827
2815
  "data-testid": testid ? `${testid}:sort-asc` : void 0,
2828
- children: [jsx(IconArrowUp, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.sortAsc", "По возрастанию")]
2816
+ children: [jsx(IconArrowUp, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.sortAsc", "Ascending")]
2829
2817
  }),
2830
2818
  jsxs(DropdownMenuItem, {
2831
2819
  onClick: () => onSort("desc"),
2832
2820
  "data-testid": testid ? `${testid}:sort-desc` : void 0,
2833
- children: [jsx(IconArrowDown, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.sortDesc", "По убыванию")]
2821
+ children: [jsx(IconArrowDown, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.sortDesc", "Descending")]
2834
2822
  }),
2835
2823
  sortDirection && jsxs(DropdownMenuItem, {
2836
2824
  onClick: () => onSort(null),
2837
- children: [jsx(IconX, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.clearSort", "Сбросить")]
2825
+ children: [jsx(IconX, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.clearSort", "Clear")]
2838
2826
  })
2839
2827
  ] }),
2840
2828
  onPin && jsxs(Fragment$1, { children: [sortable && onSort && jsx(DropdownMenuSeparator, {}), jsxs(DropdownMenuGroup, { children: [
2841
2829
  jsx(DropdownMenuLabel, {
2842
2830
  className: "text-xs font-medium text-muted-foreground",
2843
- children: tr("columnMenu.pinSection", "Закрепление")
2831
+ children: tr("columnMenu.pinSection", "Pin")
2844
2832
  }),
2845
2833
  pinned !== "left" && jsxs(DropdownMenuItem, {
2846
2834
  onClick: () => onPin("left"),
2847
2835
  "data-testid": testid ? `${testid}:pin-left` : void 0,
2848
- children: [jsx(IconPinned, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.pinLeft", "Слева")]
2836
+ children: [jsx(IconPinned, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.pinLeft", "Left")]
2849
2837
  }),
2850
2838
  pinned !== "right" && jsxs(DropdownMenuItem, {
2851
2839
  onClick: () => onPin("right"),
2852
- children: [jsx(IconPinned, { className: "mr-2 size-4 -scale-x-100 text-muted-foreground" }), tr("columnMenu.pinRight", "Справа")]
2840
+ children: [jsx(IconPinned, { className: "mr-2 size-4 -scale-x-100 text-muted-foreground" }), tr("columnMenu.pinRight", "Right")]
2853
2841
  }),
2854
2842
  pinned !== false && jsxs(DropdownMenuItem, {
2855
2843
  onClick: () => onPin(false),
2856
2844
  "data-testid": testid ? `${testid}:unpin` : void 0,
2857
- children: [jsx(IconPinnedOff, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.unpin", "Открепить")]
2845
+ children: [jsx(IconPinnedOff, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.unpin", "Unpin")]
2858
2846
  })
2859
2847
  ] })] }),
2860
2848
  canMove && jsxs(Fragment$1, { children: [jsx(DropdownMenuSeparator, {}), jsxs(DropdownMenuGroup, { children: [
2861
2849
  jsx(DropdownMenuLabel, {
2862
2850
  className: "text-xs font-medium text-muted-foreground",
2863
- children: tr("columnMenu.moveSection", "Перемещение")
2851
+ children: tr("columnMenu.moveSection", "Move")
2864
2852
  }),
2865
2853
  canMoveLeft && jsxs(DropdownMenuItem, {
2866
2854
  onClick: () => onMove?.("left"),
2867
2855
  "data-testid": testid ? `${testid}:move-left` : void 0,
2868
- children: [jsx(IconArrowLeft, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.moveLeft", "Влево")]
2856
+ children: [jsx(IconArrowLeft, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.moveLeft", "Left")]
2869
2857
  }),
2870
2858
  canMoveRight && jsxs(DropdownMenuItem, {
2871
2859
  onClick: () => onMove?.("right"),
2872
2860
  "data-testid": testid ? `${testid}:move-right` : void 0,
2873
- children: [jsx(IconArrowRight, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.moveRight", "Вправо")]
2861
+ children: [jsx(IconArrowRight, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.moveRight", "Right")]
2874
2862
  })
2875
2863
  ] })] }),
2876
2864
  canHide && onHide && jsxs(Fragment$1, { children: [jsx(DropdownMenuSeparator, {}), jsxs(DropdownMenuItem, {
2877
2865
  onClick: onHide,
2878
2866
  "data-testid": testid ? `${testid}:hide` : void 0,
2879
- children: [jsx(IconEyeOff, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.hide", "Скрыть колонку")]
2867
+ children: [jsx(IconEyeOff, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.hide", "Hide column")]
2880
2868
  })] })
2881
2869
  ]
2882
2870
  })]
2883
2871
  });
2884
2872
  }
2885
2873
  //#endregion
2874
+ //#region src/resource/column-accessor.ts
2875
+ function columnAccessor(column) {
2876
+ return column.includes(".") ? { accessorFn: (row) => row[column] } : { accessorKey: column };
2877
+ }
2878
+ //#endregion
2879
+ //#region src/resource/column-target.ts
2880
+ function columnTarget(registry, resource, column) {
2881
+ if (!column.includes(".")) return void 0;
2882
+ const resolved = resolveColumnField(registry, resource, column);
2883
+ if (resolved === void 0) return void 0;
2884
+ const ref = registry.get(resolved.resource)?.ref ?? {
2885
+ namespace: "default",
2886
+ id: resolved.resource
2887
+ };
2888
+ return {
2889
+ field: resolved.field,
2890
+ name: column.slice(column.lastIndexOf(".") + 1),
2891
+ resource: resolved.resource,
2892
+ ref
2893
+ };
2894
+ }
2895
+ function capsOf(caps, resource) {
2896
+ return {
2897
+ has: (key, options) => caps.has(key, {
2898
+ ...options,
2899
+ resource: options?.resource ?? resource
2900
+ }),
2901
+ t: (key, options) => caps.t(key, {
2902
+ ...options,
2903
+ resource: options?.resource ?? resource
2904
+ })
2905
+ };
2906
+ }
2907
+ //#endregion
2886
2908
  //#region src/data-table/use-buro-data-table.ts
2887
2909
  function useBuroDataTable(opts) {
2888
2910
  const { data, columns, total, getRowId, pagination, onPaginationChange, sorting, onSortingChange, columnFilters, onColumnFiltersChange, columnVisibility, onColumnVisibilityChange, rowSelection, onRowSelectionChange, enableRowSelection, columnPinning, onColumnPinningChange, columnSizing, onColumnSizingChange, columnOrder, onColumnOrderChange, enableColumnResizing } = opts;
@@ -2959,9 +2981,8 @@ function resolveUpdater(updater, prev) {
2959
2981
  //#region src/resource/list-error-state.tsx
2960
2982
  function ListErrorState({ error, onRetry, resource, title, className }) {
2961
2983
  const t = useT();
2962
- const locale = useLocale();
2963
2984
  const raw = error.message ?? "";
2964
- const friendly = toFriendlyError(raw, "", locale);
2985
+ const friendly = toFriendlyError(raw, "", friendlyStringsFrom(t));
2965
2986
  const friendlyError = friendly.replaced ? friendly.detail : raw;
2966
2987
  return jsxs("div", {
2967
2988
  role: "alert",
@@ -3086,7 +3107,7 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3086
3107
  25,
3087
3108
  50,
3088
3109
  100
3089
- ], onPage, loadMore, selectable = false, selectedIds, onSelectionChange, className, isLoading = false, error = null, onRetry, createHref, isFiltered = false, onClearFilter, emptyState, rowsView, rowHref, rowQuick, rowLinkKey, renderCell, sort, onSort, onHideColumn, requiredColumns, resetLayout, columns: columnsOverride, tableRef }) {
3110
+ ], onPage, loadMore, selectable = false, rowActions = true, selectedIds, onSelectionChange, className, isLoading = false, error = null, onRetry, createHref, isFiltered = false, onClearFilter, emptyState, rowsView, rowHref, rowQuick, rowLinkKey, renderCell, sort, onSort, onHideColumn, requiredColumns, resetLayout, columns: columnsOverride, tableRef }) {
3090
3111
  const app = useApp();
3091
3112
  const tid = useTestIds();
3092
3113
  const t = useOptionalT();
@@ -3133,15 +3154,19 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3133
3154
  setOwnSelection({});
3134
3155
  }, [data]);
3135
3156
  const listAccess = useListAccess(resource);
3136
- const accessPending = listAccess.status === "pending";
3157
+ const pathAccess = usePathAccess(resource);
3158
+ const accessPending = listAccess.status === "pending" || pathAccess.pending;
3137
3159
  const declaredColumnKeys = useMemo(() => {
3138
3160
  if (!def) return [];
3139
3161
  return [...columnsOverride ?? def.views?.list?.columns ?? Object.keys(def.fields)];
3140
3162
  }, [def, columnsOverride]);
3141
- const visibleColumnKeys = useMemo(() => accessPending ? [] : declaredColumnKeys.filter((col) => listAccess.columnVisible(col)), [
3163
+ const visibleColumnKeys = useMemo(() => accessPending ? [] : declaredColumnKeys.filter((col) => listAccess.columnVisible(col) && (columnTarget(app.registry, resource, col) === void 0 || listAccess.columnVisible(col.split(".")[0]) && pathAccess.visible(col))), [
3142
3164
  accessPending,
3143
3165
  declaredColumnKeys,
3144
- listAccess
3166
+ listAccess,
3167
+ pathAccess,
3168
+ app,
3169
+ resource
3145
3170
  ]);
3146
3171
  const skeletonColumnKeys = accessPending ? declaredColumnKeys : visibleColumnKeys;
3147
3172
  const rows = useMemo(() => data ?? [], [data]);
@@ -3242,14 +3267,18 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3242
3267
  })
3243
3268
  });
3244
3269
  for (const col of visibleColumnKeys) {
3245
- const field = def?.fields?.[col];
3246
- const headerLabel = resolveFieldLabel(volatileRef.current.i18nCaps, col, field?.label);
3270
+ const target = columnTarget(app.registry, resource, col);
3271
+ const field = target === void 0 ? def?.fields?.[col] : target.field;
3272
+ const declaredLabel = declaredText("field", field, "label");
3273
+ const headerLabel = target === void 0 ? resolveFieldLabel(volatileRef.current.i18nCaps, col, declaredLabel) : resolveFieldLabel(capsOf(volatileRef.current.i18nCaps, target.resource), target.name, declaredLabel);
3247
3274
  const kindSize = columnSize(field);
3275
+ const declared = target === void 0 && def !== void 0 ? declaredField(def, col) : void 0;
3276
+ const linkColumn = declared !== null && typeof declared === "object" && isLinkField(declared);
3248
3277
  cols.push({
3249
3278
  id: col,
3250
- accessorKey: col,
3279
+ ...columnAccessor(col),
3251
3280
  ...kindSize !== void 0 ? { size: kindSize } : {},
3252
- enableSorting: Boolean(volatileRef.current.onSort),
3281
+ enableSorting: !linkColumn && Boolean(volatileRef.current.onSort),
3253
3282
  enableHiding: true,
3254
3283
  meta: { testid: col },
3255
3284
  header: ({ column, table }) => {
@@ -3282,9 +3311,9 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3282
3311
  };
3283
3312
  return jsx(ColumnHeaderMenu, {
3284
3313
  label: headerLabel,
3285
- sortable: Boolean(v.onSort),
3314
+ sortable: !linkColumn && Boolean(v.onSort),
3286
3315
  sortDirection: v.sort?.[0]?.field === col ? v.sort[0].direction : null,
3287
- onSort: v.onSort ? (dir) => v.onSort?.(col, dir) : void 0,
3316
+ onSort: !linkColumn && v.onSort ? (dir) => v.onSort?.(col, dir) : void 0,
3288
3317
  pinned: column.getIsPinned(),
3289
3318
  onPin: (side) => column.pin(side),
3290
3319
  canHide: Boolean(v.onHideColumn) && !v.requiredColumns?.includes(col),
@@ -3301,8 +3330,8 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3301
3330
  const value = record[col];
3302
3331
  const customCell = volatileRef.current.renderCell?.(col, value, record);
3303
3332
  const cellInner = customCell !== void 0 ? customCell : jsx(ResolvedFieldDisplay, {
3304
- resource: resourceRef,
3305
- name: col,
3333
+ resource: target === void 0 ? resourceRef : target.ref,
3334
+ name: target === void 0 ? col : target.name,
3306
3335
  field: field ?? { type: "unknown" },
3307
3336
  value,
3308
3337
  record,
@@ -3335,6 +3364,7 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3335
3364
  }
3336
3365
  });
3337
3366
  }
3367
+ if (!rowActions) return cols;
3338
3368
  cols.push({
3339
3369
  id: ACTIONS_COL_ID,
3340
3370
  enableSorting: false,
@@ -3358,7 +3388,9 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3358
3388
  });
3359
3389
  return cols;
3360
3390
  }, [
3391
+ app,
3361
3392
  selectable,
3393
+ rowActions,
3362
3394
  resourceRef,
3363
3395
  visibleColumnKeys,
3364
3396
  def,
@@ -3792,7 +3824,7 @@ function ForceTableView(props) {
3792
3824
  function ListBodyView() {
3793
3825
  usePieceMount("body");
3794
3826
  const list = useResourceListContext();
3795
- const { resource, route, tableView, createAvailable, createPage, rowProps, rowsViewFor, emptyState, renderCell } = useListSurface();
3827
+ const { resource, route, tableView, createAvailable, createPage, rowProps, rowsViewFor, emptyState, renderCell, readOnly } = useListSurface();
3796
3828
  const item = useContext(ListItemContext);
3797
3829
  const rowsView = useMemo(() => rowsViewFor?.(item), [rowsViewFor, item]);
3798
3830
  const { query, pagination, cursor, count, columns, selection, filters, sorting, routing } = list;
@@ -3820,7 +3852,8 @@ function ListBodyView() {
3820
3852
  createHref: route && createAvailable && createPage ? routing.createHref : void 0,
3821
3853
  ...rowProps,
3822
3854
  ...rowsView === void 0 ? {} : { rowsView },
3823
- selectable: tableView,
3855
+ selectable: tableView && !readOnly,
3856
+ rowActions: !readOnly,
3824
3857
  selectedIds: selection.ids,
3825
3858
  onSelectionChange: selection.set,
3826
3859
  isFiltered: filters.isFiltered,
@@ -3931,7 +3964,10 @@ function PanelHost({ node, region = "panel-body", renderChildren }) {
3931
3964
  const state = useScreenState();
3932
3965
  const text = useNodeText();
3933
3966
  const options = compiled.nodes[node.index].options;
3934
- const title = text(options.title);
3967
+ const title = options.title?.humanized === true ? text({
3968
+ ...options.title,
3969
+ default: ""
3970
+ }) || void 0 : text(options.title);
3935
3971
  const description = text(options.description);
3936
3972
  const collapsible = options.collapse !== void 0;
3937
3973
  const open = !collapsible || node.open !== false;
@@ -4001,7 +4037,7 @@ function TabsHost({ node, renderChildren }) {
4001
4037
  const panel = panels.find((candidate) => panelValue(candidate) === key);
4002
4038
  if (panel !== void 0) select(panel, false);
4003
4039
  };
4004
- const titleOf = (panel) => text(compiled.nodes[panel.index].options.title) ?? panel.key ?? panel.id;
4040
+ const titleOf = (panel) => text(compiled.nodes[panel.index].options.title) ?? panel.id;
4005
4041
  const tabs = panels.map((panel) => ({
4006
4042
  key: panelValue(panel),
4007
4043
  title: titleOf(panel),
@@ -4044,7 +4080,7 @@ function StackedStepsHost({ node, renderChildren }) {
4044
4080
  const t = useFrameT(id);
4045
4081
  const steps = node.children.filter((child) => child.state !== "absent").map((panel) => {
4046
4082
  const options = compiled.nodes[panel.index].options;
4047
- const title = text(options.title) ?? panel.key ?? panel.id;
4083
+ const title = text(options.title) ?? panel.id;
4048
4084
  const description = text(options.description);
4049
4085
  return {
4050
4086
  key: panel.key ?? panel.id,
@@ -4092,7 +4128,7 @@ function WizardHost({ node, renderChildren }) {
4092
4128
  const current = panels.find((child) => child.open === true) ?? panels[0];
4093
4129
  const index = current === void 0 ? -1 : panels.indexOf(current);
4094
4130
  const idOf = (panel) => panel.key ?? panel.id;
4095
- const titleOf = (panel) => text(compiled.nodes[panel.index].options.title) ?? panel.key ?? panel.id;
4131
+ const titleOf = (panel) => text(compiled.nodes[panel.index].options.title) ?? panel.id;
4096
4132
  const headingRef = useRef(null);
4097
4133
  const shown = useRef(void 0);
4098
4134
  const currentId = current === void 0 ? void 0 : idOf(current);
@@ -4484,28 +4520,39 @@ function DeclarativeFormBody(props) {
4484
4520
  }
4485
4521
  //#endregion
4486
4522
  //#region src/export/format-option-labels.ts
4487
- function exportFormatOptionKey(formatId, field, value) {
4488
- return value === void 0 ? `export.format.${formatId}.${field}.label` : `export.format.${formatId}.${field}.option.${value}`;
4489
- }
4490
4523
  function localizeFormatOptions(caps, format) {
4491
4524
  const fields = format.options;
4492
4525
  if (fields === void 0) return void 0;
4493
4526
  const out = {};
4494
4527
  for (const [name, field] of Object.entries(fields)) {
4495
4528
  const declared = field;
4529
+ const label = resolveContentSlot(caps, [exportFormatFieldKey(format.id, name)], {
4530
+ default: declaredText("field", field, "label"),
4531
+ humanize: () => humanizeKey(name)
4532
+ });
4533
+ const options = declared.options?.map((option) => ({
4534
+ value: String(option.value),
4535
+ label: resolveContentSlot(caps, [exportFormatOptionKey(format.id, name, String(option.value))], {
4536
+ default: fieldOptionText(field, String(option.value)),
4537
+ humanize: () => String(option.value)
4538
+ })
4539
+ }));
4540
+ const declaredTexts = typeof declared.texts === "object" && declared.texts !== null ? declared.texts : {};
4541
+ const declaredOptions = declaredTexts.options ?? {};
4542
+ const texts = {
4543
+ ...declaredTexts,
4544
+ label,
4545
+ ...options === void 0 ? {} : { options: Object.fromEntries(options.map(({ value, label: optionLabel }) => {
4546
+ const entry = declaredOptions[value];
4547
+ return [value, typeof entry === "object" && entry !== null ? {
4548
+ ...entry,
4549
+ label: optionLabel
4550
+ } : optionLabel];
4551
+ })) }
4552
+ };
4496
4553
  out[name] = {
4497
4554
  ...field,
4498
- label: resolveContentSlot(caps, [exportFormatOptionKey(format.id, name)], {
4499
- default: typeof declared.label === "string" ? declared.label : void 0,
4500
- humanize: () => humanizeKey(name)
4501
- }),
4502
- ...declared.options === void 0 ? {} : { options: declared.options.map((option) => ({
4503
- ...option,
4504
- label: resolveContentSlot(caps, [exportFormatOptionKey(format.id, name, String(option.value))], {
4505
- default: option.label,
4506
- humanize: () => String(option.value)
4507
- })
4508
- })) }
4555
+ texts
4509
4556
  };
4510
4557
  }
4511
4558
  return out;
@@ -4544,10 +4591,13 @@ function ExportOptionsDirty({ dirty }) {
4544
4591
  return null;
4545
4592
  }
4546
4593
  function getNoRunState() {}
4547
- function ExportDialog({ open, onOpenChange, resource, target, visibleColumns, estimatedCount }) {
4594
+ function ExportDialog({ open, onOpenChange, resource, target, visibleColumns, estimatedCount, scope }) {
4548
4595
  const t = useOptionalT();
4549
4596
  const dialogTestId = useTestIds().exportDialog(resource);
4550
- const { formats, start, exporter, available, error, loading } = useResourceExport(resource, { load: open });
4597
+ const { formats, start, exporter, available, error, loading } = useResourceExport(resource, {
4598
+ load: open,
4599
+ ...scope === void 0 ? {} : { scope }
4600
+ });
4551
4601
  const [mode, setMode] = React.useState("form");
4552
4602
  const [formatIdOverride, setFormatIdOverride] = React.useState(void 0);
4553
4603
  const [columnsMode, setColumnsMode] = React.useState("visible");
@@ -4569,6 +4619,15 @@ function ExportDialog({ open, onOpenChange, resource, target, visibleColumns, es
4569
4619
  ]);
4570
4620
  const requestColumns = columnsMode === "visible" && visibleColumns.length > 0 ? exportableVisible : allowedListColumns;
4571
4621
  const selectedFormat = formats.find((f) => f.id === formatIdOverride) ?? formats[0];
4622
+ const reportedLabels = React.useRef(new Set());
4623
+ React.useEffect(() => {
4624
+ if (process.env.NODE_ENV === "production") return;
4625
+ for (const format of formats) {
4626
+ if ((Object.hasOwn(format, "label") ? format.label : void 0) === void 0 || reportedLabels.current.has(format.id)) continue;
4627
+ reportedLabels.current.add(format.id);
4628
+ console.error(`[ExportDialog] export format '${format.id}' declares label, which was removed: write texts — the text the bundle holds at common.${exportFormatLabelKey(format.id)} (see docs/i18n-guide.md).`);
4629
+ }
4630
+ }, [formats]);
4572
4631
  const caps = useI18nCaps();
4573
4632
  const localizedOptions = React.useMemo(() => selectedFormat === void 0 ? void 0 : localizeFormatOptions(caps, selectedFormat), [caps, selectedFormat]);
4574
4633
  const wasOpenRef = React.useRef(open);
@@ -4682,7 +4741,10 @@ function ExportDialog({ open, onOpenChange, resource, target, visibleColumns, es
4682
4741
  }), jsx(SelectContent, { children: formats.map((format) => jsx(SelectItem, {
4683
4742
  value: format.id,
4684
4743
  "data-testid": `${dialogTestId}:format:option:${format.id}`,
4685
- children: typeof format.label === "string" ? format.label : format.id
4744
+ children: resolveContentSlot(caps, [exportFormatLabelKey(format.id)], {
4745
+ default: declaredText("export-format", format, "label"),
4746
+ humanize: () => format.id
4747
+ })
4686
4748
  }, format.id)) })]
4687
4749
  })]
4688
4750
  }),
@@ -4896,7 +4958,7 @@ function orderBulkActions(actions) {
4896
4958
  seq: index
4897
4959
  })).sort((a, b) => a.weight - b.weight || a.seq - b.seq).map(({ action }) => action);
4898
4960
  }
4899
- function BulkActionToolbar({ resource, table, selectedRecords, selectedIds, onClearSelection, onSelectionChange, className, visibleColumns }) {
4961
+ function BulkActionToolbar({ resource, table, selectedRecords, selectedIds, onClearSelection, onSelectionChange, className, visibleColumns, scope }) {
4900
4962
  const app = useApp();
4901
4963
  const tid = useTestIds();
4902
4964
  const t = useOptionalT();
@@ -4944,7 +5006,8 @@ function BulkActionToolbar({ resource, table, selectedRecords, selectedIds, onCl
4944
5006
  jsx(BulkExportButton, {
4945
5007
  resource,
4946
5008
  ids,
4947
- visibleColumns: visibleColumns ?? []
5009
+ visibleColumns: visibleColumns ?? [],
5010
+ ...scope === void 0 ? {} : { scope }
4948
5011
  }),
4949
5012
  jsxs(Button, {
4950
5013
  type: "button",
@@ -4967,15 +5030,16 @@ function BulkActionToolbar({ resource, table, selectedRecords, selectedIds, onCl
4967
5030
  className: "h-20 sm:h-24"
4968
5031
  })] });
4969
5032
  }
4970
- function BulkExportButton({ resource, ids, visibleColumns }) {
5033
+ function BulkExportButton({ resource, ids, visibleColumns, scope }) {
4971
5034
  if (!(useOptionalDataRuntime() !== null)) return null;
4972
5035
  return jsx(BulkExportButtonActive, {
4973
5036
  resource,
4974
5037
  ids,
4975
- visibleColumns
5038
+ visibleColumns,
5039
+ ...scope === void 0 ? {} : { scope }
4976
5040
  });
4977
5041
  }
4978
- function BulkExportButtonActive({ resource, ids, visibleColumns }) {
5042
+ function BulkExportButtonActive({ resource, ids, visibleColumns, scope }) {
4979
5043
  const tid = useTestIds();
4980
5044
  const t = useOptionalT();
4981
5045
  const { available, prefetch } = useResourceExport(resource);
@@ -5010,23 +5074,25 @@ function BulkExportButtonActive({ resource, ids, visibleColumns }) {
5010
5074
  onOpenChange: setOpen,
5011
5075
  resource,
5012
5076
  target,
5013
- visibleColumns
5077
+ visibleColumns,
5078
+ ...scope === void 0 ? {} : { scope }
5014
5079
  })] });
5015
5080
  }
5016
5081
  //#endregion
5017
5082
  //#region src/list-kit/pieces/list-bulk-bar.tsx
5018
5083
  function ListBulkBarView() {
5019
5084
  usePieceMount("bulk-bar");
5020
- const { selection, columns } = useResourceListContext();
5021
- const { resource, tableView } = useListSurface();
5022
- if (!tableView || selection.ids.length === 0) return null;
5085
+ const { selection, columns, scope } = useResourceListContext();
5086
+ const { resource, tableView, readOnly } = useListSurface();
5087
+ if (!tableView || readOnly || selection.ids.length === 0) return null;
5023
5088
  return jsx(BulkActionToolbar, {
5024
5089
  resource,
5025
5090
  selectedRecords: selection.records,
5026
5091
  selectedIds: selection.ids,
5027
5092
  onClearSelection: selection.clear,
5028
5093
  onSelectionChange: selection.set,
5029
- visibleColumns: columns.visible
5094
+ visibleColumns: columns.visible,
5095
+ scope
5030
5096
  });
5031
5097
  }
5032
5098
  const ListBulkBar = listPiece("ListBulkBar", ListBulkBarView);
@@ -5111,6 +5177,7 @@ function DataTableViewOptions({ table, getColumnLabel, isColumnRequired, getTest
5111
5177
  function ColumnsToggle({ resource, def, allAvailable, required, visibleColumns, defaultVisible, onChange, onResetSizes, onRestoreDefaults }) {
5112
5178
  const t = useT();
5113
5179
  const columnsCaps = useI18nCaps(resource);
5180
+ const app = useApp();
5114
5181
  const visibleSet = useMemo(() => new Set(visibleColumns), [visibleColumns]);
5115
5182
  const requiredSet = useMemo(() => new Set(required), [required]);
5116
5183
  const defaultSet = useMemo(() => new Set(defaultVisible), [defaultVisible]);
@@ -5175,8 +5242,9 @@ function ColumnsToggle({ resource, def, allAvailable, required, visibleColumns,
5175
5242
  testid: `list-columns-restore-defaults:${resource}`
5176
5243
  }] : []],
5177
5244
  getColumnLabel: (column) => {
5178
- const fieldDef = def.fields?.[column.id];
5179
- return resolveFieldLabel(columnsCaps, column.id, fieldDef?.label);
5245
+ const target = columnTarget(app.registry, resource, column.id);
5246
+ if (target !== void 0) return resolveFieldLabel(capsOf(columnsCaps, target.resource), target.name, declaredText("field", target.field, "label"));
5247
+ return resolveFieldLabel(columnsCaps, column.id, declaredText("field", def.fields?.[column.id], "label"));
5180
5248
  },
5181
5249
  isColumnRequired: (column) => requiredSet.has(column.id),
5182
5250
  getTestId: (role, columnId) => {
@@ -5374,7 +5442,8 @@ function ExportButtonActive({ resource, className }) {
5374
5442
  resource,
5375
5443
  target,
5376
5444
  visibleColumns: list.columns.visible,
5377
- estimatedCount: list.pagination.total
5445
+ estimatedCount: list.pagination.total,
5446
+ scope: list.scope
5378
5447
  })] });
5379
5448
  }
5380
5449
  //#endregion
@@ -5382,8 +5451,8 @@ function ExportButtonActive({ resource, className }) {
5382
5451
  function ListExportView() {
5383
5452
  usePieceMount("export");
5384
5453
  const { def } = useResourceListContext();
5385
- const { resource } = useListSurface();
5386
- if (!def) return null;
5454
+ const { resource, exportable } = useListSurface();
5455
+ if (!def || !exportable) return null;
5387
5456
  return jsx(ExportButton, { resource });
5388
5457
  }
5389
5458
  const ListExport = listPiece("ListExport", ListExportView);
@@ -5432,7 +5501,7 @@ function FilterRegion({ search } = {}) {
5432
5501
  return searchDecl.fields.map((entry) => typeof entry === "string" ? entry : entry.field).find((name) => access.fieldVisible(name));
5433
5502
  })() : void 0;
5434
5503
  const searchGenericLabel = resolveContentSlot(listCaps, ["list.search"]) ?? "Search";
5435
- const searchLabel = searchField ? resolveFieldLabel(listCaps, searchField, (def?.fields[searchField])?.label) : searchGenericLabel;
5504
+ const searchLabel = searchField ? resolveFieldLabel(listCaps, searchField, declaredText("field", def?.fields[searchField], "label")) : searchGenericLabel;
5436
5505
  const searchPlaceholder = searchField ? t("toolbar.searchBy", { params: { name: searchLabel } }) : searchGenericLabel;
5437
5506
  return jsxs("div", {
5438
5507
  className: "flex flex-wrap items-center gap-2",
@@ -5578,13 +5647,19 @@ function ListLiveView() {
5578
5647
  const ListLive = listPiece("ListLive", ListLiveView);
5579
5648
  //#endregion
5580
5649
  //#region src/saved-views/saved-views-dropdown.tsx
5581
- function ViewItem({ view, onClick, testid }) {
5650
+ function ViewItem({ view, caps, resource, onClick, testid }) {
5651
+ const own = resource === void 0 ? void 0 : `resources.${resource}.${savedViewKey(view.id)}`;
5652
+ const declared = declaredText("saved-view", view, "label");
5653
+ const label = own === void 0 ? declared ?? humanizeKey(view.id) : resolveContentSlot(caps, [[`${own}.label`, own]], {
5654
+ default: declared,
5655
+ humanize: () => humanizeKey(view.id)
5656
+ });
5582
5657
  return jsx("button", {
5583
5658
  type: "button",
5584
5659
  onClick,
5585
5660
  "data-testid": testid,
5586
5661
  className: "w-full text-left rounded-sm px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
5587
- children: view.label
5662
+ children: label
5588
5663
  });
5589
5664
  }
5590
5665
  function EntryRow({ entry, onApply, onRename, onFork, onDelete, forkAvailable, applyTestId, renameTestId, forkTestId, deleteTestId, tr }) {
@@ -5674,8 +5749,9 @@ function groupByScope(entries) {
5674
5749
  }
5675
5750
  return order.map((id) => byId.get(id));
5676
5751
  }
5677
- function SavedViewsDropdown({ adopterViews, entries, issues = [], onApply, onSaveCurrent, canSaveCurrent = true, onManage, onRenameEntry, onDeleteEntry, onForkEntry, canFork = true, getTestId, triggerLabel = "Views", iconOnly = false, triggerClassName = "h-9", popoverContentClassName = "w-64 p-1", popoverAlign = "start" }) {
5752
+ function SavedViewsDropdown({ resource, adopterViews, entries, issues = [], onApply, onSaveCurrent, canSaveCurrent = true, onManage, onRenameEntry, onDeleteEntry, onForkEntry, canFork = true, getTestId, triggerLabel = "Views", iconOnly = false, triggerClassName = "h-9", popoverContentClassName = "w-64 p-1", popoverAlign = "start" }) {
5678
5753
  const t = useOptionalT();
5754
+ const caps = useI18nCaps(resource);
5679
5755
  const tr = (key, fallback) => t?.(key, { defaultValue: fallback }) ?? fallback;
5680
5756
  const [open, setOpen] = useState(false);
5681
5757
  const hasAdopter = adopterViews.length > 0;
@@ -5729,6 +5805,8 @@ function SavedViewsDropdown({ adopterViews, entries, issues = [], onApply, onSav
5729
5805
  className: "max-h-[200px] overflow-auto",
5730
5806
  children: adopterViews.map((v) => jsx(ViewItem, {
5731
5807
  view: v,
5808
+ caps,
5809
+ resource,
5732
5810
  testid: getTestId?.("view-item", v.id),
5733
5811
  onClick: closeAfter(() => onApply(v))
5734
5812
  }, v.id))
@@ -5785,6 +5863,7 @@ function ListSavedViewsView() {
5785
5863
  const { resource, route, savedViewsUi } = useListSurface();
5786
5864
  if (!def || !route) return null;
5787
5865
  return jsx(SavedViewsDropdown, {
5866
+ resource,
5788
5867
  adopterViews: savedViews.adopter,
5789
5868
  entries: savedViews.entries,
5790
5869
  issues: savedViews.issues,
@@ -5951,7 +6030,6 @@ function FormActionsView() {
5951
6030
  const navigate = useRouteNavigate();
5952
6031
  const t = useOptionalT();
5953
6032
  const tid = useTestIds();
5954
- const locale = useLocale();
5955
6033
  const id = useFrameId();
5956
6034
  if (mode === "show") return null;
5957
6035
  const busy = controller.isSubmitting;
@@ -5984,7 +6062,7 @@ function FormActionsView() {
5984
6062
  if (issue.params?.cause === void 0 || typeof checkId !== "string") continue;
5985
6063
  if (!retryable.includes(checkId)) retryable.push(checkId);
5986
6064
  }
5987
- const failure = chrome.submitError === void 0 ? void 0 : failureText(chrome.submitError, t, locale);
6065
+ const failure = chrome.submitError === void 0 ? void 0 : failureText(chrome.submitError, t);
5988
6066
  const steps = controller.steps;
5989
6067
  const midSteps = steps !== null && steps.ids.length > 1 && steps.current !== void 0 && steps.current !== steps.ids[steps.ids.length - 1];
5990
6068
  return jsxs("div", {
@@ -6093,8 +6171,8 @@ function issueKey(issue) {
6093
6171
  issue.params ?? null
6094
6172
  ]);
6095
6173
  }
6096
- function failureText(error, t, locale) {
6097
- const friendly = toFriendlyError(safeMessage(error), void 0, locale);
6174
+ function failureText(error, t) {
6175
+ const friendly = toFriendlyError(safeMessage(error), void 0, friendlyStringsFrom(t));
6098
6176
  return friendly.replaced ? friendly.title : t("errors.failed", { defaultValue: "Failed" });
6099
6177
  }
6100
6178
  function safeMessage(error) {
@@ -6421,14 +6499,16 @@ function ListFrameHost({ resource }) {
6421
6499
  }
6422
6500
  //#endregion
6423
6501
  //#region src/list-kit/resource-list-surface.tsx
6424
- const RelatedCards = lazy(async () => ({ default: (await import("./related-list-cards-B6x9HQQp.js")).RelatedCards }));
6425
- const RelatedTimeline = lazy(async () => ({ default: (await import("./related-list-timeline-DEdfd-rr.js")).RelatedTimeline }));
6502
+ const RelatedCards = lazy(async () => ({ default: (await import("./related-list-cards-BWZ9GfOG.js")).RelatedCards }));
6503
+ const RelatedTimeline = lazy(async () => ({ default: (await import("./related-list-timeline-yrPsjA3F.js")).RelatedTimeline }));
6426
6504
  function discriminatorOptionLabel(field, value) {
6505
+ const text = fieldOptionText(field, value);
6506
+ if (text !== void 0) return text;
6427
6507
  const declared = field;
6428
6508
  const label = (Array.isArray(declared?.options) ? declared.options : Array.isArray(declared?.meta?.options) ? declared.meta.options : []).find((option) => option?.value === value)?.label;
6429
6509
  return typeof label === "string" ? label : value;
6430
6510
  }
6431
- function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize, search: searchField, columns: columnNames, open, title, view, item, placementKey, onCreate, meta, renderCell, emptyState }) {
6511
+ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize, search: searchField, columns: columnNames, open, title, scope, view, item, placementKey, onCreate, count: countPolicy, rowTarget, readOnly, exportable, meta, renderCell, emptyState }) {
6432
6512
  const route = variant === "route";
6433
6513
  const t = useT();
6434
6514
  const optionalT = useOptionalT();
@@ -6451,7 +6531,9 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6451
6531
  ...fixedFilters === void 0 ? {} : { fixedFilters },
6452
6532
  ...pageSize === void 0 ? {} : { pageSize },
6453
6533
  ...searchDecl === void 0 ? {} : { search: searchDecl },
6454
- ...columnNames === void 0 ? {} : { columns: columnNames }
6534
+ ...columnNames === void 0 ? {} : { columns: columnNames },
6535
+ ...scope === void 0 ? {} : { scope },
6536
+ ...countPolicy === void 0 ? {} : { countPolicy }
6455
6537
  });
6456
6538
  const { def, query, pagination, cursor, count, filters, sorting, columns, selection, savedViews, routing, live, droppedPredicates } = list;
6457
6539
  policyRowsOf(list, list.rows);
@@ -6464,7 +6546,7 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6464
6546
  const gate = useEntryGate();
6465
6547
  const openQuick = useQuickOpener();
6466
6548
  const effectiveOpen = open ?? (route ? def !== void 0 && !hasRecordPage(def, "show") ? "quick" : "page" : "quick");
6467
- const quickRows = effectiveOpen === "quick";
6549
+ const quickRows = effectiveOpen === "quick" && rowTarget === void 0;
6468
6550
  useDeepLinkOpen(resource, resource, route && quickRows);
6469
6551
  const rowQuick = useMemo(() => quickRows ? (row) => gate(resource, "show", row).state === "open" ? () => void openQuick(resource, String(row.id), { row }) : null : void 0, [
6470
6552
  quickRows,
@@ -6472,8 +6554,31 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6472
6554
  openQuick,
6473
6555
  resource
6474
6556
  ]);
6475
- const rowHref = useMemo(() => effectiveOpen === "none" ? void 0 : quickRows ? (row) => gate(resource, "show", row).state === "undecided" ? void 0 : routing.rowHref(row) : routing.rowHref, [
6557
+ const registry = useApp().registry;
6558
+ const targetName = rowTarget?.resource;
6559
+ const targetField = rowTarget?.field;
6560
+ const targetGate = useAvailabilityResolver(targetName ?? resource);
6561
+ const targetHref = useMemo(() => {
6562
+ if (targetName === void 0 || targetField === void 0) return void 0;
6563
+ const targetDef = registry.get(targetName);
6564
+ const delegate = targetDef?.routesTo?.show;
6565
+ const showDef = delegate === void 0 ? targetDef : registry.get(delegate);
6566
+ const showPage = targetDef !== void 0 && showDef !== void 0 && hasRecordPage(showDef, "show");
6567
+ return (row) => {
6568
+ const key = row[targetField];
6569
+ if (!showPage || key === null || key === void 0 || key === "") return void 0;
6570
+ if (targetGate("show").state !== "available") return void 0;
6571
+ return resourceShowHref(registry, targetDef, targetName, String(key));
6572
+ };
6573
+ }, [
6574
+ registry,
6575
+ targetName,
6576
+ targetField,
6577
+ targetGate
6578
+ ]);
6579
+ const rowHref = useMemo(() => effectiveOpen === "none" ? void 0 : targetHref !== void 0 ? targetHref : quickRows ? (row) => gate(resource, "show", row).state === "undecided" ? void 0 : routing.rowHref(row) : routing.rowHref, [
6476
6580
  effectiveOpen,
6581
+ targetHref,
6477
6582
  quickRows,
6478
6583
  gate,
6479
6584
  resource,
@@ -6601,7 +6706,7 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6601
6706
  const fieldDef = def.fields[col];
6602
6707
  const inline = discriminatorOptionLabel(fieldDef, raw);
6603
6708
  const namespace = enumNamespaceOf(fieldDef);
6604
- const label = namespace === void 0 ? resolveContentSlot(listCaps, [fieldOptionKey(col, raw)], { default: inline }) : resolveEnumLabel(listCaps, namespace, raw, inline);
6709
+ const label = namespace === void 0 ? resolveFieldOptionLabel(listCaps, col, raw, inline) : resolveEnumLabel(listCaps, namespace, raw, inline);
6605
6710
  return jsx(Badge, {
6606
6711
  variant: "secondary",
6607
6712
  "data-testid": `list-cell-type:${resource}:${raw}`,
@@ -6643,7 +6748,9 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6643
6748
  },
6644
6749
  rowsViewFor,
6645
6750
  emptyState,
6646
- renderCell: renderCellLadder
6751
+ renderCell: renderCellLadder,
6752
+ readOnly: readOnly === true,
6753
+ exportable: exportable !== false
6647
6754
  };
6648
6755
  return jsx(ResourceListProvider, {
6649
6756
  value: list,
@@ -6872,6 +6979,180 @@ function ExportRunWatcherMount() {
6872
6979
  return null;
6873
6980
  }
6874
6981
  //#endregion
6982
+ //#region src/quick/peek-filter.ts
6983
+ function peekFieldDefinition(def, name) {
6984
+ return declaredField(def, name);
6985
+ }
6986
+ function peekLeafAllowed(def, name, capabilityFor, fieldVisible) {
6987
+ const field = peekFieldDefinition(def, name);
6988
+ if (field === void 0 || fieldSensitivity(field) !== void 0) return false;
6989
+ if (capabilityFor("view", {
6990
+ kind: "column",
6991
+ name
6992
+ }).allowed === false) return false;
6993
+ return fieldVisible(name);
6994
+ }
6995
+ function peekRow(def, row, idField, capabilityFor, fieldVisible, drawn) {
6996
+ const out = {};
6997
+ for (const [name, value] of Object.entries(row)) out[name] = name === idField || (drawn === void 0 || drawn.has(name)) && peekLeafAllowed(def, name, capabilityFor, fieldVisible) ? value : null;
6998
+ return Object.freeze(out);
6999
+ }
7000
+ function peekRecord(def, row, idField, capabilityFor, fieldVisible) {
7001
+ if (def === void 0) return Object.freeze({ [idField]: row[idField] });
7002
+ return peekRow(def, row, idField, capabilityFor, fieldVisible);
7003
+ }
7004
+ //#endregion
7005
+ //#region src/blocks/related-list-unbound.tsx
7006
+ function UnboundRelatedList(props) {
7007
+ const t = useOptionalT();
7008
+ return jsxs("div", {
7009
+ className: "flex flex-col gap-2",
7010
+ "data-testid": `list-unbound:${props.resource}`,
7011
+ children: [props.title === void 0 ? null : jsx("h3", {
7012
+ className: "text-sm font-semibold",
7013
+ children: props.title
7014
+ }), jsx("p", {
7015
+ className: "text-sm text-muted-foreground",
7016
+ children: t("table.empty", { defaultValue: "No records" })
7017
+ })]
7018
+ });
7019
+ }
7020
+ function placementScope(scope, owner) {
7021
+ return scope ?? (owner === void 0 ? "session" : "none");
7022
+ }
7023
+ //#endregion
7024
+ //#region src/blocks/link-panel.tsx
7025
+ const isRecord = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
7026
+ const isResourceHandle = (value) => isRecord(value) && value.kind === "resource";
7027
+ function qualify(ref, owner) {
7028
+ try {
7029
+ const namespace = normalizeEntityRef(owner).namespace;
7030
+ return resourceKey(normalizeEntityRef(isResourceHandle(ref) ? ref.ref : ref, { defaultNamespace: namespace }));
7031
+ } catch {
7032
+ return;
7033
+ }
7034
+ }
7035
+ function linkField(registry, owner, link) {
7036
+ if (owner === void 0) return void 0;
7037
+ const def = registry.get(owner);
7038
+ const field = def === void 0 ? void 0 : peekFieldDefinition(def, link);
7039
+ if (!isRecord(field)) return void 0;
7040
+ const declaration = linkOf(field);
7041
+ return declaration === void 0 ? void 0 : {
7042
+ field,
7043
+ declaration
7044
+ };
7045
+ }
7046
+ function linkTarget(registry, owner, link) {
7047
+ const found = linkField(registry, owner, link);
7048
+ if (found === void 0 || owner === void 0) return void 0;
7049
+ return qualify(found.field.meta?.to, owner);
7050
+ }
7051
+ function idFieldOf(def) {
7052
+ const declared = isRecord(def) && isRecord(def.data) ? def.data.idField : void 0;
7053
+ return typeof declared === "string" && declared.length > 0 ? declared : "id";
7054
+ }
7055
+ function byOf(field) {
7056
+ const by = isRecord(field) && isRecord(field.meta) ? field.meta.by : void 0;
7057
+ return typeof by === "string" && by.length > 0 ? by : void 0;
7058
+ }
7059
+ const MAX_TARGET_HOPS = 2;
7060
+ function targetColumns(registry, target, def) {
7061
+ if (!isRecord(def) || !isRecord(def.fields)) return [];
7062
+ const source = def;
7063
+ const views = isRecord(def.views) ? def.views : void 0;
7064
+ const list = views !== void 0 && isRecord(views.list) ? views.list : void 0;
7065
+ return (list !== void 0 && Array.isArray(list.columns) ? list.columns.filter((name) => typeof name === "string") : dtoFields(source, "list")).filter((name) => {
7066
+ if (name.includes(".")) return name.split(".").length - 1 <= MAX_TARGET_HOPS && resolveColumnField(registry, target, name) !== void 0;
7067
+ const field = peekFieldDefinition(source, name);
7068
+ return isRecord(field) && !isRelationField(field) && fieldSensitivity(field) === void 0;
7069
+ });
7070
+ }
7071
+ function LinkPanel(props) {
7072
+ const { link, owner, own } = props;
7073
+ const app = useApp();
7074
+ const frame = usePlacementFrame();
7075
+ const routeScreen = useIsRouteScreen();
7076
+ const record = useOptionalRecordFrame()?.record;
7077
+ const storage = useMemo(() => {
7078
+ const found = linkField(app.registry, owner, link);
7079
+ if (found === void 0) return void 0;
7080
+ const { declaration } = found;
7081
+ const junction = qualify(declaration.junction, owner);
7082
+ const target = qualify(found.field.meta?.to, owner);
7083
+ if (junction === void 0 || target === void 0) return void 0;
7084
+ const junctionDef = app.registry.get(junction);
7085
+ if (junctionDef === void 0) return void 0;
7086
+ const junctionFields = junctionDef.fields;
7087
+ return {
7088
+ junction,
7089
+ target,
7090
+ sourceKey: declaration.sourceKey,
7091
+ targetKey: declaration.targetKey,
7092
+ ownerField: byOf(junctionFields[declaration.sourceKey]) ?? idFieldOf(app.registry.get(owner)),
7093
+ targetKeyedBy: byOf(junctionFields[declaration.targetKey]) !== void 0,
7094
+ where: declaration.where,
7095
+ targetDef: app.registry.get(target)
7096
+ };
7097
+ }, [
7098
+ app.registry,
7099
+ owner,
7100
+ link
7101
+ ]);
7102
+ const ownerKey = storage === void 0 ? void 0 : record?.[storage.ownerField];
7103
+ const whereKey = JSON.stringify(own.where ?? []);
7104
+ const fixedFilters = useMemo(() => {
7105
+ if (storage === void 0 || ownerKey === null || ownerKey === void 0) return void 0;
7106
+ const { sourceKey, targetKey } = storage;
7107
+ return [
7108
+ whereEntryToFilter(sourceKey, "eq", ownerKey),
7109
+ ...storage.where.map((entry) => whereEntryToFilter(entry.field, entry.op, entry.value)),
7110
+ ...(own.where ?? []).map((entry) => whereEntryToFilter(`${targetKey}.${entry.field}`, entry.op, entry.value))
7111
+ ];
7112
+ }, [
7113
+ storage,
7114
+ ownerKey,
7115
+ whereKey
7116
+ ]);
7117
+ const columnsKey = JSON.stringify([own.columns ?? null, own.linkColumns ?? null]);
7118
+ const columns = useMemo(() => {
7119
+ if (storage === void 0) return void 0;
7120
+ return [...(own.columns ?? targetColumns(app.registry, storage.target, storage.targetDef)).map((name) => `${storage.targetKey}.${name}`), ...own.linkColumns ?? []];
7121
+ }, [
7122
+ storage,
7123
+ columnsKey,
7124
+ app.registry
7125
+ ]);
7126
+ const rowTarget = useMemo(() => storage === void 0 || storage.targetKeyedBy ? void 0 : {
7127
+ resource: storage.target,
7128
+ field: storage.targetKey
7129
+ }, [storage]);
7130
+ const unbound = fixedFilters === void 0 || own.where?.some((entry) => entry.value === null || entry.value === void 0) === true;
7131
+ if (storage === void 0 || unbound) return jsx(UnboundRelatedList, {
7132
+ resource: storage?.target ?? "",
7133
+ title: own.title
7134
+ });
7135
+ const state = frame?.state === "url" && routeScreen && !frame.nested ? { url: frame.key } : "memory";
7136
+ const count = own.count === false ? "off" : own.count;
7137
+ return jsx(ResourceListSurface, {
7138
+ resource: storage.junction,
7139
+ variant: "placement",
7140
+ state,
7141
+ fixedFilters,
7142
+ ...own.pageSize === void 0 ? {} : { pageSize: own.pageSize },
7143
+ ...own.search === void 0 ? {} : { search: `${storage.targetKey}.${own.search}` },
7144
+ ...columns === void 0 ? {} : { columns },
7145
+ open: rowTarget === void 0 || own.open === "none" ? "none" : "page",
7146
+ ...rowTarget === void 0 ? {} : { rowTarget },
7147
+ ...frame === null ? {} : { placementKey: frame.key },
7148
+ ...own.title === void 0 ? {} : { title: own.title },
7149
+ scope: placementScope(own.scope, owner),
7150
+ ...count === void 0 ? {} : { count },
7151
+ readOnly: true,
7152
+ exportable: false
7153
+ });
7154
+ }
7155
+ //#endregion
6875
7156
  //#region src/blocks/route-list-context.ts
6876
7157
  const RouteListContext = createContext(null);
6877
7158
  function useRouteList() {
@@ -6883,29 +7164,33 @@ function RelatedListView({ props }) {
6883
7164
  const own = props;
6884
7165
  const route = useRouteList();
6885
7166
  const frame = usePlacementFrame();
6886
- const resource = resourceKey(own.resource);
7167
+ const app = useApp();
7168
+ const linked = own.link !== void 0;
7169
+ const resource = linked ? linkTarget(app.registry, frame?.owner, own.link) ?? "" : resourceKey(own.resource);
6887
7170
  const whereKey = JSON.stringify(own.where ?? []);
6888
- const fixedFilters = useMemo(() => own.where === void 0 ? void 0 : own.where.map(({ field, op, value }) => ({
6889
- field,
6890
- op,
6891
- value
6892
- })), [whereKey]);
7171
+ const fixedFilters = useMemo(() => own.where === void 0 ? void 0 : own.where.map(({ field, op, value }) => whereEntryToFilter(field, op, value)), [whereKey]);
6893
7172
  const columnsKey = JSON.stringify(own.columns ?? null);
6894
7173
  const columns = useMemo(() => own.columns, [columnsKey]);
6895
7174
  const routeScreen = useIsRouteScreen();
6896
7175
  const inQuick = useQuickEntry() !== null;
6897
7176
  useMemoryNotice(frame, routeScreen || inQuick, route !== null);
6898
- const t = useOptionalT();
6899
7177
  const permissions = useCtx((c) => c.permissions);
6900
- const app = useApp();
6901
7178
  const gate = useEntryGate();
6902
7179
  const quick = useQuick();
6903
7180
  const ownerDef = frame?.owner === void 0 ? void 0 : app.registry.get(frame.owner);
6904
7181
  const granted = ownerDef === void 0 ? "unknown" : grantedPlacementKeys(ownerDef);
6905
7182
  const trusted = frame !== null && !frame.nested && granted !== "unknown" && !granted.has(frame.key);
6906
- const onCreate = route === null && trusted && gate(resource, "create").state === "open" && frame !== null ? () => void quick.create(resource, { defaults: placementSeeds(frame.where ?? [], own.where ?? [], frame.closure ?? {}) }) : void 0;
6907
- useDeepLinkOpen(frame?.key ?? null, resource, route === null && frame !== null && !frame.nested && routeScreen && (own.open ?? "quick") === "quick");
7183
+ const onCreate = route === null && !linked && trusted && gate(resource, "create").state === "open" && frame !== null ? () => void quick.create(resource, { defaults: placementSeeds(frame.where ?? [], own.where ?? [], frame.closure ?? {}) }) : void 0;
7184
+ useDeepLinkOpen(frame?.key ?? null, resource, route === null && !linked && frame !== null && !frame.nested && routeScreen && (own.open ?? "quick") === "quick");
6908
7185
  const unbound = own.where?.some((entry) => entry.value === null || entry.value === void 0) === true;
7186
+ if (linked) return frame?.owner === void 0 ? jsx(UnboundRelatedList, {
7187
+ resource,
7188
+ title: own.title
7189
+ }) : jsx(LinkPanel, {
7190
+ link: own.link,
7191
+ owner: frame.owner,
7192
+ own
7193
+ });
6909
7194
  if (route !== null) return jsx(ResourceListSurface, {
6910
7195
  resource,
6911
7196
  variant: "route",
@@ -6919,18 +7204,13 @@ function RelatedListView({ props }) {
6919
7204
  "data-testid": `list-undecided:${resource}`,
6920
7205
  children: own.view === "cards" ? jsx(RelatedCardsSkeleton, {}) : jsx(RelatedTimelineSkeleton, {})
6921
7206
  });
6922
- if (unbound) return jsxs("div", {
6923
- className: "flex flex-col gap-2",
6924
- "data-testid": `list-unbound:${resource}`,
6925
- children: [own.title === void 0 ? null : jsx("h3", {
6926
- className: "text-sm font-semibold",
6927
- children: own.title
6928
- }), jsx("p", {
6929
- className: "text-sm text-muted-foreground",
6930
- children: t("table.empty", { defaultValue: "No records" })
6931
- })]
7207
+ if (unbound) return jsx(UnboundRelatedList, {
7208
+ resource,
7209
+ title: own.title
6932
7210
  });
6933
7211
  const state = frame?.state === "url" && routeScreen && !frame.nested ? { url: frame.key } : "memory";
7212
+ const scope = placementScope(own.scope, frame?.owner);
7213
+ const count = own.count === false ? "off" : own.count;
6934
7214
  return jsx(ResourceListSurface, {
6935
7215
  resource,
6936
7216
  variant: "placement",
@@ -6944,6 +7224,8 @@ function RelatedListView({ props }) {
6944
7224
  ...isItemHandle(own.item) ? { item: own.item } : {},
6945
7225
  ...frame === null ? {} : { placementKey: frame.key },
6946
7226
  ...own.title === void 0 ? {} : { title: own.title },
7227
+ scope,
7228
+ ...count === void 0 ? {} : { count },
6947
7229
  ...onCreate === void 0 ? {} : { onCreate }
6948
7230
  });
6949
7231
  }
@@ -7048,7 +7330,7 @@ function RelatedRecordView({ props }) {
7048
7330
  className: "flex min-w-0 flex-col gap-0.5",
7049
7331
  children: [jsx("dt", {
7050
7332
  className: FIELD_LABEL_SHOW,
7051
- children: resolveFieldLabel(caps, name, field?.label)
7333
+ children: resolveFieldLabel(caps, name, declaredText("field", field, "label"))
7052
7334
  }), jsx("dd", {
7053
7335
  className: "min-w-0 break-words text-sm",
7054
7336
  children: jsx(ResolvedFieldDisplay, {
@@ -7310,6 +7592,6 @@ function PlaceNode({ node }) {
7310
7592
  });
7311
7593
  }
7312
7594
  //#endregion
7313
- export { Tabs as $, ListColumns as A, ShellProvider as At, RouteScreenClaimContext as B, ListFilters as C, AppFlowButton as Ct, ExportButton as D, ResolvedFieldDisplay as Dt, ListExport as E, i18nPrefixToRef$1 as Et, ExportDialog as F, CursorLoadMore as G, useIsRouteScreen as H, DeclarativeForm as I, resolveUpdater as J, ListErrorState as K, ScreenTree as L, DataTableViewOptions as M, usePaletteState as Mt, ListBulkBar as N, useShell as Nt, ListCreate as O, lowerLegacyField as Ot, BulkActionToolbar as P, Checkbox as Q, useTabsUrlState as R, ListFlows as S, DeepLinkScope as St, ListSearchInput as T, FieldDisplay as Tt, ListBody as U, RouteScreenContext as V, ResourceList as W, useBuroDataTable as X, tanStackSortingToBuro as Y, DataTable as Z, useFrameChrome as _, ActionOverflow as _t, isBuiltinRecordView as a, RELATED_GRID_CLASS as at, SavedViewsDropdown as b, downloadArtifact as bt, ChangeTypeButton as c, ShowPageHeader as ct, UndeclaredTypeNotice as d, typography as dt, TabsContent as et, CopyId as f, isShowAvailable as ft, FrameChromeContext as g, showTarget as gt, RecordTitle as h, recordRouteAvailable as ht, RouteListContext as i, useItemDrawn as it, ColumnsToggle as j, defaultUserMapper as jt, CreateButton as k, toDisplayText as kt, HeaderTypeNotice as l, DocumentTitleProvider as lt, RecordActions as m, recordReturnTarget as mt, viewOf as n, TabsTrigger as nt, resolveFrameView as o, EditPageHeader as ot, FormActions as p, listTarget as pt, buroSortingToTanStack as q, shadcnBlockImplementations as r, RelatedItem as rt, shadcnFrameViews as s, PageHeader as st, selectImplementation as t, TabsList as tt, TypeChromeDrawnContext as u, useDocumentTitle as ut, ListControls as v, useShownItemActions as vt, FilterRegion as w, Field as wt, ListLive as x, EnumBadge as xt, ListSavedViews as y, useExportRunWatcher as yt, QuickScreenClaimContext as z };
7595
+ export { tanStackSortingToBuro as $, ListExport as A, i18nPrefixToRef$1 as At, DeclarativeForm as B, ListSavedViews as C, useExportRunWatcher as Ct, ListFilters as D, AppFlowButton as Dt, ListFlows as E, DeepLinkScope as Et, ColumnsToggle as F, defaultUserMapper as Ft, RouteScreenContext as G, useTabsUrlState as H, DataTableViewOptions as I, usePaletteState as It, ResourceList as J, useIsRouteScreen as K, ListBulkBar as L, useShell as Lt, ListCreate as M, lowerLegacyField as Mt, CreateButton as N, toDisplayText as Nt, FilterRegion as O, Field as Ot, ListColumns as P, ShellProvider as Pt, resolveUpdater as Q, BulkActionToolbar as R, ListControls as S, useShownItemActions as St, ListLive as T, EnumBadge as Tt, QuickScreenClaimContext as U, ScreenTree as V, RouteScreenClaimContext as W, ListErrorState as X, CursorLoadMore as Y, buroSortingToTanStack as Z, FormActions as _, listTarget as _t, peekFieldDefinition as a, TabsList as at, FrameChromeContext as b, showTarget as bt, peekRow as c, useItemDrawn as ct, shadcnFrameViews as d, PageHeader as dt, useBuroDataTable as et, ChangeTypeButton as f, ShowPageHeader as ft, CopyId as g, isShowAvailable as gt, UndeclaredTypeNotice as h, typography as ht, RouteListContext as i, TabsContent as it, ExportButton as j, ResolvedFieldDisplay as jt, ListSearchInput as k, FieldDisplay as kt, isBuiltinRecordView as l, RELATED_GRID_CLASS as lt, TypeChromeDrawnContext as m, useDocumentTitle as mt, viewOf as n, Checkbox as nt, peekLeafAllowed as o, TabsTrigger as ot, HeaderTypeNotice as p, DocumentTitleProvider as pt, ListBody as q, shadcnBlockImplementations as r, Tabs as rt, peekRecord as s, RelatedItem as st, selectImplementation as t, DataTable as tt, resolveFrameView as u, EditPageHeader as ut, RecordActions as v, recordReturnTarget as vt, SavedViewsDropdown as w, downloadArtifact as wt, useFrameChrome as x, ActionOverflow as xt, RecordTitle as y, recordRouteAvailable as yt, ExportDialog as z };
7314
7596
 
7315
- //# sourceMappingURL=place-node--GdsP688.js.map
7597
+ //# sourceMappingURL=place-node-NraNYKPx.js.map