@burojs/ui-shadcn 0.7.0 → 0.9.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 (122) hide show
  1. package/dist/{bulk-summary-CrEij5vq.cjs → bulk-summary-2HLgz7Il.cjs} +31 -5
  2. package/dist/bulk-summary-2HLgz7Il.cjs.map +1 -0
  3. package/dist/{bulk-summary-BWSAS7k2.js → bulk-summary-D6A0ua21.js} +32 -6
  4. package/dist/bulk-summary-D6A0ua21.js.map +1 -0
  5. package/dist/{candidates-relation-picker-CS_JZ4Fd.js → candidates-relation-picker-QvoY2bOQ.js} +3 -3
  6. package/dist/{candidates-relation-picker-CS_JZ4Fd.js.map → candidates-relation-picker-QvoY2bOQ.js.map} +1 -1
  7. package/dist/{candidates-relation-picker-y5M6_oe4.cjs → candidates-relation-picker-pEAWKQEY.cjs} +3 -3
  8. package/dist/{candidates-relation-picker-y5M6_oe4.cjs.map → candidates-relation-picker-pEAWKQEY.cjs.map} +1 -1
  9. package/dist/{check-confirm-dialog-2j0gOd7x.js → check-confirm-dialog-B-CbJTln.js} +68 -8
  10. package/dist/{check-confirm-dialog-2j0gOd7x.js.map → check-confirm-dialog-B-CbJTln.js.map} +1 -1
  11. package/dist/{check-confirm-dialog-C-NHgMST.cjs → check-confirm-dialog-W-8WOmGh.cjs} +72 -6
  12. package/dist/check-confirm-dialog-W-8WOmGh.cjs.map +1 -0
  13. package/dist/{filter-builder-DaWHUZuV.js → filter-builder-04nas3eq.js} +127 -61
  14. package/dist/filter-builder-04nas3eq.js.map +1 -0
  15. package/dist/{filter-builder-DFu0JP-1.cjs → filter-builder-DQX-TMFh.cjs} +140 -68
  16. package/dist/filter-builder-DQX-TMFh.cjs.map +1 -0
  17. package/dist/{flow-runtime-DyqTmK3H.js → flow-runtime-BEIyym7d.js} +7 -4
  18. package/dist/{flow-runtime-DyqTmK3H.js.map → flow-runtime-BEIyym7d.js.map} +1 -1
  19. package/dist/{flow-runtime-BpmrIUb6.cjs → flow-runtime-DyNIYfUP.cjs} +7 -4
  20. package/dist/{flow-runtime-BpmrIUb6.cjs.map → flow-runtime-DyNIYfUP.cjs.map} +1 -1
  21. package/dist/{flow-screen-DCdli6Ha.js → flow-screen-DY1Z9PbG.js} +56 -15
  22. package/dist/flow-screen-DY1Z9PbG.js.map +1 -0
  23. package/dist/{flow-screen-Bcz9NF2V.cjs → flow-screen-FE5Xhb3t.cjs} +54 -13
  24. package/dist/flow-screen-FE5Xhb3t.cjs.map +1 -0
  25. package/dist/index.cjs +564 -170
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +235 -95
  28. package/dist/index.d.ts +235 -95
  29. package/dist/index.js +562 -169
  30. package/dist/index.js.map +1 -1
  31. package/dist/{inline-flow-host-C0rI9B7f.js → inline-flow-host-D6u-RlsV.js} +3 -3
  32. package/dist/{inline-flow-host-C0rI9B7f.js.map → inline-flow-host-D6u-RlsV.js.map} +1 -1
  33. package/dist/{inline-flow-host-3vw7LzzD.cjs → inline-flow-host-yVLo6-sM.cjs} +3 -3
  34. package/dist/{inline-flow-host-3vw7LzzD.cjs.map → inline-flow-host-yVLo6-sM.cjs.map} +1 -1
  35. package/dist/{lazy-relation-picker-dialog-CAScLPb2.js → lazy-relation-picker-dialog-BaORufxQ.js} +2 -2
  36. package/dist/{lazy-relation-picker-dialog-CAScLPb2.js.map → lazy-relation-picker-dialog-BaORufxQ.js.map} +1 -1
  37. package/dist/{lazy-relation-picker-dialog-Bt8lrEIu.cjs → lazy-relation-picker-dialog-C_VlGlDz.cjs} +2 -2
  38. package/dist/{lazy-relation-picker-dialog-Bt8lrEIu.cjs.map → lazy-relation-picker-dialog-C_VlGlDz.cjs.map} +1 -1
  39. package/dist/{page-flow-route-BHUEpn0I.js → page-flow-route-CyMzUidK.js} +8 -9
  40. package/dist/page-flow-route-CyMzUidK.js.map +1 -0
  41. package/dist/{page-flow-route-DS8IVTVH.cjs → page-flow-route-OFx7h7Ja.cjs} +8 -9
  42. package/dist/page-flow-route-OFx7h7Ja.cjs.map +1 -0
  43. package/dist/{place-node-CNb3w-c7.cjs → place-node-BZF5Af6x.cjs} +224 -151
  44. package/dist/place-node-BZF5Af6x.cjs.map +1 -0
  45. package/dist/{place-node-CfzQvh4Y.js → place-node-DRjmJGQ_.js} +210 -125
  46. package/dist/place-node-DRjmJGQ_.js.map +1 -0
  47. package/dist/{related-list-cards-BIqqY69Y.js → related-list-cards-2hLitVkg.js} +3 -3
  48. package/dist/{related-list-cards-BIqqY69Y.js.map → related-list-cards-2hLitVkg.js.map} +1 -1
  49. package/dist/{related-list-cards-CelMxl4q.cjs → related-list-cards-xVvgSlu-.cjs} +3 -3
  50. package/dist/{related-list-cards-CelMxl4q.cjs.map → related-list-cards-xVvgSlu-.cjs.map} +1 -1
  51. package/dist/related-list-timeline-CxJqe6eK.js +167 -0
  52. package/dist/related-list-timeline-CxJqe6eK.js.map +1 -0
  53. package/dist/related-list-timeline-Dsf5WewG.cjs +167 -0
  54. package/dist/related-list-timeline-Dsf5WewG.cjs.map +1 -0
  55. package/dist/{related-rows-MPnLCmPF.cjs → related-rows-DDhp9axl.cjs} +4 -4
  56. package/dist/{related-rows-MPnLCmPF.cjs.map → related-rows-DDhp9axl.cjs.map} +1 -1
  57. package/dist/{related-rows--uP2iKQC.js → related-rows-DL6CWsrj.js} +4 -4
  58. package/dist/{related-rows--uP2iKQC.js.map → related-rows-DL6CWsrj.js.map} +1 -1
  59. package/dist/{relation-create-C43cdPQt.js → relation-create-6WicROWA.js} +33 -5
  60. package/dist/relation-create-6WicROWA.js.map +1 -0
  61. package/dist/{relation-create-DDEYcKfw.cjs → relation-create-_SFuPQGM.cjs} +37 -3
  62. package/dist/relation-create-_SFuPQGM.cjs.map +1 -0
  63. package/dist/{relation-many-picker-DzuGJpEl.cjs → relation-many-picker-BBNsmkaX.cjs} +18 -11
  64. package/dist/relation-many-picker-BBNsmkaX.cjs.map +1 -0
  65. package/dist/{relation-many-picker-BJhaEqxz.js → relation-many-picker-mGEQDWo2.js} +18 -11
  66. package/dist/relation-many-picker-mGEQDWo2.js.map +1 -0
  67. package/dist/{relation-picker-D-tBBZW_.js → relation-picker-BbO41cFV.js} +19 -11
  68. package/dist/relation-picker-BbO41cFV.js.map +1 -0
  69. package/dist/{relation-picker-dialog-DoEY8EkH.js → relation-picker-dialog-BgSG_8bU.js} +5 -5
  70. package/dist/relation-picker-dialog-BgSG_8bU.js.map +1 -0
  71. package/dist/{relation-picker-dialog-9Vg5vvR1.cjs → relation-picker-dialog-Duqy2r0n.cjs} +5 -5
  72. package/dist/relation-picker-dialog-Duqy2r0n.cjs.map +1 -0
  73. package/dist/{relation-picker-DaIMzf2H.cjs → relation-picker-jk9D_uwn.cjs} +19 -11
  74. package/dist/relation-picker-jk9D_uwn.cjs.map +1 -0
  75. package/dist/{relation-select-Cr3CfNLy.cjs → relation-select-C3aV18kT.cjs} +2 -2
  76. package/dist/{relation-select-Cr3CfNLy.cjs.map → relation-select-C3aV18kT.cjs.map} +1 -1
  77. package/dist/{relation-select-B8Fq4o-t.js → relation-select-CjQT9LpS.js} +2 -2
  78. package/dist/{relation-select-B8Fq4o-t.js.map → relation-select-CjQT9LpS.js.map} +1 -1
  79. package/dist/{resource-page-router-Diw6S6TK.js → resource-page-router-CzaNATSp.js} +209 -30
  80. package/dist/resource-page-router-CzaNATSp.js.map +1 -0
  81. package/dist/{resource-page-router-C_kGW2o_.cjs → resource-page-router-dmVIeu5s.cjs} +235 -32
  82. package/dist/resource-page-router-dmVIeu5s.cjs.map +1 -0
  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-B_MqzHaT.js → use-dialog-filter-state-CJoeY-1j.js} +2 -2
  88. package/dist/{use-dialog-filter-state-B_MqzHaT.js.map → use-dialog-filter-state-CJoeY-1j.js.map} +1 -1
  89. package/dist/{use-dialog-filter-state-tNvqAAjh.cjs → use-dialog-filter-state-lsTJxrB4.cjs} +2 -2
  90. package/dist/{use-dialog-filter-state-tNvqAAjh.cjs.map → use-dialog-filter-state-lsTJxrB4.cjs.map} +1 -1
  91. package/dist/use-record-subtitle-BJ9rnj6F.cjs +67 -0
  92. package/dist/use-record-subtitle-BJ9rnj6F.cjs.map +1 -0
  93. package/dist/use-record-subtitle-w3ZhXNlf.js +50 -0
  94. package/dist/use-record-subtitle-w3ZhXNlf.js.map +1 -0
  95. package/package.json +9 -9
  96. package/dist/bulk-summary-BWSAS7k2.js.map +0 -1
  97. package/dist/bulk-summary-CrEij5vq.cjs.map +0 -1
  98. package/dist/check-confirm-dialog-C-NHgMST.cjs.map +0 -1
  99. package/dist/filter-builder-DFu0JP-1.cjs.map +0 -1
  100. package/dist/filter-builder-DaWHUZuV.js.map +0 -1
  101. package/dist/flow-screen-Bcz9NF2V.cjs.map +0 -1
  102. package/dist/flow-screen-DCdli6Ha.js.map +0 -1
  103. package/dist/page-flow-route-BHUEpn0I.js.map +0 -1
  104. package/dist/page-flow-route-DS8IVTVH.cjs.map +0 -1
  105. package/dist/place-node-CNb3w-c7.cjs.map +0 -1
  106. package/dist/place-node-CfzQvh4Y.js.map +0 -1
  107. package/dist/related-list-timeline-CRh7xwLD.js +0 -141
  108. package/dist/related-list-timeline-CRh7xwLD.js.map +0 -1
  109. package/dist/related-list-timeline-DsLdi8sv.cjs +0 -141
  110. package/dist/related-list-timeline-DsLdi8sv.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-BJhaEqxz.js.map +0 -1
  114. package/dist/relation-many-picker-DzuGJpEl.cjs.map +0 -1
  115. package/dist/relation-picker-D-tBBZW_.js.map +0 -1
  116. package/dist/relation-picker-DaIMzf2H.cjs.map +0 -1
  117. package/dist/relation-picker-dialog-9Vg5vvR1.cjs.map +0 -1
  118. package/dist/relation-picker-dialog-DoEY8EkH.js.map +0 -1
  119. package/dist/resource-page-router-C_kGW2o_.cjs.map +0 -1
  120. package/dist/resource-page-router-Diw6S6TK.js.map +0 -1
  121. package/dist/success-notices-Dl3M1fZP.cjs.map +0 -1
  122. package/dist/success-notices-LDEgEkc4.js.map +0 -1
@@ -47,7 +47,27 @@ function FlowBulkSummary({ resource, actionName, label, total, progress, texts }
47
47
  };
48
48
  const textOf = (error, fallback) => (error === void 0 ? void 0 : (0, _burojs_react.specificErrorText)(error, textCaps, place) ?? (0, _burojs_react.kindErrorText)(error.kind, textCaps, place)) ?? fallback();
49
49
  const neutral = () => t("flow.rejected.validation", { defaultValue: "Not accepted. Nothing was saved." });
50
- const notProcessed = progress.rejected.filter((entry) => entry.reason !== "server");
50
+ const gone = progress.rejected.filter((entry) => entry.reason === "gone");
51
+ const byCheck = new Map();
52
+ for (const entry of progress.rejected) {
53
+ if (entry.reason !== "check" || entry.check === void 0) continue;
54
+ const own = `checks.${entry.check}`;
55
+ const title = entry.message ?? (caps.has(own) ? caps.t(own) : entry.check);
56
+ const group = byCheck.get(entry.check);
57
+ if (group === void 0) byCheck.set(entry.check, {
58
+ check: entry.check,
59
+ title,
60
+ ids: [entry.id]
61
+ });
62
+ else group.ids.push(entry.id);
63
+ }
64
+ const checkGroups = [...byCheck.values()].map(({ check, title, ids }) => ({
65
+ key: `check:${check}`,
66
+ title,
67
+ lines: [{ ids }]
68
+ }));
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" });
51
71
  const notApplied = [...progress.rejected.filter((entry) => entry.reason === "server").map((entry) => ({
52
72
  id: entry.id,
53
73
  text: textOf(entry.error, neutral)
@@ -60,10 +80,16 @@ function FlowBulkSummary({ resource, actionName, label, total, progress, texts }
60
80
  text: textOf(entry.error, () => entry.error?.applied === "partial" ? t("flow.unknownPartial", { defaultValue: "Part of this may have been applied. Nothing was resent." }) : t("flow.unknown", { defaultValue: "It may have been applied. Nothing was resent." }))
61
81
  }));
62
82
  const groups = [
83
+ ...checkGroups,
84
+ {
85
+ key: "gone",
86
+ title: goneTitle,
87
+ lines: [{ ids: gone.map((entry) => entry.id) }]
88
+ },
63
89
  {
64
- key: "not-processed",
65
- title: t("flow.rejected.precondition", { defaultValue: "The record changed. Nothing was sent." }),
66
- lines: [{ ids: notProcessed.map((entry) => entry.id) }]
90
+ key: "reread-skipped",
91
+ title: t("flow.bulkSentWithoutReread", { defaultValue: "Sent without a current record" }),
92
+ lines: [{ ids: progress.rereadSkipped.filter((entry) => entry.policy === "warn").map((entry) => entry.id) }]
67
93
  },
68
94
  {
69
95
  key: "not-applied",
@@ -140,4 +166,4 @@ function FlowBulkSummary({ resource, actionName, label, total, progress, texts }
140
166
  //#endregion
141
167
  exports.FlowBulkSummary = FlowBulkSummary;
142
168
 
143
- //# sourceMappingURL=bulk-summary-CrEij5vq.cjs.map
169
+ //# sourceMappingURL=bulk-summary-2HLgz7Il.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bulk-summary-2HLgz7Il.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\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}: 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 own = `resources.${resource}.actions.${actionName}.summary`;\n const count = progress.success.length;\n const heading = caps.has(own, { count })\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: `resources.${resource}.actions.${actionName}`, 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 = `resources.${resource}.actions.${actionName}.rereadGone`;\n const goneTitle = caps.has(ownGone)\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
1
  import { t as Button } from "./button-MWVeZaqj.js";
2
- import { BULK_SUMMARY_IDS } from "@burojs/core";
2
+ import { BULK_SUMMARY_IDS, declaredText } from "@burojs/core";
3
3
  import { kindErrorText, specificErrorText, useI18nCaps, useOptionalT, useTestIds } from "@burojs/react";
4
4
  import { useState } from "react";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -47,7 +47,27 @@ function FlowBulkSummary({ resource, actionName, label, total, progress, texts }
47
47
  };
48
48
  const textOf = (error, fallback) => (error === void 0 ? void 0 : specificErrorText(error, textCaps, place) ?? kindErrorText(error.kind, textCaps, place)) ?? fallback();
49
49
  const neutral = () => t("flow.rejected.validation", { defaultValue: "Not accepted. Nothing was saved." });
50
- const notProcessed = progress.rejected.filter((entry) => entry.reason !== "server");
50
+ const gone = progress.rejected.filter((entry) => entry.reason === "gone");
51
+ const byCheck = new Map();
52
+ for (const entry of progress.rejected) {
53
+ if (entry.reason !== "check" || entry.check === void 0) continue;
54
+ const own = `checks.${entry.check}`;
55
+ const title = entry.message ?? (caps.has(own) ? caps.t(own) : entry.check);
56
+ const group = byCheck.get(entry.check);
57
+ if (group === void 0) byCheck.set(entry.check, {
58
+ check: entry.check,
59
+ title,
60
+ ids: [entry.id]
61
+ });
62
+ else group.ids.push(entry.id);
63
+ }
64
+ const checkGroups = [...byCheck.values()].map(({ check, title, ids }) => ({
65
+ key: `check:${check}`,
66
+ title,
67
+ lines: [{ ids }]
68
+ }));
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" });
51
71
  const notApplied = [...progress.rejected.filter((entry) => entry.reason === "server").map((entry) => ({
52
72
  id: entry.id,
53
73
  text: textOf(entry.error, neutral)
@@ -60,10 +80,16 @@ function FlowBulkSummary({ resource, actionName, label, total, progress, texts }
60
80
  text: textOf(entry.error, () => entry.error?.applied === "partial" ? t("flow.unknownPartial", { defaultValue: "Part of this may have been applied. Nothing was resent." }) : t("flow.unknown", { defaultValue: "It may have been applied. Nothing was resent." }))
61
81
  }));
62
82
  const groups = [
83
+ ...checkGroups,
84
+ {
85
+ key: "gone",
86
+ title: goneTitle,
87
+ lines: [{ ids: gone.map((entry) => entry.id) }]
88
+ },
63
89
  {
64
- key: "not-processed",
65
- title: t("flow.rejected.precondition", { defaultValue: "The record changed. Nothing was sent." }),
66
- lines: [{ ids: notProcessed.map((entry) => entry.id) }]
90
+ key: "reread-skipped",
91
+ title: t("flow.bulkSentWithoutReread", { defaultValue: "Sent without a current record" }),
92
+ lines: [{ ids: progress.rereadSkipped.filter((entry) => entry.policy === "warn").map((entry) => entry.id) }]
67
93
  },
68
94
  {
69
95
  key: "not-applied",
@@ -140,4 +166,4 @@ function FlowBulkSummary({ resource, actionName, label, total, progress, texts }
140
166
  //#endregion
141
167
  export { FlowBulkSummary };
142
168
 
143
- //# sourceMappingURL=bulk-summary-BWSAS7k2.js.map
169
+ //# sourceMappingURL=bulk-summary-D6A0ua21.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bulk-summary-D6A0ua21.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\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}: 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 own = `resources.${resource}.actions.${actionName}.summary`;\n const count = progress.success.length;\n const heading = caps.has(own, { count })\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: `resources.${resource}.actions.${actionName}`, 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 = `resources.${resource}.actions.${actionName}.rereadGone`;\n const goneTitle = caps.has(ownGone)\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-CAScLPb2.js";
2
- import { t as FieldRelationPicker } from "./relation-picker-D-tBBZW_.js";
1
+ import { n as useCandidateSelection } from "./lazy-relation-picker-dialog-BaORufxQ.js";
2
+ import { t as FieldRelationPicker } from "./relation-picker-BbO41cFV.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-CS_JZ4Fd.js.map
31
+ //# sourceMappingURL=candidates-relation-picker-QvoY2bOQ.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"candidates-relation-picker-CS_JZ4Fd.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-QvoY2bOQ.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-Bt8lrEIu.cjs");
2
- const require_relation_picker = require("./relation-picker-DaIMzf2H.cjs");
1
+ const require_lazy_relation_picker_dialog = require("./lazy-relation-picker-dialog-C_VlGlDz.cjs");
2
+ const require_relation_picker = require("./relation-picker-jk9D_uwn.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-y5M6_oe4.cjs.map
31
+ //# sourceMappingURL=candidates-relation-picker-pEAWKQEY.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"candidates-relation-picker-y5M6_oe4.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-pEAWKQEY.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"}
@@ -2,7 +2,7 @@ import { l as cn } from "./use-theme-dnE3Od3I.js";
2
2
  import { l as useLinkComponent, m as PopoverTrigger, n as toast, p as PopoverContent, u as Popover } from "./toaster-Ct_YHGs6.js";
3
3
  import { t as Button } from "./button-MWVeZaqj.js";
4
4
  import { a as DialogFooter, i as DialogDescription, o as DialogHeader, r as DialogContent, s as DialogTitle, t as Dialog } from "./dialog-C123sVQ8.js";
5
- import { FRAMEWORK_TEXT_KEYS, canonicalEntityNodeKey, checkFailedDefault, compileFlow, declaredText, docAddressToArticle, flowRecordOf, hasRecordPage, hrefFor, humanizeKey, isBuiltinItemAction, normalizeEntityRef, recordEntries, resolveContentSlot, resolveDocSee, routeResourceKey, textsValueAt } from "@burojs/core";
5
+ import { FRAMEWORK_TEXT_KEYS, canonicalEntityNodeKey, checkFailedDefault, compileFlow, constraintText, declaredText, docAddressToArticle, flowRecordOf, hasRecordPage, hrefFor, humanizeKey, isBuiltinItemAction, normalizeEntityRef, recordEntries, resolveContentSlot, resolveDocSee, routeResourceKey, textsValueAt } from "@burojs/core";
6
6
  import { buildDI, conjoinHostPage, modeForSurface, recordKeyOf, resolveRoute, useActionWhenSources, useApp, useAvailabilityResolver, useChromeT, useComponent, useDoc, useDocPanel, useDocTopics, useEntryGate, useFlowRowResolver, useHostPage, useI18nCaps, useOptionalRouterAdapter, useOptionalT, usePresentBlock, usePresentFlow, useProjectedTitle, useQuick, useQuickEntry, useTestIds, useUIInstance } from "@burojs/react";
7
7
  import { IconArrowRight, IconArrowUpRight, IconArrowsLeftRight, IconBan, IconBell, IconBox, IconBoxMultiple, IconBuilding, IconCheck, IconChevronRight, IconCircle, IconCircleCaretRight, IconCircleCheck, IconCircleX, IconClipboardList, IconClock, IconCopy, IconDots, IconEye, IconFileOff, IconFilePencil, IconFileText, IconFileX, IconGitBranch, IconHammer, IconHash, IconHistory, IconInfoHexagon, IconKey, IconKeyOff, IconLink, IconList, IconLoader2, IconMapPin, IconNetwork, IconPackage, IconPackageExport, IconPackageImport, IconPackageOff, IconPackages, IconPencil, IconPlayerPlay, IconPlayerTrackNext, IconPlus, IconQrcode, IconRefresh, IconRotate, IconScript, IconSettings, IconShieldCheck, IconTag, IconTool, IconTrash, IconTruck, IconUserPlus, IconUsers, IconX } from "@tabler/icons-react";
8
8
  import * as React from "react";
@@ -488,11 +488,11 @@ function retrying(importer) {
488
488
  return loading;
489
489
  };
490
490
  }
491
- const loadFlowRuntime = retrying(() => import("./flow-runtime-DyqTmK3H.js"));
492
- const loadFlowScreen = retrying(() => import("./flow-screen-DCdli6Ha.js"));
493
- const loadPageFlowRoute = retrying(() => import("./page-flow-route-BHUEpn0I.js"));
494
- const loadInlineFlowHost = retrying(() => import("./inline-flow-host-C0rI9B7f.js"));
495
- const loadBulkSummary = retrying(() => import("./bulk-summary-BWSAS7k2.js"));
491
+ const loadFlowRuntime = retrying(() => import("./flow-runtime-BEIyym7d.js"));
492
+ const loadFlowScreen = retrying(() => import("./flow-screen-DY1Z9PbG.js"));
493
+ const loadPageFlowRoute = retrying(() => import("./page-flow-route-CyMzUidK.js"));
494
+ const loadInlineFlowHost = retrying(() => import("./inline-flow-host-D6u-RlsV.js"));
495
+ const loadBulkSummary = retrying(() => import("./bulk-summary-D6A0ua21.js"));
496
496
  function preloadFlowRuntime() {
497
497
  loadFlowRuntime().catch(() => void 0);
498
498
  }
@@ -1077,6 +1077,35 @@ function DisabledAction({ reason, label, icon, testid, size, variant, className,
1077
1077
  children: chrome.content
1078
1078
  }), label, chrome.compact, text);
1079
1079
  }
1080
+ function UndecidedAction({ label, icon, testid, size, variant, className, asMenuItem, density = "regular", actionName, surface }) {
1081
+ if (asMenuItem) return jsx(DropdownMenuItem, {
1082
+ "data-testid": testid,
1083
+ disabled: true,
1084
+ "aria-busy": "true",
1085
+ children: jsx(ActionInner, {
1086
+ icon,
1087
+ label
1088
+ })
1089
+ });
1090
+ const chrome = resolveControlChrome({
1091
+ density,
1092
+ icon,
1093
+ label,
1094
+ actionName: actionName ?? testid ?? "",
1095
+ surface: surface ?? "unknown"
1096
+ });
1097
+ return withActionTooltip(jsx(Button, {
1098
+ type: "button",
1099
+ size: size ?? chrome.size,
1100
+ variant: variant ?? "outline",
1101
+ className: cn(chrome.className, className),
1102
+ "data-testid": testid,
1103
+ disabled: true,
1104
+ "aria-busy": "true",
1105
+ "aria-label": chrome.ariaLabel,
1106
+ children: chrome.content
1107
+ }), label, chrome.compact);
1108
+ }
1080
1109
  const DESTRUCTIVE_ITEM = "text-destructive focus:bg-destructive/10 focus:text-destructive data-[highlighted]:text-destructive";
1081
1110
  const DEFAULT_ACTION_ICONS = {
1082
1111
  create: "Plus",
@@ -1234,6 +1263,18 @@ function LinkActionButton({ resource, actionName, record, scope = "row", variant
1234
1263
  const Anchor = target === "_blank" || isExternalHref(href) ? "a" : RouterLink;
1235
1264
  const anchorHref = target === "_blank" ? toBrowser(href) : href;
1236
1265
  if (editRoute.kind === "none") return null;
1266
+ if (availability.state === "undecided") return jsx(UndecidedAction, {
1267
+ label,
1268
+ icon: resolveActionIcon(action, actionName),
1269
+ testid,
1270
+ size,
1271
+ variant: buttonVariant,
1272
+ className,
1273
+ asMenuItem,
1274
+ density,
1275
+ actionName,
1276
+ surface: scope
1277
+ });
1237
1278
  if (availability.state === "disabled") return jsx(DisabledAction, {
1238
1279
  reason: availability.reason,
1239
1280
  label,
@@ -1326,6 +1367,18 @@ function ModalActionButton({ resource, actionName, record, scope = "row", varian
1326
1367
  const recordId = String(recordKeyOf(app.registry.get(resource), record) ?? "");
1327
1368
  const testid = makeTestId(scope, resource, actionName, recordId, tid);
1328
1369
  const label = useResolvedLabel(action, actionName, children, resource);
1370
+ if (availability.state === "undecided") return jsx(UndecidedAction, {
1371
+ label,
1372
+ icon: resolveActionIcon(action, actionName),
1373
+ testid,
1374
+ size,
1375
+ variant: buttonVariant,
1376
+ className,
1377
+ asMenuItem,
1378
+ density,
1379
+ actionName,
1380
+ surface: scope
1381
+ });
1329
1382
  if (availability.state === "disabled") return jsx(DisabledAction, {
1330
1383
  reason: availability.reason,
1331
1384
  label,
@@ -1400,6 +1453,13 @@ function issueText(issue, t, caps, resource) {
1400
1453
  params
1401
1454
  });
1402
1455
  if (declared !== void 0) return declared;
1456
+ if (issue.check?.constraint !== void 0) {
1457
+ const text = constraintText(issue.check.constraint, String(params?.limit ?? ""));
1458
+ return t(text.key, {
1459
+ defaultValue: text.defaultValue,
1460
+ params
1461
+ });
1462
+ }
1403
1463
  const name = String(params?.name ?? checkId);
1404
1464
  return t(FRAMEWORK_TEXT_KEYS.checkFailed, {
1405
1465
  defaultValue: checkFailedDefault(name),
@@ -1516,6 +1576,6 @@ function CheckConfirmDialog({ state, testid, onAnchorFocus, title, proceedLabel,
1516
1576
  });
1517
1577
  }
1518
1578
  //#endregion
1519
- export { Tooltip as $, OwnTitleHeading as A, DropdownMenuContent as B, loadBulkSummary as C, loadPageFlowRoute as D, loadInlineFlowHost as E, Icon as F, DropdownMenuRadioGroup as G, DropdownMenuItem as H, hasIcon as I, DropdownMenuShortcut as J, DropdownMenuRadioItem as K, registerIcons as L, DialogPresentationShell as M, OwnTitleContext as N, preloadFlowRuntime as O, SheetPresentationShell as P, DropdownMenuTrigger as Q, DropdownMenu as R, RuntimeFlowRunner as S, loadFlowScreen as T, DropdownMenuLabel as U, DropdownMenuGroup as V, DropdownMenuPortal as W, DropdownMenuSubContent as X, DropdownMenuSub as Y, DropdownMenuSubTrigger as Z, reasonText as _, modeForSurface as a, SheetContent as at, RuntimeAppFlowRunner as b, useListSlot as c, SheetHeader as ct, useToBrowserHref as d, DocInfo as dt, TooltipContent as et, FlowActionButton as f, ActionInner as g, useFlowDialogTexts as h, makeTestId as i, SheetClose as it, useFocusOnMount as j, useLoaded as k, isExternalHref as l, SheetTitle as lt, useFlowChrome as m, ActionButton as n, TooltipTrigger as nt, canonicalResourceName as o, SheetDescription as ot, FlowMenuItem as p, DropdownMenuSeparator as q, DisabledAction as r, Sheet as rt, listSlot as s, SheetFooter as st, CheckConfirmDialog as t, TooltipProvider as tt, openExternal as u, SheetTrigger as ut, FlowBoundary as v, loadFailedText as w, RuntimeBulkFlowRunner as x, FlowLoadFailed as y, DropdownMenuCheckboxItem as z };
1579
+ export { DropdownMenuTrigger as $, useLoaded as A, DropdownMenuCheckboxItem as B, RuntimeFlowRunner as C, loadInlineFlowHost as D, loadFlowScreen as E, SheetPresentationShell as F, DropdownMenuPortal as G, DropdownMenuGroup as H, Icon as I, DropdownMenuSeparator as J, DropdownMenuRadioGroup as K, hasIcon as L, useFocusOnMount as M, DialogPresentationShell as N, loadPageFlowRoute as O, OwnTitleContext as P, DropdownMenuSubTrigger as Q, registerIcons as R, RuntimeBulkFlowRunner as S, loadFailedText as T, DropdownMenuItem as U, DropdownMenuContent as V, DropdownMenuLabel as W, DropdownMenuSub as X, DropdownMenuShortcut as Y, DropdownMenuSubContent as Z, ActionInner as _, makeTestId as a, SheetClose as at, FlowLoadFailed as b, listSlot as c, SheetFooter as ct, openExternal as d, SheetTrigger as dt, Tooltip as et, useToBrowserHref as f, DocInfo as ft, useFlowDialogTexts as g, useFlowChrome as h, UndecidedAction as i, Sheet as it, OwnTitleHeading as j, preloadFlowRuntime as k, useListSlot as l, SheetHeader as lt, FlowMenuItem as m, ActionButton as n, TooltipProvider as nt, modeForSurface as o, SheetContent as ot, FlowActionButton as p, DropdownMenuRadioItem as q, DisabledAction as r, TooltipTrigger as rt, canonicalResourceName as s, SheetDescription as st, CheckConfirmDialog as t, TooltipContent as tt, isExternalHref as u, SheetTitle as ut, reasonText as v, loadBulkSummary as w, RuntimeAppFlowRunner as x, FlowBoundary as y, DropdownMenu as z };
1520
1580
 
1521
- //# sourceMappingURL=check-confirm-dialog-2j0gOd7x.js.map
1581
+ //# sourceMappingURL=check-confirm-dialog-B-CbJTln.js.map