@burojs/ui-shadcn 0.8.0 → 0.10.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 (126) hide show
  1. package/dist/{bulk-summary-2HLgz7Il.cjs → bulk-summary-Chc61Pyw.cjs} +9 -7
  2. package/dist/bulk-summary-Chc61Pyw.cjs.map +1 -0
  3. package/dist/{bulk-summary-D6A0ua21.js → bulk-summary-DpSQD2Fq.js} +9 -7
  4. package/dist/bulk-summary-DpSQD2Fq.js.map +1 -0
  5. package/dist/{candidates-relation-picker-CGXItMN0.js → candidates-relation-picker-DRsHKe6N.js} +3 -3
  6. package/dist/{candidates-relation-picker-CGXItMN0.js.map → candidates-relation-picker-DRsHKe6N.js.map} +1 -1
  7. package/dist/{candidates-relation-picker-C47mF260.cjs → candidates-relation-picker-GIxsp7D_.cjs} +3 -3
  8. package/dist/{candidates-relation-picker-C47mF260.cjs.map → candidates-relation-picker-GIxsp7D_.cjs.map} +1 -1
  9. package/dist/{check-confirm-dialog-BT04Mieo.cjs → check-confirm-dialog-BMSb7wFv.cjs} +76 -9
  10. package/dist/check-confirm-dialog-BMSb7wFv.cjs.map +1 -0
  11. package/dist/{check-confirm-dialog-CtiRzOAt.js → check-confirm-dialog-B_u3YVHS.js} +72 -11
  12. package/dist/{check-confirm-dialog-CtiRzOAt.js.map → check-confirm-dialog-B_u3YVHS.js.map} +1 -1
  13. package/dist/{filter-builder-z3Axzf9Y.js → filter-builder-DX-xC3Yd.js} +14 -6
  14. package/dist/filter-builder-DX-xC3Yd.js.map +1 -0
  15. package/dist/{filter-builder-ByGhxLf_.cjs → filter-builder-Dt5E8PSX.cjs} +14 -6
  16. package/dist/filter-builder-Dt5E8PSX.cjs.map +1 -0
  17. package/dist/{flow-runtime-BVFjMU5-.cjs → flow-runtime-CQ4wf8co.cjs} +3 -3
  18. package/dist/{flow-runtime-BVFjMU5-.cjs.map → flow-runtime-CQ4wf8co.cjs.map} +1 -1
  19. package/dist/{flow-runtime-DrUWyTS0.js → flow-runtime-Q2vD7R3c.js} +3 -3
  20. package/dist/{flow-runtime-DrUWyTS0.js.map → flow-runtime-Q2vD7R3c.js.map} +1 -1
  21. package/dist/{flow-screen-3fk6J33y.js → flow-screen-B1y2yizP.js} +68 -29
  22. package/dist/flow-screen-B1y2yizP.js.map +1 -0
  23. package/dist/{flow-screen-6y5E_HT6.cjs → flow-screen-sw2cP70t.cjs} +67 -28
  24. package/dist/flow-screen-sw2cP70t.cjs.map +1 -0
  25. package/dist/index.cjs +2304 -247
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +119 -12
  28. package/dist/index.d.ts +119 -12
  29. package/dist/index.js +2225 -172
  30. package/dist/index.js.map +1 -1
  31. package/dist/{inline-flow-host-C4KmZIYE.cjs → inline-flow-host-CkhoA69R.cjs} +3 -3
  32. package/dist/{inline-flow-host-C4KmZIYE.cjs.map → inline-flow-host-CkhoA69R.cjs.map} +1 -1
  33. package/dist/{inline-flow-host-YnnvWjdU.js → inline-flow-host-DqbXqcPS.js} +3 -3
  34. package/dist/{inline-flow-host-YnnvWjdU.js.map → inline-flow-host-DqbXqcPS.js.map} +1 -1
  35. package/dist/{lazy-relation-picker-dialog-DN4bvQfg.js → lazy-relation-picker-dialog-BaIEWLbF.js} +3 -52
  36. package/dist/lazy-relation-picker-dialog-BaIEWLbF.js.map +1 -0
  37. package/dist/{lazy-relation-picker-dialog-BAKBRn3V.cjs → lazy-relation-picker-dialog-CeRzOAi0.cjs} +3 -52
  38. package/dist/lazy-relation-picker-dialog-CeRzOAi0.cjs.map +1 -0
  39. package/dist/{page-flow-route-CtEfqAvU.js → page-flow-route-CP7cS7FY.js} +7 -7
  40. package/dist/page-flow-route-CP7cS7FY.js.map +1 -0
  41. package/dist/{page-flow-route-DEjAxHe3.cjs → page-flow-route-UDx8qvdM.cjs} +10 -10
  42. package/dist/page-flow-route-UDx8qvdM.cjs.map +1 -0
  43. package/dist/{place-node-Bhl8B3fF.cjs → place-node-C5ZmuHaN.cjs} +208 -55
  44. package/dist/place-node-C5ZmuHaN.cjs.map +1 -0
  45. package/dist/{place-node-BdxT-30h.js → place-node-DwWAigv0.js} +205 -58
  46. package/dist/place-node-DwWAigv0.js.map +1 -0
  47. package/dist/record-trail-store-Cjo9vtod.cjs +126 -0
  48. package/dist/record-trail-store-Cjo9vtod.cjs.map +1 -0
  49. package/dist/record-trail-store-Dn6bVry4.js +91 -0
  50. package/dist/record-trail-store-Dn6bVry4.js.map +1 -0
  51. package/dist/{related-list-cards-Bc_vfCE_.cjs → related-list-cards-BypKfm9t.cjs} +3 -3
  52. package/dist/{related-list-cards-Bc_vfCE_.cjs.map → related-list-cards-BypKfm9t.cjs.map} +1 -1
  53. package/dist/{related-list-cards-BvkD5OcC.js → related-list-cards-Dcmruy09.js} +3 -3
  54. package/dist/{related-list-cards-BvkD5OcC.js.map → related-list-cards-Dcmruy09.js.map} +1 -1
  55. package/dist/{related-list-timeline-k0DtnxTs.cjs → related-list-timeline-D-KClgKb.cjs} +4 -4
  56. package/dist/related-list-timeline-D-KClgKb.cjs.map +1 -0
  57. package/dist/{related-list-timeline-DCrwN9oO.js → related-list-timeline-DZON_qSc.js} +4 -4
  58. package/dist/related-list-timeline-DZON_qSc.js.map +1 -0
  59. package/dist/{related-rows-BW9Jr07T.cjs → related-rows-DgF05ssi.cjs} +4 -4
  60. package/dist/{related-rows-BW9Jr07T.cjs.map → related-rows-DgF05ssi.cjs.map} +1 -1
  61. package/dist/{related-rows-CPE-9FFr.js → related-rows-ETZl5CB9.js} +4 -4
  62. package/dist/{related-rows-CPE-9FFr.js.map → related-rows-ETZl5CB9.js.map} +1 -1
  63. package/dist/{relation-create-DDEYcKfw.cjs → relation-create-B8zngAcA.cjs} +82 -13
  64. package/dist/relation-create-B8zngAcA.cjs.map +1 -0
  65. package/dist/{relation-create-C43cdPQt.js → relation-create-CeCWyxIb.js} +79 -16
  66. package/dist/relation-create-CeCWyxIb.js.map +1 -0
  67. package/dist/{relation-many-picker-BlrGRwMV.js → relation-many-picker-CT7nKfE2.js} +12 -10
  68. package/dist/relation-many-picker-CT7nKfE2.js.map +1 -0
  69. package/dist/{relation-many-picker-Br-zBHxT.cjs → relation-many-picker-Cq0EHY5I.cjs} +12 -10
  70. package/dist/relation-many-picker-Cq0EHY5I.cjs.map +1 -0
  71. package/dist/{relation-picker-x7P5HKie.js → relation-picker-CCyuMeGq.js} +13 -10
  72. package/dist/relation-picker-CCyuMeGq.js.map +1 -0
  73. package/dist/{relation-picker-ADjxI_TI.cjs → relation-picker-DmwTzgsd.cjs} +13 -10
  74. package/dist/relation-picker-DmwTzgsd.cjs.map +1 -0
  75. package/dist/{relation-picker-dialog-CyKliBkN.js → relation-picker-dialog-CoWKjNv8.js} +5 -5
  76. package/dist/relation-picker-dialog-CoWKjNv8.js.map +1 -0
  77. package/dist/{relation-picker-dialog-DimVQF9Y.cjs → relation-picker-dialog-mbwyNK43.cjs} +5 -5
  78. package/dist/relation-picker-dialog-mbwyNK43.cjs.map +1 -0
  79. package/dist/{relation-select-Cr3CfNLy.cjs → relation-select-CguIo2M5.cjs} +2 -2
  80. package/dist/{relation-select-Cr3CfNLy.cjs.map → relation-select-CguIo2M5.cjs.map} +1 -1
  81. package/dist/{relation-select-B8Fq4o-t.js → relation-select-nAYxhopN.js} +2 -2
  82. package/dist/{relation-select-B8Fq4o-t.js.map → relation-select-nAYxhopN.js.map} +1 -1
  83. package/dist/{success-notices-Dl3M1fZP.cjs → success-notices-Cl4b6MLQ.cjs} +3 -2
  84. package/dist/success-notices-Cl4b6MLQ.cjs.map +1 -0
  85. package/dist/{success-notices-LDEgEkc4.js → success-notices-CrcWOGSo.js} +3 -2
  86. package/dist/success-notices-CrcWOGSo.js.map +1 -0
  87. package/dist/{use-dialog-filter-state-tNvqAAjh.cjs → use-dialog-filter-state-CpWblz3C.cjs} +2 -2
  88. package/dist/{use-dialog-filter-state-tNvqAAjh.cjs.map → use-dialog-filter-state-CpWblz3C.cjs.map} +1 -1
  89. package/dist/{use-dialog-filter-state-B_MqzHaT.js → use-dialog-filter-state-ZYxOp5WO.js} +2 -2
  90. package/dist/{use-dialog-filter-state-B_MqzHaT.js.map → use-dialog-filter-state-ZYxOp5WO.js.map} +1 -1
  91. package/dist/{use-record-subtitle-bfwIoUme.cjs → use-record-subtitle-B4lTR7pf.cjs} +5 -8
  92. package/dist/use-record-subtitle-B4lTR7pf.cjs.map +1 -0
  93. package/dist/{use-record-subtitle-gIaCGgbI.js → use-record-subtitle-pWMBqQx9.js} +5 -8
  94. package/dist/use-record-subtitle-pWMBqQx9.js.map +1 -0
  95. package/package.json +9 -9
  96. package/dist/bulk-summary-2HLgz7Il.cjs.map +0 -1
  97. package/dist/bulk-summary-D6A0ua21.js.map +0 -1
  98. package/dist/check-confirm-dialog-BT04Mieo.cjs.map +0 -1
  99. package/dist/filter-builder-ByGhxLf_.cjs.map +0 -1
  100. package/dist/filter-builder-z3Axzf9Y.js.map +0 -1
  101. package/dist/flow-screen-3fk6J33y.js.map +0 -1
  102. package/dist/flow-screen-6y5E_HT6.cjs.map +0 -1
  103. package/dist/lazy-relation-picker-dialog-BAKBRn3V.cjs.map +0 -1
  104. package/dist/lazy-relation-picker-dialog-DN4bvQfg.js.map +0 -1
  105. package/dist/page-flow-route-CtEfqAvU.js.map +0 -1
  106. package/dist/page-flow-route-DEjAxHe3.cjs.map +0 -1
  107. package/dist/place-node-BdxT-30h.js.map +0 -1
  108. package/dist/place-node-Bhl8B3fF.cjs.map +0 -1
  109. package/dist/related-list-timeline-DCrwN9oO.js.map +0 -1
  110. package/dist/related-list-timeline-k0DtnxTs.cjs.map +0 -1
  111. package/dist/relation-create-C43cdPQt.js.map +0 -1
  112. package/dist/relation-create-DDEYcKfw.cjs.map +0 -1
  113. package/dist/relation-many-picker-BlrGRwMV.js.map +0 -1
  114. package/dist/relation-many-picker-Br-zBHxT.cjs.map +0 -1
  115. package/dist/relation-picker-ADjxI_TI.cjs.map +0 -1
  116. package/dist/relation-picker-dialog-CyKliBkN.js.map +0 -1
  117. package/dist/relation-picker-dialog-DimVQF9Y.cjs.map +0 -1
  118. package/dist/relation-picker-x7P5HKie.js.map +0 -1
  119. package/dist/resource-page-router-BRpUnhay.js +0 -1958
  120. package/dist/resource-page-router-BRpUnhay.js.map +0 -1
  121. package/dist/resource-page-router-qEd2xb55.cjs +0 -2167
  122. package/dist/resource-page-router-qEd2xb55.cjs.map +0 -1
  123. package/dist/success-notices-Dl3M1fZP.cjs.map +0 -1
  124. package/dist/success-notices-LDEgEkc4.js.map +0 -1
  125. package/dist/use-record-subtitle-bfwIoUme.cjs.map +0 -1
  126. package/dist/use-record-subtitle-gIaCGgbI.js.map +0 -1
@@ -17,7 +17,7 @@ function linesByText(entries) {
17
17
  ids
18
18
  }));
19
19
  }
20
- function FlowBulkSummary({ resource, actionName, label, total, progress, texts }) {
20
+ function FlowBulkSummary({ resource, actionName, label, total, progress, texts, prefixes }) {
21
21
  const t = (0, _burojs_react.useOptionalT)();
22
22
  const caps = (0, _burojs_react.useI18nCaps)(resource);
23
23
  const forget = (0, _burojs_react_flows.useForgetEachAttempt)({
@@ -27,9 +27,10 @@ function FlowBulkSummary({ resource, actionName, label, total, progress, texts }
27
27
  const [forgotten, setForgotten] = (0, react.useState)(() => new Set());
28
28
  const forgetText = t("flow.forget", { defaultValue: "I've checked — forget it" });
29
29
  const testid = (0, _burojs_react.useTestIds)().bulkSummary(resource, actionName);
30
- const own = `resources.${resource}.actions.${actionName}.summary`;
30
+ const levels = prefixes ?? [`resources.${resource}.actions.${actionName}`];
31
31
  const count = progress.success.length;
32
- const heading = caps.has(own, { count }) ? caps.t(own, {
32
+ const own = levels.map((prefix) => `${prefix}.summary`).find((key) => caps.has(key, { count }));
33
+ const heading = own !== void 0 ? caps.t(own, {
33
34
  params: { total },
34
35
  count
35
36
  }) : `${label}: ${t("flow.bulkSummary", {
@@ -38,7 +39,8 @@ function FlowBulkSummary({ resource, actionName, label, total, progress, texts }
38
39
  count
39
40
  })} / ${total}`;
40
41
  const place = { action: {
41
- prefix: `resources.${resource}.actions.${actionName}`,
42
+ prefix: levels[0] ?? "",
43
+ prefixes: levels,
42
44
  texts
43
45
  } };
44
46
  const textCaps = {
@@ -66,8 +68,8 @@ function FlowBulkSummary({ resource, actionName, label, total, progress, texts }
66
68
  title,
67
69
  lines: [{ ids }]
68
70
  }));
69
- const ownGone = `resources.${resource}.actions.${actionName}.rereadGone`;
70
- const goneTitle = caps.has(ownGone) ? caps.t(ownGone) : (0, _burojs_core.declaredText)("flow", { texts }, "rereadGone") ?? t("flow.bulkGone", { defaultValue: "No longer available" });
71
+ const ownGone = levels.map((prefix) => `${prefix}.rereadGone`).find((key) => caps.has(key));
72
+ const goneTitle = ownGone !== void 0 ? caps.t(ownGone) : (0, _burojs_core.declaredText)("flow", { texts }, "rereadGone") ?? t("flow.bulkGone", { defaultValue: "No longer available" });
71
73
  const notApplied = [...progress.rejected.filter((entry) => entry.reason === "server").map((entry) => ({
72
74
  id: entry.id,
73
75
  text: textOf(entry.error, neutral)
@@ -166,4 +168,4 @@ function FlowBulkSummary({ resource, actionName, label, total, progress, texts }
166
168
  //#endregion
167
169
  exports.FlowBulkSummary = FlowBulkSummary;
168
170
 
169
- //# sourceMappingURL=bulk-summary-2HLgz7Il.cjs.map
171
+ //# sourceMappingURL=bulk-summary-Chc61Pyw.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bulk-summary-Chc61Pyw.cjs","names":["useOptionalT","useI18nCaps","useForgetEachAttempt","useState","useTestIds","specificErrorText","kindErrorText","declaredText","BULK_SUMMARY_IDS","Button"],"sources":["../src/flows/bulk-summary.tsx"],"sourcesContent":["'use client';\nimport { BULK_SUMMARY_IDS, type BulkProgress, type DataError, declaredText } from '@burojs/core';\nimport {\n type ErrorTextPlace,\n kindErrorText,\n specificErrorText,\n useI18nCaps,\n useOptionalT,\n useTestIds,\n} from '@burojs/react';\nimport { useForgetEachAttempt } from '@burojs/react/flows';\nimport { type ReactElement, useState } from 'react';\nimport { Button } from '../primitives/button.js';\n\nexport interface FlowBulkSummaryProps {\n readonly resource: string;\n readonly actionName: string;\n /** The action's label. */\n readonly label: string;\n /** How many ids the run was given. */\n readonly total: number;\n readonly progress: BulkProgress;\n /** The action's declared texts (`texts.validation`, `texts.rejected`): the resolver's action place. */\n readonly texts?: unknown;\n /**\n * The compiled flow's `textKeys.prefixes`, nearest first (a base member's, then its base's,\n * REF-131 §9.5); default `resources.<resource>.actions.<actionName>` alone.\n */\n readonly prefixes?: readonly string[];\n}\n\n/** One line of a group: the ids that read the same text; `text` absent for a group without lines. */\ninterface SummaryLine {\n readonly text?: string;\n readonly ids: readonly string[];\n}\n\ninterface SummaryGroup {\n readonly key: string;\n readonly title: string;\n readonly lines: readonly SummaryLine[];\n}\n\n/** The ids by their text, in the order each text first appears. */\nfunction linesByText(entries: readonly { readonly id: string; readonly text: string }[]) {\n const lines = new Map<string, string[]>();\n for (const { id, text } of entries) {\n const ids = lines.get(text);\n if (ids === undefined) lines.set(text, [id]);\n else ids.push(id);\n }\n return [...lines].map(([text, ids]): SummaryLine => ({ text, ids }));\n}\n\n/**\n * A bulk flow's summary (P4 spec 4.16, T1 spec 4.17): the count that succeeded of the ids given\n * (the flow's own `resources.<r>.actions.<name>.summary`, `{{count}}` of `{{total}}`, else the\n * framework's count text), then one group per other outcome with its count and up to\n * `BULK_SUMMARY_IDS` ids per line. The ids the server answered for are grouped first by\n * `applied` — not applied (refused or failed) and may have been applied (unknown) — and then by\n * the text each one's error resolves to (spec 4.15, with the action as the place), so\n * \"3 records: Already linked\" and \"2 records: Not allowed\" are separate lines. A row a check\n * rejected is grouped under that check's resolved text (`checks.<id>`), a row that was gone under\n * the flow's `texts.rereadGone` else \"No longer available\", and a row sent without a re-read\n * (`rereadSkipped` under `warn`, even when every row succeeded) under its own group (REF-135 §2.3).\n * Unresolved from an earlier run and not attempted keep their own groups.\n * Every text resolves at render, so a language switch re-renders it.\n */\nexport function FlowBulkSummary({\n resource,\n actionName,\n label,\n total,\n progress,\n texts,\n prefixes,\n}: FlowBulkSummaryProps): ReactElement {\n const t = useOptionalT();\n const caps = useI18nCaps(resource);\n // An id the run left unknown, or found unresolved, has its exit here (P4-C review I3): the user\n // checked the record, and the id's attempt is forgotten — the next run sends it again.\n const forget = useForgetEachAttempt({ resource, action: actionName });\n const [forgotten, setForgotten] = useState<ReadonlySet<string>>(() => new Set());\n const forgetText = t('flow.forget', { defaultValue: \"I've checked — forget it\" });\n const tid = useTestIds();\n const testid = tid.bulkSummary(resource, actionName);\n const levels = prefixes ?? [`resources.${resource}.actions.${actionName}`];\n const count = progress.success.length;\n const own = levels.map((prefix) => `${prefix}.summary`).find((key) => caps.has(key, { count }));\n const heading =\n own !== undefined\n ? caps.t(own, { params: { total }, count })\n : `${label}: ${t('flow.bulkSummary', { defaultValue: `${count} processed`, params: { total }, count })} / ${total}`;\n // A bulk flow is a resource's action: its texts live under `resources.<r>.actions.<name>`.\n const place: ErrorTextPlace = {\n action: { prefix: levels[0] ?? '', prefixes: levels, texts },\n };\n const textCaps = { has: (key: string) => caps.has(key), t: caps.t };\n // Steps 1 to 5 of spec 4.15; the fallback is the outcome's own sentence.\n const textOf = (error: DataError | undefined, fallback: () => string): string =>\n (error === undefined\n ? undefined\n : (specificErrorText(error, textCaps, place) ??\n kindErrorText(error.kind, textCaps, place))) ?? fallback();\n const neutral = () =>\n t('flow.rejected.validation', { defaultValue: 'Not accepted. Nothing was saved.' });\n const gone = progress.rejected.filter((entry) => entry.reason === 'gone');\n // One group per check, in the order each first appears, headed by the first entry's text. The machine resolved the\n // text (bundle entry, the check's declared `texts`, the framework's sentence); an entry without\n // it reads the check's `checks.<id>` bundle entry, else names the check.\n const byCheck = new Map<string, { check: string; title: string; ids: string[] }>();\n for (const entry of progress.rejected) {\n if (entry.reason !== 'check' || entry.check === undefined) continue;\n const own = `checks.${entry.check}`;\n const title = entry.message ?? (caps.has(own) ? caps.t(own) : entry.check);\n const group = byCheck.get(entry.check);\n if (group === undefined)\n byCheck.set(entry.check, { check: entry.check, title, ids: [entry.id] });\n else group.ids.push(entry.id);\n }\n const checkGroups = [...byCheck.values()].map(\n ({ check, title, ids }): SummaryGroup => ({ key: `check:${check}`, title, lines: [{ ids }] }),\n );\n const ownGone = levels.map((prefix) => `${prefix}.rereadGone`).find((key) => caps.has(key));\n const goneTitle =\n ownGone !== undefined\n ? caps.t(ownGone)\n : (declaredText('flow', { texts }, 'rereadGone') ??\n t('flow.bulkGone', { defaultValue: 'No longer available' }));\n const notApplied = [\n ...progress.rejected\n .filter((entry) => entry.reason === 'server')\n .map((entry) => ({ id: entry.id, text: textOf(entry.error, neutral) })),\n ...progress.failed.map((entry) => ({\n id: entry.id,\n text: textOf(entry.error, () =>\n entry.reason === 'reread'\n ? t('flow.couldNotReread', {\n defaultValue: \"Couldn't re-read the record. Nothing was sent.\",\n })\n : t('flow.failed', {\n defaultValue: 'The request could not be sent. Nothing was saved.',\n }),\n ),\n })),\n ];\n const unknown = progress.unknown\n .filter((entry) => !forgotten.has(entry.id))\n .map((entry) => ({\n id: entry.id,\n text: textOf(entry.error, () =>\n entry.error?.applied === 'partial'\n ? t('flow.unknownPartial', {\n defaultValue: 'Part of this may have been applied. Nothing was resent.',\n })\n : t('flow.unknown', { defaultValue: 'It may have been applied. Nothing was resent.' }),\n ),\n }));\n const groups: readonly SummaryGroup[] = [\n ...checkGroups,\n { key: 'gone', title: goneTitle, lines: [{ ids: gone.map((entry) => entry.id) }] },\n {\n key: 'reread-skipped',\n title: t('flow.bulkSentWithoutReread', { defaultValue: 'Sent without a current record' }),\n lines: [\n {\n ids: progress.rereadSkipped\n .filter((entry) => entry.policy === 'warn')\n .map((entry) => entry.id),\n },\n ],\n },\n {\n key: 'not-applied',\n title: t('flow.bulkNotApplied', { defaultValue: 'Not applied' }),\n lines: linesByText(notApplied),\n },\n {\n key: 'unknown',\n title: t('flow.bulkMayHaveBeenApplied', { defaultValue: 'May have been applied' }),\n lines: linesByText(unknown),\n },\n {\n key: 'unresolved',\n title: t('flow.bulkUnresolved', {\n defaultValue: 'Skipped: an earlier request for it may have been applied.',\n }),\n lines: [{ ids: progress.unresolved.filter((id) => !forgotten.has(id)) }],\n },\n {\n key: 'not-attempted',\n title: t('flow.bulkNotAttempted', { defaultValue: 'Not attempted.' }),\n lines: [{ ids: progress.notAttempted }],\n },\n ];\n const sizeOf = (group: SummaryGroup) =>\n group.lines.reduce((sum, line) => sum + line.ids.length, 0);\n return (\n <div data-testid={testid} className=\"flex flex-col gap-3 text-sm\">\n <p data-testid={`${testid}:heading`} className=\"font-medium\">\n {heading}\n </p>\n {groups\n .filter((group) => sizeOf(group) > 0)\n .map((group) => (\n <section key={group.key} data-testid={`${testid}:${group.key}`}>\n <h3 className=\"font-medium\">\n {group.title}{' '}\n <span data-testid={`${testid}:${group.key}:count`} className=\"tabular-nums\">\n ({sizeOf(group)})\n </span>\n </h3>\n {group.lines.map((line, index) => (\n <div\n key={line.text ?? index}\n data-testid={line.text === undefined ? undefined : `${testid}:${group.key}:line`}\n >\n {line.text === undefined ? null : (\n <p>\n {t('flow.bulkLine', {\n defaultValue: `${line.ids.length}: ${line.text}`,\n params: { message: line.text },\n count: line.ids.length,\n })}\n </p>\n )}\n <ul className=\"flex flex-wrap gap-1 text-muted-foreground\">\n {line.ids.slice(0, BULK_SUMMARY_IDS).map((id) => (\n <li\n key={id}\n data-testid={`${testid}:${group.key}:${id}`}\n className=\"flex items-center gap-1\"\n >\n {id}\n {group.key === 'unknown' || group.key === 'unresolved' ? (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-6 px-1.5 text-xs\"\n data-testid={`${testid}:forget:${id}`}\n onClick={() =>\n void forget(id).then(() =>\n setForgotten((previous) => new Set([...previous, id])),\n )\n }\n >\n {forgetText}\n </Button>\n ) : null}\n </li>\n ))}\n {line.ids.length > BULK_SUMMARY_IDS ? (\n <li>+{line.ids.length - BULK_SUMMARY_IDS}</li>\n ) : null}\n </ul>\n </div>\n ))}\n </section>\n ))}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -17,7 +17,7 @@ function linesByText(entries) {
17
17
  ids
18
18
  }));
19
19
  }
20
- function FlowBulkSummary({ resource, actionName, label, total, progress, texts }) {
20
+ function FlowBulkSummary({ resource, actionName, label, total, progress, texts, prefixes }) {
21
21
  const t = useOptionalT();
22
22
  const caps = useI18nCaps(resource);
23
23
  const forget = useForgetEachAttempt({
@@ -27,9 +27,10 @@ function FlowBulkSummary({ resource, actionName, label, total, progress, texts }
27
27
  const [forgotten, setForgotten] = useState(() => new Set());
28
28
  const forgetText = t("flow.forget", { defaultValue: "I've checked — forget it" });
29
29
  const testid = useTestIds().bulkSummary(resource, actionName);
30
- const own = `resources.${resource}.actions.${actionName}.summary`;
30
+ const levels = prefixes ?? [`resources.${resource}.actions.${actionName}`];
31
31
  const count = progress.success.length;
32
- const heading = caps.has(own, { count }) ? caps.t(own, {
32
+ const own = levels.map((prefix) => `${prefix}.summary`).find((key) => caps.has(key, { count }));
33
+ const heading = own !== void 0 ? caps.t(own, {
33
34
  params: { total },
34
35
  count
35
36
  }) : `${label}: ${t("flow.bulkSummary", {
@@ -38,7 +39,8 @@ function FlowBulkSummary({ resource, actionName, label, total, progress, texts }
38
39
  count
39
40
  })} / ${total}`;
40
41
  const place = { action: {
41
- prefix: `resources.${resource}.actions.${actionName}`,
42
+ prefix: levels[0] ?? "",
43
+ prefixes: levels,
42
44
  texts
43
45
  } };
44
46
  const textCaps = {
@@ -66,8 +68,8 @@ function FlowBulkSummary({ resource, actionName, label, total, progress, texts }
66
68
  title,
67
69
  lines: [{ ids }]
68
70
  }));
69
- const ownGone = `resources.${resource}.actions.${actionName}.rereadGone`;
70
- const goneTitle = caps.has(ownGone) ? caps.t(ownGone) : declaredText("flow", { texts }, "rereadGone") ?? t("flow.bulkGone", { defaultValue: "No longer available" });
71
+ const ownGone = levels.map((prefix) => `${prefix}.rereadGone`).find((key) => caps.has(key));
72
+ const goneTitle = ownGone !== void 0 ? caps.t(ownGone) : declaredText("flow", { texts }, "rereadGone") ?? t("flow.bulkGone", { defaultValue: "No longer available" });
71
73
  const notApplied = [...progress.rejected.filter((entry) => entry.reason === "server").map((entry) => ({
72
74
  id: entry.id,
73
75
  text: textOf(entry.error, neutral)
@@ -166,4 +168,4 @@ function FlowBulkSummary({ resource, actionName, label, total, progress, texts }
166
168
  //#endregion
167
169
  export { FlowBulkSummary };
168
170
 
169
- //# sourceMappingURL=bulk-summary-D6A0ua21.js.map
171
+ //# sourceMappingURL=bulk-summary-DpSQD2Fq.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bulk-summary-DpSQD2Fq.js","names":[],"sources":["../src/flows/bulk-summary.tsx"],"sourcesContent":["'use client';\nimport { BULK_SUMMARY_IDS, type BulkProgress, type DataError, declaredText } from '@burojs/core';\nimport {\n type ErrorTextPlace,\n kindErrorText,\n specificErrorText,\n useI18nCaps,\n useOptionalT,\n useTestIds,\n} from '@burojs/react';\nimport { useForgetEachAttempt } from '@burojs/react/flows';\nimport { type ReactElement, useState } from 'react';\nimport { Button } from '../primitives/button.js';\n\nexport interface FlowBulkSummaryProps {\n readonly resource: string;\n readonly actionName: string;\n /** The action's label. */\n readonly label: string;\n /** How many ids the run was given. */\n readonly total: number;\n readonly progress: BulkProgress;\n /** The action's declared texts (`texts.validation`, `texts.rejected`): the resolver's action place. */\n readonly texts?: unknown;\n /**\n * The compiled flow's `textKeys.prefixes`, nearest first (a base member's, then its base's,\n * REF-131 §9.5); default `resources.<resource>.actions.<actionName>` alone.\n */\n readonly prefixes?: readonly string[];\n}\n\n/** One line of a group: the ids that read the same text; `text` absent for a group without lines. */\ninterface SummaryLine {\n readonly text?: string;\n readonly ids: readonly string[];\n}\n\ninterface SummaryGroup {\n readonly key: string;\n readonly title: string;\n readonly lines: readonly SummaryLine[];\n}\n\n/** The ids by their text, in the order each text first appears. */\nfunction linesByText(entries: readonly { readonly id: string; readonly text: string }[]) {\n const lines = new Map<string, string[]>();\n for (const { id, text } of entries) {\n const ids = lines.get(text);\n if (ids === undefined) lines.set(text, [id]);\n else ids.push(id);\n }\n return [...lines].map(([text, ids]): SummaryLine => ({ text, ids }));\n}\n\n/**\n * A bulk flow's summary (P4 spec 4.16, T1 spec 4.17): the count that succeeded of the ids given\n * (the flow's own `resources.<r>.actions.<name>.summary`, `{{count}}` of `{{total}}`, else the\n * framework's count text), then one group per other outcome with its count and up to\n * `BULK_SUMMARY_IDS` ids per line. The ids the server answered for are grouped first by\n * `applied` — not applied (refused or failed) and may have been applied (unknown) — and then by\n * the text each one's error resolves to (spec 4.15, with the action as the place), so\n * \"3 records: Already linked\" and \"2 records: Not allowed\" are separate lines. A row a check\n * rejected is grouped under that check's resolved text (`checks.<id>`), a row that was gone under\n * the flow's `texts.rereadGone` else \"No longer available\", and a row sent without a re-read\n * (`rereadSkipped` under `warn`, even when every row succeeded) under its own group (REF-135 §2.3).\n * Unresolved from an earlier run and not attempted keep their own groups.\n * Every text resolves at render, so a language switch re-renders it.\n */\nexport function FlowBulkSummary({\n resource,\n actionName,\n label,\n total,\n progress,\n texts,\n prefixes,\n}: FlowBulkSummaryProps): ReactElement {\n const t = useOptionalT();\n const caps = useI18nCaps(resource);\n // An id the run left unknown, or found unresolved, has its exit here (P4-C review I3): the user\n // checked the record, and the id's attempt is forgotten — the next run sends it again.\n const forget = useForgetEachAttempt({ resource, action: actionName });\n const [forgotten, setForgotten] = useState<ReadonlySet<string>>(() => new Set());\n const forgetText = t('flow.forget', { defaultValue: \"I've checked — forget it\" });\n const tid = useTestIds();\n const testid = tid.bulkSummary(resource, actionName);\n const levels = prefixes ?? [`resources.${resource}.actions.${actionName}`];\n const count = progress.success.length;\n const own = levels.map((prefix) => `${prefix}.summary`).find((key) => caps.has(key, { count }));\n const heading =\n own !== undefined\n ? caps.t(own, { params: { total }, count })\n : `${label}: ${t('flow.bulkSummary', { defaultValue: `${count} processed`, params: { total }, count })} / ${total}`;\n // A bulk flow is a resource's action: its texts live under `resources.<r>.actions.<name>`.\n const place: ErrorTextPlace = {\n action: { prefix: levels[0] ?? '', prefixes: levels, texts },\n };\n const textCaps = { has: (key: string) => caps.has(key), t: caps.t };\n // Steps 1 to 5 of spec 4.15; the fallback is the outcome's own sentence.\n const textOf = (error: DataError | undefined, fallback: () => string): string =>\n (error === undefined\n ? undefined\n : (specificErrorText(error, textCaps, place) ??\n kindErrorText(error.kind, textCaps, place))) ?? fallback();\n const neutral = () =>\n t('flow.rejected.validation', { defaultValue: 'Not accepted. Nothing was saved.' });\n const gone = progress.rejected.filter((entry) => entry.reason === 'gone');\n // One group per check, in the order each first appears, headed by the first entry's text. The machine resolved the\n // text (bundle entry, the check's declared `texts`, the framework's sentence); an entry without\n // it reads the check's `checks.<id>` bundle entry, else names the check.\n const byCheck = new Map<string, { check: string; title: string; ids: string[] }>();\n for (const entry of progress.rejected) {\n if (entry.reason !== 'check' || entry.check === undefined) continue;\n const own = `checks.${entry.check}`;\n const title = entry.message ?? (caps.has(own) ? caps.t(own) : entry.check);\n const group = byCheck.get(entry.check);\n if (group === undefined)\n byCheck.set(entry.check, { check: entry.check, title, ids: [entry.id] });\n else group.ids.push(entry.id);\n }\n const checkGroups = [...byCheck.values()].map(\n ({ check, title, ids }): SummaryGroup => ({ key: `check:${check}`, title, lines: [{ ids }] }),\n );\n const ownGone = levels.map((prefix) => `${prefix}.rereadGone`).find((key) => caps.has(key));\n const goneTitle =\n ownGone !== undefined\n ? caps.t(ownGone)\n : (declaredText('flow', { texts }, 'rereadGone') ??\n t('flow.bulkGone', { defaultValue: 'No longer available' }));\n const notApplied = [\n ...progress.rejected\n .filter((entry) => entry.reason === 'server')\n .map((entry) => ({ id: entry.id, text: textOf(entry.error, neutral) })),\n ...progress.failed.map((entry) => ({\n id: entry.id,\n text: textOf(entry.error, () =>\n entry.reason === 'reread'\n ? t('flow.couldNotReread', {\n defaultValue: \"Couldn't re-read the record. Nothing was sent.\",\n })\n : t('flow.failed', {\n defaultValue: 'The request could not be sent. Nothing was saved.',\n }),\n ),\n })),\n ];\n const unknown = progress.unknown\n .filter((entry) => !forgotten.has(entry.id))\n .map((entry) => ({\n id: entry.id,\n text: textOf(entry.error, () =>\n entry.error?.applied === 'partial'\n ? t('flow.unknownPartial', {\n defaultValue: 'Part of this may have been applied. Nothing was resent.',\n })\n : t('flow.unknown', { defaultValue: 'It may have been applied. Nothing was resent.' }),\n ),\n }));\n const groups: readonly SummaryGroup[] = [\n ...checkGroups,\n { key: 'gone', title: goneTitle, lines: [{ ids: gone.map((entry) => entry.id) }] },\n {\n key: 'reread-skipped',\n title: t('flow.bulkSentWithoutReread', { defaultValue: 'Sent without a current record' }),\n lines: [\n {\n ids: progress.rereadSkipped\n .filter((entry) => entry.policy === 'warn')\n .map((entry) => entry.id),\n },\n ],\n },\n {\n key: 'not-applied',\n title: t('flow.bulkNotApplied', { defaultValue: 'Not applied' }),\n lines: linesByText(notApplied),\n },\n {\n key: 'unknown',\n title: t('flow.bulkMayHaveBeenApplied', { defaultValue: 'May have been applied' }),\n lines: linesByText(unknown),\n },\n {\n key: 'unresolved',\n title: t('flow.bulkUnresolved', {\n defaultValue: 'Skipped: an earlier request for it may have been applied.',\n }),\n lines: [{ ids: progress.unresolved.filter((id) => !forgotten.has(id)) }],\n },\n {\n key: 'not-attempted',\n title: t('flow.bulkNotAttempted', { defaultValue: 'Not attempted.' }),\n lines: [{ ids: progress.notAttempted }],\n },\n ];\n const sizeOf = (group: SummaryGroup) =>\n group.lines.reduce((sum, line) => sum + line.ids.length, 0);\n return (\n <div data-testid={testid} className=\"flex flex-col gap-3 text-sm\">\n <p data-testid={`${testid}:heading`} className=\"font-medium\">\n {heading}\n </p>\n {groups\n .filter((group) => sizeOf(group) > 0)\n .map((group) => (\n <section key={group.key} data-testid={`${testid}:${group.key}`}>\n <h3 className=\"font-medium\">\n {group.title}{' '}\n <span data-testid={`${testid}:${group.key}:count`} className=\"tabular-nums\">\n ({sizeOf(group)})\n </span>\n </h3>\n {group.lines.map((line, index) => (\n <div\n key={line.text ?? index}\n data-testid={line.text === undefined ? undefined : `${testid}:${group.key}:line`}\n >\n {line.text === undefined ? null : (\n <p>\n {t('flow.bulkLine', {\n defaultValue: `${line.ids.length}: ${line.text}`,\n params: { message: line.text },\n count: line.ids.length,\n })}\n </p>\n )}\n <ul className=\"flex flex-wrap gap-1 text-muted-foreground\">\n {line.ids.slice(0, BULK_SUMMARY_IDS).map((id) => (\n <li\n key={id}\n data-testid={`${testid}:${group.key}:${id}`}\n className=\"flex items-center gap-1\"\n >\n {id}\n {group.key === 'unknown' || group.key === 'unresolved' ? (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-6 px-1.5 text-xs\"\n data-testid={`${testid}:forget:${id}`}\n onClick={() =>\n void forget(id).then(() =>\n setForgotten((previous) => new Set([...previous, id])),\n )\n }\n >\n {forgetText}\n </Button>\n ) : null}\n </li>\n ))}\n {line.ids.length > BULK_SUMMARY_IDS ? (\n <li>+{line.ids.length - BULK_SUMMARY_IDS}</li>\n ) : null}\n </ul>\n </div>\n ))}\n </section>\n ))}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { n as useCandidateSelection } from "./lazy-relation-picker-dialog-DN4bvQfg.js";
2
- import { t as FieldRelationPicker } from "./relation-picker-x7P5HKie.js";
1
+ import { n as useCandidateSelection } from "./lazy-relation-picker-dialog-BaIEWLbF.js";
2
+ import { t as FieldRelationPicker } from "./relation-picker-CCyuMeGq.js";
3
3
  import { resourceKey } from "@burojs/core";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  //#region src/fields/candidates-relation-picker.tsx
@@ -28,4 +28,4 @@ function CandidatesRelationPicker(props) {
28
28
  //#endregion
29
29
  export { CandidatesRelationPicker };
30
30
 
31
- //# sourceMappingURL=candidates-relation-picker-CGXItMN0.js.map
31
+ //# sourceMappingURL=candidates-relation-picker-DRsHKe6N.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"candidates-relation-picker-CGXItMN0.js","names":[],"sources":["../src/fields/candidates-relation-picker.tsx"],"sourcesContent":["import { type RelationCandidate, type ResourceRefInput, resourceKey } from '@burojs/core';\nimport type * as React from 'react';\nimport { useCandidateSelection } from './candidates-gate.js';\nimport { FieldRelationPicker } from './relation-picker.js';\nimport type { FieldInputProps } from './registry.js';\n\n/** The select of a field that declares `candidates`: the gate and the filters it resolves. */\nexport function CandidatesRelationPicker(props: FieldInputProps): React.ReactElement {\n const { name, field, metaSources, resource, fixedFilters } = props;\n const meta = field?.meta as { to?: ResourceRefInput; candidates?: unknown };\n const to = resourceKey(meta.to as ResourceRefInput);\n const selection = useCandidateSelection({\n to,\n candidates: meta.candidates as readonly RelationCandidate[],\n sources: metaSources,\n resource: resource ?? '',\n fieldName: field?.name ?? name,\n fixedFilters,\n });\n return (\n <FieldRelationPicker\n props={props}\n to={to}\n extra={{\n fixedFilters: selection.fixedFilters,\n ...(selection.gate === undefined ? {} : { candidatesGate: selection.gate }),\n ...(selection.rowFits === undefined ? {} : { rowFits: selection.rowFits }),\n }}\n />\n );\n}\n"],"mappings":";;;;;AAOA,SAAgB,yBAAyB,OAA4C;CACnF,MAAM,EAAE,MAAM,OAAO,aAAa,UAAU,iBAAiB;CAC7D,MAAM,OAAO,OAAO;CACpB,MAAM,KAAK,YAAY,KAAK,EAAsB;CAClD,MAAM,YAAY,sBAAsB;EACtC;EACA,YAAY,KAAK;EACjB,SAAS;EACT,UAAU,YAAY;EACtB,WAAW,OAAO,QAAQ;EAC1B;CACF,CAAC;CACD,OACE,IAAC,qBAAD;EACS;EACH;EACJ,OAAO;GACL,cAAc,UAAU;GACxB,GAAI,UAAU,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,gBAAgB,UAAU,KAAK;GACzE,GAAI,UAAU,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,UAAU,QAAQ;EAC1E;CACD,CAAA;AAEL"}
1
+ {"version":3,"file":"candidates-relation-picker-DRsHKe6N.js","names":[],"sources":["../src/fields/candidates-relation-picker.tsx"],"sourcesContent":["import { type RelationCandidate, type ResourceRefInput, resourceKey } from '@burojs/core';\nimport type * as React from 'react';\nimport { useCandidateSelection } from './candidates-gate.js';\nimport { FieldRelationPicker } from './relation-picker.js';\nimport type { FieldInputProps } from './registry.js';\n\n/** The select of a field that declares `candidates`: the gate and the filters it resolves. */\nexport function CandidatesRelationPicker(props: FieldInputProps): React.ReactElement {\n const { name, field, metaSources, resource, fixedFilters } = props;\n const meta = field?.meta as { to?: ResourceRefInput; candidates?: unknown };\n const to = resourceKey(meta.to as ResourceRefInput);\n const selection = useCandidateSelection({\n to,\n candidates: meta.candidates as readonly RelationCandidate[],\n sources: metaSources,\n resource: resource ?? '',\n fieldName: field?.name ?? name,\n fixedFilters,\n });\n return (\n <FieldRelationPicker\n props={props}\n to={to}\n extra={{\n fixedFilters: selection.fixedFilters,\n ...(selection.gate === undefined ? {} : { candidatesGate: selection.gate }),\n ...(selection.rowFits === undefined ? {} : { rowFits: selection.rowFits }),\n }}\n />\n );\n}\n"],"mappings":";;;;;AAOA,SAAgB,yBAAyB,OAA4C;CACnF,MAAM,EAAE,MAAM,OAAO,aAAa,UAAU,iBAAiB;CAC7D,MAAM,OAAO,OAAO;CACpB,MAAM,KAAK,YAAY,KAAK,EAAsB;CAClD,MAAM,YAAY,sBAAsB;EACtC;EACA,YAAY,KAAK;EACjB,SAAS;EACT,UAAU,YAAY;EACtB,WAAW,OAAO,QAAQ;EAC1B;CACF,CAAC;CACD,OACE,IAAC,qBAAD;EACS;EACH;EACJ,OAAO;GACL,cAAc,UAAU;GACxB,GAAI,UAAU,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,gBAAgB,UAAU,KAAK;GACzE,GAAI,UAAU,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,UAAU,QAAQ;EAC1E;CACD,CAAA;AAEL"}
@@ -1,5 +1,5 @@
1
- const require_lazy_relation_picker_dialog = require("./lazy-relation-picker-dialog-BAKBRn3V.cjs");
2
- const require_relation_picker = require("./relation-picker-ADjxI_TI.cjs");
1
+ const require_lazy_relation_picker_dialog = require("./lazy-relation-picker-dialog-CeRzOAi0.cjs");
2
+ const require_relation_picker = require("./relation-picker-DmwTzgsd.cjs");
3
3
  let _burojs_core = require("@burojs/core");
4
4
  let react_jsx_runtime = require("react/jsx-runtime");
5
5
  //#region src/fields/candidates-relation-picker.tsx
@@ -28,4 +28,4 @@ function CandidatesRelationPicker(props) {
28
28
  //#endregion
29
29
  exports.CandidatesRelationPicker = CandidatesRelationPicker;
30
30
 
31
- //# sourceMappingURL=candidates-relation-picker-C47mF260.cjs.map
31
+ //# sourceMappingURL=candidates-relation-picker-GIxsp7D_.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"candidates-relation-picker-C47mF260.cjs","names":["resourceKey","useCandidateSelection","FieldRelationPicker"],"sources":["../src/fields/candidates-relation-picker.tsx"],"sourcesContent":["import { type RelationCandidate, type ResourceRefInput, resourceKey } from '@burojs/core';\nimport type * as React from 'react';\nimport { useCandidateSelection } from './candidates-gate.js';\nimport { FieldRelationPicker } from './relation-picker.js';\nimport type { FieldInputProps } from './registry.js';\n\n/** The select of a field that declares `candidates`: the gate and the filters it resolves. */\nexport function CandidatesRelationPicker(props: FieldInputProps): React.ReactElement {\n const { name, field, metaSources, resource, fixedFilters } = props;\n const meta = field?.meta as { to?: ResourceRefInput; candidates?: unknown };\n const to = resourceKey(meta.to as ResourceRefInput);\n const selection = useCandidateSelection({\n to,\n candidates: meta.candidates as readonly RelationCandidate[],\n sources: metaSources,\n resource: resource ?? '',\n fieldName: field?.name ?? name,\n fixedFilters,\n });\n return (\n <FieldRelationPicker\n props={props}\n to={to}\n extra={{\n fixedFilters: selection.fixedFilters,\n ...(selection.gate === undefined ? {} : { candidatesGate: selection.gate }),\n ...(selection.rowFits === undefined ? {} : { rowFits: selection.rowFits }),\n }}\n />\n );\n}\n"],"mappings":";;;;;AAOA,SAAgB,yBAAyB,OAA4C;CACnF,MAAM,EAAE,MAAM,OAAO,aAAa,UAAU,iBAAiB;CAC7D,MAAM,OAAO,OAAO;CACpB,MAAM,MAAA,GAAKA,aAAAA,YAAAA,CAAY,KAAK,EAAsB;CAClD,MAAM,YAAYC,oCAAAA,sBAAsB;EACtC;EACA,YAAY,KAAK;EACjB,SAAS;EACT,UAAU,YAAY;EACtB,WAAW,OAAO,QAAQ;EAC1B;CACF,CAAC;CACD,QACE,GAAA,kBAAA,IAAA,CAACC,wBAAAA,qBAAD;EACS;EACH;EACJ,OAAO;GACL,cAAc,UAAU;GACxB,GAAI,UAAU,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,gBAAgB,UAAU,KAAK;GACzE,GAAI,UAAU,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,UAAU,QAAQ;EAC1E;CACD,CAAA;AAEL"}
1
+ {"version":3,"file":"candidates-relation-picker-GIxsp7D_.cjs","names":["resourceKey","useCandidateSelection","FieldRelationPicker"],"sources":["../src/fields/candidates-relation-picker.tsx"],"sourcesContent":["import { type RelationCandidate, type ResourceRefInput, resourceKey } from '@burojs/core';\nimport type * as React from 'react';\nimport { useCandidateSelection } from './candidates-gate.js';\nimport { FieldRelationPicker } from './relation-picker.js';\nimport type { FieldInputProps } from './registry.js';\n\n/** The select of a field that declares `candidates`: the gate and the filters it resolves. */\nexport function CandidatesRelationPicker(props: FieldInputProps): React.ReactElement {\n const { name, field, metaSources, resource, fixedFilters } = props;\n const meta = field?.meta as { to?: ResourceRefInput; candidates?: unknown };\n const to = resourceKey(meta.to as ResourceRefInput);\n const selection = useCandidateSelection({\n to,\n candidates: meta.candidates as readonly RelationCandidate[],\n sources: metaSources,\n resource: resource ?? '',\n fieldName: field?.name ?? name,\n fixedFilters,\n });\n return (\n <FieldRelationPicker\n props={props}\n to={to}\n extra={{\n fixedFilters: selection.fixedFilters,\n ...(selection.gate === undefined ? {} : { candidatesGate: selection.gate }),\n ...(selection.rowFits === undefined ? {} : { rowFits: selection.rowFits }),\n }}\n />\n );\n}\n"],"mappings":";;;;;AAOA,SAAgB,yBAAyB,OAA4C;CACnF,MAAM,EAAE,MAAM,OAAO,aAAa,UAAU,iBAAiB;CAC7D,MAAM,OAAO,OAAO;CACpB,MAAM,MAAA,GAAKA,aAAAA,YAAAA,CAAY,KAAK,EAAsB;CAClD,MAAM,YAAYC,oCAAAA,sBAAsB;EACtC;EACA,YAAY,KAAK;EACjB,SAAS;EACT,UAAU,YAAY;EACtB,WAAW,OAAO,QAAQ;EAC1B;CACF,CAAC;CACD,QACE,GAAA,kBAAA,IAAA,CAACC,wBAAAA,qBAAD;EACS;EACH;EACJ,OAAO;GACL,cAAc,UAAU;GACxB,GAAI,UAAU,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,gBAAgB,UAAU,KAAK;GACzE,GAAI,UAAU,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,UAAU,QAAQ;EAC1E;CACD,CAAA;AAEL"}
@@ -492,11 +492,11 @@ function retrying(importer) {
492
492
  return loading;
493
493
  };
494
494
  }
495
- const loadFlowRuntime = retrying(() => Promise.resolve().then(() => require("./flow-runtime-BVFjMU5-.cjs")));
496
- const loadFlowScreen = retrying(() => Promise.resolve().then(() => require("./flow-screen-6y5E_HT6.cjs")));
497
- const loadPageFlowRoute = retrying(() => Promise.resolve().then(() => require("./page-flow-route-DEjAxHe3.cjs")));
498
- const loadInlineFlowHost = retrying(() => Promise.resolve().then(() => require("./inline-flow-host-C4KmZIYE.cjs")));
499
- const loadBulkSummary = retrying(() => Promise.resolve().then(() => require("./bulk-summary-2HLgz7Il.cjs")));
495
+ const loadFlowRuntime = retrying(() => Promise.resolve().then(() => require("./flow-runtime-CQ4wf8co.cjs")));
496
+ const loadFlowScreen = retrying(() => Promise.resolve().then(() => require("./flow-screen-sw2cP70t.cjs")));
497
+ const loadPageFlowRoute = retrying(() => Promise.resolve().then(() => require("./page-flow-route-UDx8qvdM.cjs")));
498
+ const loadInlineFlowHost = retrying(() => Promise.resolve().then(() => require("./inline-flow-host-CkhoA69R.cjs")));
499
+ const loadBulkSummary = retrying(() => Promise.resolve().then(() => require("./bulk-summary-Chc61Pyw.cjs")));
500
500
  function preloadFlowRuntime() {
501
501
  loadFlowRuntime().catch(() => void 0);
502
502
  }
@@ -694,14 +694,22 @@ function declaredFlow(app, resource, actionName) {
694
694
  return;
695
695
  }
696
696
  }
697
+ function resourceChain(app, resource) {
698
+ try {
699
+ const def = app.registry.get(resource);
700
+ return def === void 0 ? [resource] : [resource, ...(0, _burojs_core.textChainOf)(def).slice(1)];
701
+ } catch {
702
+ return [resource];
703
+ }
704
+ }
697
705
  function useFlowDialogTexts(resource, actionName, labelText) {
698
706
  const app = (0, _burojs_react.useApp)();
699
707
  const caps = (0, _burojs_react.useI18nCaps)("");
700
708
  const texts = declaredFlow(app, resource, actionName)?.texts;
701
- const prefix = resource === "" ? `appActions.${actionName}` : `resources.${resource}.actions.${actionName}`;
709
+ const prefixes = resource === "" ? [`appActions.${actionName}`] : resourceChain(app, resource).map((name) => `resources.${name}.actions.${actionName}`);
702
710
  const own = (path) => {
703
- const key = `${prefix}.${path.join(".")}`;
704
- return caps.has(key) ? caps.t(key) : (0, _burojs_core.textsValueAt)(texts, path);
711
+ const key = prefixes.map((prefix) => `${prefix}.${path.join(".")}`).find((key) => caps.has(key));
712
+ return key !== void 0 ? caps.t(key) : (0, _burojs_core.textsValueAt)(texts, path);
705
713
  };
706
714
  return {
707
715
  confirmTitle: own(["confirm", "title"]) ?? labelText,
@@ -1081,6 +1089,35 @@ function DisabledAction({ reason, label, icon, testid, size, variant, className,
1081
1089
  children: chrome.content
1082
1090
  }), label, chrome.compact, text);
1083
1091
  }
1092
+ function UndecidedAction({ label, icon, testid, size, variant, className, asMenuItem, density = "regular", actionName, surface }) {
1093
+ if (asMenuItem) return (0, react_jsx_runtime.jsx)(DropdownMenuItem, {
1094
+ "data-testid": testid,
1095
+ disabled: true,
1096
+ "aria-busy": "true",
1097
+ children: (0, react_jsx_runtime.jsx)(ActionInner, {
1098
+ icon,
1099
+ label
1100
+ })
1101
+ });
1102
+ const chrome = resolveControlChrome({
1103
+ density,
1104
+ icon,
1105
+ label,
1106
+ actionName: actionName ?? testid ?? "",
1107
+ surface: surface ?? "unknown"
1108
+ });
1109
+ return withActionTooltip((0, react_jsx_runtime.jsx)(require_button.Button, {
1110
+ type: "button",
1111
+ size: size ?? chrome.size,
1112
+ variant: variant ?? "outline",
1113
+ className: require_use_theme.cn(chrome.className, className),
1114
+ "data-testid": testid,
1115
+ disabled: true,
1116
+ "aria-busy": "true",
1117
+ "aria-label": chrome.ariaLabel,
1118
+ children: chrome.content
1119
+ }), label, chrome.compact);
1120
+ }
1084
1121
  const DESTRUCTIVE_ITEM = "text-destructive focus:bg-destructive/10 focus:text-destructive data-[highlighted]:text-destructive";
1085
1122
  const DEFAULT_ACTION_ICONS = {
1086
1123
  create: "Plus",
@@ -1238,6 +1275,18 @@ function LinkActionButton({ resource, actionName, record, scope = "row", variant
1238
1275
  const Anchor = target === "_blank" || isExternalHref(href) ? "a" : RouterLink;
1239
1276
  const anchorHref = target === "_blank" ? toBrowser(href) : href;
1240
1277
  if (editRoute.kind === "none") return null;
1278
+ if (availability.state === "undecided") return (0, react_jsx_runtime.jsx)(UndecidedAction, {
1279
+ label,
1280
+ icon: resolveActionIcon(action, actionName),
1281
+ testid,
1282
+ size,
1283
+ variant: buttonVariant,
1284
+ className,
1285
+ asMenuItem,
1286
+ density,
1287
+ actionName,
1288
+ surface: scope
1289
+ });
1241
1290
  if (availability.state === "disabled") return (0, react_jsx_runtime.jsx)(DisabledAction, {
1242
1291
  reason: availability.reason,
1243
1292
  label,
@@ -1330,6 +1379,18 @@ function ModalActionButton({ resource, actionName, record, scope = "row", varian
1330
1379
  const recordId = String((0, _burojs_react.recordKeyOf)(app.registry.get(resource), record) ?? "");
1331
1380
  const testid = makeTestId(scope, resource, actionName, recordId, tid);
1332
1381
  const label = useResolvedLabel(action, actionName, children, resource);
1382
+ if (availability.state === "undecided") return (0, react_jsx_runtime.jsx)(UndecidedAction, {
1383
+ label,
1384
+ icon: resolveActionIcon(action, actionName),
1385
+ testid,
1386
+ size,
1387
+ variant: buttonVariant,
1388
+ className,
1389
+ asMenuItem,
1390
+ density,
1391
+ actionName,
1392
+ surface: scope
1393
+ });
1333
1394
  if (availability.state === "disabled") return (0, react_jsx_runtime.jsx)(DisabledAction, {
1334
1395
  reason: availability.reason,
1335
1396
  label,
@@ -1791,6 +1852,12 @@ Object.defineProperty(exports, "TooltipTrigger", {
1791
1852
  return TooltipTrigger;
1792
1853
  }
1793
1854
  });
1855
+ Object.defineProperty(exports, "UndecidedAction", {
1856
+ enumerable: true,
1857
+ get: function() {
1858
+ return UndecidedAction;
1859
+ }
1860
+ });
1794
1861
  Object.defineProperty(exports, "canonicalResourceName", {
1795
1862
  enumerable: true,
1796
1863
  get: function() {
@@ -1912,4 +1979,4 @@ Object.defineProperty(exports, "useToBrowserHref", {
1912
1979
  }
1913
1980
  });
1914
1981
 
1915
- //# sourceMappingURL=check-confirm-dialog-BT04Mieo.cjs.map
1982
+ //# sourceMappingURL=check-confirm-dialog-BMSb7wFv.cjs.map