@burojs/ui-shadcn 0.9.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.
- package/dist/{bulk-summary-2HLgz7Il.cjs → bulk-summary-Chc61Pyw.cjs} +9 -7
- package/dist/bulk-summary-Chc61Pyw.cjs.map +1 -0
- package/dist/{bulk-summary-D6A0ua21.js → bulk-summary-DpSQD2Fq.js} +9 -7
- package/dist/bulk-summary-DpSQD2Fq.js.map +1 -0
- package/dist/{candidates-relation-picker-QvoY2bOQ.js → candidates-relation-picker-DRsHKe6N.js} +3 -3
- package/dist/{candidates-relation-picker-QvoY2bOQ.js.map → candidates-relation-picker-DRsHKe6N.js.map} +1 -1
- package/dist/{candidates-relation-picker-pEAWKQEY.cjs → candidates-relation-picker-GIxsp7D_.cjs} +3 -3
- package/dist/{candidates-relation-picker-pEAWKQEY.cjs.map → candidates-relation-picker-GIxsp7D_.cjs.map} +1 -1
- package/dist/{check-confirm-dialog-W-8WOmGh.cjs → check-confirm-dialog-BMSb7wFv.cjs} +17 -9
- package/dist/check-confirm-dialog-BMSb7wFv.cjs.map +1 -0
- package/dist/{check-confirm-dialog-B-CbJTln.js → check-confirm-dialog-B_u3YVHS.js} +18 -10
- package/dist/{check-confirm-dialog-B-CbJTln.js.map → check-confirm-dialog-B_u3YVHS.js.map} +1 -1
- package/dist/{filter-builder-04nas3eq.js → filter-builder-DX-xC3Yd.js} +2 -2
- package/dist/{filter-builder-04nas3eq.js.map → filter-builder-DX-xC3Yd.js.map} +1 -1
- package/dist/{filter-builder-DQX-TMFh.cjs → filter-builder-Dt5E8PSX.cjs} +2 -2
- package/dist/{filter-builder-DQX-TMFh.cjs.map → filter-builder-Dt5E8PSX.cjs.map} +1 -1
- package/dist/{flow-runtime-DyNIYfUP.cjs → flow-runtime-CQ4wf8co.cjs} +2 -2
- package/dist/{flow-runtime-DyNIYfUP.cjs.map → flow-runtime-CQ4wf8co.cjs.map} +1 -1
- package/dist/{flow-runtime-BEIyym7d.js → flow-runtime-Q2vD7R3c.js} +2 -2
- package/dist/{flow-runtime-BEIyym7d.js.map → flow-runtime-Q2vD7R3c.js.map} +1 -1
- package/dist/{flow-screen-DY1Z9PbG.js → flow-screen-B1y2yizP.js} +18 -18
- package/dist/flow-screen-B1y2yizP.js.map +1 -0
- package/dist/{flow-screen-FE5Xhb3t.cjs → flow-screen-sw2cP70t.cjs} +18 -18
- package/dist/flow-screen-sw2cP70t.cjs.map +1 -0
- package/dist/index.cjs +2183 -109
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +76 -8
- package/dist/index.d.ts +76 -8
- package/dist/index.js +2095 -24
- package/dist/index.js.map +1 -1
- package/dist/{inline-flow-host-yVLo6-sM.cjs → inline-flow-host-CkhoA69R.cjs} +3 -3
- package/dist/{inline-flow-host-yVLo6-sM.cjs.map → inline-flow-host-CkhoA69R.cjs.map} +1 -1
- package/dist/{inline-flow-host-D6u-RlsV.js → inline-flow-host-DqbXqcPS.js} +3 -3
- package/dist/{inline-flow-host-D6u-RlsV.js.map → inline-flow-host-DqbXqcPS.js.map} +1 -1
- package/dist/{lazy-relation-picker-dialog-BaORufxQ.js → lazy-relation-picker-dialog-BaIEWLbF.js} +3 -52
- package/dist/lazy-relation-picker-dialog-BaIEWLbF.js.map +1 -0
- package/dist/{lazy-relation-picker-dialog-C_VlGlDz.cjs → lazy-relation-picker-dialog-CeRzOAi0.cjs} +3 -52
- package/dist/lazy-relation-picker-dialog-CeRzOAi0.cjs.map +1 -0
- package/dist/{page-flow-route-CyMzUidK.js → page-flow-route-CP7cS7FY.js} +5 -5
- package/dist/page-flow-route-CP7cS7FY.js.map +1 -0
- package/dist/{page-flow-route-OFx7h7Ja.cjs → page-flow-route-UDx8qvdM.cjs} +9 -9
- package/dist/page-flow-route-UDx8qvdM.cjs.map +1 -0
- package/dist/{place-node-BZF5Af6x.cjs → place-node-C5ZmuHaN.cjs} +149 -40
- package/dist/place-node-C5ZmuHaN.cjs.map +1 -0
- package/dist/{place-node-DRjmJGQ_.js → place-node-DwWAigv0.js} +146 -43
- package/dist/place-node-DwWAigv0.js.map +1 -0
- package/dist/record-trail-store-Cjo9vtod.cjs +126 -0
- package/dist/record-trail-store-Cjo9vtod.cjs.map +1 -0
- package/dist/record-trail-store-Dn6bVry4.js +91 -0
- package/dist/record-trail-store-Dn6bVry4.js.map +1 -0
- package/dist/{related-list-cards-xVvgSlu-.cjs → related-list-cards-BypKfm9t.cjs} +3 -3
- package/dist/{related-list-cards-xVvgSlu-.cjs.map → related-list-cards-BypKfm9t.cjs.map} +1 -1
- package/dist/{related-list-cards-2hLitVkg.js → related-list-cards-Dcmruy09.js} +3 -3
- package/dist/{related-list-cards-2hLitVkg.js.map → related-list-cards-Dcmruy09.js.map} +1 -1
- package/dist/{related-list-timeline-Dsf5WewG.cjs → related-list-timeline-D-KClgKb.cjs} +4 -4
- package/dist/{related-list-timeline-Dsf5WewG.cjs.map → related-list-timeline-D-KClgKb.cjs.map} +1 -1
- package/dist/{related-list-timeline-CxJqe6eK.js → related-list-timeline-DZON_qSc.js} +4 -4
- package/dist/{related-list-timeline-CxJqe6eK.js.map → related-list-timeline-DZON_qSc.js.map} +1 -1
- package/dist/{related-rows-DDhp9axl.cjs → related-rows-DgF05ssi.cjs} +4 -4
- package/dist/{related-rows-DDhp9axl.cjs.map → related-rows-DgF05ssi.cjs.map} +1 -1
- package/dist/{related-rows-DL6CWsrj.js → related-rows-ETZl5CB9.js} +4 -4
- package/dist/{related-rows-DL6CWsrj.js.map → related-rows-ETZl5CB9.js.map} +1 -1
- package/dist/{relation-create-_SFuPQGM.cjs → relation-create-B8zngAcA.cjs} +46 -11
- package/dist/relation-create-B8zngAcA.cjs.map +1 -0
- package/dist/{relation-create-6WicROWA.js → relation-create-CeCWyxIb.js} +47 -12
- package/dist/relation-create-CeCWyxIb.js.map +1 -0
- package/dist/{relation-many-picker-mGEQDWo2.js → relation-many-picker-CT7nKfE2.js} +4 -4
- package/dist/{relation-many-picker-mGEQDWo2.js.map → relation-many-picker-CT7nKfE2.js.map} +1 -1
- package/dist/{relation-many-picker-BBNsmkaX.cjs → relation-many-picker-Cq0EHY5I.cjs} +4 -4
- package/dist/{relation-many-picker-BBNsmkaX.cjs.map → relation-many-picker-Cq0EHY5I.cjs.map} +1 -1
- package/dist/{relation-picker-BbO41cFV.js → relation-picker-CCyuMeGq.js} +6 -6
- package/dist/{relation-picker-BbO41cFV.js.map → relation-picker-CCyuMeGq.js.map} +1 -1
- package/dist/{relation-picker-jk9D_uwn.cjs → relation-picker-DmwTzgsd.cjs} +6 -6
- package/dist/{relation-picker-jk9D_uwn.cjs.map → relation-picker-DmwTzgsd.cjs.map} +1 -1
- package/dist/{relation-picker-dialog-BgSG_8bU.js → relation-picker-dialog-CoWKjNv8.js} +4 -4
- package/dist/{relation-picker-dialog-BgSG_8bU.js.map → relation-picker-dialog-CoWKjNv8.js.map} +1 -1
- package/dist/{relation-picker-dialog-Duqy2r0n.cjs → relation-picker-dialog-mbwyNK43.cjs} +4 -4
- package/dist/{relation-picker-dialog-Duqy2r0n.cjs.map → relation-picker-dialog-mbwyNK43.cjs.map} +1 -1
- package/dist/{relation-select-C3aV18kT.cjs → relation-select-CguIo2M5.cjs} +2 -2
- package/dist/{relation-select-C3aV18kT.cjs.map → relation-select-CguIo2M5.cjs.map} +1 -1
- package/dist/{relation-select-CjQT9LpS.js → relation-select-nAYxhopN.js} +2 -2
- package/dist/{relation-select-CjQT9LpS.js.map → relation-select-nAYxhopN.js.map} +1 -1
- package/dist/{use-dialog-filter-state-lsTJxrB4.cjs → use-dialog-filter-state-CpWblz3C.cjs} +2 -2
- package/dist/{use-dialog-filter-state-lsTJxrB4.cjs.map → use-dialog-filter-state-CpWblz3C.cjs.map} +1 -1
- package/dist/{use-dialog-filter-state-CJoeY-1j.js → use-dialog-filter-state-ZYxOp5WO.js} +2 -2
- package/dist/{use-dialog-filter-state-CJoeY-1j.js.map → use-dialog-filter-state-ZYxOp5WO.js.map} +1 -1
- package/dist/{use-record-subtitle-BJ9rnj6F.cjs → use-record-subtitle-B4lTR7pf.cjs} +2 -2
- package/dist/{use-record-subtitle-BJ9rnj6F.cjs.map → use-record-subtitle-B4lTR7pf.cjs.map} +1 -1
- package/dist/{use-record-subtitle-w3ZhXNlf.js → use-record-subtitle-pWMBqQx9.js} +2 -2
- package/dist/{use-record-subtitle-w3ZhXNlf.js.map → use-record-subtitle-pWMBqQx9.js.map} +1 -1
- package/package.json +9 -9
- package/dist/bulk-summary-2HLgz7Il.cjs.map +0 -1
- package/dist/bulk-summary-D6A0ua21.js.map +0 -1
- package/dist/check-confirm-dialog-W-8WOmGh.cjs.map +0 -1
- package/dist/flow-screen-DY1Z9PbG.js.map +0 -1
- package/dist/flow-screen-FE5Xhb3t.cjs.map +0 -1
- package/dist/lazy-relation-picker-dialog-BaORufxQ.js.map +0 -1
- package/dist/lazy-relation-picker-dialog-C_VlGlDz.cjs.map +0 -1
- package/dist/page-flow-route-CyMzUidK.js.map +0 -1
- package/dist/page-flow-route-OFx7h7Ja.cjs.map +0 -1
- package/dist/place-node-BZF5Af6x.cjs.map +0 -1
- package/dist/place-node-DRjmJGQ_.js.map +0 -1
- package/dist/relation-create-6WicROWA.js.map +0 -1
- package/dist/relation-create-_SFuPQGM.cjs.map +0 -1
- package/dist/resource-page-router-CzaNATSp.js +0 -2010
- package/dist/resource-page-router-CzaNATSp.js.map +0 -1
- package/dist/resource-page-router-dmVIeu5s.cjs +0 -2231
- package/dist/resource-page-router-dmVIeu5s.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_use_theme = require("./use-theme-DFlpXils.cjs");
|
|
3
3
|
const require_toaster = require("./toaster-BbByOytP.cjs");
|
|
4
|
-
const require_check_confirm_dialog = require("./check-confirm-dialog-
|
|
4
|
+
const require_check_confirm_dialog = require("./check-confirm-dialog-BMSb7wFv.cjs");
|
|
5
5
|
const require_button = require("./button-BxnnE28H.cjs");
|
|
6
6
|
const require_input = require("./input-BI0czGyI.cjs");
|
|
7
7
|
const require_dialog = require("./dialog-vmMdfUWs.cjs");
|
|
8
|
-
const require_relation_create = require("./relation-create-
|
|
8
|
+
const require_relation_create = require("./relation-create-B8zngAcA.cjs");
|
|
9
9
|
const require_skeleton = require("./skeleton-_1gP7wan.cjs");
|
|
10
|
-
const require_place_node = require("./place-node-
|
|
10
|
+
const require_place_node = require("./place-node-C5ZmuHaN.cjs");
|
|
11
11
|
const require_layout_theme_storage_key = require("./layout/theme-storage-key.cjs");
|
|
12
|
-
const require_filter_builder = require("./filter-builder-
|
|
13
|
-
const
|
|
12
|
+
const require_filter_builder = require("./filter-builder-Dt5E8PSX.cjs");
|
|
13
|
+
const require_record_trail_store = require("./record-trail-store-Cjo9vtod.cjs");
|
|
14
14
|
const require_label = require("./label-w6JYf2cF.cjs");
|
|
15
|
-
const require_lazy_relation_picker_dialog = require("./lazy-relation-picker-dialog-
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
15
|
+
const require_lazy_relation_picker_dialog = require("./lazy-relation-picker-dialog-CeRzOAi0.cjs");
|
|
16
|
+
const require_success_notices = require("./success-notices-Cl4b6MLQ.cjs");
|
|
17
|
+
const require_use_record_subtitle = require("./use-record-subtitle-B4lTR7pf.cjs");
|
|
18
|
+
const require_relation_picker = require("./relation-picker-DmwTzgsd.cjs");
|
|
19
|
+
const require_use_dialog_filter_state = require("./use-dialog-filter-state-CpWblz3C.cjs");
|
|
19
20
|
let _burojs_react_web = require("@burojs/react/web");
|
|
20
21
|
let _burojs_core = require("@burojs/core");
|
|
21
22
|
let _burojs_react = require("@burojs/react");
|
|
@@ -303,7 +304,7 @@ function DocBrowser({ className }) {
|
|
|
303
304
|
label,
|
|
304
305
|
summary: (0, _burojs_core.resolveDoc)(caps, entry.scope)?.summary,
|
|
305
306
|
nested: entry.kind === "variant",
|
|
306
|
-
group: entry.kind === "concept" ? glossaryLabel : entry.kind === "resource" ? areasLabel : void 0
|
|
307
|
+
group: entry.kind === "concept" ? glossaryLabel : entry.kind === "resource" || entry.kind === "base" ? areasLabel : void 0
|
|
307
308
|
};
|
|
308
309
|
}), [
|
|
309
310
|
app,
|
|
@@ -1724,6 +1725,231 @@ function useShellWaiting() {
|
|
|
1724
1725
|
return (0, _burojs_react.usePermissionsUndecided)();
|
|
1725
1726
|
}
|
|
1726
1727
|
//#endregion
|
|
1728
|
+
//#region src/layout/build-nav-items.ts
|
|
1729
|
+
function groupNavHref(registry, group, isVisible) {
|
|
1730
|
+
let href;
|
|
1731
|
+
try {
|
|
1732
|
+
href = (0, _burojs_core.navHrefFor)(registry, group, { isVisible });
|
|
1733
|
+
} catch {
|
|
1734
|
+
return;
|
|
1735
|
+
}
|
|
1736
|
+
return (0, _burojs_core.matchPath)(registry, href, { isVisible }) === null ? void 0 : href;
|
|
1737
|
+
}
|
|
1738
|
+
function buildNavItems(args) {
|
|
1739
|
+
const { registry, caps, groupName, match, isVisible, entryFilter, icons } = args;
|
|
1740
|
+
const chain = match?.groupChain ?? [];
|
|
1741
|
+
const qualifiedMatch = match;
|
|
1742
|
+
const activeLeaf = qualifiedMatch == null ? void 0 : qualifiedMatch.kind === "group-index" ? require_record_trail_store.canonicalNavKey({
|
|
1743
|
+
name: qualifiedMatch.target ?? qualifiedMatch.name,
|
|
1744
|
+
ref: qualifiedMatch.targetRef
|
|
1745
|
+
}) : require_record_trail_store.canonicalNavKey(qualifiedMatch);
|
|
1746
|
+
const isEligible = (node) => isVisible(node) && (entryFilter ? entryFilter(node) : true);
|
|
1747
|
+
const out = [];
|
|
1748
|
+
for (const child of registry.groups.childrenOf(groupName)) {
|
|
1749
|
+
if (!isEligible(child)) continue;
|
|
1750
|
+
const kind = (0, _burojs_core.nodeKind)(child);
|
|
1751
|
+
const childKey = require_record_trail_store.canonicalNavKey(child);
|
|
1752
|
+
if (kind === "group") {
|
|
1753
|
+
const href = groupNavHref(registry, childKey, isEligible);
|
|
1754
|
+
if (href === void 0) continue;
|
|
1755
|
+
const label = (0, _burojs_core.resolveNavLabel)(caps, `groups.${childKey}`, (0, _burojs_core.declaredText)("chrome", child, "label"));
|
|
1756
|
+
const active = chain.some((g) => require_record_trail_store.canonicalNavKey(g) === childKey);
|
|
1757
|
+
out.push({
|
|
1758
|
+
kind: "group",
|
|
1759
|
+
name: childKey,
|
|
1760
|
+
label,
|
|
1761
|
+
href,
|
|
1762
|
+
icon: icons?.group?.(childKey),
|
|
1763
|
+
active
|
|
1764
|
+
});
|
|
1765
|
+
continue;
|
|
1766
|
+
}
|
|
1767
|
+
const href = (0, _burojs_core.navHrefFor)(registry, childKey, { isVisible: isEligible });
|
|
1768
|
+
if (kind === "custom-page") out.push({
|
|
1769
|
+
kind: "custom-page",
|
|
1770
|
+
name: childKey,
|
|
1771
|
+
label: (0, _burojs_core.resolveNavLabel)(caps, `pages.${childKey}`, (0, _burojs_core.declaredText)("chrome", child, "label")),
|
|
1772
|
+
href,
|
|
1773
|
+
icon: icons?.page?.(childKey),
|
|
1774
|
+
active: activeLeaf === childKey
|
|
1775
|
+
});
|
|
1776
|
+
else out.push({
|
|
1777
|
+
kind: "resource",
|
|
1778
|
+
name: childKey,
|
|
1779
|
+
label: (0, _burojs_core.resolveResourceNavLabel)(caps, childKey, child),
|
|
1780
|
+
href,
|
|
1781
|
+
icon: icons?.resource?.(childKey),
|
|
1782
|
+
active: activeLeaf === childKey
|
|
1783
|
+
});
|
|
1784
|
+
}
|
|
1785
|
+
return out;
|
|
1786
|
+
}
|
|
1787
|
+
//#endregion
|
|
1788
|
+
//#region src/layout/layouts/secondary-sidebar-layout.tsx
|
|
1789
|
+
function Row({ it }) {
|
|
1790
|
+
const RouterLink = require_toaster.useLinkComponent();
|
|
1791
|
+
return (0, react_jsx_runtime.jsx)("li", { children: (0, react_jsx_runtime.jsxs)(RouterLink, {
|
|
1792
|
+
href: it.href,
|
|
1793
|
+
"data-testid": `nav-secondary-item:${it.name}`,
|
|
1794
|
+
"aria-current": it.active ? "page" : void 0,
|
|
1795
|
+
className: require_use_theme.cn("flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium outline-hidden ring-offset-background transition-colors", "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", it.active ? "bg-secondary text-secondary-foreground" : "text-muted-foreground hover:bg-secondary/50 hover:text-foreground"),
|
|
1796
|
+
children: [it.icon != null && (0, react_jsx_runtime.jsx)("span", {
|
|
1797
|
+
className: "inline-flex h-4 w-4 shrink-0 items-center justify-center",
|
|
1798
|
+
"aria-hidden": "true",
|
|
1799
|
+
children: it.icon
|
|
1800
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
1801
|
+
className: "truncate",
|
|
1802
|
+
title: it.label,
|
|
1803
|
+
children: it.label
|
|
1804
|
+
})]
|
|
1805
|
+
}) });
|
|
1806
|
+
}
|
|
1807
|
+
function SecondarySidebarLayout({ group, groupKey, items, children }) {
|
|
1808
|
+
const RouterLink = require_toaster.useLinkComponent();
|
|
1809
|
+
const caps = (0, _burojs_react.useI18nCaps)();
|
|
1810
|
+
const id = groupKey ?? group.name;
|
|
1811
|
+
const label = (0, _burojs_core.resolveNavLabel)(caps, `groups.${id}`, (0, _burojs_core.declaredText)("chrome", group, "label"));
|
|
1812
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
1813
|
+
className: "md:-m-6 md:flex md:min-h-[calc(100%+3rem)]",
|
|
1814
|
+
"data-testid": `nav-secondary:${id}`,
|
|
1815
|
+
children: [
|
|
1816
|
+
(0, react_jsx_runtime.jsx)("aside", {
|
|
1817
|
+
className: "hidden w-64 shrink-0 border-r bg-background text-foreground md:block",
|
|
1818
|
+
children: (0, react_jsx_runtime.jsxs)("div", {
|
|
1819
|
+
className: "space-y-4 p-4",
|
|
1820
|
+
children: [(0, react_jsx_runtime.jsx)("p", {
|
|
1821
|
+
className: "px-3 text-base font-semibold tracking-tight",
|
|
1822
|
+
children: label
|
|
1823
|
+
}), (0, react_jsx_runtime.jsx)("nav", {
|
|
1824
|
+
"aria-label": label,
|
|
1825
|
+
children: (0, react_jsx_runtime.jsx)("ul", {
|
|
1826
|
+
className: "space-y-0.5",
|
|
1827
|
+
children: items.map((it) => (0, react_jsx_runtime.jsx)(Row, { it }, it.name))
|
|
1828
|
+
})
|
|
1829
|
+
})]
|
|
1830
|
+
})
|
|
1831
|
+
}),
|
|
1832
|
+
(0, react_jsx_runtime.jsx)("nav", {
|
|
1833
|
+
"aria-label": label,
|
|
1834
|
+
"data-testid": `nav-secondary-select:${id}`,
|
|
1835
|
+
className: "-mx-1 mb-4 flex snap-x snap-proximity gap-1.5 overflow-x-auto scroll-smooth px-1 pb-1 [-ms-overflow-style:none] [mask-image:linear-gradient(to_right,transparent,black_8px,black_calc(100%-8px),transparent)] [scrollbar-width:none] md:hidden [&::-webkit-scrollbar]:hidden",
|
|
1836
|
+
children: items.map((it) => (0, react_jsx_runtime.jsx)(RouterLink, {
|
|
1837
|
+
href: it.href,
|
|
1838
|
+
"aria-current": it.active ? "page" : void 0,
|
|
1839
|
+
className: require_use_theme.cn("snap-start whitespace-nowrap rounded-full border px-3 py-1.5 text-sm outline-hidden ring-offset-background transition-colors duration-150", "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", it.active ? "border-primary/40 bg-primary/10 font-medium text-foreground" : "border-border text-muted-foreground hover:bg-accent/60 hover:text-accent-foreground"),
|
|
1840
|
+
children: it.label
|
|
1841
|
+
}, it.name))
|
|
1842
|
+
}),
|
|
1843
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
1844
|
+
className: "min-w-0 flex-1 md:overflow-x-hidden md:p-6",
|
|
1845
|
+
children
|
|
1846
|
+
})
|
|
1847
|
+
]
|
|
1848
|
+
});
|
|
1849
|
+
}
|
|
1850
|
+
//#endregion
|
|
1851
|
+
//#region src/layout/layouts/tabs-layout.tsx
|
|
1852
|
+
function TabsLayout({ group, groupKey, items, children }) {
|
|
1853
|
+
const RouterLink = require_toaster.useLinkComponent();
|
|
1854
|
+
const caps = (0, _burojs_react.useI18nCaps)();
|
|
1855
|
+
const id = groupKey ?? group.name;
|
|
1856
|
+
const label = (0, _burojs_core.resolveNavLabel)(caps, `groups.${id}`, (0, _burojs_core.declaredText)("chrome", group, "label"));
|
|
1857
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
1858
|
+
className: "flex flex-col gap-4",
|
|
1859
|
+
"data-testid": `nav-tabs:${id}`,
|
|
1860
|
+
children: [(0, react_jsx_runtime.jsx)("nav", {
|
|
1861
|
+
"aria-label": label,
|
|
1862
|
+
className: "flex gap-1 overflow-x-auto scroll-smooth border-b border-border [-ms-overflow-style:none] [mask-image:linear-gradient(to_right,transparent,black_8px,black_calc(100%-8px),transparent)] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
1863
|
+
children: items.map((it) => (0, react_jsx_runtime.jsxs)(RouterLink, {
|
|
1864
|
+
href: it.href,
|
|
1865
|
+
"aria-current": it.active ? "page" : void 0,
|
|
1866
|
+
"data-testid": `nav-tab:${it.name}`,
|
|
1867
|
+
className: require_use_theme.cn("group/tab relative flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-t-sm px-3 py-2.5 text-sm outline-hidden ring-offset-background transition-colors duration-150", "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", it.active ? "font-medium text-foreground" : "text-muted-foreground hover:text-foreground"),
|
|
1868
|
+
children: [
|
|
1869
|
+
it.icon != null && (0, react_jsx_runtime.jsx)("span", {
|
|
1870
|
+
className: "inline-flex h-4 w-4 shrink-0 items-center justify-center",
|
|
1871
|
+
"aria-hidden": "true",
|
|
1872
|
+
children: it.icon
|
|
1873
|
+
}),
|
|
1874
|
+
it.label,
|
|
1875
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
1876
|
+
"aria-hidden": "true",
|
|
1877
|
+
className: require_use_theme.cn("pointer-events-none absolute inset-x-2 -bottom-px h-0.5 origin-center scale-x-0 rounded-full bg-primary opacity-0 transition-all duration-300 ease-out", it.active ? "scale-x-100 opacity-100" : "group-hover/tab:scale-x-100 group-hover/tab:opacity-30")
|
|
1878
|
+
})
|
|
1879
|
+
]
|
|
1880
|
+
}, it.name))
|
|
1881
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
1882
|
+
className: "min-w-0",
|
|
1883
|
+
children
|
|
1884
|
+
})]
|
|
1885
|
+
});
|
|
1886
|
+
}
|
|
1887
|
+
//#endregion
|
|
1888
|
+
//#region src/layout/nav-slots.ts
|
|
1889
|
+
function layoutSlot(key) {
|
|
1890
|
+
return `layout.${key}`;
|
|
1891
|
+
}
|
|
1892
|
+
function useLayout(key) {
|
|
1893
|
+
return (0, _burojs_react.useComponent)(layoutSlot(key));
|
|
1894
|
+
}
|
|
1895
|
+
const BUILTIN_LAYOUTS = {
|
|
1896
|
+
[layoutSlot("secondary-sidebar")]: SecondarySidebarLayout,
|
|
1897
|
+
[layoutSlot("tabs")]: TabsLayout
|
|
1898
|
+
};
|
|
1899
|
+
function useLayoutResolver() {
|
|
1900
|
+
const components = (0, react.useContext)(_burojs_react.ComponentsContext);
|
|
1901
|
+
return (key) => components[layoutSlot(key)] ?? BUILTIN_LAYOUTS[layoutSlot(key)];
|
|
1902
|
+
}
|
|
1903
|
+
const unresolvedLayoutReported = new WeakMap();
|
|
1904
|
+
function useReportUnresolvedLayouts(groups, resolve) {
|
|
1905
|
+
const app = (0, _burojs_react.useApp)();
|
|
1906
|
+
(0, react.useEffect)(() => {
|
|
1907
|
+
if (process.env.NODE_ENV === "production") return;
|
|
1908
|
+
for (const group of groups) {
|
|
1909
|
+
const layout = group.layout;
|
|
1910
|
+
if (layout === "flat" || layout === "collapsible" || resolve(layout)) continue;
|
|
1911
|
+
const key = require_record_trail_store.canonicalNavKey(group);
|
|
1912
|
+
let seen = unresolvedLayoutReported.get(app);
|
|
1913
|
+
if (!seen) {
|
|
1914
|
+
seen = new Set();
|
|
1915
|
+
unresolvedLayoutReported.set(app, seen);
|
|
1916
|
+
}
|
|
1917
|
+
if (seen.has(key)) continue;
|
|
1918
|
+
seen.add(key);
|
|
1919
|
+
console.error(`[burojs] Nav group "${key}" declares layout "${layout}", and no renderer is registered for it. Register one as components["layout.${layout}"] on <BuroProvider>, or use a built-in layout: "secondary-sidebar", "tabs", "flat", "collapsible".`);
|
|
1920
|
+
}
|
|
1921
|
+
});
|
|
1922
|
+
}
|
|
1923
|
+
//#endregion
|
|
1924
|
+
//#region src/layout/use-nav-routing.ts
|
|
1925
|
+
function useNavVisible() {
|
|
1926
|
+
const ctx = (0, _burojs_react.useVisibilityCtx)();
|
|
1927
|
+
const allowed = usePageAllowed();
|
|
1928
|
+
return (0, react.useCallback)((node) => (0, _burojs_core.evaluateVisible)(node.visible, ctx) && (!(0, _burojs_core.isCustomPageDef)(node) || allowed(node)), [ctx, allowed]);
|
|
1929
|
+
}
|
|
1930
|
+
function useResourceVisible() {
|
|
1931
|
+
const ctx = (0, _burojs_react.useVisibilityCtx)();
|
|
1932
|
+
return (0, react.useCallback)((def) => (0, _burojs_core.evaluateVisible)(def.visible, ctx), [ctx]);
|
|
1933
|
+
}
|
|
1934
|
+
function usePageAllowed() {
|
|
1935
|
+
const permissions = (0, _burojs_react.usePermissions)();
|
|
1936
|
+
return (0, react.useCallback)((page) => (0, _burojs_react.pageAccessFor)(page, permissions) === "allowed", [permissions]);
|
|
1937
|
+
}
|
|
1938
|
+
function useHref(name, opts) {
|
|
1939
|
+
const app = (0, _burojs_react.useApp)();
|
|
1940
|
+
const isVisible = useNavVisible();
|
|
1941
|
+
return (0, _burojs_core.hrefFor)(app.registry, name, {
|
|
1942
|
+
...opts,
|
|
1943
|
+
isVisible
|
|
1944
|
+
});
|
|
1945
|
+
}
|
|
1946
|
+
function useMatch() {
|
|
1947
|
+
const app = (0, _burojs_react.useApp)();
|
|
1948
|
+
const isVisible = useNavVisible();
|
|
1949
|
+
const path = (0, _burojs_react.useOptionalRouterAdapter)()?.pathname;
|
|
1950
|
+
return path === void 0 ? null : (0, _burojs_core.matchPath)(app.registry, path, { isVisible });
|
|
1951
|
+
}
|
|
1952
|
+
//#endregion
|
|
1727
1953
|
//#region src/layout/use-nav-tree.ts
|
|
1728
1954
|
function isActiveHref(href, currentPath) {
|
|
1729
1955
|
if (!currentPath) return false;
|
|
@@ -1737,18 +1963,18 @@ function useNavTree(opts = {}) {
|
|
|
1737
1963
|
const passesEntryFilter = (entry) => entryFilter ? entryFilter(entry) : true;
|
|
1738
1964
|
const app = (0, _burojs_react.useApp)();
|
|
1739
1965
|
const caps = (0, _burojs_react.useI18nCaps)();
|
|
1740
|
-
const isResourceVisible =
|
|
1741
|
-
const resolveLayout =
|
|
1742
|
-
const match =
|
|
1743
|
-
const isVisible =
|
|
1744
|
-
const pageAllowed =
|
|
1966
|
+
const isResourceVisible = useResourceVisible();
|
|
1967
|
+
const resolveLayout = useLayoutResolver();
|
|
1968
|
+
const match = useMatch();
|
|
1969
|
+
const isVisible = useNavVisible();
|
|
1970
|
+
const pageAllowed = usePageAllowed();
|
|
1745
1971
|
const isNavEligible = (node) => isVisible(node) && passesEntryFilter(node);
|
|
1746
1972
|
const allResources = app.registry.list();
|
|
1747
1973
|
const allCustomPages = app.registry.customPages.list();
|
|
1748
1974
|
const sections = app.registry.sections.list();
|
|
1749
1975
|
const groups = app.registry.groups.rootNodes().filter((n) => (0, _burojs_core.nodeKind)(n) === "group");
|
|
1750
|
-
|
|
1751
|
-
const topLevelResources = allResources.filter((r) => (0, _burojs_core.
|
|
1976
|
+
useReportUnresolvedLayouts(app.registry.groups.list(), resolveLayout);
|
|
1977
|
+
const topLevelResources = allResources.filter((r) => (0, _burojs_core.hasMenuEntry)(r)).filter(isResourceVisible).filter(passesEntryFilter).filter((r) => !r.section && !r.group).map((r, idx) => ({
|
|
1752
1978
|
r,
|
|
1753
1979
|
idx
|
|
1754
1980
|
})).sort((a, b) => {
|
|
@@ -1757,16 +1983,16 @@ function useNavTree(opts = {}) {
|
|
|
1757
1983
|
return ao !== bo ? ao - bo : a.idx - b.idx;
|
|
1758
1984
|
}).map((x) => x.r);
|
|
1759
1985
|
const topLevelCustomPages = allCustomPages.filter((p) => !p.section && !p.group).filter(pageAllowed).filter(passesEntryFilter);
|
|
1760
|
-
const resourceHref = (def) => (0, _burojs_core.hrefFor)(app.registry,
|
|
1761
|
-
const resourceLabel = (def) => (0, _burojs_core.resolveResourceNavLabel)(caps,
|
|
1762
|
-
const pageLabel = (page) => (0, _burojs_core.resolveNavLabel)(caps, `pages.${
|
|
1763
|
-
const sectionLabel = (section) => (0, _burojs_core.resolveNavLabel)(caps, `sections.${
|
|
1764
|
-
const groupLabel = (group) => (0, _burojs_core.resolveNavLabel)(caps, `groups.${
|
|
1986
|
+
const resourceHref = (def) => (0, _burojs_core.hrefFor)(app.registry, require_record_trail_store.canonicalResourceKey(def));
|
|
1987
|
+
const resourceLabel = (def) => (0, _burojs_core.resolveResourceNavLabel)(caps, require_record_trail_store.canonicalResourceKey(def), def);
|
|
1988
|
+
const pageLabel = (page) => (0, _burojs_core.resolveNavLabel)(caps, `pages.${require_record_trail_store.canonicalNavKey(page)}`, (0, _burojs_core.declaredText)("chrome", page, "label"));
|
|
1989
|
+
const sectionLabel = (section) => (0, _burojs_core.resolveNavLabel)(caps, `sections.${require_record_trail_store.canonicalNavKey(section)}`, (0, _burojs_core.declaredText)("chrome", section, "label"));
|
|
1990
|
+
const groupLabel = (group) => (0, _burojs_core.resolveNavLabel)(caps, `groups.${require_record_trail_store.canonicalNavKey(group)}`, (0, _burojs_core.declaredText)("chrome", group, "label"));
|
|
1765
1991
|
const pageEntry = (page) => {
|
|
1766
1992
|
const href = page.path;
|
|
1767
1993
|
return {
|
|
1768
1994
|
kind: "page",
|
|
1769
|
-
key:
|
|
1995
|
+
key: require_record_trail_store.canonicalNavKey(page),
|
|
1770
1996
|
label: pageLabel(page),
|
|
1771
1997
|
href,
|
|
1772
1998
|
icon: page.icon,
|
|
@@ -1777,7 +2003,7 @@ function useNavTree(opts = {}) {
|
|
|
1777
2003
|
const href = resourceHref(def);
|
|
1778
2004
|
return {
|
|
1779
2005
|
kind: "resource",
|
|
1780
|
-
key:
|
|
2006
|
+
key: require_record_trail_store.canonicalResourceKey(def),
|
|
1781
2007
|
label: resourceLabel(def),
|
|
1782
2008
|
href,
|
|
1783
2009
|
icon: def.icon,
|
|
@@ -1785,7 +2011,7 @@ function useNavTree(opts = {}) {
|
|
|
1785
2011
|
};
|
|
1786
2012
|
};
|
|
1787
2013
|
const layoutOf = (group) => resolveLayout(group.layout) ? group.layout : group.collapsible ? "collapsible" : "flat";
|
|
1788
|
-
const groupChildren = (groupKey) =>
|
|
2014
|
+
const groupChildren = (groupKey) => buildNavItems({
|
|
1789
2015
|
registry: app.registry,
|
|
1790
2016
|
caps,
|
|
1791
2017
|
groupName: groupKey,
|
|
@@ -1794,7 +2020,7 @@ function useNavTree(opts = {}) {
|
|
|
1794
2020
|
entryFilter
|
|
1795
2021
|
}).map(itemEntry);
|
|
1796
2022
|
const groupEntry = (group, label, href, active) => {
|
|
1797
|
-
const key =
|
|
2023
|
+
const key = require_record_trail_store.canonicalNavKey(group);
|
|
1798
2024
|
return {
|
|
1799
2025
|
kind: "group",
|
|
1800
2026
|
key,
|
|
@@ -1832,8 +2058,8 @@ function useNavTree(opts = {}) {
|
|
|
1832
2058
|
entries: topEntries
|
|
1833
2059
|
}];
|
|
1834
2060
|
for (const section of sections) {
|
|
1835
|
-
const sectionKey =
|
|
1836
|
-
const entries = app.registry.sections.childrenOf(sectionKey).filter((c) => !("parent" in c) || (0, _burojs_core.
|
|
2061
|
+
const sectionKey = require_record_trail_store.canonicalNavKey(section);
|
|
2062
|
+
const entries = app.registry.sections.childrenOf(sectionKey).filter((c) => !("parent" in c) || (0, _burojs_core.hasMenuEntry)(c)).filter((c) => (0, _burojs_core.isCustomPageDef)(c) ? pageAllowed(c) : isResourceVisible(c)).filter(passesEntryFilter).map((c) => (0, _burojs_core.isCustomPageDef)(c) ? pageEntry(c) : resourceEntry(c));
|
|
1837
2063
|
if (entries.length === 0) continue;
|
|
1838
2064
|
const active = entries.some((e) => e.active);
|
|
1839
2065
|
out.push({
|
|
@@ -1847,11 +2073,11 @@ function useNavTree(opts = {}) {
|
|
|
1847
2073
|
});
|
|
1848
2074
|
}
|
|
1849
2075
|
for (const group of groups) {
|
|
1850
|
-
const groupKey =
|
|
2076
|
+
const groupKey = require_record_trail_store.canonicalNavKey(group);
|
|
1851
2077
|
if (!isNavEligible(group)) continue;
|
|
1852
2078
|
const gLabel = groupLabel(group);
|
|
1853
2079
|
if (resolveLayout(group.layout)) {
|
|
1854
|
-
const href =
|
|
2080
|
+
const href = groupNavHref(app.registry, groupKey, isNavEligible);
|
|
1855
2081
|
if (href === void 0) continue;
|
|
1856
2082
|
const entry = groupEntry(group, gLabel, href, isActiveHref(href, currentPath));
|
|
1857
2083
|
out.push({
|
|
@@ -2047,6 +2273,13 @@ function AppSidebar({ header, filters, nav, footer }) {
|
|
|
2047
2273
|
});
|
|
2048
2274
|
}
|
|
2049
2275
|
//#endregion
|
|
2276
|
+
//#region src/layout/nav-chrome-mounted.ts
|
|
2277
|
+
const NavChromeMountedContext = (0, react.createContext)(false);
|
|
2278
|
+
const NavChromeMountedProvider = NavChromeMountedContext.Provider;
|
|
2279
|
+
function useNavChromeMounted() {
|
|
2280
|
+
return (0, react.useContext)(NavChromeMountedContext);
|
|
2281
|
+
}
|
|
2282
|
+
//#endregion
|
|
2050
2283
|
//#region src/layout/nav-chrome.tsx
|
|
2051
2284
|
const DETAIL_ACTIONS = new Set([
|
|
2052
2285
|
"show",
|
|
@@ -2056,11 +2289,11 @@ const DETAIL_ACTIONS = new Set([
|
|
|
2056
2289
|
function NavChrome({ children, entryFilter, icons }) {
|
|
2057
2290
|
const app = (0, _burojs_react.useApp)();
|
|
2058
2291
|
const caps = (0, _burojs_react.useI18nCaps)();
|
|
2059
|
-
const isVisible =
|
|
2060
|
-
const match =
|
|
2061
|
-
const resolveLayout =
|
|
2062
|
-
|
|
2063
|
-
if (!match) return (0, react_jsx_runtime.jsx)(
|
|
2292
|
+
const isVisible = useNavVisible();
|
|
2293
|
+
const match = useMatch();
|
|
2294
|
+
const resolveLayout = useLayoutResolver();
|
|
2295
|
+
useReportUnresolvedLayouts(match?.groupChain ?? [], resolveLayout);
|
|
2296
|
+
if (!match) return (0, react_jsx_runtime.jsx)(NavChromeMountedProvider, {
|
|
2064
2297
|
value: true,
|
|
2065
2298
|
children
|
|
2066
2299
|
});
|
|
@@ -2068,11 +2301,11 @@ function NavChrome({ children, entryFilter, icons }) {
|
|
|
2068
2301
|
for (let i = match.groupChain.length - 1; i >= 0; i--) {
|
|
2069
2302
|
const group = match.groupChain[i];
|
|
2070
2303
|
if (!group) continue;
|
|
2071
|
-
const groupKey =
|
|
2304
|
+
const groupKey = require_record_trail_store.canonicalNavKey(group);
|
|
2072
2305
|
if (group.chromeOn === "list" && match.kind === "resource" && DETAIL_ACTIONS.has(match.action)) continue;
|
|
2073
2306
|
const Layout = resolveLayout(group.layout);
|
|
2074
2307
|
if (!Layout) continue;
|
|
2075
|
-
const items =
|
|
2308
|
+
const items = buildNavItems({
|
|
2076
2309
|
registry: app.registry,
|
|
2077
2310
|
caps,
|
|
2078
2311
|
groupName: groupKey,
|
|
@@ -2088,12 +2321,1847 @@ function NavChrome({ children, entryFilter, icons }) {
|
|
|
2088
2321
|
children: content
|
|
2089
2322
|
});
|
|
2090
2323
|
}
|
|
2091
|
-
return (0, react_jsx_runtime.jsx)(
|
|
2324
|
+
return (0, react_jsx_runtime.jsx)(NavChromeMountedProvider, {
|
|
2092
2325
|
value: true,
|
|
2093
2326
|
children: content
|
|
2094
2327
|
});
|
|
2095
2328
|
}
|
|
2096
2329
|
//#endregion
|
|
2330
|
+
//#region src/flows/page-flow-loader.tsx
|
|
2331
|
+
function PageFlowRouteLoader({ match }) {
|
|
2332
|
+
const t = (0, _burojs_react.useOptionalT)();
|
|
2333
|
+
const chromeT = (0, _burojs_react.useChromeT)();
|
|
2334
|
+
const loaded = require_check_confirm_dialog.useLoaded(require_check_confirm_dialog.loadPageFlowRoute);
|
|
2335
|
+
const failed = (retry) => (0, react_jsx_runtime.jsxs)("div", {
|
|
2336
|
+
role: "alert",
|
|
2337
|
+
"data-buro-flow-load": "failed",
|
|
2338
|
+
className: "flex flex-col gap-3 p-6 text-sm",
|
|
2339
|
+
children: [(0, react_jsx_runtime.jsx)("p", { children: require_check_confirm_dialog.loadFailedText(t) }), (0, react_jsx_runtime.jsx)("div", { children: (0, react_jsx_runtime.jsx)(require_button.Button, {
|
|
2340
|
+
type: "button",
|
|
2341
|
+
onClick: retry,
|
|
2342
|
+
children: chromeT("actions.retry", { defaultValue: "Retry" })
|
|
2343
|
+
}) })]
|
|
2344
|
+
});
|
|
2345
|
+
if (loaded.error !== void 0) return failed(loaded.retry);
|
|
2346
|
+
if (loaded.module === void 0) return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "loading" });
|
|
2347
|
+
const Route = loaded.module.PageFlowRoute;
|
|
2348
|
+
return (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.FlowBoundary, {
|
|
2349
|
+
fallback: (_error, reset) => failed(reset),
|
|
2350
|
+
children: (0, react_jsx_runtime.jsx)(Route, { match })
|
|
2351
|
+
});
|
|
2352
|
+
}
|
|
2353
|
+
//#endregion
|
|
2354
|
+
//#region src/list-kit/resource-list-page.tsx
|
|
2355
|
+
function ResourceListPage({ resource: resourceInput, meta, renderCell, emptyState }) {
|
|
2356
|
+
const resource = (0, _burojs_core.routeResourceKey)(resourceInput);
|
|
2357
|
+
const app = (0, _burojs_react.useRouteListImplementation)();
|
|
2358
|
+
const implementation = require_place_node.selectImplementation("buro:related-list", app);
|
|
2359
|
+
const View = implementation === void 0 ? void 0 : require_place_node.viewOf(implementation);
|
|
2360
|
+
const translate = (0, _burojs_react.useTranslate)();
|
|
2361
|
+
const route = (0, react.useMemo)(() => ({
|
|
2362
|
+
meta,
|
|
2363
|
+
renderCell,
|
|
2364
|
+
emptyState
|
|
2365
|
+
}), [
|
|
2366
|
+
meta,
|
|
2367
|
+
renderCell,
|
|
2368
|
+
emptyState
|
|
2369
|
+
]);
|
|
2370
|
+
const viewProps = (0, react.useMemo)(() => ({
|
|
2371
|
+
props: { resource: (0, _burojs_core.normalizeEntityRef)(resource) },
|
|
2372
|
+
data: {},
|
|
2373
|
+
t: (key, options) => translate(`blocks.buro:related-list.${key}`, options)
|
|
2374
|
+
}), [resource, translate]);
|
|
2375
|
+
return (0, react_jsx_runtime.jsx)("div", {
|
|
2376
|
+
"data-buro-node": "place",
|
|
2377
|
+
"data-buro-size": "full",
|
|
2378
|
+
className: "min-w-0",
|
|
2379
|
+
children: (0, react_jsx_runtime.jsx)(require_place_node.RouteListContext.Provider, {
|
|
2380
|
+
value: route,
|
|
2381
|
+
children: (0, react_jsx_runtime.jsx)(react.Suspense, {
|
|
2382
|
+
fallback: null,
|
|
2383
|
+
children: View === void 0 ? null : (0, react_jsx_runtime.jsx)(View, { ...viewProps })
|
|
2384
|
+
})
|
|
2385
|
+
})
|
|
2386
|
+
});
|
|
2387
|
+
}
|
|
2388
|
+
//#endregion
|
|
2389
|
+
//#region src/resource/collection-create-picker.tsx
|
|
2390
|
+
function CollectionCreatePicker({ collection }) {
|
|
2391
|
+
const app = (0, _burojs_react.useApp)();
|
|
2392
|
+
const t = (0, _burojs_react.useOptionalT)();
|
|
2393
|
+
const caps = (0, _burojs_react.useI18nCaps)();
|
|
2394
|
+
const gate = (0, _burojs_react.useAvailabilityGate)("create");
|
|
2395
|
+
const Link = require_toaster.useLinkComponent();
|
|
2396
|
+
const key = (0, _burojs_core.routeResourceKey)(collection);
|
|
2397
|
+
const testid = `collection-create-picker:${key}`;
|
|
2398
|
+
let undecided = false;
|
|
2399
|
+
const members = ((0, _burojs_core.collectionFactOf)(app.registry.get(key))?.members ?? []).flatMap((entry) => {
|
|
2400
|
+
const def = app.registry.get(entry.ref);
|
|
2401
|
+
if (def === void 0 || !(0, _burojs_core.hasRecordPage)(def, "create")) return [];
|
|
2402
|
+
const member = (0, _burojs_core.routeResourceKey)(entry.ref);
|
|
2403
|
+
const state = gate(member, "create").state;
|
|
2404
|
+
if (state === "undecided") undecided = true;
|
|
2405
|
+
if (state !== "available") return [];
|
|
2406
|
+
return [{
|
|
2407
|
+
member,
|
|
2408
|
+
href: (0, _burojs_core.resourceCreateHref)(app.registry, def, member),
|
|
2409
|
+
label: (0, _burojs_core.resolveResourceLabel)(caps, member, "single", def)
|
|
2410
|
+
}];
|
|
2411
|
+
});
|
|
2412
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
2413
|
+
"data-testid": testid,
|
|
2414
|
+
className: "mx-auto flex max-w-md flex-col gap-3 px-6 py-12",
|
|
2415
|
+
children: [(0, react_jsx_runtime.jsx)("h2", {
|
|
2416
|
+
className: "text-base font-semibold tracking-tight",
|
|
2417
|
+
children: t("collection.createTitle", { defaultValue: "What do you want to create?" })
|
|
2418
|
+
}), members.length > 0 ? (0, react_jsx_runtime.jsx)("ul", {
|
|
2419
|
+
className: "flex flex-col gap-2",
|
|
2420
|
+
children: members.map((entry) => (0, react_jsx_runtime.jsx)("li", { children: (0, react_jsx_runtime.jsx)(require_button.Button, {
|
|
2421
|
+
asChild: true,
|
|
2422
|
+
variant: "outline",
|
|
2423
|
+
className: "w-full justify-start",
|
|
2424
|
+
"data-testid": `${testid}:${entry.member}`,
|
|
2425
|
+
children: (0, react_jsx_runtime.jsxs)(Link, {
|
|
2426
|
+
href: entry.href,
|
|
2427
|
+
children: [(0, react_jsx_runtime.jsx)(require_check_confirm_dialog.Icon, {
|
|
2428
|
+
name: "Plus",
|
|
2429
|
+
className: "mr-1 h-4 w-4"
|
|
2430
|
+
}), entry.label]
|
|
2431
|
+
})
|
|
2432
|
+
}) }, entry.member))
|
|
2433
|
+
}) : undecided ? (0, react_jsx_runtime.jsx)("div", {
|
|
2434
|
+
role: "status",
|
|
2435
|
+
"aria-busy": "true",
|
|
2436
|
+
className: "h-9 w-full animate-pulse rounded bg-muted/40"
|
|
2437
|
+
}) : (0, react_jsx_runtime.jsx)("p", {
|
|
2438
|
+
className: "text-sm text-muted-foreground",
|
|
2439
|
+
children: t("collection.createNone", { defaultValue: "There is nothing here you can create." })
|
|
2440
|
+
})]
|
|
2441
|
+
});
|
|
2442
|
+
}
|
|
2443
|
+
//#endregion
|
|
2444
|
+
//#region src/frames/obligations.tsx
|
|
2445
|
+
const SlotMountsContext = (0, react.createContext)(null);
|
|
2446
|
+
function useSlotOnce(slot) {
|
|
2447
|
+
const mounts = (0, react.useContext)(SlotMountsContext);
|
|
2448
|
+
const token = (0, react.useId)();
|
|
2449
|
+
const first = mounts === null || mounts.claim(slot, token);
|
|
2450
|
+
(0, react.useEffect)(() => {
|
|
2451
|
+
if (mounts === null) return;
|
|
2452
|
+
mounts.claim(slot, token);
|
|
2453
|
+
return () => mounts.release(slot, token);
|
|
2454
|
+
}, [
|
|
2455
|
+
mounts,
|
|
2456
|
+
slot,
|
|
2457
|
+
token
|
|
2458
|
+
]);
|
|
2459
|
+
(0, react.useEffect)(() => {
|
|
2460
|
+
if (!first) mounts?.twice(slot);
|
|
2461
|
+
}, [
|
|
2462
|
+
first,
|
|
2463
|
+
mounts,
|
|
2464
|
+
slot
|
|
2465
|
+
]);
|
|
2466
|
+
return first;
|
|
2467
|
+
}
|
|
2468
|
+
function FrameObligations({ id, mode, showActions, root, children }) {
|
|
2469
|
+
const told = (0, react.useRef)(new Set());
|
|
2470
|
+
const counts = (0, react.useRef)(new Map());
|
|
2471
|
+
const owners = (0, react.useRef)(new Map());
|
|
2472
|
+
const tell = (key, write) => {
|
|
2473
|
+
if (told.current.has(key) || process.env.NODE_ENV === "production") return;
|
|
2474
|
+
told.current.add(key);
|
|
2475
|
+
write();
|
|
2476
|
+
};
|
|
2477
|
+
const latestId = (0, react.useRef)(id);
|
|
2478
|
+
latestId.current = id;
|
|
2479
|
+
const slotMounts = (0, react.useMemo)(() => ({
|
|
2480
|
+
claim(slot, token) {
|
|
2481
|
+
const owner = owners.current.get(slot);
|
|
2482
|
+
if (owner === void 0) {
|
|
2483
|
+
owners.current.set(slot, token);
|
|
2484
|
+
return true;
|
|
2485
|
+
}
|
|
2486
|
+
return owner === token;
|
|
2487
|
+
},
|
|
2488
|
+
release(slot, token) {
|
|
2489
|
+
if (owners.current.get(slot) === token) owners.current.delete(slot);
|
|
2490
|
+
},
|
|
2491
|
+
twice(slot) {
|
|
2492
|
+
tell(`slot-twice:${slot}`, () => console.error(`[burojs] frame.slot-twice: ${latestId.current} renders slots.${slot} twice; a slot renders at most once (body twice would mount every field twice under one form).`));
|
|
2493
|
+
}
|
|
2494
|
+
}), []);
|
|
2495
|
+
const pieces = (0, react.useMemo)(() => ({
|
|
2496
|
+
stub: false,
|
|
2497
|
+
mount(piece) {
|
|
2498
|
+
counts.current.set(piece, (counts.current.get(piece) ?? 0) + 1);
|
|
2499
|
+
return () => counts.current.set(piece, (counts.current.get(piece) ?? 1) - 1);
|
|
2500
|
+
}
|
|
2501
|
+
}), []);
|
|
2502
|
+
return (0, react_jsx_runtime.jsx)(SlotMountsContext.Provider, {
|
|
2503
|
+
value: slotMounts,
|
|
2504
|
+
children: (0, react_jsx_runtime.jsxs)(_burojs_react.FrameCheckContext.Provider, {
|
|
2505
|
+
value: pieces,
|
|
2506
|
+
children: [children, (0, react_jsx_runtime.jsx)(ObligationCheck, { check: () => {
|
|
2507
|
+
const mounted = (piece) => (counts.current.get(piece) ?? 0) > 0;
|
|
2508
|
+
if (mode !== "show" && !mounted("FormActions")) tell("no-form-actions", () => console.error(`[burojs] frame.no-form-actions: ${id} renders no <FormActions/> in ${mode}; nothing can submit or cancel the form.`));
|
|
2509
|
+
if (mode === "show" && showActions && !mounted("RecordActions")) tell("no-actions", () => console.warn(`[burojs] screen.no-actions: ${id} renders no <RecordActions/> in show, and the resource has item actions there.`));
|
|
2510
|
+
if (root.current?.querySelector("h1") != null) tell("h1", () => console.error(`[burojs] ${id} renders an h1; the route draws the screen's one h1.`));
|
|
2511
|
+
} })]
|
|
2512
|
+
})
|
|
2513
|
+
});
|
|
2514
|
+
}
|
|
2515
|
+
function ObligationCheck({ check }) {
|
|
2516
|
+
(0, react.useEffect)(() => {
|
|
2517
|
+
check();
|
|
2518
|
+
});
|
|
2519
|
+
return null;
|
|
2520
|
+
}
|
|
2521
|
+
//#endregion
|
|
2522
|
+
//#region src/frames/slot-wrapper.tsx
|
|
2523
|
+
function DraftBanner() {
|
|
2524
|
+
const { resource, mode, controller } = (0, _burojs_react.useRecordFrame)();
|
|
2525
|
+
const t = (0, _burojs_react.useOptionalT)();
|
|
2526
|
+
const tid = (0, _burojs_react.useTestIds)();
|
|
2527
|
+
const { draft } = controller;
|
|
2528
|
+
if (mode === "show" || draft.pending === null) return null;
|
|
2529
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
2530
|
+
"data-testid": tid.formDraftBanner(resource, mode),
|
|
2531
|
+
role: "status",
|
|
2532
|
+
"aria-live": "polite",
|
|
2533
|
+
className: "flex flex-wrap items-center gap-2 rounded-md border border-warning/50 bg-warning/10 px-3 py-2 text-sm",
|
|
2534
|
+
children: [
|
|
2535
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
2536
|
+
className: "font-medium",
|
|
2537
|
+
children: draft.recordChanged ? t("draft.recordChanged") : t("draft.found", { params: { time: timeAgo(draft.pending.savedAt, t) } })
|
|
2538
|
+
}),
|
|
2539
|
+
draft.recordChanged ? null : (0, react_jsx_runtime.jsx)("span", {
|
|
2540
|
+
className: "text-muted-foreground",
|
|
2541
|
+
children: t("draft.restorePrompt")
|
|
2542
|
+
}),
|
|
2543
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
2544
|
+
className: "ml-auto flex gap-2",
|
|
2545
|
+
children: [draft.recordChanged ? null : (0, react_jsx_runtime.jsx)(require_button.Button, {
|
|
2546
|
+
type: "button",
|
|
2547
|
+
size: "sm",
|
|
2548
|
+
variant: "outline",
|
|
2549
|
+
"data-testid": tid.formDraftRestore(resource, mode),
|
|
2550
|
+
onClick: draft.restore,
|
|
2551
|
+
children: t("draft.restore")
|
|
2552
|
+
}), (0, react_jsx_runtime.jsx)(require_button.Button, {
|
|
2553
|
+
type: "button",
|
|
2554
|
+
size: "sm",
|
|
2555
|
+
variant: "ghost",
|
|
2556
|
+
"data-testid": tid.formDraftDiscard(resource, mode),
|
|
2557
|
+
onClick: draft.discard,
|
|
2558
|
+
children: t("draft.discard")
|
|
2559
|
+
})]
|
|
2560
|
+
})
|
|
2561
|
+
]
|
|
2562
|
+
});
|
|
2563
|
+
}
|
|
2564
|
+
function timeAgo(savedAt, t) {
|
|
2565
|
+
const then = new Date(savedAt).getTime();
|
|
2566
|
+
if (!Number.isFinite(then)) return t("draft.timeAgoRecently");
|
|
2567
|
+
const diff = Date.now() - then;
|
|
2568
|
+
if (diff < 6e4) return t("draft.timeAgoMoment");
|
|
2569
|
+
if (diff < 36e5) return t("draft.timeAgoMinutes", { count: Math.round(diff / 6e4) });
|
|
2570
|
+
if (diff < 864e5) return t("draft.timeAgoHours", { count: Math.round(diff / 36e5) });
|
|
2571
|
+
return t("draft.timeAgoDays", { count: Math.round(diff / 864e5) });
|
|
2572
|
+
}
|
|
2573
|
+
function frameRecordId(frame, def) {
|
|
2574
|
+
if (frame.recordId !== void 0) return frame.recordId;
|
|
2575
|
+
const id = (0, _burojs_react.recordKeyOf)(def, frame.record);
|
|
2576
|
+
return typeof id === "string" || typeof id === "number" ? String(id) : void 0;
|
|
2577
|
+
}
|
|
2578
|
+
function BodySlot() {
|
|
2579
|
+
const frame = (0, _burojs_react.useRecordFrame)();
|
|
2580
|
+
const { resource, mode, controller } = frame;
|
|
2581
|
+
const chrome = require_place_node.useFrameChrome();
|
|
2582
|
+
const tid = (0, _burojs_react.useTestIds)();
|
|
2583
|
+
const id = frameRecordId(frame, (0, _burojs_react.useApp)().registry.get(resource));
|
|
2584
|
+
const tree = (0, react_jsx_runtime.jsx)("div", {
|
|
2585
|
+
"data-buro-region": "record-body",
|
|
2586
|
+
"data-buro-slot": _burojs_core.FORM_SLOT,
|
|
2587
|
+
children: (0, react_jsx_runtime.jsx)(require_place_node.ScreenTree, {
|
|
2588
|
+
region: "record",
|
|
2589
|
+
slot: _burojs_core.FORM_SLOT,
|
|
2590
|
+
resource,
|
|
2591
|
+
mode,
|
|
2592
|
+
compiled: controller.screen,
|
|
2593
|
+
controller
|
|
2594
|
+
})
|
|
2595
|
+
});
|
|
2596
|
+
if (mode === "show") return tree;
|
|
2597
|
+
return (0, react_jsx_runtime.jsxs)("form", {
|
|
2598
|
+
id: chrome.formId,
|
|
2599
|
+
noValidate: true,
|
|
2600
|
+
"data-testid": tid.form(resource, mode, id),
|
|
2601
|
+
onSubmit: (event) => {
|
|
2602
|
+
event.preventDefault();
|
|
2603
|
+
const steps = controller.steps;
|
|
2604
|
+
if (steps !== null && steps.current !== void 0 && steps.current !== steps.ids[steps.ids.length - 1]) steps.next();
|
|
2605
|
+
else chrome.submit();
|
|
2606
|
+
},
|
|
2607
|
+
className: "flex flex-col gap-4",
|
|
2608
|
+
children: [(0, react_jsx_runtime.jsx)(DraftBanner, {}), tree]
|
|
2609
|
+
});
|
|
2610
|
+
}
|
|
2611
|
+
function DisplaySlot({ name }) {
|
|
2612
|
+
const { resource, mode, controller } = (0, _burojs_react.useRecordFrame)();
|
|
2613
|
+
return (0, react_jsx_runtime.jsx)(require_place_node.ScreenTree, {
|
|
2614
|
+
region: "record",
|
|
2615
|
+
slot: name,
|
|
2616
|
+
resource,
|
|
2617
|
+
mode,
|
|
2618
|
+
compiled: controller.screen,
|
|
2619
|
+
controller
|
|
2620
|
+
});
|
|
2621
|
+
}
|
|
2622
|
+
function SlotWrapper({ name }) {
|
|
2623
|
+
if (!useSlotOnce(name)) return null;
|
|
2624
|
+
return name === _burojs_core.FORM_SLOT ? (0, react_jsx_runtime.jsx)(BodySlot, {}) : (0, react_jsx_runtime.jsx)(DisplaySlot, { name });
|
|
2625
|
+
}
|
|
2626
|
+
//#endregion
|
|
2627
|
+
//#region src/frames/record-frame-host.tsx
|
|
2628
|
+
const NO_ROOT = { current: null };
|
|
2629
|
+
function drawnFields(roots, compiled, out) {
|
|
2630
|
+
for (const node of roots) {
|
|
2631
|
+
if (node.state === "absent") continue;
|
|
2632
|
+
const field = node.field ?? compiled.nodes[node.index]?.field;
|
|
2633
|
+
if (node.kind === "field" && field !== void 0 && node.state === "ready") out.add(field);
|
|
2634
|
+
drawnFields(node.children, compiled, out);
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2637
|
+
function frameRecord(record, compiled, slots, idField, visible = () => true) {
|
|
2638
|
+
if (record === void 0 || compiled === null || slots === void 0) return void 0;
|
|
2639
|
+
const drawn = new Set();
|
|
2640
|
+
for (const roots of Object.values(slots)) drawnFields(roots, compiled, drawn);
|
|
2641
|
+
const declarations = new Map(compiled.fields.map((entry) => [entry.name, entry.declaration]));
|
|
2642
|
+
const out = {};
|
|
2643
|
+
if (Object.hasOwn(record, idField)) out[idField] = record[idField];
|
|
2644
|
+
for (const name of drawn) {
|
|
2645
|
+
if (!Object.hasOwn(record, name) || !visible(name)) continue;
|
|
2646
|
+
if ((0, _burojs_core.fieldSensitivity)(declarations.get(name)) !== void 0) continue;
|
|
2647
|
+
out[name] = record[name];
|
|
2648
|
+
}
|
|
2649
|
+
return Object.freeze(out);
|
|
2650
|
+
}
|
|
2651
|
+
function declaredSlots(compiled) {
|
|
2652
|
+
if (compiled === null) return [];
|
|
2653
|
+
return Object.entries(compiled.slots).filter(([, nodes]) => nodes.length > 0).map(([name]) => name);
|
|
2654
|
+
}
|
|
2655
|
+
function useEffectiveFrame(instance) {
|
|
2656
|
+
const { resource, mode, controller } = (0, _burojs_react.useRecordFrame)();
|
|
2657
|
+
const compiled = controller.screen;
|
|
2658
|
+
const missing = (0, react.useMemo)(() => {
|
|
2659
|
+
if (instance === void 0 || instance.for !== "record") return void 0;
|
|
2660
|
+
const own = new Set(Object.keys(instance.slots));
|
|
2661
|
+
return declaredSlots(compiled).find((slot) => !own.has(slot));
|
|
2662
|
+
}, [instance, compiled]);
|
|
2663
|
+
const told = (0, react.useRef)(false);
|
|
2664
|
+
const instanceId = instance === void 0 ? void 0 : (0, _burojs_core.formatEntityRef)(instance.ref);
|
|
2665
|
+
(0, react.useEffect)(() => {
|
|
2666
|
+
if (missing === void 0 || told.current || process.env.NODE_ENV === "production") return;
|
|
2667
|
+
told.current = true;
|
|
2668
|
+
console.error(`[burojs] <RecordScreen frame={${instanceId}}> lacks the slot ${missing} that ${resource}'s ${mode} screen fills; the screen's own frame draws it.`);
|
|
2669
|
+
}, [
|
|
2670
|
+
missing,
|
|
2671
|
+
instanceId,
|
|
2672
|
+
resource,
|
|
2673
|
+
mode
|
|
2674
|
+
]);
|
|
2675
|
+
if (instance !== void 0 && instance.for === "record" && missing === void 0 && compiled !== null) return {
|
|
2676
|
+
ref: instance.ref,
|
|
2677
|
+
slotNames: Object.keys(instance.slots)
|
|
2678
|
+
};
|
|
2679
|
+
return {
|
|
2680
|
+
ref: compiled?.frame ?? _burojs_core.builtinFrames.record.ref,
|
|
2681
|
+
slotNames: compiled === null ? ["header", _burojs_core.FORM_SLOT] : Object.keys(compiled.slots)
|
|
2682
|
+
};
|
|
2683
|
+
}
|
|
2684
|
+
function RecordFrameView({ frame: instance }) {
|
|
2685
|
+
const { resource, mode, controller, record } = (0, _burojs_react.useRecordFrame)();
|
|
2686
|
+
const chrome = require_place_node.useFrameChrome();
|
|
2687
|
+
const quick = (0, _burojs_react.useQuickEntry)();
|
|
2688
|
+
const app = (0, _burojs_react.useApp)();
|
|
2689
|
+
const catalog = (0, _burojs_react.useFrameImplementations)();
|
|
2690
|
+
const { ref, slotNames } = useEffectiveFrame(instance);
|
|
2691
|
+
const id = (0, _burojs_core.formatEntityRef)(ref);
|
|
2692
|
+
const resolved = (0, react.useMemo)(() => require_place_node.resolveFrameView(ref, catalog, "record"), [ref, catalog]);
|
|
2693
|
+
const t = (0, _burojs_react.useFrameT)(id);
|
|
2694
|
+
const compiled = controller.screen;
|
|
2695
|
+
const plan = controller.plan;
|
|
2696
|
+
const slots = {};
|
|
2697
|
+
for (const name of slotNames) {
|
|
2698
|
+
if (name === _burojs_core.FORM_SLOT) {
|
|
2699
|
+
slots[name] = (0, react_jsx_runtime.jsx)(SlotWrapper, { name }, name);
|
|
2700
|
+
continue;
|
|
2701
|
+
}
|
|
2702
|
+
slots[name] = (plan?.slots[name] ?? []).every((node) => node.state === "absent") ? null : (0, react_jsx_runtime.jsx)(SlotWrapper, { name }, name);
|
|
2703
|
+
}
|
|
2704
|
+
slots[_burojs_core.FORM_SLOT] ??= (0, react_jsx_runtime.jsx)(SlotWrapper, { name: _burojs_core.FORM_SLOT });
|
|
2705
|
+
const idField = app.registry.get(resource)?.data?.idField ?? "id";
|
|
2706
|
+
const access = (0, _burojs_react.useFieldAccess)(resource, "record", record === void 0 ? void 0 : (0, _burojs_react.policyRecordOf)(controller, record));
|
|
2707
|
+
const projected = (0, react.useMemo)(() => frameRecord(record, compiled, plan?.slots, idField, (name) => access[name]?.view === "visible"), [
|
|
2708
|
+
record,
|
|
2709
|
+
compiled,
|
|
2710
|
+
plan,
|
|
2711
|
+
idField,
|
|
2712
|
+
access
|
|
2713
|
+
]);
|
|
2714
|
+
const quickHost = chrome.hostTitle === true && quick !== null;
|
|
2715
|
+
const props = {
|
|
2716
|
+
slots,
|
|
2717
|
+
host: quickHost ? quick.host : "page",
|
|
2718
|
+
mode,
|
|
2719
|
+
screen: {
|
|
2720
|
+
resource,
|
|
2721
|
+
entry: quickHost ? "quick" : "route"
|
|
2722
|
+
},
|
|
2723
|
+
record: mode === "create" ? void 0 : projected,
|
|
2724
|
+
t
|
|
2725
|
+
};
|
|
2726
|
+
const policyRecord = (0, _burojs_react.policyRecordOf)(controller, record);
|
|
2727
|
+
const rowId = record?.[idField];
|
|
2728
|
+
const actionRow = (0, react.useMemo)(() => ({
|
|
2729
|
+
...policyRecord ?? {},
|
|
2730
|
+
id: typeof rowId === "string" || typeof rowId === "number" ? String(rowId) : ""
|
|
2731
|
+
}), [policyRecord, rowId]);
|
|
2732
|
+
const showItemActions = require_place_node.useShownItemActions(resource, actionRow, "show", void 0, controller.sources);
|
|
2733
|
+
const showActions = mode === "show" && record !== void 0 && showItemActions.length > 0;
|
|
2734
|
+
const View = resolved.view;
|
|
2735
|
+
const builtin = require_place_node.isBuiltinRecordView(resolved);
|
|
2736
|
+
return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [builtin ? null : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(require_place_node.HeaderTypeNotice, { resource }), (0, react_jsx_runtime.jsx)(require_place_node.ChangeTypeButton, {})] }), (0, react_jsx_runtime.jsx)(require_place_node.TypeChromeDrawnContext.Provider, {
|
|
2737
|
+
value: !builtin,
|
|
2738
|
+
children: (0, react_jsx_runtime.jsx)(react.Suspense, {
|
|
2739
|
+
fallback: (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "loading" }),
|
|
2740
|
+
children: (0, react_jsx_runtime.jsx)(FrameObligations, {
|
|
2741
|
+
id,
|
|
2742
|
+
mode,
|
|
2743
|
+
showActions,
|
|
2744
|
+
root: chrome.root ?? NO_ROOT,
|
|
2745
|
+
children: (0, react_jsx_runtime.jsx)(View, { ...props })
|
|
2746
|
+
})
|
|
2747
|
+
})
|
|
2748
|
+
})] });
|
|
2749
|
+
}
|
|
2750
|
+
function useResourceDimensionOptions(dimension, resource, labelField) {
|
|
2751
|
+
const def = (0, _burojs_react.useApp)().registry.get(resource);
|
|
2752
|
+
const rowTitle = require_relation_create.useRowTitle(resource, labelField ?? def?.displayField);
|
|
2753
|
+
const rows = (0, _burojs_react.useList)(resource, {
|
|
2754
|
+
pagination: {
|
|
2755
|
+
kind: "offset",
|
|
2756
|
+
page: 1,
|
|
2757
|
+
pageSize: 100
|
|
2758
|
+
},
|
|
2759
|
+
total: false,
|
|
2760
|
+
scope: {
|
|
2761
|
+
default: "session",
|
|
2762
|
+
dimensions: { [dimension]: "none" }
|
|
2763
|
+
}
|
|
2764
|
+
}).data?.data;
|
|
2765
|
+
return (0, react.useMemo)(() => (rows ?? []).flatMap((row) => {
|
|
2766
|
+
const key = (0, _burojs_react.recordKeyOf)(def, row);
|
|
2767
|
+
return key === null || key === void 0 ? [] : [{
|
|
2768
|
+
value: key,
|
|
2769
|
+
label: rowTitle(row)
|
|
2770
|
+
}];
|
|
2771
|
+
}), [
|
|
2772
|
+
rows,
|
|
2773
|
+
def,
|
|
2774
|
+
rowTitle
|
|
2775
|
+
]);
|
|
2776
|
+
}
|
|
2777
|
+
//#endregion
|
|
2778
|
+
//#region src/record/scope-mismatch-banner.tsx
|
|
2779
|
+
const asList = (value) => value === null ? [] : Array.isArray(value) ? value : [value];
|
|
2780
|
+
const isScalar = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
2781
|
+
function ScopeMismatchBanner(props) {
|
|
2782
|
+
const app = (0, _burojs_react.useApp)();
|
|
2783
|
+
const mapping = app.registry.get(props.resource)?.data?.scope;
|
|
2784
|
+
if (app.scope === void 0 || mapping === void 0 || props.record === void 0) return null;
|
|
2785
|
+
return (0, react_jsx_runtime.jsx)(Banner, {
|
|
2786
|
+
...props,
|
|
2787
|
+
record: props.record,
|
|
2788
|
+
mapping
|
|
2789
|
+
});
|
|
2790
|
+
}
|
|
2791
|
+
function Banner({ record, mapping, kind = "record" }) {
|
|
2792
|
+
const scope = (0, _burojs_react.useScope)();
|
|
2793
|
+
const chromeT = (0, _burojs_react.useChromeT)();
|
|
2794
|
+
const differences = (0, react.useMemo)(() => {
|
|
2795
|
+
const out = [];
|
|
2796
|
+
for (const [dimension, target] of Object.entries(mapping)) {
|
|
2797
|
+
const definition = scope.definition?.dimensions[dimension];
|
|
2798
|
+
if (definition === void 0 || definition.select === "none") continue;
|
|
2799
|
+
const selected = asList(scope.selection[dimension] ?? null);
|
|
2800
|
+
if (selected.length === 0) continue;
|
|
2801
|
+
const column = (0, _burojs_core.scopeColumnOf)(target);
|
|
2802
|
+
if (!Object.hasOwn(record, column)) continue;
|
|
2803
|
+
const held = record[column];
|
|
2804
|
+
if (held === null || held === void 0 || held === "") {
|
|
2805
|
+
if (kind === "created" || "field" in target && target.empty === "shared") continue;
|
|
2806
|
+
out.push({
|
|
2807
|
+
dimension,
|
|
2808
|
+
value: null,
|
|
2809
|
+
selected,
|
|
2810
|
+
select: definition.select
|
|
2811
|
+
});
|
|
2812
|
+
continue;
|
|
2813
|
+
}
|
|
2814
|
+
if (!isScalar(held)) continue;
|
|
2815
|
+
if (selected.some((value) => String(value) === String(held))) continue;
|
|
2816
|
+
out.push({
|
|
2817
|
+
dimension,
|
|
2818
|
+
value: held,
|
|
2819
|
+
selected,
|
|
2820
|
+
select: definition.select
|
|
2821
|
+
});
|
|
2822
|
+
}
|
|
2823
|
+
return out;
|
|
2824
|
+
}, [
|
|
2825
|
+
mapping,
|
|
2826
|
+
record,
|
|
2827
|
+
scope.definition,
|
|
2828
|
+
scope.selection,
|
|
2829
|
+
kind
|
|
2830
|
+
]);
|
|
2831
|
+
if (differences.length === 0) return null;
|
|
2832
|
+
const apply = () => {
|
|
2833
|
+
for (const difference of differences) scope.select(difference.dimension, difference.value === null ? null : difference.select === "multiple" ? [difference.value] : difference.value);
|
|
2834
|
+
};
|
|
2835
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
2836
|
+
role: "status",
|
|
2837
|
+
"data-testid": "scope-mismatch:banner",
|
|
2838
|
+
className: "flex flex-wrap items-center justify-between gap-3 rounded-md border bg-muted/50 px-3 py-2 text-sm",
|
|
2839
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
2840
|
+
className: "space-y-1",
|
|
2841
|
+
children: [(0, react_jsx_runtime.jsx)("p", {
|
|
2842
|
+
className: "font-medium",
|
|
2843
|
+
children: kind === "created" ? chromeT("scope.mismatch.createdOutside", { defaultValue: "Created outside the current scope" }) : chromeT("scope.mismatch.title", { defaultValue: "This record is outside the current scope" })
|
|
2844
|
+
}), (0, react_jsx_runtime.jsx)("ul", {
|
|
2845
|
+
className: "text-muted-foreground",
|
|
2846
|
+
children: differences.map((difference) => (0, react_jsx_runtime.jsx)(DifferenceLine, {
|
|
2847
|
+
difference,
|
|
2848
|
+
definition: scope.definition.dimensions[difference.dimension]
|
|
2849
|
+
}, difference.dimension))
|
|
2850
|
+
})]
|
|
2851
|
+
}), (0, react_jsx_runtime.jsx)(require_button.Button, {
|
|
2852
|
+
type: "button",
|
|
2853
|
+
size: "sm",
|
|
2854
|
+
"data-testid": "scope-mismatch:switch",
|
|
2855
|
+
onClick: apply,
|
|
2856
|
+
children: chromeT("scope.mismatch.switch", { defaultValue: "Switch" })
|
|
2857
|
+
})]
|
|
2858
|
+
});
|
|
2859
|
+
}
|
|
2860
|
+
function DifferenceLine(props) {
|
|
2861
|
+
const source = props.definition.values;
|
|
2862
|
+
if (source !== void 0 && !Array.isArray(source)) {
|
|
2863
|
+
const { resource, label } = source;
|
|
2864
|
+
return (0, react_jsx_runtime.jsx)(ResourceLine, {
|
|
2865
|
+
...props,
|
|
2866
|
+
resource,
|
|
2867
|
+
...label ? { labelField: label } : {}
|
|
2868
|
+
});
|
|
2869
|
+
}
|
|
2870
|
+
return (0, react_jsx_runtime.jsx)(LineText, {
|
|
2871
|
+
difference: props.difference,
|
|
2872
|
+
options: source ?? []
|
|
2873
|
+
});
|
|
2874
|
+
}
|
|
2875
|
+
function ResourceLine({ difference, resource, labelField }) {
|
|
2876
|
+
const options = useResourceDimensionOptions(difference.dimension, resource, labelField);
|
|
2877
|
+
return (0, react_jsx_runtime.jsx)(LineText, {
|
|
2878
|
+
difference,
|
|
2879
|
+
options
|
|
2880
|
+
});
|
|
2881
|
+
}
|
|
2882
|
+
function LineText({ difference, options }) {
|
|
2883
|
+
const chromeT = (0, _burojs_react.useChromeT)();
|
|
2884
|
+
const labelOf = (value) => options.find((option) => String(option.value) === String(value))?.label ?? String(value);
|
|
2885
|
+
const field = (0, _burojs_core.humanizeKey)(difference.dimension);
|
|
2886
|
+
const item = difference.value === null ? chromeT("scope.mismatch.empty", { defaultValue: "not set" }) : labelOf(difference.value);
|
|
2887
|
+
const items = difference.selected.map(labelOf).join(", ");
|
|
2888
|
+
return (0, react_jsx_runtime.jsx)("li", {
|
|
2889
|
+
"data-testid": `scope-mismatch:line:${difference.dimension}`,
|
|
2890
|
+
children: chromeT("scope.mismatch.line", {
|
|
2891
|
+
params: {
|
|
2892
|
+
field,
|
|
2893
|
+
item,
|
|
2894
|
+
items
|
|
2895
|
+
},
|
|
2896
|
+
defaultValue: `${field}: ${item} (selected: ${items})`
|
|
2897
|
+
})
|
|
2898
|
+
});
|
|
2899
|
+
}
|
|
2900
|
+
//#endregion
|
|
2901
|
+
//#region src/record/type-offer.tsx
|
|
2902
|
+
function TypeOffer({ resource, offer, onChoose }) {
|
|
2903
|
+
const app = (0, _burojs_react.useApp)();
|
|
2904
|
+
const t = (0, _burojs_react.useOptionalT)();
|
|
2905
|
+
const tid = (0, _burojs_react.useTestIds)();
|
|
2906
|
+
const def = app.registry.get(resource);
|
|
2907
|
+
const by = def?.types?.by;
|
|
2908
|
+
const field = by === void 0 ? void 0 : def?.fields[by];
|
|
2909
|
+
const ref = def?.ref ?? {
|
|
2910
|
+
namespace: "default",
|
|
2911
|
+
id: resource
|
|
2912
|
+
};
|
|
2913
|
+
return (0, react_jsx_runtime.jsxs)("section", {
|
|
2914
|
+
"aria-labelledby": "type-offer-title",
|
|
2915
|
+
className: "flex flex-col gap-3",
|
|
2916
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
2917
|
+
className: "flex flex-col gap-1",
|
|
2918
|
+
children: [(0, react_jsx_runtime.jsx)("h2", {
|
|
2919
|
+
id: "type-offer-title",
|
|
2920
|
+
className: "text-base font-semibold",
|
|
2921
|
+
children: t("create.typeOffer.title", { defaultValue: "Choose a type" })
|
|
2922
|
+
}), (0, react_jsx_runtime.jsx)("p", {
|
|
2923
|
+
className: "text-sm text-muted-foreground",
|
|
2924
|
+
children: t("create.typeOffer.hint", { defaultValue: "The type decides which fields the record has." })
|
|
2925
|
+
})]
|
|
2926
|
+
}), offer.status === "pending" ? (0, react_jsx_runtime.jsxs)("div", {
|
|
2927
|
+
"aria-busy": "true",
|
|
2928
|
+
className: "flex flex-col gap-2",
|
|
2929
|
+
children: [(0, react_jsx_runtime.jsx)(require_skeleton.Skeleton, { className: "h-10 w-full" }), (0, react_jsx_runtime.jsx)(require_skeleton.Skeleton, { className: "h-10 w-full" })]
|
|
2930
|
+
}) : offer.types.length === 0 ? (0, react_jsx_runtime.jsx)("p", {
|
|
2931
|
+
role: "status",
|
|
2932
|
+
className: "text-sm text-muted-foreground",
|
|
2933
|
+
children: t("create.typeOffer.empty", { defaultValue: "No type can be created here." })
|
|
2934
|
+
}) : (0, react_jsx_runtime.jsx)("ul", {
|
|
2935
|
+
className: "grid grid-cols-1 gap-2 sm:grid-cols-2",
|
|
2936
|
+
children: offer.types.map((type) => (0, react_jsx_runtime.jsx)("li", { children: (0, react_jsx_runtime.jsx)("button", {
|
|
2937
|
+
type: "button",
|
|
2938
|
+
"data-testid": tid.typeOffer(resource, type),
|
|
2939
|
+
onClick: () => onChoose(type),
|
|
2940
|
+
className: "flex w-full items-center gap-2 rounded-md border px-3 py-2 text-left text-sm hover:bg-muted focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
|
|
2941
|
+
children: by === void 0 || field === void 0 ? type : (0, react_jsx_runtime.jsx)(require_place_node.FieldDisplay, {
|
|
2942
|
+
resource: ref,
|
|
2943
|
+
name: by,
|
|
2944
|
+
field,
|
|
2945
|
+
value: type,
|
|
2946
|
+
fallback: (0, react_jsx_runtime.jsx)("span", { children: type })
|
|
2947
|
+
})
|
|
2948
|
+
}) }, type))
|
|
2949
|
+
})]
|
|
2950
|
+
});
|
|
2951
|
+
}
|
|
2952
|
+
//#endregion
|
|
2953
|
+
//#region src/record/record-screen.tsx
|
|
2954
|
+
function isAbort(error) {
|
|
2955
|
+
if (error === null || typeof error !== "object" && typeof error !== "function") return false;
|
|
2956
|
+
try {
|
|
2957
|
+
return error.name === "AbortError";
|
|
2958
|
+
} catch {
|
|
2959
|
+
return false;
|
|
2960
|
+
}
|
|
2961
|
+
}
|
|
2962
|
+
const NO_ISSUES = Object.freeze([]);
|
|
2963
|
+
const APPLIED_UNREADABLE = Object.freeze({
|
|
2964
|
+
code: "applied-unreadable",
|
|
2965
|
+
message: Object.freeze({
|
|
2966
|
+
key: "errors.appliedUnreadable",
|
|
2967
|
+
default: "Saved. The server's answer could not be read, so the screen may not show the latest values."
|
|
2968
|
+
}),
|
|
2969
|
+
path: Object.freeze([]),
|
|
2970
|
+
source: "server",
|
|
2971
|
+
severity: "info"
|
|
2972
|
+
});
|
|
2973
|
+
function issuesOf(error) {
|
|
2974
|
+
if (error === null || typeof error !== "object") return void 0;
|
|
2975
|
+
try {
|
|
2976
|
+
const descriptor = Object.getOwnPropertyDescriptor(error, "issues");
|
|
2977
|
+
return descriptor !== void 0 && "value" in descriptor ? descriptor.value : void 0;
|
|
2978
|
+
} catch {
|
|
2979
|
+
return;
|
|
2980
|
+
}
|
|
2981
|
+
}
|
|
2982
|
+
const NO_EDITED = new Set();
|
|
2983
|
+
function sameValue(a, b) {
|
|
2984
|
+
if (Object.is(a, b)) return true;
|
|
2985
|
+
try {
|
|
2986
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
2987
|
+
} catch {
|
|
2988
|
+
return false;
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
function RecordFrameHost(props) {
|
|
2992
|
+
const { resource, mode } = props;
|
|
2993
|
+
const [failed, setFailed] = (0, react.useState)(NO_ISSUES);
|
|
2994
|
+
const named = (0, react.useMemo)(() => failed.length === 0 ? NO_ISSUES : (0, _burojs_core.routeServerIssues)({ issues: failed }, (segment) => segment, (field) => field !== "_form").fields, [failed]);
|
|
2995
|
+
const atFailure = (0, react.useRef)({});
|
|
2996
|
+
const [edited, setEdited] = (0, react.useState)(NO_EDITED);
|
|
2997
|
+
const controller = (0, _burojs_react.useFormController)({
|
|
2998
|
+
resource,
|
|
2999
|
+
mode,
|
|
3000
|
+
...props.recordId === void 0 ? {} : { recordId: props.recordId },
|
|
3001
|
+
...props.type === void 0 ? {} : { type: props.type },
|
|
3002
|
+
...props.record === void 0 ? {} : { record: props.record },
|
|
3003
|
+
...props.defaults === void 0 ? {} : { defaults: props.defaults },
|
|
3004
|
+
...props.onSubmit === void 0 ? {} : { onSubmit: props.onSubmit },
|
|
3005
|
+
...props.hostTitle ? { entry: "quick" } : {},
|
|
3006
|
+
serverIssues: named
|
|
3007
|
+
});
|
|
3008
|
+
const inputApplied = (0, react.useRef)(false);
|
|
3009
|
+
const { input } = props;
|
|
3010
|
+
const plan = controller.plan;
|
|
3011
|
+
(0, react.useEffect)(() => {
|
|
3012
|
+
if (inputApplied.current || input === void 0 || mode !== "create" || plan === null) return;
|
|
3013
|
+
inputApplied.current = true;
|
|
3014
|
+
for (const [key, value] of Object.entries(input)) if (plan.fields[key] === "active") controller.setValue(key, value);
|
|
3015
|
+
}, [
|
|
3016
|
+
input,
|
|
3017
|
+
mode,
|
|
3018
|
+
plan,
|
|
3019
|
+
controller
|
|
3020
|
+
]);
|
|
3021
|
+
const tid = (0, _burojs_react.useTestIds)();
|
|
3022
|
+
const formId = `record-form-${(0, react.useId)()}`;
|
|
3023
|
+
const root = (0, react.useRef)(null);
|
|
3024
|
+
const [submitError, setSubmitError] = (0, react.useState)(void 0);
|
|
3025
|
+
const [submitApplied, setSubmitApplied] = (0, react.useState)(void 0);
|
|
3026
|
+
(0, react.useEffect)(() => {
|
|
3027
|
+
if (plan === null) return;
|
|
3028
|
+
const now = Object.keys(atFailure.current).filter((name) => !edited.has(name) && plan.fields[name] === "active" && !sameValue(controller.field(name).value, atFailure.current[name]));
|
|
3029
|
+
if (now.length > 0) setEdited((previous) => new Set([...previous, ...now]));
|
|
3030
|
+
}, [
|
|
3031
|
+
plan,
|
|
3032
|
+
controller,
|
|
3033
|
+
edited
|
|
3034
|
+
]);
|
|
3035
|
+
const notify = require_success_notices.useNoticeSink(resource);
|
|
3036
|
+
const routeScreen = require_place_node.useIsRouteScreen();
|
|
3037
|
+
const leavesOnCreate = mode === "create" && routeScreen;
|
|
3038
|
+
const [created, setCreated] = (0, react.useState)(false);
|
|
3039
|
+
const createdRef = (0, react.useRef)(false);
|
|
3040
|
+
const latest = (0, react.useRef)({
|
|
3041
|
+
controller,
|
|
3042
|
+
onSuccess: props.onSuccess,
|
|
3043
|
+
notify,
|
|
3044
|
+
leavesOnCreate
|
|
3045
|
+
});
|
|
3046
|
+
latest.current = {
|
|
3047
|
+
controller,
|
|
3048
|
+
onSuccess: props.onSuccess,
|
|
3049
|
+
notify,
|
|
3050
|
+
leavesOnCreate
|
|
3051
|
+
};
|
|
3052
|
+
const mounted = (0, react.useRef)(true);
|
|
3053
|
+
(0, react.useEffect)(() => {
|
|
3054
|
+
mounted.current = true;
|
|
3055
|
+
return () => {
|
|
3056
|
+
mounted.current = false;
|
|
3057
|
+
};
|
|
3058
|
+
}, []);
|
|
3059
|
+
const submit = (0, react.useCallback)(async () => {
|
|
3060
|
+
if (createdRef.current) return;
|
|
3061
|
+
setSubmitError(void 0);
|
|
3062
|
+
setSubmitApplied(void 0);
|
|
3063
|
+
setFailed(NO_ISSUES);
|
|
3064
|
+
setEdited(NO_EDITED);
|
|
3065
|
+
atFailure.current = {};
|
|
3066
|
+
const outcome = await latest.current.controller.submit();
|
|
3067
|
+
if (!mounted.current) return;
|
|
3068
|
+
if (latest.current.leavesOnCreate && (outcome.status === "submitted" || outcome.status === "failed" && outcome.applied === "yes")) {
|
|
3069
|
+
createdRef.current = true;
|
|
3070
|
+
setCreated(true);
|
|
3071
|
+
}
|
|
3072
|
+
if (outcome.status === "submitted") {
|
|
3073
|
+
const notices = (0, _burojs_core.successNoticesOf)(outcome.result);
|
|
3074
|
+
if (notices.length > 0) latest.current.notify(notices);
|
|
3075
|
+
latest.current.onSuccess?.(outcome.result);
|
|
3076
|
+
} else if (outcome.status === "failed" && outcome.applied === "yes") {
|
|
3077
|
+
latest.current.notify([APPLIED_UNREADABLE]);
|
|
3078
|
+
latest.current.onSuccess?.(void 0);
|
|
3079
|
+
} else if (outcome.status === "failed" && !isAbort(outcome.error)) {
|
|
3080
|
+
setSubmitError(outcome.error ?? null);
|
|
3081
|
+
setSubmitApplied(outcome.applied);
|
|
3082
|
+
const issues = (0, _burojs_core.normalizeIssueInputs)(issuesOf(outcome.error)).issues;
|
|
3083
|
+
const next = issues.length === 0 ? NO_ISSUES : Object.freeze(issues.map(_burojs_core.issueOfInput));
|
|
3084
|
+
const held = {};
|
|
3085
|
+
const now = latest.current.controller;
|
|
3086
|
+
for (const issue of next) {
|
|
3087
|
+
const head = issue.path[0];
|
|
3088
|
+
if (typeof head === "string" && head !== "_form" && now.plan?.fields[head] === "active") held[head] = now.field(head).value;
|
|
3089
|
+
}
|
|
3090
|
+
atFailure.current = held;
|
|
3091
|
+
setFailed(next);
|
|
3092
|
+
}
|
|
3093
|
+
}, []);
|
|
3094
|
+
const record = controller.record;
|
|
3095
|
+
const recordText = props.recordId === void 0 ? void 0 : String(props.recordId);
|
|
3096
|
+
const frame = (0, react.useMemo)(() => ({
|
|
3097
|
+
resource,
|
|
3098
|
+
recordId: recordText,
|
|
3099
|
+
mode,
|
|
3100
|
+
record,
|
|
3101
|
+
controller
|
|
3102
|
+
}), [
|
|
3103
|
+
resource,
|
|
3104
|
+
recordText,
|
|
3105
|
+
mode,
|
|
3106
|
+
record,
|
|
3107
|
+
controller
|
|
3108
|
+
]);
|
|
3109
|
+
const { chooseType } = props;
|
|
3110
|
+
const typedAndAccepted = mode === "create" && controller.typeOffer !== null && controller.failure === null;
|
|
3111
|
+
const adapter = (0, _burojs_react.useOptionalRouterAdapter)();
|
|
3112
|
+
const hostRouter = routeScreen ? adapter : null;
|
|
3113
|
+
const guardText = (0, _burojs_react.useNavigationGuardText)();
|
|
3114
|
+
const changeType = (0, react.useMemo)(() => typedAndAccepted ? () => {
|
|
3115
|
+
if (hostRouter === null && latest.current.controller.isDirty && !window.confirm(`${guardText.title}\n\n${guardText.body}`)) return;
|
|
3116
|
+
chooseType(void 0);
|
|
3117
|
+
} : void 0, [
|
|
3118
|
+
typedAndAccepted,
|
|
3119
|
+
chooseType,
|
|
3120
|
+
hostRouter,
|
|
3121
|
+
guardText.title,
|
|
3122
|
+
guardText.body
|
|
3123
|
+
]);
|
|
3124
|
+
const app = (0, _burojs_react.useApp)();
|
|
3125
|
+
const typesDecl = app.registry.get(resource)?.types;
|
|
3126
|
+
const loaded = controller.record;
|
|
3127
|
+
const unsupportedType = (0, react.useMemo)(() => {
|
|
3128
|
+
if (mode === "create" || typesDecl === void 0 || loaded === void 0) return void 0;
|
|
3129
|
+
const value = loaded[typesDecl.by];
|
|
3130
|
+
const name = typeof value === "string" && value !== "" ? value : null;
|
|
3131
|
+
return name !== null && typesDecl.items.some((item) => item.name === name) ? void 0 : name;
|
|
3132
|
+
}, [
|
|
3133
|
+
mode,
|
|
3134
|
+
typesDecl,
|
|
3135
|
+
loaded
|
|
3136
|
+
]);
|
|
3137
|
+
const shownFailed = (0, react.useMemo)(() => edited.size === 0 ? failed : Object.freeze(failed.filter((issue) => {
|
|
3138
|
+
const head = issue.path[0];
|
|
3139
|
+
return typeof head !== "string" || !edited.has(head);
|
|
3140
|
+
})), [failed, edited]);
|
|
3141
|
+
const chrome = (0, react.useMemo)(() => ({
|
|
3142
|
+
...props.onCancel === void 0 ? {} : { onCancel: props.onCancel },
|
|
3143
|
+
...props.submitLabel === void 0 ? {} : { submitLabel: props.submitLabel },
|
|
3144
|
+
...props.extraActions === void 0 ? {} : { extraActions: props.extraActions },
|
|
3145
|
+
...changeType === void 0 ? {} : { changeType },
|
|
3146
|
+
...unsupportedType === void 0 ? {} : { unsupportedType },
|
|
3147
|
+
...props.hostTitle ? { hostTitle: true } : {},
|
|
3148
|
+
formId,
|
|
3149
|
+
submitError,
|
|
3150
|
+
...submitApplied === void 0 ? {} : { submitApplied },
|
|
3151
|
+
serverIssues: shownFailed,
|
|
3152
|
+
...created ? { created: true } : {},
|
|
3153
|
+
submit,
|
|
3154
|
+
root
|
|
3155
|
+
}), [
|
|
3156
|
+
props.onCancel,
|
|
3157
|
+
props.submitLabel,
|
|
3158
|
+
props.extraActions,
|
|
3159
|
+
changeType,
|
|
3160
|
+
unsupportedType,
|
|
3161
|
+
props.hostTitle,
|
|
3162
|
+
formId,
|
|
3163
|
+
submitError,
|
|
3164
|
+
submitApplied,
|
|
3165
|
+
shownFailed,
|
|
3166
|
+
created,
|
|
3167
|
+
submit
|
|
3168
|
+
]);
|
|
3169
|
+
(0, _burojs_react.usePublishDocVariant)(mode === "show" ? resource : void 0, record);
|
|
3170
|
+
const failure = controller.failure;
|
|
3171
|
+
const offering = failure?.kind === "type-required" && controller.typeOffer !== null;
|
|
3172
|
+
(0, react.useEffect)(() => {
|
|
3173
|
+
if (failure === null || offering || process.env.NODE_ENV === "production") return;
|
|
3174
|
+
console.error(`[burojs] <RecordScreen resource="${resource}" mode="${mode}"> cannot render its screen: ${failure.kind === "screen" ? `${failure.failure.code} at ${failure.failure.path.join(".")}: ${failure.failure.message}` : "a typed create needs an accepted type"}.`);
|
|
3175
|
+
}, [
|
|
3176
|
+
failure,
|
|
3177
|
+
offering,
|
|
3178
|
+
resource,
|
|
3179
|
+
mode
|
|
3180
|
+
]);
|
|
3181
|
+
const formControl = require_place_node.useFormControlOf(controller);
|
|
3182
|
+
const id = frameRecordId(frame, app.registry.get(frame.resource));
|
|
3183
|
+
const rootId = mode === "show" ? tid.pageShow(resource, id ?? "") : mode === "edit" ? tid.pageEdit(resource, id ?? "") : tid.pageCreate(resource);
|
|
3184
|
+
const claimedRoute = (0, react.useContext)(_burojs_react.RouteSourceContext);
|
|
3185
|
+
const scopeValues = mode === "show" ? controller.record : controller.values;
|
|
3186
|
+
return (0, react_jsx_runtime.jsx)(_burojs_react.RecordScopeProvider, {
|
|
3187
|
+
resource,
|
|
3188
|
+
...recordText === void 0 ? {} : { recordId: recordText },
|
|
3189
|
+
values: scopeValues,
|
|
3190
|
+
create: mode === "create",
|
|
3191
|
+
children: (0, react_jsx_runtime.jsx)(_burojs_react.RouteSourceContext.Provider, {
|
|
3192
|
+
value: null,
|
|
3193
|
+
children: (0, react_jsx_runtime.jsx)(_burojs_react.ActionRouteContext.Provider, {
|
|
3194
|
+
value: claimedRoute,
|
|
3195
|
+
children: (0, react_jsx_runtime.jsx)(_burojs_react.RecordFrameContext.Provider, {
|
|
3196
|
+
value: frame,
|
|
3197
|
+
children: (0, react_jsx_runtime.jsx)(require_place_node.FrameChromeContext.Provider, {
|
|
3198
|
+
value: chrome,
|
|
3199
|
+
children: (0, react_jsx_runtime.jsxs)(require_place_node.FormControlProvider, {
|
|
3200
|
+
value: formControl,
|
|
3201
|
+
children: [(0, react_jsx_runtime.jsx)(require_place_node.DeepLinkScope, {
|
|
3202
|
+
plan: controller.plan,
|
|
3203
|
+
enabled: routeScreen && mode !== "create",
|
|
3204
|
+
children: (0, react_jsx_runtime.jsx)("div", {
|
|
3205
|
+
ref: root,
|
|
3206
|
+
"data-testid": rootId,
|
|
3207
|
+
className: "flex flex-col gap-[var(--buro-section-gap)]",
|
|
3208
|
+
children: offering && controller.typeOffer !== null ? (0, react_jsx_runtime.jsx)(TypeOffer, {
|
|
3209
|
+
resource,
|
|
3210
|
+
offer: controller.typeOffer,
|
|
3211
|
+
onChoose: (type) => chooseType(type)
|
|
3212
|
+
}) : failure !== null ? (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "error" }), (0, react_jsx_runtime.jsx)(require_place_node.FormActions, {})] }) : mode === "edit" && unsupportedType !== void 0 ? (0, react_jsx_runtime.jsx)(require_place_node.UndeclaredTypeNotice, {
|
|
3213
|
+
resource,
|
|
3214
|
+
typeValue: unsupportedType
|
|
3215
|
+
}) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(ScopeMismatchBanner, {
|
|
3216
|
+
resource,
|
|
3217
|
+
record: mode === "create" ? controller.trustedSeeds : controller.record,
|
|
3218
|
+
kind: mode === "create" ? "created" : "record"
|
|
3219
|
+
}), (0, react_jsx_runtime.jsx)(RecordFrameView, { ...props.frame === void 0 ? {} : { frame: props.frame } })] })
|
|
3220
|
+
})
|
|
3221
|
+
}), controller.checkGate === null ? null : (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.CheckConfirmDialog, {
|
|
3222
|
+
state: controller.checkGate,
|
|
3223
|
+
testid: `${tid.form(resource, mode, id)}:checks`
|
|
3224
|
+
})]
|
|
3225
|
+
})
|
|
3226
|
+
})
|
|
3227
|
+
})
|
|
3228
|
+
})
|
|
3229
|
+
})
|
|
3230
|
+
});
|
|
3231
|
+
}
|
|
3232
|
+
function RecordScreen(props) {
|
|
3233
|
+
const app = (0, _burojs_react.useApp)();
|
|
3234
|
+
const routeScreen = (0, react.useContext)(require_place_node.RouteScreenClaimContext);
|
|
3235
|
+
const quickScreen = (0, react.useContext)(require_place_node.QuickScreenClaimContext);
|
|
3236
|
+
const route = (0, react.useContext)(_burojs_react.RouteSourceContext);
|
|
3237
|
+
const resourceInput = props.resource;
|
|
3238
|
+
const resource = (0, _burojs_core.resourceKey)(resourceInput);
|
|
3239
|
+
const tabs = require_place_node.useTabsUrlState(props.mode, routeScreen);
|
|
3240
|
+
const adapter = (0, _burojs_react.useOptionalRouterAdapter)();
|
|
3241
|
+
const router = routeScreen ? adapter : null;
|
|
3242
|
+
const navigate = (0, _burojs_react.useRouteNavigate)();
|
|
3243
|
+
const [local, setLocal] = (0, react.useState)(props.type);
|
|
3244
|
+
const [typeProp, setTypeProp] = (0, react.useState)(props.type);
|
|
3245
|
+
if (props.type !== typeProp) {
|
|
3246
|
+
setTypeProp(props.type);
|
|
3247
|
+
setLocal(props.type);
|
|
3248
|
+
}
|
|
3249
|
+
const [chose, setChose] = (0, react.useState)(false);
|
|
3250
|
+
const fromUrl = router?.searchParams.get("type") ?? void 0;
|
|
3251
|
+
const type = props.mode !== "create" ? props.type : router === null ? local : chose ? fromUrl : props.type ?? fromUrl;
|
|
3252
|
+
const chooseType = (0, react.useCallback)((next) => {
|
|
3253
|
+
if (router === null) {
|
|
3254
|
+
setLocal(next);
|
|
3255
|
+
return;
|
|
3256
|
+
}
|
|
3257
|
+
setChose(true);
|
|
3258
|
+
const params = new URLSearchParams(router.searchParams);
|
|
3259
|
+
if (next === void 0) params.delete("type");
|
|
3260
|
+
else params.set("type", next);
|
|
3261
|
+
const query = params.toString();
|
|
3262
|
+
navigate(query === "" ? router.pathname : `${router.pathname}?${query}`);
|
|
3263
|
+
}, [router, navigate]);
|
|
3264
|
+
if (app.registry.get(resource) === void 0) return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "not-found" });
|
|
3265
|
+
const { type: _declared, ...rest } = props;
|
|
3266
|
+
return (0, react_jsx_runtime.jsx)(require_place_node.RouteScreenClaimContext.Provider, {
|
|
3267
|
+
value: false,
|
|
3268
|
+
children: (0, react_jsx_runtime.jsx)(require_place_node.QuickScreenClaimContext.Provider, {
|
|
3269
|
+
value: false,
|
|
3270
|
+
children: (0, react_jsx_runtime.jsx)(_burojs_react.RouteSourceContext.Provider, {
|
|
3271
|
+
value: routeScreen || quickScreen ? route : null,
|
|
3272
|
+
children: (0, react_jsx_runtime.jsx)(require_place_node.RouteScreenContext.Provider, {
|
|
3273
|
+
value: routeScreen,
|
|
3274
|
+
children: (0, react_jsx_runtime.jsx)(_burojs_react.ResourceContext.Provider, {
|
|
3275
|
+
value: { resource },
|
|
3276
|
+
children: (0, react_jsx_runtime.jsx)(_burojs_react.ScreenStateProvider, {
|
|
3277
|
+
open: tabs.open,
|
|
3278
|
+
onOpenChange: tabs.onOpenChange,
|
|
3279
|
+
children: (0, react_jsx_runtime.jsx)(RecordFrameHost, {
|
|
3280
|
+
...rest,
|
|
3281
|
+
...type === void 0 ? {} : { type },
|
|
3282
|
+
resource,
|
|
3283
|
+
chooseType,
|
|
3284
|
+
hostTitle: quickScreen
|
|
3285
|
+
}, type ?? "")
|
|
3286
|
+
})
|
|
3287
|
+
})
|
|
3288
|
+
})
|
|
3289
|
+
})
|
|
3290
|
+
})
|
|
3291
|
+
});
|
|
3292
|
+
}
|
|
3293
|
+
//#endregion
|
|
3294
|
+
//#region src/layout/record-targets.ts
|
|
3295
|
+
function isShowAvailable(registry, resource) {
|
|
3296
|
+
return (0, _burojs_react.recordRouteAvailable)(registry, resource, "show");
|
|
3297
|
+
}
|
|
3298
|
+
function showTarget(resource, id) {
|
|
3299
|
+
return {
|
|
3300
|
+
resource,
|
|
3301
|
+
action: "show",
|
|
3302
|
+
params: { id }
|
|
3303
|
+
};
|
|
3304
|
+
}
|
|
3305
|
+
function listTarget(resource) {
|
|
3306
|
+
return {
|
|
3307
|
+
resource,
|
|
3308
|
+
action: "list"
|
|
3309
|
+
};
|
|
3310
|
+
}
|
|
3311
|
+
//#endregion
|
|
3312
|
+
//#region src/layout/route-trail.ts
|
|
3313
|
+
function useTrailContext() {
|
|
3314
|
+
const app = (0, _burojs_react.useApp)();
|
|
3315
|
+
const caps = (0, _burojs_react.useI18nCaps)();
|
|
3316
|
+
const isVisible = useNavVisible();
|
|
3317
|
+
const t = (0, _burojs_react.useT)();
|
|
3318
|
+
return {
|
|
3319
|
+
registry: app.registry,
|
|
3320
|
+
caps,
|
|
3321
|
+
isVisible,
|
|
3322
|
+
t
|
|
3323
|
+
};
|
|
3324
|
+
}
|
|
3325
|
+
function groupCrumbs(ctx, chain) {
|
|
3326
|
+
return chain.map((group) => {
|
|
3327
|
+
const key = require_record_trail_store.canonicalNavKey(group);
|
|
3328
|
+
return {
|
|
3329
|
+
label: (0, _burojs_core.resolveNavLabel)(ctx.caps, `groups.${key}`, (0, _burojs_core.declaredText)("chrome", group, "label")),
|
|
3330
|
+
href: groupNavHref(ctx.registry, key, ctx.isVisible),
|
|
3331
|
+
jump: true
|
|
3332
|
+
};
|
|
3333
|
+
});
|
|
3334
|
+
}
|
|
3335
|
+
function nonEmpty(crumbs) {
|
|
3336
|
+
return crumbs.length > 0 ? crumbs : void 0;
|
|
3337
|
+
}
|
|
3338
|
+
function recordActionOf(match) {
|
|
3339
|
+
if (match === null || match.kind !== "resource") return void 0;
|
|
3340
|
+
switch (match.action) {
|
|
3341
|
+
case "show":
|
|
3342
|
+
case "edit":
|
|
3343
|
+
case "create": return match.action;
|
|
3344
|
+
default: return;
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
function pathOf(href) {
|
|
3348
|
+
const path = href.split(/[?#]/, 1)[0] ?? "";
|
|
3349
|
+
return path.length > 1 && path.endsWith("/") ? path.slice(0, -1) : path;
|
|
3350
|
+
}
|
|
3351
|
+
function originTrail(ctx, origin, depth = _burojs_react.ORIGIN_DEPTH) {
|
|
3352
|
+
const match = (0, _burojs_core.matchPath)(ctx.registry, pathOf(origin.href), { isVisible: ctx.isVisible });
|
|
3353
|
+
if (match === null) return void 0;
|
|
3354
|
+
switch (match.kind) {
|
|
3355
|
+
case "resource": {
|
|
3356
|
+
const key = require_record_trail_store.canonicalNavKey(match);
|
|
3357
|
+
if (match.action === "list") return {
|
|
3358
|
+
leading: groupCrumbs(ctx, match.groupChain),
|
|
3359
|
+
resource: key,
|
|
3360
|
+
resourceHref: origin.href,
|
|
3361
|
+
segments: []
|
|
3362
|
+
};
|
|
3363
|
+
const def = ctx.registry.get(key);
|
|
3364
|
+
const crumb = {
|
|
3365
|
+
label: match.action === "create" ? ctx.t("breadcrumbs.create") : origin.title || (match.id === void 0 ? "" : `#${match.id}`),
|
|
3366
|
+
href: origin.href
|
|
3367
|
+
};
|
|
3368
|
+
const parent = depth > 1 && origin.origin !== void 0 ? originTrail(ctx, origin.origin, depth - 1) : void 0;
|
|
3369
|
+
if (parent !== void 0) return {
|
|
3370
|
+
...parent,
|
|
3371
|
+
segments: [...parent.segments, crumb]
|
|
3372
|
+
};
|
|
3373
|
+
return {
|
|
3374
|
+
leading: groupCrumbs(ctx, match.groupChain),
|
|
3375
|
+
resource: key,
|
|
3376
|
+
...def !== void 0 && (0, _burojs_core.hasListPage)(def) ? { resourceHref: (0, _burojs_core.hrefFor)(ctx.registry, key) } : {},
|
|
3377
|
+
segments: [crumb]
|
|
3378
|
+
};
|
|
3379
|
+
}
|
|
3380
|
+
case "custom-page": {
|
|
3381
|
+
const trail = headerTrail(ctx, match);
|
|
3382
|
+
if (trail === null || trail.pageLabel === void 0) return void 0;
|
|
3383
|
+
return {
|
|
3384
|
+
leading: trail.leadingSegments ?? [],
|
|
3385
|
+
segments: [{
|
|
3386
|
+
label: trail.pageLabel,
|
|
3387
|
+
href: origin.href
|
|
3388
|
+
}]
|
|
3389
|
+
};
|
|
3390
|
+
}
|
|
3391
|
+
case "group-index": {
|
|
3392
|
+
const crumbs = groupCrumbs(ctx, match.groupChain);
|
|
3393
|
+
const own = crumbs[crumbs.length - 1];
|
|
3394
|
+
if (own === void 0) return void 0;
|
|
3395
|
+
return {
|
|
3396
|
+
leading: crumbs.slice(0, -1),
|
|
3397
|
+
segments: [{
|
|
3398
|
+
label: own.label,
|
|
3399
|
+
href: origin.href
|
|
3400
|
+
}]
|
|
3401
|
+
};
|
|
3402
|
+
}
|
|
3403
|
+
default: return;
|
|
3404
|
+
}
|
|
3405
|
+
}
|
|
3406
|
+
function recordTrail(ctx, input) {
|
|
3407
|
+
const { resource, action, id, origin } = input;
|
|
3408
|
+
if (origin !== void 0 && (action === "create" || id !== "")) return originRooted(ctx, input, origin);
|
|
3409
|
+
const leadingSegments = nonEmpty(groupCrumbs(ctx, input.groupChain));
|
|
3410
|
+
if (action !== "create" && id === "") return {
|
|
3411
|
+
resource,
|
|
3412
|
+
leadingSegments
|
|
3413
|
+
};
|
|
3414
|
+
const recordLabel = input.title || id;
|
|
3415
|
+
const middleSegments = action === "edit" ? [isShowAvailable(ctx.registry, resource) ? {
|
|
3416
|
+
label: recordLabel,
|
|
3417
|
+
href: (0, _burojs_react.resolveRoute)(showTarget(resource, id), ctx.registry)
|
|
3418
|
+
} : { label: recordLabel }] : void 0;
|
|
3419
|
+
const pageLabel = action === "create" ? ctx.t("breadcrumbs.create") : action === "edit" ? ctx.t("breadcrumbs.edit") : recordLabel;
|
|
3420
|
+
return {
|
|
3421
|
+
resource,
|
|
3422
|
+
recordId: action === "create" ? void 0 : id,
|
|
3423
|
+
pageLabel,
|
|
3424
|
+
leadingSegments,
|
|
3425
|
+
middleSegments
|
|
3426
|
+
};
|
|
3427
|
+
}
|
|
3428
|
+
function originRooted(ctx, input, origin) {
|
|
3429
|
+
const { resource, action, id } = input;
|
|
3430
|
+
const recordLabel = input.title || id;
|
|
3431
|
+
const drawn = new Set(origin.segments.flatMap((crumb) => crumb.href === void 0 ? [] : [pathOf(crumb.href)]));
|
|
3432
|
+
const own = action === "edit" ? [isShowAvailable(ctx.registry, resource) ? {
|
|
3433
|
+
label: recordLabel,
|
|
3434
|
+
href: (0, _burojs_react.resolveRoute)(showTarget(resource, id), ctx.registry)
|
|
3435
|
+
} : { label: recordLabel }].filter((crumb) => crumb.href === void 0 || !drawn.has(pathOf(crumb.href))) : [];
|
|
3436
|
+
const pageLabel = action === "create" ? ctx.t("breadcrumbs.create") : action === "edit" ? ctx.t("breadcrumbs.edit") : recordLabel;
|
|
3437
|
+
const recordId = action === "create" ? void 0 : id;
|
|
3438
|
+
const middleSegments = nonEmpty([...origin.segments, ...own]);
|
|
3439
|
+
if (origin.resource !== void 0 && ctx.registry.get(origin.resource) === ctx.registry.get(resource)) return {
|
|
3440
|
+
resource,
|
|
3441
|
+
recordId,
|
|
3442
|
+
pageLabel,
|
|
3443
|
+
leadingSegments: nonEmpty([...origin.leading]),
|
|
3444
|
+
...origin.resourceHref === void 0 ? {} : { resourceHref: origin.resourceHref },
|
|
3445
|
+
middleSegments
|
|
3446
|
+
};
|
|
3447
|
+
const def = origin.resource === void 0 ? void 0 : ctx.registry.get(origin.resource);
|
|
3448
|
+
const resourceCrumb = origin.resource === void 0 ? [] : [{
|
|
3449
|
+
label: (0, _burojs_core.resolveResourceLabel)(ctx.caps, origin.resource, "plural", def),
|
|
3450
|
+
...origin.resourceHref === void 0 ? {} : { href: origin.resourceHref }
|
|
3451
|
+
}];
|
|
3452
|
+
return {
|
|
3453
|
+
resource,
|
|
3454
|
+
recordId,
|
|
3455
|
+
pageLabel,
|
|
3456
|
+
rootSegments: [
|
|
3457
|
+
...origin.leading,
|
|
3458
|
+
...resourceCrumb,
|
|
3459
|
+
...origin.segments,
|
|
3460
|
+
...own
|
|
3461
|
+
]
|
|
3462
|
+
};
|
|
3463
|
+
}
|
|
3464
|
+
function recordTrailRoute(registry, match) {
|
|
3465
|
+
if (match === null || match.kind !== "resource") return null;
|
|
3466
|
+
const resource = require_record_trail_store.canonicalNavKey(match);
|
|
3467
|
+
const { groupChain } = match;
|
|
3468
|
+
if (match.action === "flow") return {
|
|
3469
|
+
resource,
|
|
3470
|
+
action: "show",
|
|
3471
|
+
id: match.id ?? "",
|
|
3472
|
+
flow: match.flow ?? "",
|
|
3473
|
+
groupChain
|
|
3474
|
+
};
|
|
3475
|
+
const action = recordActionOf(match);
|
|
3476
|
+
if (action === void 0 || !(0, _burojs_react.recordRouteAvailable)(registry, resource, action)) return null;
|
|
3477
|
+
return {
|
|
3478
|
+
resource,
|
|
3479
|
+
action,
|
|
3480
|
+
id: action === "create" ? "" : match.id ?? "",
|
|
3481
|
+
groupChain
|
|
3482
|
+
};
|
|
3483
|
+
}
|
|
3484
|
+
function headerTrail(ctx, match) {
|
|
3485
|
+
if (match === null) return null;
|
|
3486
|
+
const key = require_record_trail_store.canonicalNavKey(match);
|
|
3487
|
+
switch (match.kind) {
|
|
3488
|
+
case "resource": {
|
|
3489
|
+
const leadingSegments = nonEmpty(groupCrumbs(ctx, match.groupChain));
|
|
3490
|
+
const action = recordActionOf(match);
|
|
3491
|
+
if (recordTrailRoute(ctx.registry, match) !== null) return null;
|
|
3492
|
+
if (action === void 0) return {
|
|
3493
|
+
resource: key,
|
|
3494
|
+
leadingSegments
|
|
3495
|
+
};
|
|
3496
|
+
return {
|
|
3497
|
+
resource: key,
|
|
3498
|
+
recordId: match.id,
|
|
3499
|
+
pageLabel: ctx.t("router.notFoundTitle"),
|
|
3500
|
+
leadingSegments
|
|
3501
|
+
};
|
|
3502
|
+
}
|
|
3503
|
+
case "custom-page": {
|
|
3504
|
+
const page = ctx.registry.customPages.get(match.name);
|
|
3505
|
+
if (page === void 0 || !ctx.isVisible(page)) return null;
|
|
3506
|
+
return {
|
|
3507
|
+
name: key,
|
|
3508
|
+
pageLabel: (0, _burojs_core.resolveNavLabel)(ctx.caps, `pages.${key}`, (0, _burojs_core.declaredText)("chrome", page, "label")),
|
|
3509
|
+
leadingSegments: nonEmpty(groupCrumbs(ctx, match.groupChain))
|
|
3510
|
+
};
|
|
3511
|
+
}
|
|
3512
|
+
case "group-index": {
|
|
3513
|
+
const own = match.groupChain[match.groupChain.length - 1];
|
|
3514
|
+
if (own === void 0) return null;
|
|
3515
|
+
const crumbs = groupCrumbs(ctx, match.groupChain);
|
|
3516
|
+
const current = crumbs[crumbs.length - 1];
|
|
3517
|
+
return {
|
|
3518
|
+
name: require_record_trail_store.canonicalNavKey(own),
|
|
3519
|
+
pageLabel: current.label,
|
|
3520
|
+
leadingSegments: nonEmpty(crumbs.slice(0, -1))
|
|
3521
|
+
};
|
|
3522
|
+
}
|
|
3523
|
+
default: return null;
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3526
|
+
function recentStorageKey(userId) {
|
|
3527
|
+
return `buro:recent:v2:${userId}`;
|
|
3528
|
+
}
|
|
3529
|
+
function isRecent(value) {
|
|
3530
|
+
if (typeof value !== "object" || value === null) return false;
|
|
3531
|
+
const entry = value;
|
|
3532
|
+
return typeof entry.canonicalRef === "string" && typeof entry.id === "string" && typeof entry.label === "string" && (entry.labelField === void 0 || typeof entry.labelField === "string") && typeof entry.at === "string";
|
|
3533
|
+
}
|
|
3534
|
+
function parse(raw) {
|
|
3535
|
+
if (raw === null) return [];
|
|
3536
|
+
try {
|
|
3537
|
+
const parsed = JSON.parse(raw);
|
|
3538
|
+
if (typeof parsed !== "object" || parsed === null) return [];
|
|
3539
|
+
const envelope = parsed;
|
|
3540
|
+
if (envelope.version !== 2 || !Array.isArray(envelope.items)) return [];
|
|
3541
|
+
return envelope.items.filter(isRecent);
|
|
3542
|
+
} catch {
|
|
3543
|
+
return [];
|
|
3544
|
+
}
|
|
3545
|
+
}
|
|
3546
|
+
function readRecentRecords(store, userId) {
|
|
3547
|
+
return (0, _burojs_react.maybeThen)((0, _burojs_react.settle)(() => store.get(recentStorageKey(userId)), null), parse);
|
|
3548
|
+
}
|
|
3549
|
+
function writeRecentRecord(store, userId, entry) {
|
|
3550
|
+
const key = recentStorageKey(userId);
|
|
3551
|
+
return (0, _burojs_react.maybeThen)((0, _burojs_react.settle)(() => store.get(key), null), (raw) => {
|
|
3552
|
+
const envelope = {
|
|
3553
|
+
version: 2,
|
|
3554
|
+
items: [entry, ...parse(raw).filter((item) => !(item.canonicalRef === entry.canonicalRef && item.id === entry.id))].slice(0, 5)
|
|
3555
|
+
};
|
|
3556
|
+
return (0, _burojs_react.settle)(() => store.set(key, JSON.stringify(envelope)), void 0);
|
|
3557
|
+
});
|
|
3558
|
+
}
|
|
3559
|
+
function text$1(value) {
|
|
3560
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
3561
|
+
}
|
|
3562
|
+
const RECENT_LABEL_KEYS = [
|
|
3563
|
+
"alias",
|
|
3564
|
+
"name",
|
|
3565
|
+
"title",
|
|
3566
|
+
"label"
|
|
3567
|
+
];
|
|
3568
|
+
function recentLabel(record, id, isGuarded = () => false) {
|
|
3569
|
+
for (const key of RECENT_LABEL_KEYS) {
|
|
3570
|
+
if (isGuarded(key)) continue;
|
|
3571
|
+
const value = text$1(record[key]);
|
|
3572
|
+
if (value !== void 0) return {
|
|
3573
|
+
label: value,
|
|
3574
|
+
field: key
|
|
3575
|
+
};
|
|
3576
|
+
}
|
|
3577
|
+
return { label: id };
|
|
3578
|
+
}
|
|
3579
|
+
//#endregion
|
|
3580
|
+
//#region src/layout/use-record-visit.ts
|
|
3581
|
+
function useRecordVisit(resource, record, opts) {
|
|
3582
|
+
const userId = (0, _burojs_react.useCurrentUserId)();
|
|
3583
|
+
const store = (0, _burojs_react.usePlatformStorage)().local;
|
|
3584
|
+
const app = (0, _burojs_react.useApp)();
|
|
3585
|
+
const def = app.registry.get(resource);
|
|
3586
|
+
const raw = (0, _burojs_react.recordKeyOf)(def, record);
|
|
3587
|
+
const id = typeof raw === "string" || typeof raw === "number" ? String(raw) : void 0;
|
|
3588
|
+
const fields = def?.fields;
|
|
3589
|
+
const rules = app.ruleSource?.rules(resource) ?? [];
|
|
3590
|
+
const isGuarded = (field) => fields !== void 0 && Object.hasOwn(fields, field) && (0, _burojs_core.fieldSensitivity)(fields[field]) !== void 0 || (0, _burojs_core.addressesCapability)(rules, "view", {
|
|
3591
|
+
kind: "field",
|
|
3592
|
+
name: field
|
|
3593
|
+
});
|
|
3594
|
+
const picked = record != null && id !== void 0 ? recentLabel(record, id, isGuarded) : void 0;
|
|
3595
|
+
const label = picked?.label;
|
|
3596
|
+
const labelField = picked?.field;
|
|
3597
|
+
const canonicalRef = require_check_confirm_dialog.canonicalResourceName(resource);
|
|
3598
|
+
const { isCurrentData } = opts;
|
|
3599
|
+
(0, react.useEffect)(() => {
|
|
3600
|
+
if (userId === null || !isCurrentData || id === void 0 || id === "") return;
|
|
3601
|
+
if (label === void 0) return;
|
|
3602
|
+
writeRecentRecord(store, userId, {
|
|
3603
|
+
canonicalRef,
|
|
3604
|
+
id,
|
|
3605
|
+
label,
|
|
3606
|
+
...labelField === void 0 ? {} : { labelField },
|
|
3607
|
+
at: new Date().toISOString()
|
|
3608
|
+
});
|
|
3609
|
+
}, [
|
|
3610
|
+
store,
|
|
3611
|
+
userId,
|
|
3612
|
+
isCurrentData,
|
|
3613
|
+
canonicalRef,
|
|
3614
|
+
id,
|
|
3615
|
+
label,
|
|
3616
|
+
labelField
|
|
3617
|
+
]);
|
|
3618
|
+
}
|
|
3619
|
+
//#endregion
|
|
3620
|
+
//#region src/layout/record-page.tsx
|
|
3621
|
+
function useMountedRef() {
|
|
3622
|
+
const mounted = (0, react.useRef)(true);
|
|
3623
|
+
(0, react.useEffect)(() => {
|
|
3624
|
+
mounted.current = true;
|
|
3625
|
+
return () => {
|
|
3626
|
+
mounted.current = false;
|
|
3627
|
+
};
|
|
3628
|
+
}, []);
|
|
3629
|
+
return mounted;
|
|
3630
|
+
}
|
|
3631
|
+
function RecordRouteHeader({ resource, action, id, record }) {
|
|
3632
|
+
const recordName = (0, _burojs_react.useRecordTitle)(resource, action === "create" ? void 0 : id, record);
|
|
3633
|
+
require_record_trail_store.usePublishRecordTrail(action === "create" ? null : {
|
|
3634
|
+
key: require_record_trail_store.recordTrailKey(resource, id, action),
|
|
3635
|
+
title: recordName
|
|
3636
|
+
});
|
|
3637
|
+
return (0, react_jsx_runtime.jsx)(require_place_node.PageHeader, {
|
|
3638
|
+
resource,
|
|
3639
|
+
mode: action,
|
|
3640
|
+
...action === "create" ? {} : { recordName }
|
|
3641
|
+
});
|
|
3642
|
+
}
|
|
3643
|
+
function RecordShow({ resource, id, recordId, record, shown }) {
|
|
3644
|
+
return (0, react_jsx_runtime.jsxs)("div", { children: [(0, react_jsx_runtime.jsx)(RecordRouteHeader, {
|
|
3645
|
+
resource,
|
|
3646
|
+
action: "show",
|
|
3647
|
+
id,
|
|
3648
|
+
record: shown
|
|
3649
|
+
}), (0, react_jsx_runtime.jsx)(RecordScreen, {
|
|
3650
|
+
resource,
|
|
3651
|
+
mode: "show",
|
|
3652
|
+
recordId,
|
|
3653
|
+
record
|
|
3654
|
+
})] });
|
|
3655
|
+
}
|
|
3656
|
+
function RecordEdit({ resource, id, recordId, record, shown }) {
|
|
3657
|
+
const navigate = (0, _burojs_react.useRouteNavigate)();
|
|
3658
|
+
const mounted = useMountedRef();
|
|
3659
|
+
const back = (0, _burojs_react.useReturnTarget)(resource, "edit", id);
|
|
3660
|
+
return (0, react_jsx_runtime.jsxs)("div", { children: [(0, react_jsx_runtime.jsx)(RecordRouteHeader, {
|
|
3661
|
+
resource,
|
|
3662
|
+
action: "edit",
|
|
3663
|
+
id,
|
|
3664
|
+
record: shown
|
|
3665
|
+
}), (0, react_jsx_runtime.jsx)(RecordScreen, {
|
|
3666
|
+
resource,
|
|
3667
|
+
mode: "edit",
|
|
3668
|
+
recordId,
|
|
3669
|
+
record,
|
|
3670
|
+
onCancel: () => navigate(back, { origin: "inherit" }),
|
|
3671
|
+
onSuccess: () => {
|
|
3672
|
+
if (mounted.current) navigate(back, { origin: "inherit" });
|
|
3673
|
+
}
|
|
3674
|
+
})] });
|
|
3675
|
+
}
|
|
3676
|
+
function createdId(result) {
|
|
3677
|
+
const id = result?.id;
|
|
3678
|
+
return typeof id === "string" || typeof id === "number" ? String(id) : void 0;
|
|
3679
|
+
}
|
|
3680
|
+
function RecordCreate({ resource, defaults }) {
|
|
3681
|
+
const app = (0, _burojs_react.useApp)();
|
|
3682
|
+
const navigate = (0, _burojs_react.useRouteNavigate)();
|
|
3683
|
+
const mounted = useMountedRef();
|
|
3684
|
+
const adapter = (0, _burojs_react.useOptionalRouterAdapter)();
|
|
3685
|
+
const list = listTarget(resource);
|
|
3686
|
+
const back = (0, _burojs_react.useReturnTarget)(resource, "create");
|
|
3687
|
+
const type = adapter?.searchParams.get("type") ?? void 0;
|
|
3688
|
+
return (0, react_jsx_runtime.jsxs)("div", { children: [(0, react_jsx_runtime.jsx)(RecordRouteHeader, {
|
|
3689
|
+
resource,
|
|
3690
|
+
action: "create",
|
|
3691
|
+
id: ""
|
|
3692
|
+
}), (0, react_jsx_runtime.jsx)(require_place_node.RouteScreenClaimContext.Provider, {
|
|
3693
|
+
value: true,
|
|
3694
|
+
children: (0, react_jsx_runtime.jsx)(RecordScreen, {
|
|
3695
|
+
resource,
|
|
3696
|
+
mode: "create",
|
|
3697
|
+
...type === void 0 ? {} : { type },
|
|
3698
|
+
...defaults === void 0 ? {} : { defaults },
|
|
3699
|
+
onCancel: () => navigate(back, { origin: "inherit" }),
|
|
3700
|
+
onSuccess: (result) => {
|
|
3701
|
+
if (!mounted.current) return;
|
|
3702
|
+
const id = createdId(result);
|
|
3703
|
+
navigate(id !== void 0 && isShowAvailable(app.registry, resource) ? showTarget(resource, id) : list, { origin: "inherit" });
|
|
3704
|
+
}
|
|
3705
|
+
})
|
|
3706
|
+
})] });
|
|
3707
|
+
}
|
|
3708
|
+
function RecordRead({ resource, action, id, recordId }) {
|
|
3709
|
+
const app = (0, _burojs_react.useApp)();
|
|
3710
|
+
const def = app.registry.get(resource);
|
|
3711
|
+
const projection = (0, react.useMemo)(() => def === void 0 ? void 0 : (0, _burojs_core.dtoFields)(def, "record"), [def]);
|
|
3712
|
+
const query = (0, _burojs_react.useOne)(resource, {
|
|
3713
|
+
id: recordId,
|
|
3714
|
+
retry: _burojs_react.retryRecordRead,
|
|
3715
|
+
...projection === void 0 ? {} : { projection }
|
|
3716
|
+
});
|
|
3717
|
+
const result = query.data;
|
|
3718
|
+
const read = result?.data;
|
|
3719
|
+
const projected = (0, _burojs_react.useProjectedRecord)(resource, read, { placeholder: query.isPlaceholderData });
|
|
3720
|
+
const showAvailability = (0, _burojs_react.useAvailabilityResolver)(resource, "show");
|
|
3721
|
+
const permissions = (0, _burojs_react.useCtx)((c) => c.permissions);
|
|
3722
|
+
const showRuled = (0, _burojs_core.addressesCapability)(app.ruleSource.rules(resource), "run", {
|
|
3723
|
+
kind: "action",
|
|
3724
|
+
name: "show"
|
|
3725
|
+
});
|
|
3726
|
+
const showHidden = showRuled && read !== null && typeof read === "object" && showAvailability("show", read).state !== "available";
|
|
3727
|
+
const showSettled = !showRuled || !query.isPlaceholderData && !(0, _burojs_core.permissionsUndecided)(permissions) && permissions?.status !== "error";
|
|
3728
|
+
useRecordVisit(resource, projected.status === "ready" && showSettled && !showHidden ? projected.value : null, { isCurrentData: !query.isPlaceholderData });
|
|
3729
|
+
const route = (0, react.useMemo)(() => Object.freeze({ id }), [id]);
|
|
3730
|
+
const availability = (0, _burojs_react.useAvailabilityResolver)(resource, "edit");
|
|
3731
|
+
if (result !== void 0) {
|
|
3732
|
+
const record = result.data;
|
|
3733
|
+
if (record === null || typeof record !== "object") return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "not-found" });
|
|
3734
|
+
const loaded = record;
|
|
3735
|
+
if (showRuled) {
|
|
3736
|
+
if (query.isPlaceholderData || (0, _burojs_core.permissionsUndecided)(permissions)) return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "loading" });
|
|
3737
|
+
if (permissions?.status === "error") return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "not-found" });
|
|
3738
|
+
if (showHidden) return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "not-found" });
|
|
3739
|
+
}
|
|
3740
|
+
if (projected.status === "pending" || projected.value === null) return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "loading" });
|
|
3741
|
+
const shown = projected.value;
|
|
3742
|
+
if (action === "edit") {
|
|
3743
|
+
const edit = availability("edit", loaded).state;
|
|
3744
|
+
if (edit === "hidden" || edit === "absent") return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "not-found" });
|
|
3745
|
+
if (edit === "undecided") return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "loading" });
|
|
3746
|
+
}
|
|
3747
|
+
return (0, react_jsx_runtime.jsx)(_burojs_react.RouteSourceContext.Provider, {
|
|
3748
|
+
value: route,
|
|
3749
|
+
children: (0, react_jsx_runtime.jsx)(require_place_node.RouteScreenClaimContext.Provider, {
|
|
3750
|
+
value: true,
|
|
3751
|
+
children: action === "edit" ? (0, react_jsx_runtime.jsx)(RecordEdit, {
|
|
3752
|
+
resource,
|
|
3753
|
+
id,
|
|
3754
|
+
recordId,
|
|
3755
|
+
record: loaded,
|
|
3756
|
+
shown
|
|
3757
|
+
}) : (0, react_jsx_runtime.jsx)(RecordShow, {
|
|
3758
|
+
resource,
|
|
3759
|
+
id,
|
|
3760
|
+
recordId,
|
|
3761
|
+
record: loaded,
|
|
3762
|
+
shown
|
|
3763
|
+
})
|
|
3764
|
+
})
|
|
3765
|
+
});
|
|
3766
|
+
}
|
|
3767
|
+
if (query.error != null) return (0, react_jsx_runtime.jsx)(require_relation_create.LoadError, {
|
|
3768
|
+
surface: "record",
|
|
3769
|
+
resource,
|
|
3770
|
+
error: query.error,
|
|
3771
|
+
retry: () => void query.refetch()
|
|
3772
|
+
});
|
|
3773
|
+
return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "loading" });
|
|
3774
|
+
}
|
|
3775
|
+
function RecordRouteBody(props) {
|
|
3776
|
+
if (props.action === "create") return (0, react_jsx_runtime.jsx)(RecordCreate, { ...props });
|
|
3777
|
+
if (props.id === "") return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "not-found" });
|
|
3778
|
+
return (0, react_jsx_runtime.jsx)(RecordReadRoute, { ...props });
|
|
3779
|
+
}
|
|
3780
|
+
function RecordReadRoute(props) {
|
|
3781
|
+
const recordId = (0, _burojs_react.useRouteRecordId)(props.resource, props.id);
|
|
3782
|
+
if (recordId === void 0) return (0, react_jsx_runtime.jsx)(require_relation_create.InvalidRouteId, { resource: props.resource });
|
|
3783
|
+
return (0, react_jsx_runtime.jsx)(RecordRead, {
|
|
3784
|
+
...props,
|
|
3785
|
+
recordId
|
|
3786
|
+
});
|
|
3787
|
+
}
|
|
3788
|
+
function RecordRoute(props) {
|
|
3789
|
+
const missingRuntime = (0, _burojs_react.useOptionalDataRuntime)() === null;
|
|
3790
|
+
(0, react.useEffect)(() => {
|
|
3791
|
+
if (!missingRuntime || process.env.NODE_ENV === "production") return;
|
|
3792
|
+
console.error(`[burojs] The '${props.resource}' record page has no data runtime to read or write with: BuroProvider.dataRuntime is not set. Pass <BuroProvider dataRuntime={…}> (createDataRuntime from @burojs/react); until then record routes render the error state.`);
|
|
3793
|
+
}, [missingRuntime, props.resource]);
|
|
3794
|
+
if (missingRuntime) return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "error" });
|
|
3795
|
+
return (0, react_jsx_runtime.jsx)(RecordRouteBody, { ...props }, `${props.resource}:${props.id}`);
|
|
3796
|
+
}
|
|
3797
|
+
function recordPageProblem(input) {
|
|
3798
|
+
const { props, resource, action } = input;
|
|
3799
|
+
if (resource === void 0 || action === void 0) return "[burojs] <RecordPage> needs both `resource` and `action`. Pass them; until then it renders not-found.";
|
|
3800
|
+
if (!input.onRecordRoute) return `[burojs] <RecordPage resource="${resource}" action="${action}"> is not on a record route (show, edit or create), so it has no record to read: render it on one, under a RouterAdapterProvider. Until then it renders not-found.`;
|
|
3801
|
+
if (props.defaults !== void 0 && action !== "create") return `[burojs] <RecordPage defaults> applies to create only; on this '${action}' route it is ignored.`;
|
|
3802
|
+
return null;
|
|
3803
|
+
}
|
|
3804
|
+
const recordPageProblemsLogged = new WeakMap();
|
|
3805
|
+
function RecordPage(props) {
|
|
3806
|
+
const app = (0, _burojs_react.useApp)();
|
|
3807
|
+
const match = useMatch();
|
|
3808
|
+
const id = match === null ? null : match.id ?? "";
|
|
3809
|
+
const { action } = props;
|
|
3810
|
+
const resource = props.resource === void 0 ? void 0 : (0, _burojs_core.routeResourceKey)(props.resource);
|
|
3811
|
+
const onRecordRoute = recordActionOf(match) !== void 0;
|
|
3812
|
+
const problem = recordPageProblem({
|
|
3813
|
+
props,
|
|
3814
|
+
resource,
|
|
3815
|
+
action,
|
|
3816
|
+
onRecordRoute
|
|
3817
|
+
});
|
|
3818
|
+
(0, react.useEffect)(() => {
|
|
3819
|
+
if (problem === null || process.env.NODE_ENV === "production") return;
|
|
3820
|
+
let logged = recordPageProblemsLogged.get(app);
|
|
3821
|
+
if (logged === void 0) {
|
|
3822
|
+
logged = new Set();
|
|
3823
|
+
recordPageProblemsLogged.set(app, logged);
|
|
3824
|
+
}
|
|
3825
|
+
if (logged.has(problem)) return;
|
|
3826
|
+
logged.add(problem);
|
|
3827
|
+
console.error(problem);
|
|
3828
|
+
}, [app, problem]);
|
|
3829
|
+
if (resource === void 0 || action === void 0 || id === null || !onRecordRoute) return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "not-found" });
|
|
3830
|
+
const route = action === "create" ? {
|
|
3831
|
+
resource,
|
|
3832
|
+
action,
|
|
3833
|
+
defaults: props.defaults
|
|
3834
|
+
} : {
|
|
3835
|
+
resource,
|
|
3836
|
+
action
|
|
3837
|
+
};
|
|
3838
|
+
return (0, react_jsx_runtime.jsx)(RecordRoute, {
|
|
3839
|
+
...route,
|
|
3840
|
+
id
|
|
3841
|
+
});
|
|
3842
|
+
}
|
|
3843
|
+
//#endregion
|
|
3844
|
+
//#region src/layout/collection-record-route.tsx
|
|
3845
|
+
function addressTail(searchParams, routerHash) {
|
|
3846
|
+
const query = searchParams?.toString() ?? "";
|
|
3847
|
+
const hash = routerHash ?? (typeof window === "undefined" ? "" : window.location.hash);
|
|
3848
|
+
return `${query === "" ? "" : `?${query}`}${hash === "#" ? "" : hash}`;
|
|
3849
|
+
}
|
|
3850
|
+
function CollectionRecordRoute(props) {
|
|
3851
|
+
const { collection, action, id } = props;
|
|
3852
|
+
const app = (0, _burojs_react.useApp)();
|
|
3853
|
+
const navigate = (0, _burojs_react.useRouteNavigate)();
|
|
3854
|
+
const adapter = (0, _burojs_react.useOptionalRouterAdapter)();
|
|
3855
|
+
const state = (0, _burojs_react.useCollectionMember)(collection, id);
|
|
3856
|
+
const flow = props.action === "flow" ? props.flow : void 0;
|
|
3857
|
+
const target = state.status === "member" ? (0, _burojs_core.hrefFor)(app.registry, state.member, {
|
|
3858
|
+
action,
|
|
3859
|
+
id,
|
|
3860
|
+
...flow === void 0 ? {} : { flow }
|
|
3861
|
+
}) : void 0;
|
|
3862
|
+
const current = (0, react.useRef)(adapter);
|
|
3863
|
+
current.current = adapter;
|
|
3864
|
+
const sent = (0, react.useRef)(void 0);
|
|
3865
|
+
(0, react.useEffect)(() => {
|
|
3866
|
+
if (target === void 0 || sent.current === target) return;
|
|
3867
|
+
sent.current = target;
|
|
3868
|
+
navigate(`${target}${addressTail(current.current?.searchParams, current.current?.hash)}`, { replace: true });
|
|
3869
|
+
}, [target, navigate]);
|
|
3870
|
+
if (state.status === "unknown") return (0, react_jsx_runtime.jsx)(UnknownMemberCard, {
|
|
3871
|
+
collection,
|
|
3872
|
+
id,
|
|
3873
|
+
value: state.value
|
|
3874
|
+
});
|
|
3875
|
+
if (state.status === "not-found") return (0, react_jsx_runtime.jsx)(require_record_trail_store.NavAreaNotFound, {});
|
|
3876
|
+
if (state.status === "error") return (0, react_jsx_runtime.jsx)(require_relation_create.LoadError, {
|
|
3877
|
+
surface: "record",
|
|
3878
|
+
resource: (0, _burojs_core.routeResourceKey)(collection),
|
|
3879
|
+
error: state.error
|
|
3880
|
+
});
|
|
3881
|
+
return null;
|
|
3882
|
+
}
|
|
3883
|
+
function UnknownMemberCard({ collection, id, value }) {
|
|
3884
|
+
const app = (0, _burojs_react.useApp)();
|
|
3885
|
+
const t = (0, _burojs_react.useOptionalT)();
|
|
3886
|
+
const key = (0, _burojs_core.routeResourceKey)(collection);
|
|
3887
|
+
const fact = (0, _burojs_core.memberFactOf)(app.registry.get(key));
|
|
3888
|
+
const shown = value === void 0 || value === null ? "" : String(value);
|
|
3889
|
+
const known = (fact?.collection?.members ?? []).flatMap((member) => member.values).join(", ");
|
|
3890
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
3891
|
+
"data-testid": `unknown-member-card:${key}:${id}`,
|
|
3892
|
+
className: "flex flex-col gap-2",
|
|
3893
|
+
children: [
|
|
3894
|
+
process.env.NODE_ENV === "production" ? null : (0, react_jsx_runtime.jsx)("div", {
|
|
3895
|
+
role: "note",
|
|
3896
|
+
"data-testid": "unknown-member-notice",
|
|
3897
|
+
className: "mx-6 mt-4 rounded-md border border-dashed border-amber-500/60 bg-amber-500/10 px-3 py-2 text-sm",
|
|
3898
|
+
children: t("collection.unknownMemberNotice", {
|
|
3899
|
+
params: {
|
|
3900
|
+
base: fact === void 0 ? key : (0, _burojs_core.formatEntityRef)(fact.ref),
|
|
3901
|
+
value: shown,
|
|
3902
|
+
known
|
|
3903
|
+
},
|
|
3904
|
+
defaultValue: "No member of {{base}} claims the type “{{value}}”. Known types: {{known}}."
|
|
3905
|
+
})
|
|
3906
|
+
}),
|
|
3907
|
+
(0, react_jsx_runtime.jsx)("p", {
|
|
3908
|
+
"data-testid": "unknown-member-type",
|
|
3909
|
+
className: "mx-6 text-sm text-muted-foreground",
|
|
3910
|
+
children: t("collection.unknownType", {
|
|
3911
|
+
params: { value: shown },
|
|
3912
|
+
defaultValue: "Unknown type: {{value}}"
|
|
3913
|
+
})
|
|
3914
|
+
}),
|
|
3915
|
+
(0, react_jsx_runtime.jsx)(require_place_node.ItemActionsOffContext.Provider, {
|
|
3916
|
+
value: true,
|
|
3917
|
+
children: (0, react_jsx_runtime.jsx)(RecordRoute, {
|
|
3918
|
+
resource: key,
|
|
3919
|
+
action: "show",
|
|
3920
|
+
id
|
|
3921
|
+
})
|
|
3922
|
+
})
|
|
3923
|
+
]
|
|
3924
|
+
});
|
|
3925
|
+
}
|
|
3926
|
+
//#endregion
|
|
3927
|
+
//#region src/layout/page-host.tsx
|
|
3928
|
+
function PageHost({ page, match, notFound }) {
|
|
3929
|
+
const isVisible = useNavVisible();
|
|
3930
|
+
const ctx = (0, _burojs_react.useVisibilityCtx)();
|
|
3931
|
+
const access = (0, _burojs_react.usePageAccess)(page);
|
|
3932
|
+
if (!((0, _burojs_core.evaluateVisible)(page.visible, ctx) && match.groupChain.every((group) => isVisible(group)))) return notFound;
|
|
3933
|
+
if (access === "pending") return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "loading" });
|
|
3934
|
+
if (access === "denied") return notFound;
|
|
3935
|
+
return (0, react_jsx_runtime.jsx)(PageParams, {
|
|
3936
|
+
page,
|
|
3937
|
+
notFound
|
|
3938
|
+
});
|
|
3939
|
+
}
|
|
3940
|
+
const NO_SEARCH = new URLSearchParams();
|
|
3941
|
+
function PageParams({ page, notFound }) {
|
|
3942
|
+
const search = (0, _burojs_react.useOptionalRouterAdapter)()?.searchParams ?? (typeof window === "undefined" ? NO_SEARCH : new URLSearchParams(window.location.search));
|
|
3943
|
+
const raw = JSON.stringify((0, _burojs_core.pageParamNames)(page.params).map((name) => search.get(name)));
|
|
3944
|
+
const parsed = (0, react.useMemo)(() => (0, _burojs_core.parsePageParams)(page, search), [page, raw]);
|
|
3945
|
+
if (!parsed.ok) return notFound;
|
|
3946
|
+
return (0, react_jsx_runtime.jsx)(_burojs_react.RouteSourceContext.Provider, {
|
|
3947
|
+
value: parsed.route,
|
|
3948
|
+
children: (0, react_jsx_runtime.jsx)(PageBody, { page })
|
|
3949
|
+
});
|
|
3950
|
+
}
|
|
3951
|
+
function PageBody({ page }) {
|
|
3952
|
+
const snapshot = (0, _burojs_react.useApplicationSnapshot)();
|
|
3953
|
+
const compiled = (0, react.useMemo)(() => (0, _burojs_core.compilePageScreen)(page, {
|
|
3954
|
+
blocks: (0, _burojs_core.snapshotBlockLookup)(snapshot),
|
|
3955
|
+
frames: (0, _burojs_core.snapshotFrameLookup)(snapshot),
|
|
3956
|
+
appFrames: (0, _burojs_core.snapshotAppFrames)(snapshot)
|
|
3957
|
+
}), [page, snapshot]);
|
|
3958
|
+
const failure = (0, _burojs_core.isScreenFailure)(compiled) ? compiled : null;
|
|
3959
|
+
const screen = failure === null && !(0, _burojs_core.isScreenFailure)(compiled) ? compiled : null;
|
|
3960
|
+
const caps = (0, _burojs_react.useI18nCaps)();
|
|
3961
|
+
const name = require_record_trail_store.canonicalNavKey(page);
|
|
3962
|
+
const label = (0, _burojs_core.resolveNavLabel)(caps, `pages.${name}`, (0, _burojs_core.declaredText)("chrome", page, "label"));
|
|
3963
|
+
(0, react.useEffect)(() => {
|
|
3964
|
+
if (failure === null || process.env.NODE_ENV === "production") return;
|
|
3965
|
+
console.error(`[burojs] The page "${name}" cannot render its body: ${failure.code} at ${failure.path.join(".")}: ${failure.message}.`);
|
|
3966
|
+
}, [failure, name]);
|
|
3967
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
3968
|
+
className: "flex flex-col gap-4",
|
|
3969
|
+
children: [(0, react_jsx_runtime.jsx)("h1", {
|
|
3970
|
+
className: "text-2xl font-semibold tracking-tight",
|
|
3971
|
+
children: label
|
|
3972
|
+
}), screen === null ? (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "error" }) : (0, react_jsx_runtime.jsx)(PageRouteScreen, { children: (0, react_jsx_runtime.jsx)(PlannedBody, {
|
|
3973
|
+
screen,
|
|
3974
|
+
name,
|
|
3975
|
+
label
|
|
3976
|
+
}) })]
|
|
3977
|
+
});
|
|
3978
|
+
}
|
|
3979
|
+
function PageRouteScreen({ children }) {
|
|
3980
|
+
const tabs = require_place_node.useTabsUrlState("show", true);
|
|
3981
|
+
return (0, react_jsx_runtime.jsx)(require_place_node.RouteScreenClaimContext.Provider, {
|
|
3982
|
+
value: false,
|
|
3983
|
+
children: (0, react_jsx_runtime.jsx)(require_place_node.RouteScreenContext.Provider, {
|
|
3984
|
+
value: true,
|
|
3985
|
+
children: (0, react_jsx_runtime.jsx)(_burojs_react.ScreenStateProvider, {
|
|
3986
|
+
open: tabs.open,
|
|
3987
|
+
onOpenChange: tabs.onOpenChange,
|
|
3988
|
+
children
|
|
3989
|
+
})
|
|
3990
|
+
})
|
|
3991
|
+
});
|
|
3992
|
+
}
|
|
3993
|
+
function PlannedBody({ screen, name, label, record }) {
|
|
3994
|
+
const pageOptions = (0, react.useMemo)(() => record === void 0 ? {} : { record }, [record]);
|
|
3995
|
+
const page = (0, _burojs_react.usePageScreen)(screen, pageOptions);
|
|
3996
|
+
const { PlacementScope } = page;
|
|
3997
|
+
const route = (0, react.useContext)(_burojs_react.RouteSourceContext);
|
|
3998
|
+
const catalog = (0, _burojs_react.useFrameImplementations)();
|
|
3999
|
+
const id = (0, _burojs_core.formatEntityRef)(screen.frame);
|
|
4000
|
+
const resolved = (0, react.useMemo)(() => require_place_node.resolveFrameView(screen.frame, catalog, "page"), [screen.frame, catalog]);
|
|
4001
|
+
const t = (0, _burojs_react.useFrameT)(id);
|
|
4002
|
+
const slots = {};
|
|
4003
|
+
for (const slot of Object.keys(screen.slots)) slots[slot] = (page.plan.slots[slot] ?? []).every((node) => node.state === "absent") ? null : (0, react_jsx_runtime.jsx)(require_place_node.ScreenTree, {
|
|
4004
|
+
region: slot === "body" ? "page-body" : "record",
|
|
4005
|
+
slot,
|
|
4006
|
+
resource: name,
|
|
4007
|
+
mode: "show",
|
|
4008
|
+
compiled: screen,
|
|
4009
|
+
page
|
|
4010
|
+
}, slot);
|
|
4011
|
+
const View = resolved.view;
|
|
4012
|
+
const viewProps = {
|
|
4013
|
+
slots,
|
|
4014
|
+
label,
|
|
4015
|
+
params: route ?? {},
|
|
4016
|
+
t
|
|
4017
|
+
};
|
|
4018
|
+
return (0, react_jsx_runtime.jsx)(_burojs_react.RouteSourceContext.Provider, {
|
|
4019
|
+
value: null,
|
|
4020
|
+
children: (0, react_jsx_runtime.jsx)(_burojs_react.ActionRouteContext.Provider, {
|
|
4021
|
+
value: route,
|
|
4022
|
+
children: (0, react_jsx_runtime.jsx)(PlacementScope, { children: (0, react_jsx_runtime.jsx)(require_place_node.DeepLinkScope, {
|
|
4023
|
+
plan: page.plan,
|
|
4024
|
+
enabled: true,
|
|
4025
|
+
children: (0, react_jsx_runtime.jsx)("div", {
|
|
4026
|
+
"data-buro-region": "page-body",
|
|
4027
|
+
children: (0, react_jsx_runtime.jsx)(react.Suspense, {
|
|
4028
|
+
fallback: null,
|
|
4029
|
+
children: (0, react_jsx_runtime.jsx)(View, { ...viewProps })
|
|
4030
|
+
})
|
|
4031
|
+
})
|
|
4032
|
+
}) })
|
|
4033
|
+
})
|
|
4034
|
+
});
|
|
4035
|
+
}
|
|
4036
|
+
//#endregion
|
|
4037
|
+
//#region src/layout/resource-page-router.tsx
|
|
4038
|
+
function ResourcePageRouterEmpty() {
|
|
4039
|
+
const t = (0, _burojs_react.useT)();
|
|
4040
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
4041
|
+
"data-testid": "resource-page-router-empty",
|
|
4042
|
+
className: "flex flex-col items-center justify-center gap-1 px-6 py-24 text-center",
|
|
4043
|
+
children: [(0, react_jsx_runtime.jsx)("h2", {
|
|
4044
|
+
className: "text-base font-semibold tracking-tight",
|
|
4045
|
+
children: t("router.emptyTitle")
|
|
4046
|
+
}), (0, react_jsx_runtime.jsx)("p", {
|
|
4047
|
+
className: "max-w-sm text-sm text-muted-foreground",
|
|
4048
|
+
children: t("router.emptyBody")
|
|
4049
|
+
})]
|
|
4050
|
+
});
|
|
4051
|
+
}
|
|
4052
|
+
function ResourcePageRouter({ match }) {
|
|
4053
|
+
const app = (0, _burojs_react.useApp)();
|
|
4054
|
+
const qualifiedMatch = match;
|
|
4055
|
+
const resource = require_record_trail_store.canonicalNavKey(qualifiedMatch);
|
|
4056
|
+
const target = require_record_trail_store.canonicalNavKey({
|
|
4057
|
+
name: match.target ?? match.name,
|
|
4058
|
+
ref: qualifiedMatch.targetRef
|
|
4059
|
+
});
|
|
4060
|
+
const recordAction = recordActionOf(match);
|
|
4061
|
+
switch (match.kind) {
|
|
4062
|
+
case "resource": {
|
|
4063
|
+
if (match.action === "list") {
|
|
4064
|
+
const def = app.registry.get(resource);
|
|
4065
|
+
return def !== void 0 && !(0, _burojs_core.hasListPage)(def) ? (0, react_jsx_runtime.jsx)(require_record_trail_store.NavAreaNotFound, {}) : (0, react_jsx_runtime.jsx)(ResourceListPage, { resource });
|
|
4066
|
+
}
|
|
4067
|
+
const collection = (0, _burojs_core.collectionFactOf)(app.registry.get(resource)) !== void 0;
|
|
4068
|
+
if (collection && match.id !== void 0 && (match.action === "show" || match.action === "edit" || match.action === "flow")) {
|
|
4069
|
+
if (!(0, _burojs_react.recordRouteAvailable)(app.registry, resource, "show")) return (0, react_jsx_runtime.jsx)(require_record_trail_store.NavAreaNotFound, {});
|
|
4070
|
+
return match.action === "flow" ? (0, react_jsx_runtime.jsx)(CollectionRecordRoute, {
|
|
4071
|
+
collection: resource,
|
|
4072
|
+
action: "flow",
|
|
4073
|
+
id: match.id,
|
|
4074
|
+
flow: match.flow ?? ""
|
|
4075
|
+
}) : (0, react_jsx_runtime.jsx)(CollectionRecordRoute, {
|
|
4076
|
+
collection: resource,
|
|
4077
|
+
action: match.action,
|
|
4078
|
+
id: match.id
|
|
4079
|
+
});
|
|
4080
|
+
}
|
|
4081
|
+
if (match.action === "flow") return (0, react_jsx_runtime.jsx)(PageFlowRouteLoader, { match });
|
|
4082
|
+
if (recordAction === void 0) return (0, react_jsx_runtime.jsx)(ResourcePageRouterEmpty, {});
|
|
4083
|
+
if (!(0, _burojs_react.recordRouteAvailable)(app.registry, resource, recordAction)) return (0, react_jsx_runtime.jsx)(require_record_trail_store.NavAreaNotFound, {});
|
|
4084
|
+
if (collection && recordAction === "create") return (0, react_jsx_runtime.jsx)(CollectionCreatePicker, { collection: resource });
|
|
4085
|
+
return (0, react_jsx_runtime.jsx)(RecordRoute, {
|
|
4086
|
+
resource,
|
|
4087
|
+
action: recordAction,
|
|
4088
|
+
id: match.id ?? ""
|
|
4089
|
+
});
|
|
4090
|
+
}
|
|
4091
|
+
case "custom-page": {
|
|
4092
|
+
const page = app.registry.customPages.get(resource);
|
|
4093
|
+
if (page === void 0) return (0, react_jsx_runtime.jsx)(ResourcePageRouterEmpty, {});
|
|
4094
|
+
if (!page.body?.length) return (0, react_jsx_runtime.jsx)(require_record_trail_store.NavAreaNotFound, {});
|
|
4095
|
+
return (0, react_jsx_runtime.jsx)(PageHost, {
|
|
4096
|
+
page,
|
|
4097
|
+
match,
|
|
4098
|
+
notFound: (0, react_jsx_runtime.jsx)(require_record_trail_store.NavAreaNotFound, {})
|
|
4099
|
+
}, resource);
|
|
4100
|
+
}
|
|
4101
|
+
case "group-index": {
|
|
4102
|
+
const indexPage = app.registry.customPages.get(target);
|
|
4103
|
+
if (indexPage?.body?.length) return (0, react_jsx_runtime.jsx)(PageHost, {
|
|
4104
|
+
page: indexPage,
|
|
4105
|
+
match,
|
|
4106
|
+
notFound: (0, react_jsx_runtime.jsx)(require_record_trail_store.NavAreaNotFound, {})
|
|
4107
|
+
}, target);
|
|
4108
|
+
const targetDef = app.registry.get(target);
|
|
4109
|
+
if (targetDef !== void 0) return (0, _burojs_core.hasListPage)(targetDef) ? (0, react_jsx_runtime.jsx)(ResourceListPage, { resource: target }) : (0, react_jsx_runtime.jsx)(require_record_trail_store.NavAreaNotFound, {});
|
|
4110
|
+
return (0, react_jsx_runtime.jsx)(ResourcePageRouterEmpty, {});
|
|
4111
|
+
}
|
|
4112
|
+
default: return (0, react_jsx_runtime.jsx)(ResourcePageRouterEmpty, {});
|
|
4113
|
+
}
|
|
4114
|
+
}
|
|
4115
|
+
function NavAreaPageSkeleton() {
|
|
4116
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
4117
|
+
className: "space-y-3 p-6",
|
|
4118
|
+
role: "status",
|
|
4119
|
+
"aria-busy": "true",
|
|
4120
|
+
"aria-live": "polite",
|
|
4121
|
+
"data-testid": "nav-area-skeleton",
|
|
4122
|
+
children: [
|
|
4123
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
4124
|
+
className: "sr-only",
|
|
4125
|
+
children: "Loading…"
|
|
4126
|
+
}),
|
|
4127
|
+
(0, react_jsx_runtime.jsx)("div", { className: "h-6 w-48 animate-pulse rounded bg-muted/60" }),
|
|
4128
|
+
(0, react_jsx_runtime.jsx)("div", { className: "h-4 w-full animate-pulse rounded bg-muted/40" }),
|
|
4129
|
+
(0, react_jsx_runtime.jsx)("div", { className: "h-4 w-5/6 animate-pulse rounded bg-muted/40" }),
|
|
4130
|
+
(0, react_jsx_runtime.jsx)("div", { className: "h-4 w-2/3 animate-pulse rounded bg-muted/40" })
|
|
4131
|
+
]
|
|
4132
|
+
});
|
|
4133
|
+
}
|
|
4134
|
+
const adapterNoticeGiven = new WeakSet();
|
|
4135
|
+
const chromeNoticeGiven = new WeakSet();
|
|
4136
|
+
function NavAreaPage() {
|
|
4137
|
+
const match = useMatch();
|
|
4138
|
+
const app = (0, _burojs_react.useApp)();
|
|
4139
|
+
const noAdapter = (0, _burojs_react.useOptionalRouterAdapter)() === null;
|
|
4140
|
+
const chromeMounted = useNavChromeMounted();
|
|
4141
|
+
const resolveLayout = useLayoutResolver();
|
|
4142
|
+
const chromeGroup = match?.groupChain.find((g) => resolveLayout(g.layout)) ?? null;
|
|
4143
|
+
(0, react.useEffect)(() => {
|
|
4144
|
+
if (process.env.NODE_ENV === "production") return;
|
|
4145
|
+
if (chromeMounted || !chromeGroup || chromeNoticeGiven.has(app)) return;
|
|
4146
|
+
chromeNoticeGiven.add(app);
|
|
4147
|
+
console.error(`[burojs] <NavAreaPage> is inside the nav group "${require_record_trail_store.canonicalNavKey(chromeGroup)}" whose layout "${chromeGroup.layout}" draws area chrome, and no <NavChrome> is mounted above it. <AppShell> mounts one by default; with your own frame, wrap your routes in <NavChrome>.`);
|
|
4148
|
+
}, [
|
|
4149
|
+
app,
|
|
4150
|
+
chromeMounted,
|
|
4151
|
+
chromeGroup
|
|
4152
|
+
]);
|
|
4153
|
+
(0, react.useEffect)(() => {
|
|
4154
|
+
if (!noAdapter || process.env.NODE_ENV === "production") return;
|
|
4155
|
+
if (adapterNoticeGiven.has(app)) return;
|
|
4156
|
+
adapterNoticeGiven.add(app);
|
|
4157
|
+
console.error("[burojs] <NavAreaPage> has no location to match: no RouterAdapterProvider is mounted. Mount your router’s adapter (RouterAdapterProvider from @burojs/react) above <BuroProvider>; until then every route renders not-found.");
|
|
4158
|
+
}, [app, noAdapter]);
|
|
4159
|
+
return (0, react_jsx_runtime.jsx)(react.Suspense, {
|
|
4160
|
+
fallback: (0, react_jsx_runtime.jsx)(NavAreaPageSkeleton, {}),
|
|
4161
|
+
children: match ? (0, react_jsx_runtime.jsx)(ResourcePageRouter, { match }) : (0, react_jsx_runtime.jsx)(require_record_trail_store.NavAreaNotFound, {})
|
|
4162
|
+
});
|
|
4163
|
+
}
|
|
4164
|
+
//#endregion
|
|
2097
4165
|
//#region src/layout/breadcrumbs.tsx
|
|
2098
4166
|
const LINK_CLASS = "rounded hover:text-foreground transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2";
|
|
2099
4167
|
function Chevron() {
|
|
@@ -2158,7 +4226,7 @@ function Breadcrumbs(input) {
|
|
|
2158
4226
|
});
|
|
2159
4227
|
if (!def) return null;
|
|
2160
4228
|
const { recordId, pageLabel, middleSegments, rootSegments } = props;
|
|
2161
|
-
const resourceKey =
|
|
4229
|
+
const resourceKey = require_record_trail_store.canonicalResourceKey(def);
|
|
2162
4230
|
if (rootSegments !== void 0 && rootSegments.length > 0) return (0, react_jsx_runtime.jsxs)("nav", {
|
|
2163
4231
|
className: navClass,
|
|
2164
4232
|
"aria-label": ariaLabel,
|
|
@@ -2229,20 +4297,23 @@ function Breadcrumbs(input) {
|
|
|
2229
4297
|
//#region src/layout/record-breadcrumbs.tsx
|
|
2230
4298
|
function viewOrigin(ctx, trail, resource) {
|
|
2231
4299
|
if (trail === void 0 || trail.resource === void 0 || trail.segments.length > 0) return void 0;
|
|
2232
|
-
const
|
|
2233
|
-
|
|
2234
|
-
return trail.resource;
|
|
4300
|
+
const def = ctx.registry.get(trail.resource);
|
|
4301
|
+
const target = def?.routesTo?.show;
|
|
4302
|
+
if (target !== void 0 && ctx.registry.get(target) === ctx.registry.get(resource)) return trail.resource;
|
|
4303
|
+
const collected = (0, _burojs_core.collectionFactOf)(def) === void 0 ? void 0 : (0, _burojs_core.memberFactOf)(def)?.ref;
|
|
4304
|
+
const memberBase = (0, _burojs_core.memberFactOf)(ctx.registry.get(resource))?.ref;
|
|
4305
|
+
if (collected !== void 0 && memberBase !== void 0 && (0, _burojs_core.sameEntityRef)(collected, memberBase)) return trail.resource;
|
|
2235
4306
|
}
|
|
2236
4307
|
function RecordBreadcrumbs() {
|
|
2237
|
-
const ctx =
|
|
2238
|
-
const match =
|
|
4308
|
+
const ctx = useTrailContext();
|
|
4309
|
+
const match = useMatch();
|
|
2239
4310
|
const snapshot = (0, _burojs_react.useApplicationSnapshot)();
|
|
2240
|
-
const route =
|
|
2241
|
-
const published =
|
|
4311
|
+
const route = recordTrailRoute(ctx.registry, match);
|
|
4312
|
+
const published = require_record_trail_store.usePublishedRecordTrail(route === null ? "" : require_record_trail_store.recordTrailKey(route.resource, route.id, route.flow === void 0 ? route.action : `flow:${route.flow}`));
|
|
2242
4313
|
const idTitle = (0, _burojs_react.useRecordTitle)(route?.resource, route?.id);
|
|
2243
4314
|
(0, _burojs_react.usePublishOriginTitle)(published?.title || void 0);
|
|
2244
4315
|
const origin = (0, _burojs_react.useNavigationOrigin)();
|
|
2245
|
-
const rooted = origin === null ? void 0 :
|
|
4316
|
+
const rooted = origin === null ? void 0 : originTrail(ctx, origin);
|
|
2246
4317
|
const view = route === null ? void 0 : viewOrigin(ctx, rooted, route.resource);
|
|
2247
4318
|
const viewScopes = (0, _burojs_react.useDocTrailScopes)(view);
|
|
2248
4319
|
const ownScopes = (0, _burojs_react.useDocTrailScopes)(view === void 0 ? void 0 : route?.resource);
|
|
@@ -2255,7 +4326,7 @@ function RecordBreadcrumbs() {
|
|
|
2255
4326
|
if ((0, _burojs_core.effectiveFlow)(snapshot, match.ref, route.flow) === void 0) return null;
|
|
2256
4327
|
const flowLabel = published?.flowLabel;
|
|
2257
4328
|
if (flowLabel === void 0) return (0, react_jsx_runtime.jsx)(Breadcrumbs, {
|
|
2258
|
-
...
|
|
4329
|
+
...recordTrail(ctx, {
|
|
2259
4330
|
resource,
|
|
2260
4331
|
action: "show",
|
|
2261
4332
|
id,
|
|
@@ -2267,7 +4338,7 @@ function RecordBreadcrumbs() {
|
|
|
2267
4338
|
"data-testid": "record-breadcrumbs"
|
|
2268
4339
|
});
|
|
2269
4340
|
return (0, react_jsx_runtime.jsx)(Breadcrumbs, {
|
|
2270
|
-
...
|
|
4341
|
+
...recordTrail(ctx, {
|
|
2271
4342
|
resource,
|
|
2272
4343
|
action: "edit",
|
|
2273
4344
|
id,
|
|
@@ -2281,7 +4352,7 @@ function RecordBreadcrumbs() {
|
|
|
2281
4352
|
});
|
|
2282
4353
|
}
|
|
2283
4354
|
return (0, react_jsx_runtime.jsx)(Breadcrumbs, {
|
|
2284
|
-
...
|
|
4355
|
+
...recordTrail(ctx, {
|
|
2285
4356
|
resource,
|
|
2286
4357
|
action: route.action,
|
|
2287
4358
|
id,
|
|
@@ -2295,7 +4366,7 @@ function RecordBreadcrumbs() {
|
|
|
2295
4366
|
}
|
|
2296
4367
|
//#endregion
|
|
2297
4368
|
//#region src/layout/default-nav-layouts.ts
|
|
2298
|
-
const defaultNavLayouts = { ...
|
|
4369
|
+
const defaultNavLayouts = { ...BUILTIN_LAYOUTS };
|
|
2299
4370
|
//#endregion
|
|
2300
4371
|
//#region src/layout/context-picker.tsx
|
|
2301
4372
|
const ALL = "\0all";
|
|
@@ -2368,7 +4439,7 @@ function ScopeDimensionPicker(props) {
|
|
|
2368
4439
|
});
|
|
2369
4440
|
}
|
|
2370
4441
|
function ResourceDimension({ resource, labelField, ...rest }) {
|
|
2371
|
-
const options =
|
|
4442
|
+
const options = useResourceDimensionOptions(rest.dimension, resource, labelField);
|
|
2372
4443
|
return (0, react_jsx_runtime.jsx)(DimensionControl, {
|
|
2373
4444
|
...rest,
|
|
2374
4445
|
options
|
|
@@ -2455,10 +4526,10 @@ function LanguageSwitch({ onChange, className }) {
|
|
|
2455
4526
|
//#endregion
|
|
2456
4527
|
//#region src/layout/header-breadcrumbs.tsx
|
|
2457
4528
|
function HeaderBreadcrumbs() {
|
|
2458
|
-
const ctx =
|
|
2459
|
-
const match =
|
|
2460
|
-
if (
|
|
2461
|
-
const trail =
|
|
4529
|
+
const ctx = useTrailContext();
|
|
4530
|
+
const match = useMatch();
|
|
4531
|
+
if (recordTrailRoute(ctx.registry, match) !== null) return (0, react_jsx_runtime.jsx)(RecordBreadcrumbs, {});
|
|
4532
|
+
const trail = headerTrail(ctx, match);
|
|
2462
4533
|
if (trail === null) return null;
|
|
2463
4534
|
return (0, react_jsx_runtime.jsx)(Breadcrumbs, {
|
|
2464
4535
|
...trail,
|
|
@@ -2606,20 +4677,20 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2606
4677
|
const visibilityCtx = (0, _burojs_react.useVisibilityCtx)();
|
|
2607
4678
|
const t = (0, _burojs_react.useOptionalT)();
|
|
2608
4679
|
const navigate = (0, _burojs_react.useRouteNavigate)();
|
|
2609
|
-
const isVisible =
|
|
2610
|
-
const resolveLayout =
|
|
2611
|
-
const isResourceVisible =
|
|
2612
|
-
const pageAllowed =
|
|
4680
|
+
const isVisible = useNavVisible();
|
|
4681
|
+
const resolveLayout = useLayoutResolver();
|
|
4682
|
+
const isResourceVisible = useResourceVisible();
|
|
4683
|
+
const pageAllowed = usePageAllowed();
|
|
2613
4684
|
const isPageVisible = (p) => (0, _burojs_core.evaluateVisible)(p.visible, visibilityCtx) && pageAllowed(p);
|
|
2614
4685
|
const { topLevelResources, topLevelPages, sectionGroups } = (0, react.useMemo)(() => {
|
|
2615
4686
|
const allResources = app.registry.list();
|
|
2616
4687
|
const allPages = app.registry.customPages.list();
|
|
2617
4688
|
const allSections = app.registry.sections.list();
|
|
2618
|
-
const tlResources = allResources.filter((r) => (0, _burojs_core.
|
|
4689
|
+
const tlResources = allResources.filter((r) => (0, _burojs_core.hasMenuEntry)(r)).filter(isResourceVisible).filter((r) => !r.section && !r.group);
|
|
2619
4690
|
const tlPages = allPages.filter((p) => !p.section && !p.group).filter(isPageVisible);
|
|
2620
4691
|
const groups = [];
|
|
2621
4692
|
for (const section of allSections) {
|
|
2622
|
-
const children = app.registry.sections.childrenOf(
|
|
4693
|
+
const children = app.registry.sections.childrenOf(require_record_trail_store.canonicalNavKey(section)).filter((c) => !c.group).filter((c) => !("parent" in c) || (0, _burojs_core.hasMenuEntry)(c)).filter((c) => (0, _burojs_core.isCustomPageDef)(c) ? isPageVisible(c) : isResourceVisible(c));
|
|
2623
4694
|
if (children.length === 0) continue;
|
|
2624
4695
|
groups.push({
|
|
2625
4696
|
section,
|
|
@@ -2636,13 +4707,13 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2636
4707
|
onSelect?.();
|
|
2637
4708
|
navigate(href, { origin: "jump" });
|
|
2638
4709
|
};
|
|
2639
|
-
const resourceLabel = (def) => (0, _burojs_core.resolveResourceLabel)(caps,
|
|
2640
|
-
const pageLabel = (def) => (0, _burojs_core.resolveNavLabel)(caps, `pages.${
|
|
4710
|
+
const resourceLabel = (def) => (0, _burojs_core.resolveResourceLabel)(caps, require_record_trail_store.canonicalResourceKey(def), "plural", def);
|
|
4711
|
+
const pageLabel = (def) => (0, _burojs_core.resolveNavLabel)(caps, `pages.${require_record_trail_store.canonicalNavKey(def)}`, (0, _burojs_core.declaredText)("chrome", def, "label"));
|
|
2641
4712
|
const groups = [];
|
|
2642
4713
|
if (topLevelResources.length > 0) groups.push((0, react_jsx_runtime.jsx)(require_relation_create.CommandGroup, {
|
|
2643
4714
|
heading: t("commandPalette.resources", { defaultValue: "Resources" }),
|
|
2644
4715
|
children: topLevelResources.map((def) => {
|
|
2645
|
-
const resource =
|
|
4716
|
+
const resource = require_record_trail_store.canonicalResourceKey(def);
|
|
2646
4717
|
const label = resourceLabel(def);
|
|
2647
4718
|
const href = (0, _burojs_core.hrefFor)(app.registry, resource, { isVisible });
|
|
2648
4719
|
return (0, react_jsx_runtime.jsx)(require_relation_create.CommandItem, {
|
|
@@ -2656,7 +4727,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2656
4727
|
if (topLevelPages.length > 0) groups.push((0, react_jsx_runtime.jsx)(require_relation_create.CommandGroup, {
|
|
2657
4728
|
heading: t("commandPalette.pages", { defaultValue: "Pages" }),
|
|
2658
4729
|
children: topLevelPages.map((page) => {
|
|
2659
|
-
const pageKey =
|
|
4730
|
+
const pageKey = require_record_trail_store.canonicalNavKey(page);
|
|
2660
4731
|
const label = pageLabel(page);
|
|
2661
4732
|
const href = page.path;
|
|
2662
4733
|
return (0, react_jsx_runtime.jsx)(require_relation_create.CommandItem, {
|
|
@@ -2668,7 +4739,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2668
4739
|
})
|
|
2669
4740
|
}, "pages"));
|
|
2670
4741
|
for (const { section, children } of sectionGroups) {
|
|
2671
|
-
const sectionKey =
|
|
4742
|
+
const sectionKey = require_record_trail_store.canonicalNavKey(section);
|
|
2672
4743
|
const sectionLabel = (0, _burojs_core.resolveNavLabel)(caps, `sections.${sectionKey}`, (0, _burojs_core.declaredText)("chrome", section, "label"));
|
|
2673
4744
|
groups.push((0, react_jsx_runtime.jsxs)(require_relation_create.CommandGroup, {
|
|
2674
4745
|
heading: sectionLabel,
|
|
@@ -2680,7 +4751,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2680
4751
|
children: sectionLabel
|
|
2681
4752
|
}, `__section_header_${sectionKey}`), children.map((child) => {
|
|
2682
4753
|
if ((0, _burojs_core.isCustomPageDef)(child)) {
|
|
2683
|
-
const pageKey =
|
|
4754
|
+
const pageKey = require_record_trail_store.canonicalNavKey(child);
|
|
2684
4755
|
const href = child.path;
|
|
2685
4756
|
const label = pageLabel(child);
|
|
2686
4757
|
return (0, react_jsx_runtime.jsx)(require_relation_create.CommandItem, {
|
|
@@ -2691,7 +4762,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2691
4762
|
children: label
|
|
2692
4763
|
}, `section:${sectionKey}:page:${pageKey}`);
|
|
2693
4764
|
}
|
|
2694
|
-
const resource =
|
|
4765
|
+
const resource = require_record_trail_store.canonicalResourceKey(child);
|
|
2695
4766
|
const label = resourceLabel(child);
|
|
2696
4767
|
const href = (0, _burojs_core.hrefFor)(app.registry, resource, { isVisible });
|
|
2697
4768
|
return (0, react_jsx_runtime.jsx)(require_relation_create.CommandItem, {
|
|
@@ -2706,9 +4777,9 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2706
4777
|
}
|
|
2707
4778
|
const collectGroupItems = (group, idPath, depth) => {
|
|
2708
4779
|
const items = [];
|
|
2709
|
-
const href = !!resolveLayout(group.layout) ?
|
|
4780
|
+
const href = !!resolveLayout(group.layout) ? groupNavHref(app.registry, require_record_trail_store.canonicalNavKey(group), isVisible) : void 0;
|
|
2710
4781
|
if (href !== void 0) {
|
|
2711
|
-
const groupKey =
|
|
4782
|
+
const groupKey = require_record_trail_store.canonicalNavKey(group);
|
|
2712
4783
|
const label = (0, _burojs_core.resolveNavLabel)(caps, `groups.${groupKey}`, (0, _burojs_core.declaredText)("chrome", group, "label"));
|
|
2713
4784
|
items.push((0, react_jsx_runtime.jsx)(require_relation_create.CommandItem, {
|
|
2714
4785
|
value: `group:${idPath}:${label}`,
|
|
@@ -2718,18 +4789,18 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2718
4789
|
children: label
|
|
2719
4790
|
}, `group:${idPath}`));
|
|
2720
4791
|
}
|
|
2721
|
-
for (const child of app.registry.groups.childrenOf(
|
|
4792
|
+
for (const child of app.registry.groups.childrenOf(require_record_trail_store.canonicalNavKey(group))) {
|
|
2722
4793
|
const kind = (0, _burojs_core.nodeKind)(child);
|
|
2723
4794
|
if (kind === "group") {
|
|
2724
4795
|
const sub = child;
|
|
2725
4796
|
if (!isVisible(sub)) continue;
|
|
2726
|
-
items.push(...collectGroupItems(sub, `${idPath}:${
|
|
4797
|
+
items.push(...collectGroupItems(sub, `${idPath}:${require_record_trail_store.canonicalNavKey(sub)}`, depth + 1));
|
|
2727
4798
|
continue;
|
|
2728
4799
|
}
|
|
2729
4800
|
if (kind === "custom-page") {
|
|
2730
4801
|
const page = child;
|
|
2731
4802
|
if (!isPageVisible(page)) continue;
|
|
2732
|
-
const pageKey =
|
|
4803
|
+
const pageKey = require_record_trail_store.canonicalNavKey(page);
|
|
2733
4804
|
const label = pageLabel(page);
|
|
2734
4805
|
const href = page.path;
|
|
2735
4806
|
items.push((0, react_jsx_runtime.jsx)(require_relation_create.CommandItem, {
|
|
@@ -2744,7 +4815,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2744
4815
|
const resource = child;
|
|
2745
4816
|
if (!(0, _burojs_core.hasListPage)(resource)) continue;
|
|
2746
4817
|
if (!isResourceVisible(resource)) continue;
|
|
2747
|
-
const resourceId =
|
|
4818
|
+
const resourceId = require_record_trail_store.canonicalResourceKey(resource);
|
|
2748
4819
|
const label = resourceLabel(resource);
|
|
2749
4820
|
const href = (0, _burojs_core.hrefFor)(app.registry, resourceId, { isVisible });
|
|
2750
4821
|
items.push((0, react_jsx_runtime.jsx)(require_relation_create.CommandItem, {
|
|
@@ -2760,7 +4831,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2760
4831
|
const rootGroups = app.registry.groups.rootNodes().filter((n) => (0, _burojs_core.nodeKind)(n) === "group");
|
|
2761
4832
|
for (const group of rootGroups) {
|
|
2762
4833
|
if (!isVisible(group)) continue;
|
|
2763
|
-
const groupKey =
|
|
4834
|
+
const groupKey = require_record_trail_store.canonicalNavKey(group);
|
|
2764
4835
|
const items = collectGroupItems(group, groupKey, 0);
|
|
2765
4836
|
if (items.length === 0) continue;
|
|
2766
4837
|
const heading = (0, _burojs_core.resolveNavLabel)(caps, `groups.${groupKey}`, (0, _burojs_core.declaredText)("chrome", group, "label"));
|
|
@@ -2800,7 +4871,7 @@ function CommandPaletteRecentGroup({ onSelect, getTestId, heading, refreshKey, w
|
|
|
2800
4871
|
const navigate = (0, _burojs_react.useRouteNavigate)();
|
|
2801
4872
|
const quick = (0, _burojs_react.useQuick)();
|
|
2802
4873
|
const userId = (0, _burojs_react.useCurrentUserId)();
|
|
2803
|
-
const isResourceVisible =
|
|
4874
|
+
const isResourceVisible = useResourceVisible();
|
|
2804
4875
|
const resolvedHeading = heading ?? t("commandPalette.recent", { defaultValue: "Recent" });
|
|
2805
4876
|
const store = (0, _burojs_react.usePlatformStorage)().local;
|
|
2806
4877
|
const [stored, setStored] = (0, react.useState)([]);
|
|
@@ -2810,7 +4881,7 @@ function CommandPaletteRecentGroup({ onSelect, getTestId, heading, refreshKey, w
|
|
|
2810
4881
|
return;
|
|
2811
4882
|
}
|
|
2812
4883
|
let current = true;
|
|
2813
|
-
const read =
|
|
4884
|
+
const read = readRecentRecords(store, userId);
|
|
2814
4885
|
if (Array.isArray(read)) setStored(read);
|
|
2815
4886
|
else read.then((entries) => {
|
|
2816
4887
|
if (current) setStored(entries);
|
|
@@ -2859,7 +4930,7 @@ function RecentItem({ entry, href, onGo, getTestId }) {
|
|
|
2859
4930
|
const resourceLabel = (0, _burojs_core.resolveResourceLabel)(caps, entry.canonicalRef, "single", def);
|
|
2860
4931
|
const key = `${entry.canonicalRef}:${entry.id}`;
|
|
2861
4932
|
const declared = Object.keys(def?.fields ?? {});
|
|
2862
|
-
const candidates = def?.recordTitle === void 0 ? [...declared.filter((name) =>
|
|
4933
|
+
const candidates = def?.recordTitle === void 0 ? [...declared.filter((name) => RECENT_LABEL_KEYS.includes(name)), ...def?.displayField === void 0 ? [] : [def.displayField]] : declared;
|
|
2863
4934
|
const legacyTrusted = entry.label === entry.id || access.status === "ready" && candidates.every((name) => access.fieldVisible(name));
|
|
2864
4935
|
const shown = entry.labelField === void 0 ? legacyTrusted ? entry.label : entry.id : access.status === "ready" && access.fieldVisible(entry.labelField) ? entry.label : entry.id;
|
|
2865
4936
|
return (0, react_jsx_runtime.jsxs)(require_relation_create.CommandItem, {
|
|
@@ -2897,12 +4968,12 @@ function CommandPaletteRecordsGroup({ enabled = true, pageSize = 5, minQueryLeng
|
|
|
2897
4968
|
const t = (0, _burojs_react.useOptionalT)();
|
|
2898
4969
|
const navigate = (0, _burojs_react.useRouteNavigate)();
|
|
2899
4970
|
const quick = (0, _burojs_react.useQuick)();
|
|
2900
|
-
const isResourceVisible =
|
|
4971
|
+
const isResourceVisible = useResourceVisible();
|
|
2901
4972
|
const resolvedHeading = heading ?? t("commandPalette.records", { defaultValue: "Records" });
|
|
2902
4973
|
const liveQuery = (0, cmdk.useCommandState)((state) => state.search) ?? "";
|
|
2903
4974
|
const debouncedQuery = (0, _burojs_react.useDebouncedValue)(liveQuery, debounceMs);
|
|
2904
4975
|
const searchableResources = (0, react.useMemo)(() => {
|
|
2905
|
-
return app.registry.list().filter((r) =>
|
|
4976
|
+
return app.registry.list().filter((r) => isShowAvailable(app.registry, require_record_trail_store.canonicalResourceKey(r)) || opensInQuick(app.registry, require_record_trail_store.canonicalResourceKey(r), "show")).filter(isResourceVisible).map((def) => {
|
|
2906
4977
|
const displayField = resolveDisplayField(def);
|
|
2907
4978
|
return displayField ? {
|
|
2908
4979
|
def,
|
|
@@ -2928,12 +4999,12 @@ function CommandPaletteRecordsGroup({ enabled = true, pageSize = 5, minQueryLeng
|
|
|
2928
4999
|
recordHref,
|
|
2929
5000
|
registry: app.registry,
|
|
2930
5001
|
getTestId
|
|
2931
|
-
},
|
|
5002
|
+
}, require_record_trail_store.canonicalResourceKey(def)))
|
|
2932
5003
|
}, "records");
|
|
2933
5004
|
}
|
|
2934
5005
|
function PerResourceSearchHits({ def, displayField, query, pageSize, goTo, recordHref, registry, getTestId }) {
|
|
2935
5006
|
const caps = (0, _burojs_react.useI18nCaps)();
|
|
2936
|
-
const resource =
|
|
5007
|
+
const resource = require_record_trail_store.canonicalResourceKey(def);
|
|
2937
5008
|
const access = (0, _burojs_react.useListAccess)(resource);
|
|
2938
5009
|
const titleVisible = access.status === "ready" && access.fieldVisible(displayField);
|
|
2939
5010
|
const shouldFetch = query.length > 0 && titleVisible;
|
|
@@ -2958,7 +5029,7 @@ function PerResourceSearchHits({ def, displayField, query, pageSize, goTo, recor
|
|
|
2958
5029
|
report(rows.length);
|
|
2959
5030
|
}, [report, rows.length]);
|
|
2960
5031
|
if (rows.length === 0) return null;
|
|
2961
|
-
const resourceLabel = (0, _burojs_core.resolveResourceLabel)(caps,
|
|
5032
|
+
const resourceLabel = (0, _burojs_core.resolveResourceLabel)(caps, require_record_trail_store.canonicalResourceKey(def), "single", def);
|
|
2962
5033
|
const declaredIdField = def.data?.idField;
|
|
2963
5034
|
const idField = typeof declaredIdField === "string" && declaredIdField.length > 0 ? declaredIdField : "id";
|
|
2964
5035
|
return (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: rows.map((row) => {
|
|
@@ -2968,7 +5039,7 @@ function PerResourceSearchHits({ def, displayField, query, pageSize, goTo, recor
|
|
|
2968
5039
|
const display = titleVisible ? row[displayField] : void 0;
|
|
2969
5040
|
const labelText = typeof display === "string" && display.length > 0 ? display : id;
|
|
2970
5041
|
const subtitle = rowSubtitle(row) ?? null;
|
|
2971
|
-
const href = recordHref ? recordHref(resource, id) :
|
|
5042
|
+
const href = recordHref ? recordHref(resource, id) : isShowAvailable(registry, resource) ? (0, _burojs_core.resourceShowHref)(registry, def, resource, id, row) : null;
|
|
2972
5043
|
return (0, react_jsx_runtime.jsxs)(require_relation_create.CommandItem, {
|
|
2973
5044
|
value: `record:${resource}:${id}:${labelText}`,
|
|
2974
5045
|
forceMount: true,
|
|
@@ -3116,7 +5187,7 @@ function CommandPaletteActionsGroup({ actions, onSelect, getTestId, heading }) {
|
|
|
3116
5187
|
function CommandPaletteCreateGroup({ resourceFilter, onSelect, getTestId, heading, createHref, prefix }) {
|
|
3117
5188
|
const caps = (0, _burojs_react.useI18nCaps)();
|
|
3118
5189
|
const app = (0, _burojs_react.useApp)();
|
|
3119
|
-
const isResourceVisible =
|
|
5190
|
+
const isResourceVisible = useResourceVisible();
|
|
3120
5191
|
const gate = (0, _burojs_react.useAvailabilityGate)();
|
|
3121
5192
|
const t = (0, _burojs_react.useOptionalT)();
|
|
3122
5193
|
const navigate = (0, _burojs_react.useRouteNavigate)();
|
|
@@ -3124,7 +5195,7 @@ function CommandPaletteCreateGroup({ resourceFilter, onSelect, getTestId, headin
|
|
|
3124
5195
|
const resolvedHeading = heading ?? t("commandPalette.create", { defaultValue: "Create" });
|
|
3125
5196
|
const resolvedPrefix = prefix ?? t("commandPalette.createNew", { defaultValue: "Create new" });
|
|
3126
5197
|
const visibleResources = (0, react.useMemo)(() => {
|
|
3127
|
-
return app.registry.list().filter((r) => (0, _burojs_core.hasListPage)(r)).filter((r) => gate(
|
|
5198
|
+
return app.registry.list().filter((r) => (0, _burojs_core.hasListPage)(r)).filter((r) => (0, _burojs_core.collectionFactOf)(r) === void 0).filter((r) => gate(require_record_trail_store.canonicalResourceKey(r), "create").state === "available").filter((r) => (0, _burojs_core.hasRecordPage)(r, "create") || opensInQuick(app.registry, require_record_trail_store.canonicalResourceKey(r), "create")).filter(isResourceVisible).filter((r) => resourceFilter ? resourceFilter(r) : true);
|
|
3128
5199
|
}, [
|
|
3129
5200
|
app,
|
|
3130
5201
|
gate,
|
|
@@ -3142,13 +5213,13 @@ function CommandPaletteCreateGroup({ resourceFilter, onSelect, getTestId, headin
|
|
|
3142
5213
|
return;
|
|
3143
5214
|
}
|
|
3144
5215
|
onSelect?.();
|
|
3145
|
-
quick.create(
|
|
5216
|
+
quick.create(require_record_trail_store.canonicalResourceKey(def));
|
|
3146
5217
|
};
|
|
3147
|
-
const resourceLabel = (def) => (0, _burojs_core.resolveResourceLabel)(caps,
|
|
5218
|
+
const resourceLabel = (def) => (0, _burojs_core.resolveResourceLabel)(caps, require_record_trail_store.canonicalResourceKey(def), "single", def);
|
|
3148
5219
|
return (0, react_jsx_runtime.jsx)(require_relation_create.CommandGroup, {
|
|
3149
5220
|
heading: resolvedHeading,
|
|
3150
5221
|
children: visibleResources.map((def) => {
|
|
3151
|
-
const resource =
|
|
5222
|
+
const resource = require_record_trail_store.canonicalResourceKey(def);
|
|
3152
5223
|
const label = resourceLabel(def);
|
|
3153
5224
|
const href = createHref?.(def) ?? (0, _burojs_core.resourceCreateHref)(app.registry, def, resource);
|
|
3154
5225
|
const value = `create:${resource}:${resolvedPrefix}:${label}`;
|
|
@@ -4457,7 +6528,7 @@ function JsonInput({ name, id, value, onChange, testid, disabled, required, aria
|
|
|
4457
6528
|
}
|
|
4458
6529
|
//#endregion
|
|
4459
6530
|
//#region src/fields/lazy-relation-many.tsx
|
|
4460
|
-
const RelationManyPickerInput = (0, react.lazy)(() => Promise.resolve().then(() => require("./relation-many-picker-
|
|
6531
|
+
const RelationManyPickerInput = (0, react.lazy)(() => Promise.resolve().then(() => require("./relation-many-picker-Cq0EHY5I.cjs")).then((module) => ({ default: module.RelationManyPickerInput })));
|
|
4461
6532
|
function LazyRelationManyInput(props) {
|
|
4462
6533
|
return (0, react_jsx_runtime.jsx)(react.Suspense, {
|
|
4463
6534
|
fallback: (0, react_jsx_runtime.jsx)(require_skeleton.Skeleton, {
|
|
@@ -5778,7 +7849,7 @@ function BlockScreen({ block, props, resource, record, label }) {
|
|
|
5778
7849
|
children: (0, react_jsx_runtime.jsx)("div", {
|
|
5779
7850
|
"data-testid": "modal-block",
|
|
5780
7851
|
className: "min-w-0",
|
|
5781
|
-
children: (0, react_jsx_runtime.jsx)(
|
|
7852
|
+
children: (0, react_jsx_runtime.jsx)(PlannedBody, {
|
|
5782
7853
|
screen: compiled,
|
|
5783
7854
|
name: "modal",
|
|
5784
7855
|
label: label ?? "",
|
|
@@ -6304,7 +8375,7 @@ function QuickLoaded({ entry, recordId, typedId, row, isCurrentData }) {
|
|
|
6304
8375
|
const answer = gate(entry.resource, entry.mode === "edit" ? "edit" : "show", row);
|
|
6305
8376
|
const open = answer.state === "open";
|
|
6306
8377
|
const title = (0, _burojs_react.useProjectedTitle)(entry.resource, recordId, row, { placeholder: !isCurrentData });
|
|
6307
|
-
|
|
8378
|
+
useRecordVisit(entry.resource, open && entry.mode === "show" ? row : null, { isCurrentData });
|
|
6308
8379
|
const stack = quick?.stack;
|
|
6309
8380
|
(0, react.useEffect)(() => {
|
|
6310
8381
|
if (open && stack !== void 0) stack.nameTop(title);
|
|
@@ -6390,7 +8461,7 @@ function QuickScreenOf({ entry, route, recordId }) {
|
|
|
6390
8461
|
value: route,
|
|
6391
8462
|
children: (0, react_jsx_runtime.jsx)(require_place_node.QuickScreenClaimContext.Provider, {
|
|
6392
8463
|
value: true,
|
|
6393
|
-
children: (0, react_jsx_runtime.jsx)(
|
|
8464
|
+
children: (0, react_jsx_runtime.jsx)(RecordScreen, {
|
|
6394
8465
|
resource: entry.resource,
|
|
6395
8466
|
mode: entry.mode,
|
|
6396
8467
|
...recordId === void 0 ? {} : { recordId },
|
|
@@ -7143,6 +9214,8 @@ exports.Checkbox = require_place_node.Checkbox;
|
|
|
7143
9214
|
exports.Collapsible = Collapsible;
|
|
7144
9215
|
exports.CollapsibleContent = CollapsibleContent;
|
|
7145
9216
|
exports.CollapsibleTrigger = CollapsibleTrigger;
|
|
9217
|
+
exports.CollectionCreatePicker = CollectionCreatePicker;
|
|
9218
|
+
exports.CollectionRecordRoute = CollectionRecordRoute;
|
|
7146
9219
|
exports.ColumnsToggle = require_place_node.ColumnsToggle;
|
|
7147
9220
|
exports.Command = require_relation_create.Command;
|
|
7148
9221
|
exports.CommandDialog = require_relation_create.CommandDialog;
|
|
@@ -7263,8 +9336,8 @@ exports.ListLive = require_place_node.ListLive;
|
|
|
7263
9336
|
exports.ListSavedViews = require_place_node.ListSavedViews;
|
|
7264
9337
|
exports.ListSearchInput = require_place_node.ListSearchInput;
|
|
7265
9338
|
exports.LoginForm = LoginForm;
|
|
7266
|
-
exports.NavAreaNotFound =
|
|
7267
|
-
exports.NavAreaPage =
|
|
9339
|
+
exports.NavAreaNotFound = require_record_trail_store.NavAreaNotFound;
|
|
9340
|
+
exports.NavAreaPage = NavAreaPage;
|
|
7268
9341
|
exports.NavChrome = NavChrome;
|
|
7269
9342
|
exports.NavMain = NavMain;
|
|
7270
9343
|
exports.NavigationGuardDialog = NavigationGuardDialog;
|
|
@@ -7284,8 +9357,8 @@ exports.PresetFilterControls = require_filter_builder.PresetFilterControls;
|
|
|
7284
9357
|
exports.Progress = Progress;
|
|
7285
9358
|
exports.RecordActions = require_place_node.RecordActions;
|
|
7286
9359
|
exports.RecordBreadcrumbs = RecordBreadcrumbs;
|
|
7287
|
-
exports.RecordPage =
|
|
7288
|
-
exports.RecordScreen =
|
|
9360
|
+
exports.RecordPage = RecordPage;
|
|
9361
|
+
exports.RecordScreen = RecordScreen;
|
|
7289
9362
|
exports.RecordTitle = require_place_node.RecordTitle;
|
|
7290
9363
|
exports.RefreshButton = RefreshButton;
|
|
7291
9364
|
exports.RelationDisplay = require_relation_create.RelationDisplay;
|
|
@@ -7295,12 +9368,12 @@ exports.RelationPicker = require_relation_picker.RelationPicker;
|
|
|
7295
9368
|
exports.RelationPickerDialog = require_lazy_relation_picker_dialog.LazyRelationPickerDialog;
|
|
7296
9369
|
exports.RelationPickerInput = require_relation_picker.RelationPickerInput;
|
|
7297
9370
|
exports.ResourceList = require_place_node.ResourceList;
|
|
7298
|
-
exports.ResourceListPage =
|
|
7299
|
-
exports.ResourcePageRouter =
|
|
9371
|
+
exports.ResourceListPage = ResourceListPage;
|
|
9372
|
+
exports.ResourcePageRouter = ResourcePageRouter;
|
|
7300
9373
|
exports.SavedViewsDropdown = require_place_node.SavedViewsDropdown;
|
|
7301
9374
|
exports.ScopeDimensionPicker = ScopeDimensionPicker;
|
|
7302
9375
|
exports.ScopeSwitcher = ScopeSwitcher;
|
|
7303
|
-
exports.SecondarySidebarLayout =
|
|
9376
|
+
exports.SecondarySidebarLayout = SecondarySidebarLayout;
|
|
7304
9377
|
exports.Select = require_filter_builder.Select;
|
|
7305
9378
|
exports.SelectContent = require_filter_builder.SelectContent;
|
|
7306
9379
|
exports.SelectGroup = require_filter_builder.SelectGroup;
|
|
@@ -7360,7 +9433,7 @@ exports.TableHeader = require_filter_builder.TableHeader;
|
|
|
7360
9433
|
exports.TableRow = require_filter_builder.TableRow;
|
|
7361
9434
|
exports.Tabs = require_place_node.Tabs;
|
|
7362
9435
|
exports.TabsContent = require_place_node.TabsContent;
|
|
7363
|
-
exports.TabsLayout =
|
|
9436
|
+
exports.TabsLayout = TabsLayout;
|
|
7364
9437
|
exports.TabsList = require_place_node.TabsList;
|
|
7365
9438
|
exports.TabsTrigger = require_place_node.TabsTrigger;
|
|
7366
9439
|
exports.TaskRunPanel = TaskRunPanel;
|
|
@@ -7376,9 +9449,10 @@ exports.Tooltip = require_check_confirm_dialog.Tooltip;
|
|
|
7376
9449
|
exports.TooltipContent = require_check_confirm_dialog.TooltipContent;
|
|
7377
9450
|
exports.TooltipProvider = require_check_confirm_dialog.TooltipProvider;
|
|
7378
9451
|
exports.TooltipTrigger = require_check_confirm_dialog.TooltipTrigger;
|
|
9452
|
+
exports.UnknownMemberCard = UnknownMemberCard;
|
|
7379
9453
|
exports.UserMenu = UserMenu;
|
|
7380
9454
|
exports.badgeVariants = require_filter_builder.badgeVariants;
|
|
7381
|
-
exports.buildNavItems =
|
|
9455
|
+
exports.buildNavItems = buildNavItems;
|
|
7382
9456
|
exports.buroSortingToTanStack = require_place_node.buroSortingToTanStack;
|
|
7383
9457
|
exports.buttonVariants = require_button.buttonVariants;
|
|
7384
9458
|
exports.cn = require_use_theme.cn;
|
|
@@ -7389,7 +9463,7 @@ exports.formatOperatorLabel = formatOperatorLabel;
|
|
|
7389
9463
|
exports.hasIcon = require_check_confirm_dialog.hasIcon;
|
|
7390
9464
|
exports.i18nPrefixToRef = _burojs_core.i18nPrefixToRef;
|
|
7391
9465
|
exports.isImage = _burojs_file_storage.isImage;
|
|
7392
|
-
exports.layoutSlot =
|
|
9466
|
+
exports.layoutSlot = layoutSlot;
|
|
7393
9467
|
exports.listSlot = require_check_confirm_dialog.listSlot;
|
|
7394
9468
|
exports.loadLocale = require_filter_builder.loadLocale;
|
|
7395
9469
|
exports.localeLabel = localeLabel;
|
|
@@ -7419,18 +9493,18 @@ exports.useDocumentTitle = require_place_node.useDocumentTitle;
|
|
|
7419
9493
|
exports.useExportRunWatcher = require_place_node.useExportRunWatcher;
|
|
7420
9494
|
exports.useFormControl = require_place_node.useFormControl;
|
|
7421
9495
|
exports.useFormField = useFormField;
|
|
7422
|
-
exports.useHref =
|
|
9496
|
+
exports.useHref = useHref;
|
|
7423
9497
|
exports.useIsMobile = useIsMobile;
|
|
7424
9498
|
exports.useLanguagePaletteActions = useLanguagePaletteActions;
|
|
7425
9499
|
exports.useLanguageSwitch = useLanguageSwitch;
|
|
7426
|
-
exports.useLayout =
|
|
7427
|
-
exports.useLayoutResolver =
|
|
9500
|
+
exports.useLayout = useLayout;
|
|
9501
|
+
exports.useLayoutResolver = useLayoutResolver;
|
|
7428
9502
|
exports.useLinkComponent = require_toaster.useLinkComponent;
|
|
7429
9503
|
exports.useListSlot = require_check_confirm_dialog.useListSlot;
|
|
7430
|
-
exports.useMatch =
|
|
9504
|
+
exports.useMatch = useMatch;
|
|
7431
9505
|
exports.useNavIcon = useNavIcon;
|
|
7432
9506
|
exports.useNavTree = useNavTree;
|
|
7433
|
-
exports.useNavVisible =
|
|
9507
|
+
exports.useNavVisible = useNavVisible;
|
|
7434
9508
|
exports.useOptionalSidebar = useOptionalSidebar;
|
|
7435
9509
|
exports.usePaletteState = require_place_node.usePaletteState;
|
|
7436
9510
|
exports.usePresentationCopy = usePresentationCopy;
|