@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,13 +1,13 @@
1
1
  const require_use_theme = require("./use-theme-DFlpXils.cjs");
2
- const require_toaster = require("./toaster-C7CiYA4Z.cjs");
3
- const require_check_confirm_dialog = require("./check-confirm-dialog-BRByTFpg.cjs");
2
+ const require_toaster = require("./toaster-Cr51X7bz.cjs");
3
+ const require_check_confirm_dialog = require("./check-confirm-dialog--gPFnEeg.cjs");
4
4
  const require_button = require("./button-BxnnE28H.cjs");
5
5
  const require_input = require("./input-BI0czGyI.cjs");
6
6
  const require_dialog = require("./dialog-DRNUq9EA.cjs");
7
- const require_search_access = require("./search-access-B7G5oR8n.cjs");
7
+ const require_search_access = require("./search-access-Dugvttlg.cjs");
8
8
  const require_skeleton = require("./skeleton-_1gP7wan.cjs");
9
+ const require_filter_builder = require("./filter-builder-nXqtM_h4.cjs");
9
10
  const require_label = require("./label-w6JYf2cF.cjs");
10
- const require_filter_builder = require("./filter-builder-B3mZFL-K.cjs");
11
11
  let _burojs_core = require("@burojs/core");
12
12
  let _burojs_react = require("@burojs/react");
13
13
  let _tabler_icons_react = require("@tabler/icons-react");
@@ -191,8 +191,7 @@ const SEMANTIC_KEYS = Object.freeze([
191
191
  "empty",
192
192
  "default",
193
193
  "constraints",
194
- "label",
195
- "description",
194
+ "texts",
196
195
  "options",
197
196
  "items",
198
197
  "properties",
@@ -286,6 +285,7 @@ function lowerLegacyField(field) {
286
285
  const format = ownString(field, "format") ?? mapping?.format ?? kind;
287
286
  const items = type === "array" ? projectFieldDeclaration(ownData(field, "items").value) ?? mapping?.items ?? STRING_ITEM : void 0;
288
287
  const meta = ownData(field, "meta");
288
+ const texts = ownData(field, "texts");
289
289
  const required = ownData(field, "required");
290
290
  const nullable = ownData(field, "nullable");
291
291
  const opts = ownData(field, "opts").value;
@@ -298,6 +298,7 @@ function lowerLegacyField(field) {
298
298
  ...format === void 0 ? {} : { format },
299
299
  ...items === void 0 ? {} : { items },
300
300
  ...meta.present && meta.value !== void 0 ? { meta: meta.value } : {},
301
+ ...texts.present && texts.value !== void 0 ? { texts: texts.value } : {},
301
302
  ...requiredValue === true ? { required: true } : {},
302
303
  ...nullableValue === true ? { nullable: true } : {}
303
304
  });
@@ -312,13 +313,8 @@ function lowerLegacyFieldSource(field) {
312
313
  });
313
314
  }
314
315
  function fieldDescription(field) {
315
- const source = field;
316
- for (const value of [
317
- source?.declaration?.description,
318
- source?.description,
319
- source?.opts?.description,
320
- source?.meta?.description
321
- ]) if (typeof value === "string" && value !== "") return value;
316
+ const declaration = field?.declaration;
317
+ return (0, _burojs_core.declaredText)("field", declaration, "description") ?? (0, _burojs_core.declaredText)("field", field, "description");
322
318
  }
323
319
  //#endregion
324
320
  //#region src/fields/resolved-field.tsx
@@ -642,7 +638,7 @@ function MisconfiguredLeaf({ node }) {
642
638
  });
643
639
  const state = (0, _burojs_react.useFieldMeta)(field, resolved.implementation, sources);
644
640
  useFieldMetaDiagnostic(state, binding.resource, name, field, surface);
645
- const label = (0, _burojs_core.resolveFieldLabel)(caps, name, typeof binding.field.label === "string" ? binding.field.label : void 0);
641
+ const label = (0, _burojs_core.resolveFieldLabel)(caps, name, (0, _burojs_core.declaredText)("field", binding.field, "label"));
646
642
  const testId = leafIds === "record" ? tid.formField(resource, mode, name) : `${leafIds.prefix}:field:${name}`;
647
643
  return (0, react_jsx_runtime.jsxs)("div", {
648
644
  ...leafAttributes("md", void 0),
@@ -667,8 +663,7 @@ function RecordLeaf({ node }) {
667
663
  const weight = compiled.nodes[node.index]?.options.weight;
668
664
  const caps = (0, _burojs_react.useI18nCaps)(resource);
669
665
  const tid = (0, _burojs_react.useTestIds)();
670
- const declared = binding.field;
671
- const label = (0, _burojs_core.resolveFieldLabel)(caps, name, typeof declared.label === "string" ? declared.label : void 0);
666
+ const label = (0, _burojs_core.resolveFieldLabel)(caps, name, (0, _burojs_core.declaredText)("field", binding.field, "label"));
672
667
  const attributes = leafAttributes(size, weight);
673
668
  const t = (0, _burojs_react.useOptionalT)();
674
669
  if (node.restricted === true) {
@@ -928,7 +923,7 @@ function DeclarativeLeaf({ node, prefix, inputIds }) {
928
923
  if (byId !== null && element.ownerDocument.activeElement === byId) return;
929
924
  element.querySelector(FOCUSABLE)?.focus();
930
925
  });
931
- const label = (0, _burojs_core.resolveFieldLabel)(caps, name, binding.field.label);
926
+ const label = (0, _burojs_core.resolveFieldLabel)(caps, name, (0, _burojs_core.declaredText)("field", binding.field, "label"));
932
927
  const hint = (0, _burojs_core.resolveFieldSlot)(caps, name, "description", fieldDescription(binding.field));
933
928
  const info = (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.DocInfo, {
934
929
  address: `${docScope}/fields/${name}`,
@@ -1089,7 +1084,7 @@ function FactsView({ props }) {
1089
1084
  const pairs = shown.map((field) => {
1090
1085
  const value = data[field.name];
1091
1086
  const label = (0, _burojs_core.resolveContentSlot)(caps, [`queries.${queryId}.fields.${field.name}.label`, `queries.${queryId}.fields.${field.name}`], {
1092
- ...typeof field.label === "string" ? { default: field.label } : {},
1087
+ ...(0, _burojs_core.declaredText)("field", field, "label") === void 0 ? {} : { default: (0, _burojs_core.declaredText)("field", field, "label") },
1093
1088
  humanize: () => (0, _burojs_core.humanizeKey)(field.name)
1094
1089
  });
1095
1090
  const body = value === null || value === void 0 ? (0, react_jsx_runtime.jsx)("span", {
@@ -1360,11 +1355,11 @@ function PageInlineFlow({ flow }) {
1360
1355
  "data-buro-flow-state": "pending"
1361
1356
  });
1362
1357
  const appAction = "appAction" in target ? app.registry.appActions.get(target.appAction) : void 0;
1363
- const label = appAction === void 0 ? void 0 : (0, _burojs_core.resolveNavLabel)(caps, `appActions.${"appAction" in target ? target.appAction : ""}`, appAction.label);
1358
+ const label = appAction === void 0 ? void 0 : (0, _burojs_core.resolveNavLabel)(caps, `appActions.${"appAction" in target ? target.appAction : ""}`, (0, _burojs_core.declaredText)("flow", appAction, "label"));
1364
1359
  const button = "appAction" in target ? (0, react_jsx_runtime.jsx)(AppFlowButton, {
1365
1360
  action: {
1366
1361
  name: target.appAction,
1367
- label: appAction?.label ?? target.appAction,
1362
+ label: (0, _burojs_core.declaredText)("flow", appAction, "label") ?? target.appAction,
1368
1363
  ...appAction?.icon === void 0 ? {} : { icon: appAction.icon },
1369
1364
  ...answer.state === "disabled" ? { disabledReason: answer.reason ?? "" } : {}
1370
1365
  },
@@ -1582,7 +1577,7 @@ function EnumBadge({ enumName, value, testid, className, presentation }) {
1582
1577
  if (entry) {
1583
1578
  const body = (0, react_jsx_runtime.jsx)(BadgeBody, {
1584
1579
  icon: entry.icon,
1585
- label: (0, _burojs_core.resolveEnumLabel)(caps, ns, value, entry.label)
1580
+ label: (0, _burojs_core.resolveEnumLabel)(caps, ns, value, (0, _burojs_core.enumValueText)(def, value) ?? entry.label)
1586
1581
  });
1587
1582
  if (presentation === "plain") return (0, react_jsx_runtime.jsx)("span", {
1588
1583
  "data-testid": id,
@@ -1598,15 +1593,16 @@ function EnumBadge({ enumName, value, testid, className, presentation }) {
1598
1593
  children: body
1599
1594
  });
1600
1595
  }
1601
- if (def.fallback) {
1602
- const fallbackLabel = (0, _burojs_core.resolveContentSlot)(caps, [(0, _burojs_core.enumFallbackKey)(ns)], { default: def.fallback.label }) ?? value;
1596
+ const declaredFallback = (0, _burojs_core.enumFallbackText)(def);
1597
+ if (def?.fallback !== void 0 || declaredFallback !== void 0) {
1598
+ const fallbackLabel = (0, _burojs_core.resolveContentSlot)(caps, [(0, _burojs_core.enumFallbackKey)(ns)], { default: declaredFallback }) ?? value;
1603
1599
  if (presentation === "plain") return (0, react_jsx_runtime.jsx)("span", {
1604
1600
  "data-testid": `${id}:fallback`,
1605
1601
  className,
1606
1602
  children: fallbackLabel
1607
1603
  });
1608
1604
  return (0, react_jsx_runtime.jsx)(require_filter_builder.Badge, {
1609
- variant: def.fallback.color ?? "outline",
1605
+ variant: def?.fallback?.color ?? "outline",
1610
1606
  className,
1611
1607
  "data-testid": `${id}:fallback`,
1612
1608
  children: fallbackLabel
@@ -2213,15 +2209,7 @@ function nodeAttributes(node, kind = node.kind, tone) {
2213
2209
  }
2214
2210
  function useNodeText() {
2215
2211
  const caps = (0, _burojs_react.useI18nCaps)();
2216
- return (slot) => {
2217
- if (slot === void 0) return void 0;
2218
- if (caps.has(slot.key)) return caps.t(slot.key);
2219
- if (slot.entry !== void 0 && caps.has(slot.entry)) {
2220
- const entry = caps.t(slot.entry);
2221
- if (typeof entry === "string" && entry !== slot.entry) return entry;
2222
- }
2223
- return slot.default;
2224
- };
2212
+ return (slot) => slot === void 0 ? void 0 : (0, _burojs_core.resolveTextSlot)(caps, slot);
2225
2213
  }
2226
2214
  function NodeInfo({ node, name }) {
2227
2215
  const { resource } = useScreenTree();
@@ -2823,69 +2811,103 @@ function ColumnHeaderMenu({ label, sortDirection, sortable, onSort, pinned, onPi
2823
2811
  sortable && onSort && (0, react_jsx_runtime.jsxs)(require_check_confirm_dialog.DropdownMenuGroup, { children: [
2824
2812
  (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.DropdownMenuLabel, {
2825
2813
  className: "text-xs font-medium text-muted-foreground",
2826
- children: tr("columnMenu.sortSection", "Сортировка")
2814
+ children: tr("columnMenu.sortSection", "Sort")
2827
2815
  }),
2828
2816
  (0, react_jsx_runtime.jsxs)(require_check_confirm_dialog.DropdownMenuItem, {
2829
2817
  onClick: () => onSort("asc"),
2830
2818
  "data-testid": testid ? `${testid}:sort-asc` : void 0,
2831
- children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconArrowUp, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.sortAsc", "По возрастанию")]
2819
+ children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconArrowUp, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.sortAsc", "Ascending")]
2832
2820
  }),
2833
2821
  (0, react_jsx_runtime.jsxs)(require_check_confirm_dialog.DropdownMenuItem, {
2834
2822
  onClick: () => onSort("desc"),
2835
2823
  "data-testid": testid ? `${testid}:sort-desc` : void 0,
2836
- children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconArrowDown, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.sortDesc", "По убыванию")]
2824
+ children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconArrowDown, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.sortDesc", "Descending")]
2837
2825
  }),
2838
2826
  sortDirection && (0, react_jsx_runtime.jsxs)(require_check_confirm_dialog.DropdownMenuItem, {
2839
2827
  onClick: () => onSort(null),
2840
- children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconX, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.clearSort", "Сбросить")]
2828
+ children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconX, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.clearSort", "Clear")]
2841
2829
  })
2842
2830
  ] }),
2843
2831
  onPin && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [sortable && onSort && (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.DropdownMenuSeparator, {}), (0, react_jsx_runtime.jsxs)(require_check_confirm_dialog.DropdownMenuGroup, { children: [
2844
2832
  (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.DropdownMenuLabel, {
2845
2833
  className: "text-xs font-medium text-muted-foreground",
2846
- children: tr("columnMenu.pinSection", "Закрепление")
2834
+ children: tr("columnMenu.pinSection", "Pin")
2847
2835
  }),
2848
2836
  pinned !== "left" && (0, react_jsx_runtime.jsxs)(require_check_confirm_dialog.DropdownMenuItem, {
2849
2837
  onClick: () => onPin("left"),
2850
2838
  "data-testid": testid ? `${testid}:pin-left` : void 0,
2851
- children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconPinned, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.pinLeft", "Слева")]
2839
+ children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconPinned, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.pinLeft", "Left")]
2852
2840
  }),
2853
2841
  pinned !== "right" && (0, react_jsx_runtime.jsxs)(require_check_confirm_dialog.DropdownMenuItem, {
2854
2842
  onClick: () => onPin("right"),
2855
- children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconPinned, { className: "mr-2 size-4 -scale-x-100 text-muted-foreground" }), tr("columnMenu.pinRight", "Справа")]
2843
+ children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconPinned, { className: "mr-2 size-4 -scale-x-100 text-muted-foreground" }), tr("columnMenu.pinRight", "Right")]
2856
2844
  }),
2857
2845
  pinned !== false && (0, react_jsx_runtime.jsxs)(require_check_confirm_dialog.DropdownMenuItem, {
2858
2846
  onClick: () => onPin(false),
2859
2847
  "data-testid": testid ? `${testid}:unpin` : void 0,
2860
- children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconPinnedOff, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.unpin", "Открепить")]
2848
+ children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconPinnedOff, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.unpin", "Unpin")]
2861
2849
  })
2862
2850
  ] })] }),
2863
2851
  canMove && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(require_check_confirm_dialog.DropdownMenuSeparator, {}), (0, react_jsx_runtime.jsxs)(require_check_confirm_dialog.DropdownMenuGroup, { children: [
2864
2852
  (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.DropdownMenuLabel, {
2865
2853
  className: "text-xs font-medium text-muted-foreground",
2866
- children: tr("columnMenu.moveSection", "Перемещение")
2854
+ children: tr("columnMenu.moveSection", "Move")
2867
2855
  }),
2868
2856
  canMoveLeft && (0, react_jsx_runtime.jsxs)(require_check_confirm_dialog.DropdownMenuItem, {
2869
2857
  onClick: () => onMove?.("left"),
2870
2858
  "data-testid": testid ? `${testid}:move-left` : void 0,
2871
- children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconArrowLeft, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.moveLeft", "Влево")]
2859
+ children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconArrowLeft, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.moveLeft", "Left")]
2872
2860
  }),
2873
2861
  canMoveRight && (0, react_jsx_runtime.jsxs)(require_check_confirm_dialog.DropdownMenuItem, {
2874
2862
  onClick: () => onMove?.("right"),
2875
2863
  "data-testid": testid ? `${testid}:move-right` : void 0,
2876
- children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconArrowRight, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.moveRight", "Вправо")]
2864
+ children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconArrowRight, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.moveRight", "Right")]
2877
2865
  })
2878
2866
  ] })] }),
2879
2867
  canHide && onHide && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(require_check_confirm_dialog.DropdownMenuSeparator, {}), (0, react_jsx_runtime.jsxs)(require_check_confirm_dialog.DropdownMenuItem, {
2880
2868
  onClick: onHide,
2881
2869
  "data-testid": testid ? `${testid}:hide` : void 0,
2882
- children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconEyeOff, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.hide", "Скрыть колонку")]
2870
+ children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconEyeOff, { className: "mr-2 size-4 text-muted-foreground" }), tr("columnMenu.hide", "Hide column")]
2883
2871
  })] })
2884
2872
  ]
2885
2873
  })]
2886
2874
  });
2887
2875
  }
2888
2876
  //#endregion
2877
+ //#region src/resource/column-accessor.ts
2878
+ function columnAccessor(column) {
2879
+ return column.includes(".") ? { accessorFn: (row) => row[column] } : { accessorKey: column };
2880
+ }
2881
+ //#endregion
2882
+ //#region src/resource/column-target.ts
2883
+ function columnTarget(registry, resource, column) {
2884
+ if (!column.includes(".")) return void 0;
2885
+ const resolved = (0, _burojs_react.resolveColumnField)(registry, resource, column);
2886
+ if (resolved === void 0) return void 0;
2887
+ const ref = registry.get(resolved.resource)?.ref ?? {
2888
+ namespace: "default",
2889
+ id: resolved.resource
2890
+ };
2891
+ return {
2892
+ field: resolved.field,
2893
+ name: column.slice(column.lastIndexOf(".") + 1),
2894
+ resource: resolved.resource,
2895
+ ref
2896
+ };
2897
+ }
2898
+ function capsOf(caps, resource) {
2899
+ return {
2900
+ has: (key, options) => caps.has(key, {
2901
+ ...options,
2902
+ resource: options?.resource ?? resource
2903
+ }),
2904
+ t: (key, options) => caps.t(key, {
2905
+ ...options,
2906
+ resource: options?.resource ?? resource
2907
+ })
2908
+ };
2909
+ }
2910
+ //#endregion
2889
2911
  //#region src/data-table/use-buro-data-table.ts
2890
2912
  function useBuroDataTable(opts) {
2891
2913
  const { data, columns, total, getRowId, pagination, onPaginationChange, sorting, onSortingChange, columnFilters, onColumnFiltersChange, columnVisibility, onColumnVisibilityChange, rowSelection, onRowSelectionChange, enableRowSelection, columnPinning, onColumnPinningChange, columnSizing, onColumnSizingChange, columnOrder, onColumnOrderChange, enableColumnResizing } = opts;
@@ -2962,9 +2984,8 @@ function resolveUpdater(updater, prev) {
2962
2984
  //#region src/resource/list-error-state.tsx
2963
2985
  function ListErrorState({ error, onRetry, resource, title, className }) {
2964
2986
  const t = (0, _burojs_react.useT)();
2965
- const locale = (0, _burojs_react.useLocale)();
2966
2987
  const raw = error.message ?? "";
2967
- const friendly = require_toaster.toFriendlyError(raw, "", locale);
2988
+ const friendly = require_toaster.toFriendlyError(raw, "", require_toaster.friendlyStringsFrom(t));
2968
2989
  const friendlyError = friendly.replaced ? friendly.detail : raw;
2969
2990
  return (0, react_jsx_runtime.jsxs)("div", {
2970
2991
  role: "alert",
@@ -3089,7 +3110,7 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3089
3110
  25,
3090
3111
  50,
3091
3112
  100
3092
- ], 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 }) {
3113
+ ], 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 }) {
3093
3114
  const app = (0, _burojs_react.useApp)();
3094
3115
  const tid = (0, _burojs_react.useTestIds)();
3095
3116
  const t = (0, _burojs_react.useOptionalT)();
@@ -3136,15 +3157,19 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3136
3157
  setOwnSelection({});
3137
3158
  }, [data]);
3138
3159
  const listAccess = (0, _burojs_react.useListAccess)(resource);
3139
- const accessPending = listAccess.status === "pending";
3160
+ const pathAccess = (0, _burojs_react.usePathAccess)(resource);
3161
+ const accessPending = listAccess.status === "pending" || pathAccess.pending;
3140
3162
  const declaredColumnKeys = (0, react.useMemo)(() => {
3141
3163
  if (!def) return [];
3142
3164
  return [...columnsOverride ?? def.views?.list?.columns ?? Object.keys(def.fields)];
3143
3165
  }, [def, columnsOverride]);
3144
- const visibleColumnKeys = (0, react.useMemo)(() => accessPending ? [] : declaredColumnKeys.filter((col) => listAccess.columnVisible(col)), [
3166
+ const visibleColumnKeys = (0, react.useMemo)(() => accessPending ? [] : declaredColumnKeys.filter((col) => listAccess.columnVisible(col) && (columnTarget(app.registry, resource, col) === void 0 || listAccess.columnVisible(col.split(".")[0]) && pathAccess.visible(col))), [
3145
3167
  accessPending,
3146
3168
  declaredColumnKeys,
3147
- listAccess
3169
+ listAccess,
3170
+ pathAccess,
3171
+ app,
3172
+ resource
3148
3173
  ]);
3149
3174
  const skeletonColumnKeys = accessPending ? declaredColumnKeys : visibleColumnKeys;
3150
3175
  const rows = (0, react.useMemo)(() => data ?? [], [data]);
@@ -3245,14 +3270,18 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3245
3270
  })
3246
3271
  });
3247
3272
  for (const col of visibleColumnKeys) {
3248
- const field = def?.fields?.[col];
3249
- const headerLabel = (0, _burojs_core.resolveFieldLabel)(volatileRef.current.i18nCaps, col, field?.label);
3273
+ const target = columnTarget(app.registry, resource, col);
3274
+ const field = target === void 0 ? def?.fields?.[col] : target.field;
3275
+ const declaredLabel = (0, _burojs_core.declaredText)("field", field, "label");
3276
+ const headerLabel = target === void 0 ? (0, _burojs_core.resolveFieldLabel)(volatileRef.current.i18nCaps, col, declaredLabel) : (0, _burojs_core.resolveFieldLabel)(capsOf(volatileRef.current.i18nCaps, target.resource), target.name, declaredLabel);
3250
3277
  const kindSize = columnSize(field);
3278
+ const declared = target === void 0 && def !== void 0 ? (0, _burojs_core.declaredField)(def, col) : void 0;
3279
+ const linkColumn = declared !== null && typeof declared === "object" && (0, _burojs_core.isLinkField)(declared);
3251
3280
  cols.push({
3252
3281
  id: col,
3253
- accessorKey: col,
3282
+ ...columnAccessor(col),
3254
3283
  ...kindSize !== void 0 ? { size: kindSize } : {},
3255
- enableSorting: Boolean(volatileRef.current.onSort),
3284
+ enableSorting: !linkColumn && Boolean(volatileRef.current.onSort),
3256
3285
  enableHiding: true,
3257
3286
  meta: { testid: col },
3258
3287
  header: ({ column, table }) => {
@@ -3285,9 +3314,9 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3285
3314
  };
3286
3315
  return (0, react_jsx_runtime.jsx)(ColumnHeaderMenu, {
3287
3316
  label: headerLabel,
3288
- sortable: Boolean(v.onSort),
3317
+ sortable: !linkColumn && Boolean(v.onSort),
3289
3318
  sortDirection: v.sort?.[0]?.field === col ? v.sort[0].direction : null,
3290
- onSort: v.onSort ? (dir) => v.onSort?.(col, dir) : void 0,
3319
+ onSort: !linkColumn && v.onSort ? (dir) => v.onSort?.(col, dir) : void 0,
3291
3320
  pinned: column.getIsPinned(),
3292
3321
  onPin: (side) => column.pin(side),
3293
3322
  canHide: Boolean(v.onHideColumn) && !v.requiredColumns?.includes(col),
@@ -3304,8 +3333,8 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3304
3333
  const value = record[col];
3305
3334
  const customCell = volatileRef.current.renderCell?.(col, value, record);
3306
3335
  const cellInner = customCell !== void 0 ? customCell : (0, react_jsx_runtime.jsx)(ResolvedFieldDisplay, {
3307
- resource: resourceRef,
3308
- name: col,
3336
+ resource: target === void 0 ? resourceRef : target.ref,
3337
+ name: target === void 0 ? col : target.name,
3309
3338
  field: field ?? { type: "unknown" },
3310
3339
  value,
3311
3340
  record,
@@ -3338,6 +3367,7 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3338
3367
  }
3339
3368
  });
3340
3369
  }
3370
+ if (!rowActions) return cols;
3341
3371
  cols.push({
3342
3372
  id: ACTIONS_COL_ID,
3343
3373
  enableSorting: false,
@@ -3361,7 +3391,9 @@ function ResourceList({ resource, data, total, page = 1, pageSize = 10, onPageSi
3361
3391
  });
3362
3392
  return cols;
3363
3393
  }, [
3394
+ app,
3364
3395
  selectable,
3396
+ rowActions,
3365
3397
  resourceRef,
3366
3398
  visibleColumnKeys,
3367
3399
  def,
@@ -3795,7 +3827,7 @@ function ForceTableView(props) {
3795
3827
  function ListBodyView() {
3796
3828
  usePieceMount("body");
3797
3829
  const list = (0, _burojs_react.useResourceListContext)();
3798
- const { resource, route, tableView, createAvailable, createPage, rowProps, rowsViewFor, emptyState, renderCell } = useListSurface();
3830
+ const { resource, route, tableView, createAvailable, createPage, rowProps, rowsViewFor, emptyState, renderCell, readOnly } = useListSurface();
3799
3831
  const item = (0, react.useContext)(ListItemContext);
3800
3832
  const rowsView = (0, react.useMemo)(() => rowsViewFor?.(item), [rowsViewFor, item]);
3801
3833
  const { query, pagination, cursor, count, columns, selection, filters, sorting, routing } = list;
@@ -3823,7 +3855,8 @@ function ListBodyView() {
3823
3855
  createHref: route && createAvailable && createPage ? routing.createHref : void 0,
3824
3856
  ...rowProps,
3825
3857
  ...rowsView === void 0 ? {} : { rowsView },
3826
- selectable: tableView,
3858
+ selectable: tableView && !readOnly,
3859
+ rowActions: !readOnly,
3827
3860
  selectedIds: selection.ids,
3828
3861
  onSelectionChange: selection.set,
3829
3862
  isFiltered: filters.isFiltered,
@@ -3934,7 +3967,10 @@ function PanelHost({ node, region = "panel-body", renderChildren }) {
3934
3967
  const state = (0, _burojs_react.useScreenState)();
3935
3968
  const text = useNodeText();
3936
3969
  const options = compiled.nodes[node.index].options;
3937
- const title = text(options.title);
3970
+ const title = options.title?.humanized === true ? text({
3971
+ ...options.title,
3972
+ default: ""
3973
+ }) || void 0 : text(options.title);
3938
3974
  const description = text(options.description);
3939
3975
  const collapsible = options.collapse !== void 0;
3940
3976
  const open = !collapsible || node.open !== false;
@@ -4004,7 +4040,7 @@ function TabsHost({ node, renderChildren }) {
4004
4040
  const panel = panels.find((candidate) => panelValue(candidate) === key);
4005
4041
  if (panel !== void 0) select(panel, false);
4006
4042
  };
4007
- const titleOf = (panel) => text(compiled.nodes[panel.index].options.title) ?? panel.key ?? panel.id;
4043
+ const titleOf = (panel) => text(compiled.nodes[panel.index].options.title) ?? panel.id;
4008
4044
  const tabs = panels.map((panel) => ({
4009
4045
  key: panelValue(panel),
4010
4046
  title: titleOf(panel),
@@ -4047,7 +4083,7 @@ function StackedStepsHost({ node, renderChildren }) {
4047
4083
  const t = (0, _burojs_react.useFrameT)(id);
4048
4084
  const steps = node.children.filter((child) => child.state !== "absent").map((panel) => {
4049
4085
  const options = compiled.nodes[panel.index].options;
4050
- const title = text(options.title) ?? panel.key ?? panel.id;
4086
+ const title = text(options.title) ?? panel.id;
4051
4087
  const description = text(options.description);
4052
4088
  return {
4053
4089
  key: panel.key ?? panel.id,
@@ -4095,7 +4131,7 @@ function WizardHost({ node, renderChildren }) {
4095
4131
  const current = panels.find((child) => child.open === true) ?? panels[0];
4096
4132
  const index = current === void 0 ? -1 : panels.indexOf(current);
4097
4133
  const idOf = (panel) => panel.key ?? panel.id;
4098
- const titleOf = (panel) => text(compiled.nodes[panel.index].options.title) ?? panel.key ?? panel.id;
4134
+ const titleOf = (panel) => text(compiled.nodes[panel.index].options.title) ?? panel.id;
4099
4135
  const headingRef = (0, react.useRef)(null);
4100
4136
  const shown = (0, react.useRef)(void 0);
4101
4137
  const currentId = current === void 0 ? void 0 : idOf(current);
@@ -4487,28 +4523,39 @@ function DeclarativeFormBody(props) {
4487
4523
  }
4488
4524
  //#endregion
4489
4525
  //#region src/export/format-option-labels.ts
4490
- function exportFormatOptionKey(formatId, field, value) {
4491
- return value === void 0 ? `export.format.${formatId}.${field}.label` : `export.format.${formatId}.${field}.option.${value}`;
4492
- }
4493
4526
  function localizeFormatOptions(caps, format) {
4494
4527
  const fields = format.options;
4495
4528
  if (fields === void 0) return void 0;
4496
4529
  const out = {};
4497
4530
  for (const [name, field] of Object.entries(fields)) {
4498
4531
  const declared = field;
4532
+ const label = (0, _burojs_core.resolveContentSlot)(caps, [(0, _burojs_core.exportFormatFieldKey)(format.id, name)], {
4533
+ default: (0, _burojs_core.declaredText)("field", field, "label"),
4534
+ humanize: () => (0, _burojs_core.humanizeKey)(name)
4535
+ });
4536
+ const options = declared.options?.map((option) => ({
4537
+ value: String(option.value),
4538
+ label: (0, _burojs_core.resolveContentSlot)(caps, [(0, _burojs_core.exportFormatOptionKey)(format.id, name, String(option.value))], {
4539
+ default: (0, _burojs_core.fieldOptionText)(field, String(option.value)),
4540
+ humanize: () => String(option.value)
4541
+ })
4542
+ }));
4543
+ const declaredTexts = typeof declared.texts === "object" && declared.texts !== null ? declared.texts : {};
4544
+ const declaredOptions = declaredTexts.options ?? {};
4545
+ const texts = {
4546
+ ...declaredTexts,
4547
+ label,
4548
+ ...options === void 0 ? {} : { options: Object.fromEntries(options.map(({ value, label: optionLabel }) => {
4549
+ const entry = declaredOptions[value];
4550
+ return [value, typeof entry === "object" && entry !== null ? {
4551
+ ...entry,
4552
+ label: optionLabel
4553
+ } : optionLabel];
4554
+ })) }
4555
+ };
4499
4556
  out[name] = {
4500
4557
  ...field,
4501
- label: (0, _burojs_core.resolveContentSlot)(caps, [exportFormatOptionKey(format.id, name)], {
4502
- default: typeof declared.label === "string" ? declared.label : void 0,
4503
- humanize: () => (0, _burojs_core.humanizeKey)(name)
4504
- }),
4505
- ...declared.options === void 0 ? {} : { options: declared.options.map((option) => ({
4506
- ...option,
4507
- label: (0, _burojs_core.resolveContentSlot)(caps, [exportFormatOptionKey(format.id, name, String(option.value))], {
4508
- default: option.label,
4509
- humanize: () => String(option.value)
4510
- })
4511
- })) }
4558
+ texts
4512
4559
  };
4513
4560
  }
4514
4561
  return out;
@@ -4547,10 +4594,13 @@ function ExportOptionsDirty({ dirty }) {
4547
4594
  return null;
4548
4595
  }
4549
4596
  function getNoRunState() {}
4550
- function ExportDialog({ open, onOpenChange, resource, target, visibleColumns, estimatedCount }) {
4597
+ function ExportDialog({ open, onOpenChange, resource, target, visibleColumns, estimatedCount, scope }) {
4551
4598
  const t = (0, _burojs_react.useOptionalT)();
4552
4599
  const dialogTestId = (0, _burojs_react.useTestIds)().exportDialog(resource);
4553
- const { formats, start, exporter, available, error, loading } = (0, _burojs_react.useResourceExport)(resource, { load: open });
4600
+ const { formats, start, exporter, available, error, loading } = (0, _burojs_react.useResourceExport)(resource, {
4601
+ load: open,
4602
+ ...scope === void 0 ? {} : { scope }
4603
+ });
4554
4604
  const [mode, setMode] = react.useState("form");
4555
4605
  const [formatIdOverride, setFormatIdOverride] = react.useState(void 0);
4556
4606
  const [columnsMode, setColumnsMode] = react.useState("visible");
@@ -4572,6 +4622,15 @@ function ExportDialog({ open, onOpenChange, resource, target, visibleColumns, es
4572
4622
  ]);
4573
4623
  const requestColumns = columnsMode === "visible" && visibleColumns.length > 0 ? exportableVisible : allowedListColumns;
4574
4624
  const selectedFormat = formats.find((f) => f.id === formatIdOverride) ?? formats[0];
4625
+ const reportedLabels = react.useRef(new Set());
4626
+ react.useEffect(() => {
4627
+ if (process.env.NODE_ENV === "production") return;
4628
+ for (const format of formats) {
4629
+ if ((Object.hasOwn(format, "label") ? format.label : void 0) === void 0 || reportedLabels.current.has(format.id)) continue;
4630
+ reportedLabels.current.add(format.id);
4631
+ console.error(`[ExportDialog] export format '${format.id}' declares label, which was removed: write texts — the text the bundle holds at common.${(0, _burojs_core.exportFormatLabelKey)(format.id)} (see docs/i18n-guide.md).`);
4632
+ }
4633
+ }, [formats]);
4575
4634
  const caps = (0, _burojs_react.useI18nCaps)();
4576
4635
  const localizedOptions = react.useMemo(() => selectedFormat === void 0 ? void 0 : localizeFormatOptions(caps, selectedFormat), [caps, selectedFormat]);
4577
4636
  const wasOpenRef = react.useRef(open);
@@ -4685,7 +4744,10 @@ function ExportDialog({ open, onOpenChange, resource, target, visibleColumns, es
4685
4744
  }), (0, react_jsx_runtime.jsx)(require_filter_builder.SelectContent, { children: formats.map((format) => (0, react_jsx_runtime.jsx)(require_filter_builder.SelectItem, {
4686
4745
  value: format.id,
4687
4746
  "data-testid": `${dialogTestId}:format:option:${format.id}`,
4688
- children: typeof format.label === "string" ? format.label : format.id
4747
+ children: (0, _burojs_core.resolveContentSlot)(caps, [(0, _burojs_core.exportFormatLabelKey)(format.id)], {
4748
+ default: (0, _burojs_core.declaredText)("export-format", format, "label"),
4749
+ humanize: () => format.id
4750
+ })
4689
4751
  }, format.id)) })]
4690
4752
  })]
4691
4753
  }),
@@ -4899,7 +4961,7 @@ function orderBulkActions(actions) {
4899
4961
  seq: index
4900
4962
  })).sort((a, b) => a.weight - b.weight || a.seq - b.seq).map(({ action }) => action);
4901
4963
  }
4902
- function BulkActionToolbar({ resource, table, selectedRecords, selectedIds, onClearSelection, onSelectionChange, className, visibleColumns }) {
4964
+ function BulkActionToolbar({ resource, table, selectedRecords, selectedIds, onClearSelection, onSelectionChange, className, visibleColumns, scope }) {
4903
4965
  const app = (0, _burojs_react.useApp)();
4904
4966
  const tid = (0, _burojs_react.useTestIds)();
4905
4967
  const t = (0, _burojs_react.useOptionalT)();
@@ -4947,7 +5009,8 @@ function BulkActionToolbar({ resource, table, selectedRecords, selectedIds, onCl
4947
5009
  (0, react_jsx_runtime.jsx)(BulkExportButton, {
4948
5010
  resource,
4949
5011
  ids,
4950
- visibleColumns: visibleColumns ?? []
5012
+ visibleColumns: visibleColumns ?? [],
5013
+ ...scope === void 0 ? {} : { scope }
4951
5014
  }),
4952
5015
  (0, react_jsx_runtime.jsxs)(require_button.Button, {
4953
5016
  type: "button",
@@ -4970,15 +5033,16 @@ function BulkActionToolbar({ resource, table, selectedRecords, selectedIds, onCl
4970
5033
  className: "h-20 sm:h-24"
4971
5034
  })] });
4972
5035
  }
4973
- function BulkExportButton({ resource, ids, visibleColumns }) {
5036
+ function BulkExportButton({ resource, ids, visibleColumns, scope }) {
4974
5037
  if (!((0, _burojs_react.useOptionalDataRuntime)() !== null)) return null;
4975
5038
  return (0, react_jsx_runtime.jsx)(BulkExportButtonActive, {
4976
5039
  resource,
4977
5040
  ids,
4978
- visibleColumns
5041
+ visibleColumns,
5042
+ ...scope === void 0 ? {} : { scope }
4979
5043
  });
4980
5044
  }
4981
- function BulkExportButtonActive({ resource, ids, visibleColumns }) {
5045
+ function BulkExportButtonActive({ resource, ids, visibleColumns, scope }) {
4982
5046
  const tid = (0, _burojs_react.useTestIds)();
4983
5047
  const t = (0, _burojs_react.useOptionalT)();
4984
5048
  const { available, prefetch } = (0, _burojs_react.useResourceExport)(resource);
@@ -5013,23 +5077,25 @@ function BulkExportButtonActive({ resource, ids, visibleColumns }) {
5013
5077
  onOpenChange: setOpen,
5014
5078
  resource,
5015
5079
  target,
5016
- visibleColumns
5080
+ visibleColumns,
5081
+ ...scope === void 0 ? {} : { scope }
5017
5082
  })] });
5018
5083
  }
5019
5084
  //#endregion
5020
5085
  //#region src/list-kit/pieces/list-bulk-bar.tsx
5021
5086
  function ListBulkBarView() {
5022
5087
  usePieceMount("bulk-bar");
5023
- const { selection, columns } = (0, _burojs_react.useResourceListContext)();
5024
- const { resource, tableView } = useListSurface();
5025
- if (!tableView || selection.ids.length === 0) return null;
5088
+ const { selection, columns, scope } = (0, _burojs_react.useResourceListContext)();
5089
+ const { resource, tableView, readOnly } = useListSurface();
5090
+ if (!tableView || readOnly || selection.ids.length === 0) return null;
5026
5091
  return (0, react_jsx_runtime.jsx)(BulkActionToolbar, {
5027
5092
  resource,
5028
5093
  selectedRecords: selection.records,
5029
5094
  selectedIds: selection.ids,
5030
5095
  onClearSelection: selection.clear,
5031
5096
  onSelectionChange: selection.set,
5032
- visibleColumns: columns.visible
5097
+ visibleColumns: columns.visible,
5098
+ scope
5033
5099
  });
5034
5100
  }
5035
5101
  const ListBulkBar = listPiece("ListBulkBar", ListBulkBarView);
@@ -5114,6 +5180,7 @@ function DataTableViewOptions({ table, getColumnLabel, isColumnRequired, getTest
5114
5180
  function ColumnsToggle({ resource, def, allAvailable, required, visibleColumns, defaultVisible, onChange, onResetSizes, onRestoreDefaults }) {
5115
5181
  const t = (0, _burojs_react.useT)();
5116
5182
  const columnsCaps = (0, _burojs_react.useI18nCaps)(resource);
5183
+ const app = (0, _burojs_react.useApp)();
5117
5184
  const visibleSet = (0, react.useMemo)(() => new Set(visibleColumns), [visibleColumns]);
5118
5185
  const requiredSet = (0, react.useMemo)(() => new Set(required), [required]);
5119
5186
  const defaultSet = (0, react.useMemo)(() => new Set(defaultVisible), [defaultVisible]);
@@ -5178,8 +5245,9 @@ function ColumnsToggle({ resource, def, allAvailable, required, visibleColumns,
5178
5245
  testid: `list-columns-restore-defaults:${resource}`
5179
5246
  }] : []],
5180
5247
  getColumnLabel: (column) => {
5181
- const fieldDef = def.fields?.[column.id];
5182
- return (0, _burojs_core.resolveFieldLabel)(columnsCaps, column.id, fieldDef?.label);
5248
+ const target = columnTarget(app.registry, resource, column.id);
5249
+ if (target !== void 0) return (0, _burojs_core.resolveFieldLabel)(capsOf(columnsCaps, target.resource), target.name, (0, _burojs_core.declaredText)("field", target.field, "label"));
5250
+ return (0, _burojs_core.resolveFieldLabel)(columnsCaps, column.id, (0, _burojs_core.declaredText)("field", def.fields?.[column.id], "label"));
5183
5251
  },
5184
5252
  isColumnRequired: (column) => requiredSet.has(column.id),
5185
5253
  getTestId: (role, columnId) => {
@@ -5377,7 +5445,8 @@ function ExportButtonActive({ resource, className }) {
5377
5445
  resource,
5378
5446
  target,
5379
5447
  visibleColumns: list.columns.visible,
5380
- estimatedCount: list.pagination.total
5448
+ estimatedCount: list.pagination.total,
5449
+ scope: list.scope
5381
5450
  })] });
5382
5451
  }
5383
5452
  //#endregion
@@ -5385,8 +5454,8 @@ function ExportButtonActive({ resource, className }) {
5385
5454
  function ListExportView() {
5386
5455
  usePieceMount("export");
5387
5456
  const { def } = (0, _burojs_react.useResourceListContext)();
5388
- const { resource } = useListSurface();
5389
- if (!def) return null;
5457
+ const { resource, exportable } = useListSurface();
5458
+ if (!def || !exportable) return null;
5390
5459
  return (0, react_jsx_runtime.jsx)(ExportButton, { resource });
5391
5460
  }
5392
5461
  const ListExport = listPiece("ListExport", ListExportView);
@@ -5435,7 +5504,7 @@ function FilterRegion({ search } = {}) {
5435
5504
  return searchDecl.fields.map((entry) => typeof entry === "string" ? entry : entry.field).find((name) => access.fieldVisible(name));
5436
5505
  })() : void 0;
5437
5506
  const searchGenericLabel = (0, _burojs_core.resolveContentSlot)(listCaps, ["list.search"]) ?? "Search";
5438
- const searchLabel = searchField ? (0, _burojs_core.resolveFieldLabel)(listCaps, searchField, (def?.fields[searchField])?.label) : searchGenericLabel;
5507
+ const searchLabel = searchField ? (0, _burojs_core.resolveFieldLabel)(listCaps, searchField, (0, _burojs_core.declaredText)("field", def?.fields[searchField], "label")) : searchGenericLabel;
5439
5508
  const searchPlaceholder = searchField ? t("toolbar.searchBy", { params: { name: searchLabel } }) : searchGenericLabel;
5440
5509
  return (0, react_jsx_runtime.jsxs)("div", {
5441
5510
  className: "flex flex-wrap items-center gap-2",
@@ -5581,13 +5650,19 @@ function ListLiveView() {
5581
5650
  const ListLive = listPiece("ListLive", ListLiveView);
5582
5651
  //#endregion
5583
5652
  //#region src/saved-views/saved-views-dropdown.tsx
5584
- function ViewItem({ view, onClick, testid }) {
5653
+ function ViewItem({ view, caps, resource, onClick, testid }) {
5654
+ const own = resource === void 0 ? void 0 : `resources.${resource}.${(0, _burojs_core.savedViewKey)(view.id)}`;
5655
+ const declared = (0, _burojs_core.declaredText)("saved-view", view, "label");
5656
+ const label = own === void 0 ? declared ?? (0, _burojs_core.humanizeKey)(view.id) : (0, _burojs_core.resolveContentSlot)(caps, [[`${own}.label`, own]], {
5657
+ default: declared,
5658
+ humanize: () => (0, _burojs_core.humanizeKey)(view.id)
5659
+ });
5585
5660
  return (0, react_jsx_runtime.jsx)("button", {
5586
5661
  type: "button",
5587
5662
  onClick,
5588
5663
  "data-testid": testid,
5589
5664
  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",
5590
- children: view.label
5665
+ children: label
5591
5666
  });
5592
5667
  }
5593
5668
  function EntryRow({ entry, onApply, onRename, onFork, onDelete, forkAvailable, applyTestId, renameTestId, forkTestId, deleteTestId, tr }) {
@@ -5677,8 +5752,9 @@ function groupByScope(entries) {
5677
5752
  }
5678
5753
  return order.map((id) => byId.get(id));
5679
5754
  }
5680
- 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" }) {
5755
+ 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" }) {
5681
5756
  const t = (0, _burojs_react.useOptionalT)();
5757
+ const caps = (0, _burojs_react.useI18nCaps)(resource);
5682
5758
  const tr = (key, fallback) => t?.(key, { defaultValue: fallback }) ?? fallback;
5683
5759
  const [open, setOpen] = (0, react.useState)(false);
5684
5760
  const hasAdopter = adopterViews.length > 0;
@@ -5732,6 +5808,8 @@ function SavedViewsDropdown({ adopterViews, entries, issues = [], onApply, onSav
5732
5808
  className: "max-h-[200px] overflow-auto",
5733
5809
  children: adopterViews.map((v) => (0, react_jsx_runtime.jsx)(ViewItem, {
5734
5810
  view: v,
5811
+ caps,
5812
+ resource,
5735
5813
  testid: getTestId?.("view-item", v.id),
5736
5814
  onClick: closeAfter(() => onApply(v))
5737
5815
  }, v.id))
@@ -5788,6 +5866,7 @@ function ListSavedViewsView() {
5788
5866
  const { resource, route, savedViewsUi } = useListSurface();
5789
5867
  if (!def || !route) return null;
5790
5868
  return (0, react_jsx_runtime.jsx)(SavedViewsDropdown, {
5869
+ resource,
5791
5870
  adopterViews: savedViews.adopter,
5792
5871
  entries: savedViews.entries,
5793
5872
  issues: savedViews.issues,
@@ -5954,7 +6033,6 @@ function FormActionsView() {
5954
6033
  const navigate = (0, _burojs_react.useRouteNavigate)();
5955
6034
  const t = (0, _burojs_react.useOptionalT)();
5956
6035
  const tid = (0, _burojs_react.useTestIds)();
5957
- const locale = (0, _burojs_react.useLocale)();
5958
6036
  const id = useFrameId();
5959
6037
  if (mode === "show") return null;
5960
6038
  const busy = controller.isSubmitting;
@@ -5987,7 +6065,7 @@ function FormActionsView() {
5987
6065
  if (issue.params?.cause === void 0 || typeof checkId !== "string") continue;
5988
6066
  if (!retryable.includes(checkId)) retryable.push(checkId);
5989
6067
  }
5990
- const failure = chrome.submitError === void 0 ? void 0 : failureText(chrome.submitError, t, locale);
6068
+ const failure = chrome.submitError === void 0 ? void 0 : failureText(chrome.submitError, t);
5991
6069
  const steps = controller.steps;
5992
6070
  const midSteps = steps !== null && steps.ids.length > 1 && steps.current !== void 0 && steps.current !== steps.ids[steps.ids.length - 1];
5993
6071
  return (0, react_jsx_runtime.jsxs)("div", {
@@ -6096,8 +6174,8 @@ function issueKey(issue) {
6096
6174
  issue.params ?? null
6097
6175
  ]);
6098
6176
  }
6099
- function failureText(error, t, locale) {
6100
- const friendly = require_toaster.toFriendlyError(safeMessage(error), void 0, locale);
6177
+ function failureText(error, t) {
6178
+ const friendly = require_toaster.toFriendlyError(safeMessage(error), void 0, require_toaster.friendlyStringsFrom(t));
6101
6179
  return friendly.replaced ? friendly.title : t("errors.failed", { defaultValue: "Failed" });
6102
6180
  }
6103
6181
  function safeMessage(error) {
@@ -6424,14 +6502,16 @@ function ListFrameHost({ resource }) {
6424
6502
  }
6425
6503
  //#endregion
6426
6504
  //#region src/list-kit/resource-list-surface.tsx
6427
- const RelatedCards = (0, react.lazy)(async () => ({ default: (await Promise.resolve().then(() => require("./related-list-cards-nxuODlIA.cjs"))).RelatedCards }));
6428
- const RelatedTimeline = (0, react.lazy)(async () => ({ default: (await Promise.resolve().then(() => require("./related-list-timeline-BYJKEbmA.cjs"))).RelatedTimeline }));
6505
+ const RelatedCards = (0, react.lazy)(async () => ({ default: (await Promise.resolve().then(() => require("./related-list-cards-CFq3meUn.cjs"))).RelatedCards }));
6506
+ const RelatedTimeline = (0, react.lazy)(async () => ({ default: (await Promise.resolve().then(() => require("./related-list-timeline-CCzl71aA.cjs"))).RelatedTimeline }));
6429
6507
  function discriminatorOptionLabel(field, value) {
6508
+ const text = (0, _burojs_core.fieldOptionText)(field, value);
6509
+ if (text !== void 0) return text;
6430
6510
  const declared = field;
6431
6511
  const label = (Array.isArray(declared?.options) ? declared.options : Array.isArray(declared?.meta?.options) ? declared.meta.options : []).find((option) => option?.value === value)?.label;
6432
6512
  return typeof label === "string" ? label : value;
6433
6513
  }
6434
- function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize, search: searchField, columns: columnNames, open, title, view, item, placementKey, onCreate, meta, renderCell, emptyState }) {
6514
+ 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 }) {
6435
6515
  const route = variant === "route";
6436
6516
  const t = (0, _burojs_react.useT)();
6437
6517
  const optionalT = (0, _burojs_react.useOptionalT)();
@@ -6454,7 +6534,9 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6454
6534
  ...fixedFilters === void 0 ? {} : { fixedFilters },
6455
6535
  ...pageSize === void 0 ? {} : { pageSize },
6456
6536
  ...searchDecl === void 0 ? {} : { search: searchDecl },
6457
- ...columnNames === void 0 ? {} : { columns: columnNames }
6537
+ ...columnNames === void 0 ? {} : { columns: columnNames },
6538
+ ...scope === void 0 ? {} : { scope },
6539
+ ...countPolicy === void 0 ? {} : { countPolicy }
6458
6540
  });
6459
6541
  const { def, query, pagination, cursor, count, filters, sorting, columns, selection, savedViews, routing, live, droppedPredicates } = list;
6460
6542
  (0, _burojs_react.policyRowsOf)(list, list.rows);
@@ -6467,7 +6549,7 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6467
6549
  const gate = (0, _burojs_react.useEntryGate)();
6468
6550
  const openQuick = (0, _burojs_react.useQuickOpener)();
6469
6551
  const effectiveOpen = open ?? (route ? def !== void 0 && !(0, _burojs_core.hasRecordPage)(def, "show") ? "quick" : "page" : "quick");
6470
- const quickRows = effectiveOpen === "quick";
6552
+ const quickRows = effectiveOpen === "quick" && rowTarget === void 0;
6471
6553
  useDeepLinkOpen(resource, resource, route && quickRows);
6472
6554
  const rowQuick = (0, react.useMemo)(() => quickRows ? (row) => gate(resource, "show", row).state === "open" ? () => void openQuick(resource, String(row.id), { row }) : null : void 0, [
6473
6555
  quickRows,
@@ -6475,8 +6557,31 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6475
6557
  openQuick,
6476
6558
  resource
6477
6559
  ]);
6478
- const rowHref = (0, react.useMemo)(() => effectiveOpen === "none" ? void 0 : quickRows ? (row) => gate(resource, "show", row).state === "undecided" ? void 0 : routing.rowHref(row) : routing.rowHref, [
6560
+ const registry = (0, _burojs_react.useApp)().registry;
6561
+ const targetName = rowTarget?.resource;
6562
+ const targetField = rowTarget?.field;
6563
+ const targetGate = (0, _burojs_react.useAvailabilityResolver)(targetName ?? resource);
6564
+ const targetHref = (0, react.useMemo)(() => {
6565
+ if (targetName === void 0 || targetField === void 0) return void 0;
6566
+ const targetDef = registry.get(targetName);
6567
+ const delegate = targetDef?.routesTo?.show;
6568
+ const showDef = delegate === void 0 ? targetDef : registry.get(delegate);
6569
+ const showPage = targetDef !== void 0 && showDef !== void 0 && (0, _burojs_core.hasRecordPage)(showDef, "show");
6570
+ return (row) => {
6571
+ const key = row[targetField];
6572
+ if (!showPage || key === null || key === void 0 || key === "") return void 0;
6573
+ if (targetGate("show").state !== "available") return void 0;
6574
+ return (0, _burojs_core.resourceShowHref)(registry, targetDef, targetName, String(key));
6575
+ };
6576
+ }, [
6577
+ registry,
6578
+ targetName,
6579
+ targetField,
6580
+ targetGate
6581
+ ]);
6582
+ const rowHref = (0, react.useMemo)(() => effectiveOpen === "none" ? void 0 : targetHref !== void 0 ? targetHref : quickRows ? (row) => gate(resource, "show", row).state === "undecided" ? void 0 : routing.rowHref(row) : routing.rowHref, [
6479
6583
  effectiveOpen,
6584
+ targetHref,
6480
6585
  quickRows,
6481
6586
  gate,
6482
6587
  resource,
@@ -6604,7 +6709,7 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6604
6709
  const fieldDef = def.fields[col];
6605
6710
  const inline = discriminatorOptionLabel(fieldDef, raw);
6606
6711
  const namespace = (0, _burojs_core.enumNamespaceOf)(fieldDef);
6607
- const label = namespace === void 0 ? (0, _burojs_core.resolveContentSlot)(listCaps, [(0, _burojs_core.fieldOptionKey)(col, raw)], { default: inline }) : (0, _burojs_core.resolveEnumLabel)(listCaps, namespace, raw, inline);
6712
+ const label = namespace === void 0 ? (0, _burojs_core.resolveFieldOptionLabel)(listCaps, col, raw, inline) : (0, _burojs_core.resolveEnumLabel)(listCaps, namespace, raw, inline);
6608
6713
  return (0, react_jsx_runtime.jsx)(require_filter_builder.Badge, {
6609
6714
  variant: "secondary",
6610
6715
  "data-testid": `list-cell-type:${resource}:${raw}`,
@@ -6646,7 +6751,9 @@ function ResourceListSurface({ resource, variant, state, fixedFilters, pageSize,
6646
6751
  },
6647
6752
  rowsViewFor,
6648
6753
  emptyState,
6649
- renderCell: renderCellLadder
6754
+ renderCell: renderCellLadder,
6755
+ readOnly: readOnly === true,
6756
+ exportable: exportable !== false
6650
6757
  };
6651
6758
  return (0, react_jsx_runtime.jsx)(_burojs_react.ResourceListProvider, {
6652
6759
  value: list,
@@ -6875,6 +6982,180 @@ function ExportRunWatcherMount() {
6875
6982
  return null;
6876
6983
  }
6877
6984
  //#endregion
6985
+ //#region src/quick/peek-filter.ts
6986
+ function peekFieldDefinition(def, name) {
6987
+ return (0, _burojs_core.declaredField)(def, name);
6988
+ }
6989
+ function peekLeafAllowed(def, name, capabilityFor, fieldVisible) {
6990
+ const field = peekFieldDefinition(def, name);
6991
+ if (field === void 0 || (0, _burojs_core.fieldSensitivity)(field) !== void 0) return false;
6992
+ if (capabilityFor("view", {
6993
+ kind: "column",
6994
+ name
6995
+ }).allowed === false) return false;
6996
+ return fieldVisible(name);
6997
+ }
6998
+ function peekRow(def, row, idField, capabilityFor, fieldVisible, drawn) {
6999
+ const out = {};
7000
+ 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;
7001
+ return Object.freeze(out);
7002
+ }
7003
+ function peekRecord(def, row, idField, capabilityFor, fieldVisible) {
7004
+ if (def === void 0) return Object.freeze({ [idField]: row[idField] });
7005
+ return peekRow(def, row, idField, capabilityFor, fieldVisible);
7006
+ }
7007
+ //#endregion
7008
+ //#region src/blocks/related-list-unbound.tsx
7009
+ function UnboundRelatedList(props) {
7010
+ const t = (0, _burojs_react.useOptionalT)();
7011
+ return (0, react_jsx_runtime.jsxs)("div", {
7012
+ className: "flex flex-col gap-2",
7013
+ "data-testid": `list-unbound:${props.resource}`,
7014
+ children: [props.title === void 0 ? null : (0, react_jsx_runtime.jsx)("h3", {
7015
+ className: "text-sm font-semibold",
7016
+ children: props.title
7017
+ }), (0, react_jsx_runtime.jsx)("p", {
7018
+ className: "text-sm text-muted-foreground",
7019
+ children: t("table.empty", { defaultValue: "No records" })
7020
+ })]
7021
+ });
7022
+ }
7023
+ function placementScope(scope, owner) {
7024
+ return scope ?? (owner === void 0 ? "session" : "none");
7025
+ }
7026
+ //#endregion
7027
+ //#region src/blocks/link-panel.tsx
7028
+ const isRecord = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
7029
+ const isResourceHandle = (value) => isRecord(value) && value.kind === "resource";
7030
+ function qualify(ref, owner) {
7031
+ try {
7032
+ const namespace = (0, _burojs_core.normalizeEntityRef)(owner).namespace;
7033
+ return (0, _burojs_core.resourceKey)((0, _burojs_core.normalizeEntityRef)(isResourceHandle(ref) ? ref.ref : ref, { defaultNamespace: namespace }));
7034
+ } catch {
7035
+ return;
7036
+ }
7037
+ }
7038
+ function linkField(registry, owner, link) {
7039
+ if (owner === void 0) return void 0;
7040
+ const def = registry.get(owner);
7041
+ const field = def === void 0 ? void 0 : peekFieldDefinition(def, link);
7042
+ if (!isRecord(field)) return void 0;
7043
+ const declaration = (0, _burojs_core.linkOf)(field);
7044
+ return declaration === void 0 ? void 0 : {
7045
+ field,
7046
+ declaration
7047
+ };
7048
+ }
7049
+ function linkTarget(registry, owner, link) {
7050
+ const found = linkField(registry, owner, link);
7051
+ if (found === void 0 || owner === void 0) return void 0;
7052
+ return qualify(found.field.meta?.to, owner);
7053
+ }
7054
+ function idFieldOf(def) {
7055
+ const declared = isRecord(def) && isRecord(def.data) ? def.data.idField : void 0;
7056
+ return typeof declared === "string" && declared.length > 0 ? declared : "id";
7057
+ }
7058
+ function byOf(field) {
7059
+ const by = isRecord(field) && isRecord(field.meta) ? field.meta.by : void 0;
7060
+ return typeof by === "string" && by.length > 0 ? by : void 0;
7061
+ }
7062
+ const MAX_TARGET_HOPS = 2;
7063
+ function targetColumns(registry, target, def) {
7064
+ if (!isRecord(def) || !isRecord(def.fields)) return [];
7065
+ const source = def;
7066
+ const views = isRecord(def.views) ? def.views : void 0;
7067
+ const list = views !== void 0 && isRecord(views.list) ? views.list : void 0;
7068
+ return (list !== void 0 && Array.isArray(list.columns) ? list.columns.filter((name) => typeof name === "string") : (0, _burojs_core.dtoFields)(source, "list")).filter((name) => {
7069
+ if (name.includes(".")) return name.split(".").length - 1 <= MAX_TARGET_HOPS && (0, _burojs_react.resolveColumnField)(registry, target, name) !== void 0;
7070
+ const field = peekFieldDefinition(source, name);
7071
+ return isRecord(field) && !(0, _burojs_core.isRelationField)(field) && (0, _burojs_core.fieldSensitivity)(field) === void 0;
7072
+ });
7073
+ }
7074
+ function LinkPanel(props) {
7075
+ const { link, owner, own } = props;
7076
+ const app = (0, _burojs_react.useApp)();
7077
+ const frame = usePlacementFrame();
7078
+ const routeScreen = useIsRouteScreen();
7079
+ const record = (0, _burojs_react.useOptionalRecordFrame)()?.record;
7080
+ const storage = (0, react.useMemo)(() => {
7081
+ const found = linkField(app.registry, owner, link);
7082
+ if (found === void 0) return void 0;
7083
+ const { declaration } = found;
7084
+ const junction = qualify(declaration.junction, owner);
7085
+ const target = qualify(found.field.meta?.to, owner);
7086
+ if (junction === void 0 || target === void 0) return void 0;
7087
+ const junctionDef = app.registry.get(junction);
7088
+ if (junctionDef === void 0) return void 0;
7089
+ const junctionFields = junctionDef.fields;
7090
+ return {
7091
+ junction,
7092
+ target,
7093
+ sourceKey: declaration.sourceKey,
7094
+ targetKey: declaration.targetKey,
7095
+ ownerField: byOf(junctionFields[declaration.sourceKey]) ?? idFieldOf(app.registry.get(owner)),
7096
+ targetKeyedBy: byOf(junctionFields[declaration.targetKey]) !== void 0,
7097
+ where: declaration.where,
7098
+ targetDef: app.registry.get(target)
7099
+ };
7100
+ }, [
7101
+ app.registry,
7102
+ owner,
7103
+ link
7104
+ ]);
7105
+ const ownerKey = storage === void 0 ? void 0 : record?.[storage.ownerField];
7106
+ const whereKey = JSON.stringify(own.where ?? []);
7107
+ const fixedFilters = (0, react.useMemo)(() => {
7108
+ if (storage === void 0 || ownerKey === null || ownerKey === void 0) return void 0;
7109
+ const { sourceKey, targetKey } = storage;
7110
+ return [
7111
+ (0, _burojs_core.whereEntryToFilter)(sourceKey, "eq", ownerKey),
7112
+ ...storage.where.map((entry) => (0, _burojs_core.whereEntryToFilter)(entry.field, entry.op, entry.value)),
7113
+ ...(own.where ?? []).map((entry) => (0, _burojs_core.whereEntryToFilter)(`${targetKey}.${entry.field}`, entry.op, entry.value))
7114
+ ];
7115
+ }, [
7116
+ storage,
7117
+ ownerKey,
7118
+ whereKey
7119
+ ]);
7120
+ const columnsKey = JSON.stringify([own.columns ?? null, own.linkColumns ?? null]);
7121
+ const columns = (0, react.useMemo)(() => {
7122
+ if (storage === void 0) return void 0;
7123
+ return [...(own.columns ?? targetColumns(app.registry, storage.target, storage.targetDef)).map((name) => `${storage.targetKey}.${name}`), ...own.linkColumns ?? []];
7124
+ }, [
7125
+ storage,
7126
+ columnsKey,
7127
+ app.registry
7128
+ ]);
7129
+ const rowTarget = (0, react.useMemo)(() => storage === void 0 || storage.targetKeyedBy ? void 0 : {
7130
+ resource: storage.target,
7131
+ field: storage.targetKey
7132
+ }, [storage]);
7133
+ const unbound = fixedFilters === void 0 || own.where?.some((entry) => entry.value === null || entry.value === void 0) === true;
7134
+ if (storage === void 0 || unbound) return (0, react_jsx_runtime.jsx)(UnboundRelatedList, {
7135
+ resource: storage?.target ?? "",
7136
+ title: own.title
7137
+ });
7138
+ const state = frame?.state === "url" && routeScreen && !frame.nested ? { url: frame.key } : "memory";
7139
+ const count = own.count === false ? "off" : own.count;
7140
+ return (0, react_jsx_runtime.jsx)(ResourceListSurface, {
7141
+ resource: storage.junction,
7142
+ variant: "placement",
7143
+ state,
7144
+ fixedFilters,
7145
+ ...own.pageSize === void 0 ? {} : { pageSize: own.pageSize },
7146
+ ...own.search === void 0 ? {} : { search: `${storage.targetKey}.${own.search}` },
7147
+ ...columns === void 0 ? {} : { columns },
7148
+ open: rowTarget === void 0 || own.open === "none" ? "none" : "page",
7149
+ ...rowTarget === void 0 ? {} : { rowTarget },
7150
+ ...frame === null ? {} : { placementKey: frame.key },
7151
+ ...own.title === void 0 ? {} : { title: own.title },
7152
+ scope: placementScope(own.scope, owner),
7153
+ ...count === void 0 ? {} : { count },
7154
+ readOnly: true,
7155
+ exportable: false
7156
+ });
7157
+ }
7158
+ //#endregion
6878
7159
  //#region src/blocks/route-list-context.ts
6879
7160
  const RouteListContext = (0, react.createContext)(null);
6880
7161
  function useRouteList() {
@@ -6886,29 +7167,33 @@ function RelatedListView({ props }) {
6886
7167
  const own = props;
6887
7168
  const route = useRouteList();
6888
7169
  const frame = usePlacementFrame();
6889
- const resource = (0, _burojs_core.resourceKey)(own.resource);
7170
+ const app = (0, _burojs_react.useApp)();
7171
+ const linked = own.link !== void 0;
7172
+ const resource = linked ? linkTarget(app.registry, frame?.owner, own.link) ?? "" : (0, _burojs_core.resourceKey)(own.resource);
6890
7173
  const whereKey = JSON.stringify(own.where ?? []);
6891
- const fixedFilters = (0, react.useMemo)(() => own.where === void 0 ? void 0 : own.where.map(({ field, op, value }) => ({
6892
- field,
6893
- op,
6894
- value
6895
- })), [whereKey]);
7174
+ const fixedFilters = (0, react.useMemo)(() => own.where === void 0 ? void 0 : own.where.map(({ field, op, value }) => (0, _burojs_core.whereEntryToFilter)(field, op, value)), [whereKey]);
6896
7175
  const columnsKey = JSON.stringify(own.columns ?? null);
6897
7176
  const columns = (0, react.useMemo)(() => own.columns, [columnsKey]);
6898
7177
  const routeScreen = useIsRouteScreen();
6899
7178
  const inQuick = (0, _burojs_react.useQuickEntry)() !== null;
6900
7179
  useMemoryNotice(frame, routeScreen || inQuick, route !== null);
6901
- const t = (0, _burojs_react.useOptionalT)();
6902
7180
  const permissions = (0, _burojs_react.useCtx)((c) => c.permissions);
6903
- const app = (0, _burojs_react.useApp)();
6904
7181
  const gate = (0, _burojs_react.useEntryGate)();
6905
7182
  const quick = (0, _burojs_react.useQuick)();
6906
7183
  const ownerDef = frame?.owner === void 0 ? void 0 : app.registry.get(frame.owner);
6907
7184
  const granted = ownerDef === void 0 ? "unknown" : (0, _burojs_core.grantedPlacementKeys)(ownerDef);
6908
7185
  const trusted = frame !== null && !frame.nested && granted !== "unknown" && !granted.has(frame.key);
6909
- 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;
6910
- useDeepLinkOpen(frame?.key ?? null, resource, route === null && frame !== null && !frame.nested && routeScreen && (own.open ?? "quick") === "quick");
7186
+ 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;
7187
+ useDeepLinkOpen(frame?.key ?? null, resource, route === null && !linked && frame !== null && !frame.nested && routeScreen && (own.open ?? "quick") === "quick");
6911
7188
  const unbound = own.where?.some((entry) => entry.value === null || entry.value === void 0) === true;
7189
+ if (linked) return frame?.owner === void 0 ? (0, react_jsx_runtime.jsx)(UnboundRelatedList, {
7190
+ resource,
7191
+ title: own.title
7192
+ }) : (0, react_jsx_runtime.jsx)(LinkPanel, {
7193
+ link: own.link,
7194
+ owner: frame.owner,
7195
+ own
7196
+ });
6912
7197
  if (route !== null) return (0, react_jsx_runtime.jsx)(ResourceListSurface, {
6913
7198
  resource,
6914
7199
  variant: "route",
@@ -6922,18 +7207,13 @@ function RelatedListView({ props }) {
6922
7207
  "data-testid": `list-undecided:${resource}`,
6923
7208
  children: own.view === "cards" ? (0, react_jsx_runtime.jsx)(RelatedCardsSkeleton, {}) : (0, react_jsx_runtime.jsx)(RelatedTimelineSkeleton, {})
6924
7209
  });
6925
- if (unbound) return (0, react_jsx_runtime.jsxs)("div", {
6926
- className: "flex flex-col gap-2",
6927
- "data-testid": `list-unbound:${resource}`,
6928
- children: [own.title === void 0 ? null : (0, react_jsx_runtime.jsx)("h3", {
6929
- className: "text-sm font-semibold",
6930
- children: own.title
6931
- }), (0, react_jsx_runtime.jsx)("p", {
6932
- className: "text-sm text-muted-foreground",
6933
- children: t("table.empty", { defaultValue: "No records" })
6934
- })]
7210
+ if (unbound) return (0, react_jsx_runtime.jsx)(UnboundRelatedList, {
7211
+ resource,
7212
+ title: own.title
6935
7213
  });
6936
7214
  const state = frame?.state === "url" && routeScreen && !frame.nested ? { url: frame.key } : "memory";
7215
+ const scope = placementScope(own.scope, frame?.owner);
7216
+ const count = own.count === false ? "off" : own.count;
6937
7217
  return (0, react_jsx_runtime.jsx)(ResourceListSurface, {
6938
7218
  resource,
6939
7219
  variant: "placement",
@@ -6947,6 +7227,8 @@ function RelatedListView({ props }) {
6947
7227
  ...isItemHandle(own.item) ? { item: own.item } : {},
6948
7228
  ...frame === null ? {} : { placementKey: frame.key },
6949
7229
  ...own.title === void 0 ? {} : { title: own.title },
7230
+ scope,
7231
+ ...count === void 0 ? {} : { count },
6950
7232
  ...onCreate === void 0 ? {} : { onCreate }
6951
7233
  });
6952
7234
  }
@@ -7051,7 +7333,7 @@ function RelatedRecordView({ props }) {
7051
7333
  className: "flex min-w-0 flex-col gap-0.5",
7052
7334
  children: [(0, react_jsx_runtime.jsx)("dt", {
7053
7335
  className: FIELD_LABEL_SHOW,
7054
- children: (0, _burojs_core.resolveFieldLabel)(caps, name, field?.label)
7336
+ children: (0, _burojs_core.resolveFieldLabel)(caps, name, (0, _burojs_core.declaredText)("field", field, "label"))
7055
7337
  }), (0, react_jsx_runtime.jsx)("dd", {
7056
7338
  className: "min-w-0 break-words text-sm",
7057
7339
  children: (0, react_jsx_runtime.jsx)(ResolvedFieldDisplay, {
@@ -7697,6 +7979,30 @@ Object.defineProperty(exports, "lowerLegacyField", {
7697
7979
  return lowerLegacyField;
7698
7980
  }
7699
7981
  });
7982
+ Object.defineProperty(exports, "peekFieldDefinition", {
7983
+ enumerable: true,
7984
+ get: function() {
7985
+ return peekFieldDefinition;
7986
+ }
7987
+ });
7988
+ Object.defineProperty(exports, "peekLeafAllowed", {
7989
+ enumerable: true,
7990
+ get: function() {
7991
+ return peekLeafAllowed;
7992
+ }
7993
+ });
7994
+ Object.defineProperty(exports, "peekRecord", {
7995
+ enumerable: true,
7996
+ get: function() {
7997
+ return peekRecord;
7998
+ }
7999
+ });
8000
+ Object.defineProperty(exports, "peekRow", {
8001
+ enumerable: true,
8002
+ get: function() {
8003
+ return peekRow;
8004
+ }
8005
+ });
7700
8006
  Object.defineProperty(exports, "recordReturnTarget", {
7701
8007
  enumerable: true,
7702
8008
  get: function() {
@@ -7830,4 +8136,4 @@ Object.defineProperty(exports, "viewOf", {
7830
8136
  }
7831
8137
  });
7832
8138
 
7833
- //# sourceMappingURL=place-node-SIp4XYQH.cjs.map
8139
+ //# sourceMappingURL=place-node-C5SmIAYU.cjs.map