@burojs/ui-shadcn 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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-CGXItMN0.js → candidates-relation-picker-DRsHKe6N.js} +3 -3
- package/dist/{candidates-relation-picker-CGXItMN0.js.map → candidates-relation-picker-DRsHKe6N.js.map} +1 -1
- package/dist/{candidates-relation-picker-C47mF260.cjs → candidates-relation-picker-GIxsp7D_.cjs} +3 -3
- package/dist/{candidates-relation-picker-C47mF260.cjs.map → candidates-relation-picker-GIxsp7D_.cjs.map} +1 -1
- package/dist/{check-confirm-dialog-BT04Mieo.cjs → check-confirm-dialog-BMSb7wFv.cjs} +76 -9
- package/dist/check-confirm-dialog-BMSb7wFv.cjs.map +1 -0
- package/dist/{check-confirm-dialog-CtiRzOAt.js → check-confirm-dialog-B_u3YVHS.js} +72 -11
- package/dist/{check-confirm-dialog-CtiRzOAt.js.map → check-confirm-dialog-B_u3YVHS.js.map} +1 -1
- package/dist/{filter-builder-z3Axzf9Y.js → filter-builder-DX-xC3Yd.js} +14 -6
- package/dist/filter-builder-DX-xC3Yd.js.map +1 -0
- package/dist/{filter-builder-ByGhxLf_.cjs → filter-builder-Dt5E8PSX.cjs} +14 -6
- package/dist/filter-builder-Dt5E8PSX.cjs.map +1 -0
- package/dist/{flow-runtime-BVFjMU5-.cjs → flow-runtime-CQ4wf8co.cjs} +3 -3
- package/dist/{flow-runtime-BVFjMU5-.cjs.map → flow-runtime-CQ4wf8co.cjs.map} +1 -1
- package/dist/{flow-runtime-DrUWyTS0.js → flow-runtime-Q2vD7R3c.js} +3 -3
- package/dist/{flow-runtime-DrUWyTS0.js.map → flow-runtime-Q2vD7R3c.js.map} +1 -1
- package/dist/{flow-screen-3fk6J33y.js → flow-screen-B1y2yizP.js} +68 -29
- package/dist/flow-screen-B1y2yizP.js.map +1 -0
- package/dist/{flow-screen-6y5E_HT6.cjs → flow-screen-sw2cP70t.cjs} +67 -28
- package/dist/flow-screen-sw2cP70t.cjs.map +1 -0
- package/dist/index.cjs +2304 -247
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +119 -12
- package/dist/index.d.ts +119 -12
- package/dist/index.js +2225 -172
- package/dist/index.js.map +1 -1
- package/dist/{inline-flow-host-C4KmZIYE.cjs → inline-flow-host-CkhoA69R.cjs} +3 -3
- package/dist/{inline-flow-host-C4KmZIYE.cjs.map → inline-flow-host-CkhoA69R.cjs.map} +1 -1
- package/dist/{inline-flow-host-YnnvWjdU.js → inline-flow-host-DqbXqcPS.js} +3 -3
- package/dist/{inline-flow-host-YnnvWjdU.js.map → inline-flow-host-DqbXqcPS.js.map} +1 -1
- package/dist/{lazy-relation-picker-dialog-DN4bvQfg.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-BAKBRn3V.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-CtEfqAvU.js → page-flow-route-CP7cS7FY.js} +7 -7
- package/dist/page-flow-route-CP7cS7FY.js.map +1 -0
- package/dist/{page-flow-route-DEjAxHe3.cjs → page-flow-route-UDx8qvdM.cjs} +10 -10
- package/dist/page-flow-route-UDx8qvdM.cjs.map +1 -0
- package/dist/{place-node-Bhl8B3fF.cjs → place-node-C5ZmuHaN.cjs} +208 -55
- package/dist/place-node-C5ZmuHaN.cjs.map +1 -0
- package/dist/{place-node-BdxT-30h.js → place-node-DwWAigv0.js} +205 -58
- 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-Bc_vfCE_.cjs → related-list-cards-BypKfm9t.cjs} +3 -3
- package/dist/{related-list-cards-Bc_vfCE_.cjs.map → related-list-cards-BypKfm9t.cjs.map} +1 -1
- package/dist/{related-list-cards-BvkD5OcC.js → related-list-cards-Dcmruy09.js} +3 -3
- package/dist/{related-list-cards-BvkD5OcC.js.map → related-list-cards-Dcmruy09.js.map} +1 -1
- package/dist/{related-list-timeline-k0DtnxTs.cjs → related-list-timeline-D-KClgKb.cjs} +4 -4
- package/dist/related-list-timeline-D-KClgKb.cjs.map +1 -0
- package/dist/{related-list-timeline-DCrwN9oO.js → related-list-timeline-DZON_qSc.js} +4 -4
- package/dist/related-list-timeline-DZON_qSc.js.map +1 -0
- package/dist/{related-rows-BW9Jr07T.cjs → related-rows-DgF05ssi.cjs} +4 -4
- package/dist/{related-rows-BW9Jr07T.cjs.map → related-rows-DgF05ssi.cjs.map} +1 -1
- package/dist/{related-rows-CPE-9FFr.js → related-rows-ETZl5CB9.js} +4 -4
- package/dist/{related-rows-CPE-9FFr.js.map → related-rows-ETZl5CB9.js.map} +1 -1
- package/dist/{relation-create-DDEYcKfw.cjs → relation-create-B8zngAcA.cjs} +82 -13
- package/dist/relation-create-B8zngAcA.cjs.map +1 -0
- package/dist/{relation-create-C43cdPQt.js → relation-create-CeCWyxIb.js} +79 -16
- package/dist/relation-create-CeCWyxIb.js.map +1 -0
- package/dist/{relation-many-picker-BlrGRwMV.js → relation-many-picker-CT7nKfE2.js} +12 -10
- package/dist/relation-many-picker-CT7nKfE2.js.map +1 -0
- package/dist/{relation-many-picker-Br-zBHxT.cjs → relation-many-picker-Cq0EHY5I.cjs} +12 -10
- package/dist/relation-many-picker-Cq0EHY5I.cjs.map +1 -0
- package/dist/{relation-picker-x7P5HKie.js → relation-picker-CCyuMeGq.js} +13 -10
- package/dist/relation-picker-CCyuMeGq.js.map +1 -0
- package/dist/{relation-picker-ADjxI_TI.cjs → relation-picker-DmwTzgsd.cjs} +13 -10
- package/dist/relation-picker-DmwTzgsd.cjs.map +1 -0
- package/dist/{relation-picker-dialog-CyKliBkN.js → relation-picker-dialog-CoWKjNv8.js} +5 -5
- package/dist/relation-picker-dialog-CoWKjNv8.js.map +1 -0
- package/dist/{relation-picker-dialog-DimVQF9Y.cjs → relation-picker-dialog-mbwyNK43.cjs} +5 -5
- package/dist/relation-picker-dialog-mbwyNK43.cjs.map +1 -0
- package/dist/{relation-select-Cr3CfNLy.cjs → relation-select-CguIo2M5.cjs} +2 -2
- package/dist/{relation-select-Cr3CfNLy.cjs.map → relation-select-CguIo2M5.cjs.map} +1 -1
- package/dist/{relation-select-B8Fq4o-t.js → relation-select-nAYxhopN.js} +2 -2
- package/dist/{relation-select-B8Fq4o-t.js.map → relation-select-nAYxhopN.js.map} +1 -1
- package/dist/{success-notices-Dl3M1fZP.cjs → success-notices-Cl4b6MLQ.cjs} +3 -2
- package/dist/success-notices-Cl4b6MLQ.cjs.map +1 -0
- package/dist/{success-notices-LDEgEkc4.js → success-notices-CrcWOGSo.js} +3 -2
- package/dist/success-notices-CrcWOGSo.js.map +1 -0
- package/dist/{use-dialog-filter-state-tNvqAAjh.cjs → use-dialog-filter-state-CpWblz3C.cjs} +2 -2
- package/dist/{use-dialog-filter-state-tNvqAAjh.cjs.map → use-dialog-filter-state-CpWblz3C.cjs.map} +1 -1
- package/dist/{use-dialog-filter-state-B_MqzHaT.js → use-dialog-filter-state-ZYxOp5WO.js} +2 -2
- package/dist/{use-dialog-filter-state-B_MqzHaT.js.map → use-dialog-filter-state-ZYxOp5WO.js.map} +1 -1
- package/dist/{use-record-subtitle-bfwIoUme.cjs → use-record-subtitle-B4lTR7pf.cjs} +5 -8
- package/dist/use-record-subtitle-B4lTR7pf.cjs.map +1 -0
- package/dist/{use-record-subtitle-gIaCGgbI.js → use-record-subtitle-pWMBqQx9.js} +5 -8
- package/dist/use-record-subtitle-pWMBqQx9.js.map +1 -0
- 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-BT04Mieo.cjs.map +0 -1
- package/dist/filter-builder-ByGhxLf_.cjs.map +0 -1
- package/dist/filter-builder-z3Axzf9Y.js.map +0 -1
- package/dist/flow-screen-3fk6J33y.js.map +0 -1
- package/dist/flow-screen-6y5E_HT6.cjs.map +0 -1
- package/dist/lazy-relation-picker-dialog-BAKBRn3V.cjs.map +0 -1
- package/dist/lazy-relation-picker-dialog-DN4bvQfg.js.map +0 -1
- package/dist/page-flow-route-CtEfqAvU.js.map +0 -1
- package/dist/page-flow-route-DEjAxHe3.cjs.map +0 -1
- package/dist/place-node-BdxT-30h.js.map +0 -1
- package/dist/place-node-Bhl8B3fF.cjs.map +0 -1
- package/dist/related-list-timeline-DCrwN9oO.js.map +0 -1
- package/dist/related-list-timeline-k0DtnxTs.cjs.map +0 -1
- package/dist/relation-create-C43cdPQt.js.map +0 -1
- package/dist/relation-create-DDEYcKfw.cjs.map +0 -1
- package/dist/relation-many-picker-BlrGRwMV.js.map +0 -1
- package/dist/relation-many-picker-Br-zBHxT.cjs.map +0 -1
- package/dist/relation-picker-ADjxI_TI.cjs.map +0 -1
- package/dist/relation-picker-dialog-CyKliBkN.js.map +0 -1
- package/dist/relation-picker-dialog-DimVQF9Y.cjs.map +0 -1
- package/dist/relation-picker-x7P5HKie.js.map +0 -1
- package/dist/resource-page-router-BRpUnhay.js +0 -1958
- package/dist/resource-page-router-BRpUnhay.js.map +0 -1
- package/dist/resource-page-router-qEd2xb55.cjs +0 -2167
- package/dist/resource-page-router-qEd2xb55.cjs.map +0 -1
- package/dist/success-notices-Dl3M1fZP.cjs.map +0 -1
- package/dist/success-notices-LDEgEkc4.js.map +0 -1
- package/dist/use-record-subtitle-bfwIoUme.cjs.map +0 -1
- package/dist/use-record-subtitle-gIaCGgbI.js.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,
|
|
@@ -1719,25 +1720,40 @@ function useNavIcon() {
|
|
|
1719
1720
|
return (0, react.useCallback)((name) => resolveNavIcon(name, (key) => components[key]), [components]);
|
|
1720
1721
|
}
|
|
1721
1722
|
//#endregion
|
|
1723
|
+
//#region src/shell/use-shell-waiting.ts
|
|
1724
|
+
function useShellWaiting() {
|
|
1725
|
+
return (0, _burojs_react.usePermissionsUndecided)();
|
|
1726
|
+
}
|
|
1727
|
+
//#endregion
|
|
1722
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
|
+
}
|
|
1723
1738
|
function buildNavItems(args) {
|
|
1724
1739
|
const { registry, caps, groupName, match, isVisible, entryFilter, icons } = args;
|
|
1725
1740
|
const chain = match?.groupChain ?? [];
|
|
1726
1741
|
const qualifiedMatch = match;
|
|
1727
|
-
const activeLeaf = qualifiedMatch == null ? void 0 : qualifiedMatch.kind === "group-index" ?
|
|
1742
|
+
const activeLeaf = qualifiedMatch == null ? void 0 : qualifiedMatch.kind === "group-index" ? require_record_trail_store.canonicalNavKey({
|
|
1728
1743
|
name: qualifiedMatch.target ?? qualifiedMatch.name,
|
|
1729
1744
|
ref: qualifiedMatch.targetRef
|
|
1730
|
-
}) :
|
|
1745
|
+
}) : require_record_trail_store.canonicalNavKey(qualifiedMatch);
|
|
1731
1746
|
const isEligible = (node) => isVisible(node) && (entryFilter ? entryFilter(node) : true);
|
|
1732
1747
|
const out = [];
|
|
1733
1748
|
for (const child of registry.groups.childrenOf(groupName)) {
|
|
1734
1749
|
if (!isEligible(child)) continue;
|
|
1735
1750
|
const kind = (0, _burojs_core.nodeKind)(child);
|
|
1736
|
-
const childKey =
|
|
1737
|
-
const href = (0, _burojs_core.navHrefFor)(registry, childKey, { isVisible: isEligible });
|
|
1751
|
+
const childKey = require_record_trail_store.canonicalNavKey(child);
|
|
1738
1752
|
if (kind === "group") {
|
|
1753
|
+
const href = groupNavHref(registry, childKey, isEligible);
|
|
1754
|
+
if (href === void 0) continue;
|
|
1739
1755
|
const label = (0, _burojs_core.resolveNavLabel)(caps, `groups.${childKey}`, (0, _burojs_core.declaredText)("chrome", child, "label"));
|
|
1740
|
-
const active = chain.some((g) =>
|
|
1756
|
+
const active = chain.some((g) => require_record_trail_store.canonicalNavKey(g) === childKey);
|
|
1741
1757
|
out.push({
|
|
1742
1758
|
kind: "group",
|
|
1743
1759
|
name: childKey,
|
|
@@ -1746,7 +1762,10 @@ function buildNavItems(args) {
|
|
|
1746
1762
|
icon: icons?.group?.(childKey),
|
|
1747
1763
|
active
|
|
1748
1764
|
});
|
|
1749
|
-
|
|
1765
|
+
continue;
|
|
1766
|
+
}
|
|
1767
|
+
const href = (0, _burojs_core.navHrefFor)(registry, childKey, { isVisible: isEligible });
|
|
1768
|
+
if (kind === "custom-page") out.push({
|
|
1750
1769
|
kind: "custom-page",
|
|
1751
1770
|
name: childKey,
|
|
1752
1771
|
label: (0, _burojs_core.resolveNavLabel)(caps, `pages.${childKey}`, (0, _burojs_core.declaredText)("chrome", child, "label")),
|
|
@@ -1766,6 +1785,171 @@ function buildNavItems(args) {
|
|
|
1766
1785
|
return out;
|
|
1767
1786
|
}
|
|
1768
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
|
|
1769
1953
|
//#region src/layout/use-nav-tree.ts
|
|
1770
1954
|
function isActiveHref(href, currentPath) {
|
|
1771
1955
|
if (!currentPath) return false;
|
|
@@ -1779,18 +1963,18 @@ function useNavTree(opts = {}) {
|
|
|
1779
1963
|
const passesEntryFilter = (entry) => entryFilter ? entryFilter(entry) : true;
|
|
1780
1964
|
const app = (0, _burojs_react.useApp)();
|
|
1781
1965
|
const caps = (0, _burojs_react.useI18nCaps)();
|
|
1782
|
-
const isResourceVisible =
|
|
1783
|
-
const resolveLayout =
|
|
1784
|
-
const match =
|
|
1785
|
-
const isVisible =
|
|
1786
|
-
const pageAllowed =
|
|
1966
|
+
const isResourceVisible = useResourceVisible();
|
|
1967
|
+
const resolveLayout = useLayoutResolver();
|
|
1968
|
+
const match = useMatch();
|
|
1969
|
+
const isVisible = useNavVisible();
|
|
1970
|
+
const pageAllowed = usePageAllowed();
|
|
1787
1971
|
const isNavEligible = (node) => isVisible(node) && passesEntryFilter(node);
|
|
1788
1972
|
const allResources = app.registry.list();
|
|
1789
1973
|
const allCustomPages = app.registry.customPages.list();
|
|
1790
1974
|
const sections = app.registry.sections.list();
|
|
1791
1975
|
const groups = app.registry.groups.rootNodes().filter((n) => (0, _burojs_core.nodeKind)(n) === "group");
|
|
1792
|
-
|
|
1793
|
-
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) => ({
|
|
1794
1978
|
r,
|
|
1795
1979
|
idx
|
|
1796
1980
|
})).sort((a, b) => {
|
|
@@ -1799,16 +1983,16 @@ function useNavTree(opts = {}) {
|
|
|
1799
1983
|
return ao !== bo ? ao - bo : a.idx - b.idx;
|
|
1800
1984
|
}).map((x) => x.r);
|
|
1801
1985
|
const topLevelCustomPages = allCustomPages.filter((p) => !p.section && !p.group).filter(pageAllowed).filter(passesEntryFilter);
|
|
1802
|
-
const resourceHref = (def) => (0, _burojs_core.hrefFor)(app.registry,
|
|
1803
|
-
const resourceLabel = (def) => (0, _burojs_core.resolveResourceNavLabel)(caps,
|
|
1804
|
-
const pageLabel = (page) => (0, _burojs_core.resolveNavLabel)(caps, `pages.${
|
|
1805
|
-
const sectionLabel = (section) => (0, _burojs_core.resolveNavLabel)(caps, `sections.${
|
|
1806
|
-
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"));
|
|
1807
1991
|
const pageEntry = (page) => {
|
|
1808
1992
|
const href = page.path;
|
|
1809
1993
|
return {
|
|
1810
1994
|
kind: "page",
|
|
1811
|
-
key:
|
|
1995
|
+
key: require_record_trail_store.canonicalNavKey(page),
|
|
1812
1996
|
label: pageLabel(page),
|
|
1813
1997
|
href,
|
|
1814
1998
|
icon: page.icon,
|
|
@@ -1819,7 +2003,7 @@ function useNavTree(opts = {}) {
|
|
|
1819
2003
|
const href = resourceHref(def);
|
|
1820
2004
|
return {
|
|
1821
2005
|
kind: "resource",
|
|
1822
|
-
key:
|
|
2006
|
+
key: require_record_trail_store.canonicalResourceKey(def),
|
|
1823
2007
|
label: resourceLabel(def),
|
|
1824
2008
|
href,
|
|
1825
2009
|
icon: def.icon,
|
|
@@ -1836,7 +2020,7 @@ function useNavTree(opts = {}) {
|
|
|
1836
2020
|
entryFilter
|
|
1837
2021
|
}).map(itemEntry);
|
|
1838
2022
|
const groupEntry = (group, label, href, active) => {
|
|
1839
|
-
const key =
|
|
2023
|
+
const key = require_record_trail_store.canonicalNavKey(group);
|
|
1840
2024
|
return {
|
|
1841
2025
|
kind: "group",
|
|
1842
2026
|
key,
|
|
@@ -1874,8 +2058,8 @@ function useNavTree(opts = {}) {
|
|
|
1874
2058
|
entries: topEntries
|
|
1875
2059
|
}];
|
|
1876
2060
|
for (const section of sections) {
|
|
1877
|
-
const sectionKey =
|
|
1878
|
-
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));
|
|
1879
2063
|
if (entries.length === 0) continue;
|
|
1880
2064
|
const active = entries.some((e) => e.active);
|
|
1881
2065
|
out.push({
|
|
@@ -1889,11 +2073,12 @@ function useNavTree(opts = {}) {
|
|
|
1889
2073
|
});
|
|
1890
2074
|
}
|
|
1891
2075
|
for (const group of groups) {
|
|
1892
|
-
const groupKey =
|
|
2076
|
+
const groupKey = require_record_trail_store.canonicalNavKey(group);
|
|
1893
2077
|
if (!isNavEligible(group)) continue;
|
|
1894
2078
|
const gLabel = groupLabel(group);
|
|
1895
2079
|
if (resolveLayout(group.layout)) {
|
|
1896
|
-
const href = (
|
|
2080
|
+
const href = groupNavHref(app.registry, groupKey, isNavEligible);
|
|
2081
|
+
if (href === void 0) continue;
|
|
1897
2082
|
const entry = groupEntry(group, gLabel, href, isActiveHref(href, currentPath));
|
|
1898
2083
|
out.push({
|
|
1899
2084
|
key: groupKey,
|
|
@@ -1972,155 +2157,2008 @@ function CollapsibleNavSection({ name, label, icon, hasActiveChild, declaredOpen
|
|
|
1972
2157
|
})
|
|
1973
2158
|
}), (0, react_jsx_runtime.jsx)(CollapsibleContent, { children: (0, react_jsx_runtime.jsx)(SidebarMenuSub, { children }) })]
|
|
1974
2159
|
})
|
|
1975
|
-
}) }) })
|
|
2160
|
+
}) }) })
|
|
2161
|
+
});
|
|
2162
|
+
}
|
|
2163
|
+
function NavMain({ topLabel, iconForResource, iconForCustomPage, iconForSection, entryFilter }) {
|
|
2164
|
+
const tree = useNavTree({ entryFilter });
|
|
2165
|
+
const app = (0, _burojs_react.useApp)();
|
|
2166
|
+
const tid = (0, _burojs_react.useTestIds)();
|
|
2167
|
+
const t = (0, _burojs_react.useT)();
|
|
2168
|
+
const RouterLink = require_toaster.useLinkComponent();
|
|
2169
|
+
const navIcon = useNavIcon();
|
|
2170
|
+
const waiting = useShellWaiting();
|
|
2171
|
+
const intent = (0, _burojs_react.useOriginIntent)();
|
|
2172
|
+
const jump = (entry) => () => {
|
|
2173
|
+
if (entry.href !== void 0) intent(entry.href, "jump");
|
|
2174
|
+
};
|
|
2175
|
+
const ownOr = (own, name) => own !== void 0 ? own : navIcon(name);
|
|
2176
|
+
const groupAsSection = (key) => app.registry.sections.get(key) ?? app.registry.groups.get(key);
|
|
2177
|
+
const sectionIcon = (key, name) => {
|
|
2178
|
+
const def = iconForSection ? groupAsSection(key) : void 0;
|
|
2179
|
+
return ownOr(def ? iconForSection?.(def) : void 0, name);
|
|
2180
|
+
};
|
|
2181
|
+
const entryIcon = (entry) => {
|
|
2182
|
+
if (entry.kind === "group") return sectionIcon(entry.key, entry.icon);
|
|
2183
|
+
if (entry.kind === "page") {
|
|
2184
|
+
const page = iconForCustomPage ? app.registry.customPages.get(entry.key) : void 0;
|
|
2185
|
+
return ownOr(page ? iconForCustomPage?.(page) : void 0, entry.icon);
|
|
2186
|
+
}
|
|
2187
|
+
const def = iconForResource ? app.registry.get(entry.key) : void 0;
|
|
2188
|
+
return ownOr(def ? iconForResource?.(def) : void 0, entry.icon);
|
|
2189
|
+
};
|
|
2190
|
+
const entryTestId = (entry) => entry.kind === "page" ? tid.sidebarCustomPage(entry.key) : entry.kind === "group" ? tid.navGroup(entry.key) : tid.navMenuItem(entry.key);
|
|
2191
|
+
const menuItem = (entry) => {
|
|
2192
|
+
const icon = entryIcon(entry);
|
|
2193
|
+
return (0, react_jsx_runtime.jsx)(SidebarMenuItem, { children: (0, react_jsx_runtime.jsx)(SidebarMenuButton, {
|
|
2194
|
+
asChild: true,
|
|
2195
|
+
isActive: entry.active,
|
|
2196
|
+
tooltip: entry.label,
|
|
2197
|
+
children: (0, react_jsx_runtime.jsxs)(RouterLink, {
|
|
2198
|
+
href: entry.href ?? "",
|
|
2199
|
+
"aria-current": entry.active ? "page" : void 0,
|
|
2200
|
+
"data-testid": entryTestId(entry),
|
|
2201
|
+
onClick: jump(entry),
|
|
2202
|
+
children: [icon != null && (0, react_jsx_runtime.jsx)("span", {
|
|
2203
|
+
className: "inline-flex h-4 w-4 items-center justify-center",
|
|
2204
|
+
"aria-hidden": "true",
|
|
2205
|
+
children: icon
|
|
2206
|
+
}), (0, react_jsx_runtime.jsx)("span", { children: entry.label })]
|
|
2207
|
+
})
|
|
2208
|
+
}) }, entry.key);
|
|
2209
|
+
};
|
|
2210
|
+
const subItem = (entry) => (0, react_jsx_runtime.jsx)(SidebarMenuSubItem, { children: (0, react_jsx_runtime.jsx)(SidebarMenuSubButton, {
|
|
2211
|
+
asChild: true,
|
|
2212
|
+
isActive: entry.active,
|
|
2213
|
+
children: (0, react_jsx_runtime.jsx)(RouterLink, {
|
|
2214
|
+
href: entry.href ?? "",
|
|
2215
|
+
"aria-current": entry.active ? "page" : void 0,
|
|
2216
|
+
"data-testid": entryTestId(entry),
|
|
2217
|
+
onClick: jump(entry),
|
|
2218
|
+
children: (0, react_jsx_runtime.jsx)("span", { children: entry.label })
|
|
2219
|
+
})
|
|
2220
|
+
}) }, entry.key);
|
|
2221
|
+
if (waiting) return (0, react_jsx_runtime.jsx)(SidebarGroup, {
|
|
2222
|
+
"data-testid": "sidebar-nav-loading",
|
|
2223
|
+
"aria-busy": "true",
|
|
2224
|
+
children: (0, react_jsx_runtime.jsx)(SidebarGroupContent, { children: (0, react_jsx_runtime.jsx)(SidebarMenu, { children: [
|
|
2225
|
+
0,
|
|
2226
|
+
1,
|
|
2227
|
+
2,
|
|
2228
|
+
3
|
|
2229
|
+
].map((i) => (0, react_jsx_runtime.jsx)(SidebarMenuItem, { children: (0, react_jsx_runtime.jsx)(SidebarMenuSkeleton, { showIcon: true }) }, i)) }) })
|
|
2230
|
+
});
|
|
2231
|
+
const [top, ...blocks] = tree;
|
|
2232
|
+
return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [top !== void 0 && top.entries.length > 0 && (0, react_jsx_runtime.jsxs)(SidebarGroup, { children: [topLabel !== null && (0, react_jsx_runtime.jsx)(SidebarGroupLabel, { children: topLabel ?? t("nav.resources") }), (0, react_jsx_runtime.jsx)(SidebarGroupContent, { children: (0, react_jsx_runtime.jsx)(SidebarMenu, { children: top.entries.map(menuItem) }) })] }), blocks.map((block) => {
|
|
2233
|
+
const key = block.key ?? "";
|
|
2234
|
+
if (block.label === null) return (0, react_jsx_runtime.jsx)(SidebarGroup, { children: (0, react_jsx_runtime.jsx)(SidebarGroupContent, { children: (0, react_jsx_runtime.jsx)(SidebarMenu, { children: block.entries.map(menuItem) }) }) }, key);
|
|
2235
|
+
if (block.collapsible) return (0, react_jsx_runtime.jsx)(CollapsibleNavSection, {
|
|
2236
|
+
name: key,
|
|
2237
|
+
label: block.label,
|
|
2238
|
+
icon: sectionIcon(key, block.icon),
|
|
2239
|
+
hasActiveChild: block.active,
|
|
2240
|
+
declaredOpen: block.defaultOpen,
|
|
2241
|
+
children: block.entries.map(subItem)
|
|
2242
|
+
}, key);
|
|
2243
|
+
return (0, react_jsx_runtime.jsxs)(SidebarGroup, {
|
|
2244
|
+
"data-testid": `sidebar-section-group:${key}`,
|
|
2245
|
+
children: [(0, react_jsx_runtime.jsx)(SidebarGroupLabel, {
|
|
2246
|
+
"data-testid": `sidebar-section:${key}`,
|
|
2247
|
+
children: block.label
|
|
2248
|
+
}), (0, react_jsx_runtime.jsx)(SidebarGroupContent, { children: (0, react_jsx_runtime.jsx)(SidebarMenu, { children: block.entries.map(menuItem) }) })]
|
|
2249
|
+
}, key);
|
|
2250
|
+
})] });
|
|
2251
|
+
}
|
|
2252
|
+
//#endregion
|
|
2253
|
+
//#region src/layout/app-sidebar.tsx
|
|
2254
|
+
function AppSidebar({ header, filters, nav, footer }) {
|
|
2255
|
+
const headerNode = fill(header, () => (0, react_jsx_runtime.jsx)(SidebarBrand, {}));
|
|
2256
|
+
const filtersNode = fill(filters, () => null);
|
|
2257
|
+
const navNode = fill(nav, () => (0, react_jsx_runtime.jsx)(NavMain, {}));
|
|
2258
|
+
const footerNode = fill(footer, () => (0, react_jsx_runtime.jsx)(UserMenu, {}));
|
|
2259
|
+
return (0, react_jsx_runtime.jsxs)(Sidebar, {
|
|
2260
|
+
collapsible: "icon",
|
|
2261
|
+
children: [
|
|
2262
|
+
(headerNode != null || filtersNode != null) && (0, react_jsx_runtime.jsxs)(SidebarHeader, {
|
|
2263
|
+
className: "empty:hidden",
|
|
2264
|
+
children: [headerNode, filtersNode]
|
|
2265
|
+
}),
|
|
2266
|
+
(0, react_jsx_runtime.jsx)(SidebarContent, { children: navNode }),
|
|
2267
|
+
footerNode != null && (0, react_jsx_runtime.jsx)(SidebarFooter, {
|
|
2268
|
+
className: "empty:hidden",
|
|
2269
|
+
children: footerNode
|
|
2270
|
+
}),
|
|
2271
|
+
(0, react_jsx_runtime.jsx)(SidebarRail, {})
|
|
2272
|
+
]
|
|
2273
|
+
});
|
|
2274
|
+
}
|
|
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
|
|
2283
|
+
//#region src/layout/nav-chrome.tsx
|
|
2284
|
+
const DETAIL_ACTIONS = new Set([
|
|
2285
|
+
"show",
|
|
2286
|
+
"edit",
|
|
2287
|
+
"create"
|
|
2288
|
+
]);
|
|
2289
|
+
function NavChrome({ children, entryFilter, icons }) {
|
|
2290
|
+
const app = (0, _burojs_react.useApp)();
|
|
2291
|
+
const caps = (0, _burojs_react.useI18nCaps)();
|
|
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, {
|
|
2297
|
+
value: true,
|
|
2298
|
+
children
|
|
2299
|
+
});
|
|
2300
|
+
let content = children;
|
|
2301
|
+
for (let i = match.groupChain.length - 1; i >= 0; i--) {
|
|
2302
|
+
const group = match.groupChain[i];
|
|
2303
|
+
if (!group) continue;
|
|
2304
|
+
const groupKey = require_record_trail_store.canonicalNavKey(group);
|
|
2305
|
+
if (group.chromeOn === "list" && match.kind === "resource" && DETAIL_ACTIONS.has(match.action)) continue;
|
|
2306
|
+
const Layout = resolveLayout(group.layout);
|
|
2307
|
+
if (!Layout) continue;
|
|
2308
|
+
const items = buildNavItems({
|
|
2309
|
+
registry: app.registry,
|
|
2310
|
+
caps,
|
|
2311
|
+
groupName: groupKey,
|
|
2312
|
+
match,
|
|
2313
|
+
isVisible,
|
|
2314
|
+
entryFilter,
|
|
2315
|
+
icons
|
|
2316
|
+
});
|
|
2317
|
+
content = (0, react_jsx_runtime.jsx)(Layout, {
|
|
2318
|
+
group,
|
|
2319
|
+
groupKey,
|
|
2320
|
+
items,
|
|
2321
|
+
children: content
|
|
2322
|
+
});
|
|
2323
|
+
}
|
|
2324
|
+
return (0, react_jsx_runtime.jsx)(NavChromeMountedProvider, {
|
|
2325
|
+
value: true,
|
|
2326
|
+
children: content
|
|
2327
|
+
});
|
|
2328
|
+
}
|
|
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()
|
|
1976
3772
|
});
|
|
3773
|
+
return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "loading" });
|
|
1977
3774
|
}
|
|
1978
|
-
function
|
|
1979
|
-
|
|
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) {
|
|
1980
3806
|
const app = (0, _burojs_react.useApp)();
|
|
1981
|
-
const
|
|
1982
|
-
const
|
|
1983
|
-
const
|
|
1984
|
-
const
|
|
1985
|
-
const
|
|
1986
|
-
const
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
const page = iconForCustomPage ? app.registry.customPages.get(entry.key) : void 0;
|
|
1999
|
-
return ownOr(page ? iconForCustomPage?.(page) : void 0, entry.icon);
|
|
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);
|
|
2000
3824
|
}
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
"aria-current": entry.active ? "page" : void 0,
|
|
2014
|
-
"data-testid": entryTestId(entry),
|
|
2015
|
-
onClick: jump(entry),
|
|
2016
|
-
children: [icon != null && (0, react_jsx_runtime.jsx)("span", {
|
|
2017
|
-
className: "inline-flex h-4 w-4 items-center justify-center",
|
|
2018
|
-
"aria-hidden": "true",
|
|
2019
|
-
children: icon
|
|
2020
|
-
}), (0, react_jsx_runtime.jsx)("span", { children: entry.label })]
|
|
2021
|
-
})
|
|
2022
|
-
}) }, entry.key);
|
|
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
|
|
2023
3837
|
};
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
href: entry.href ?? "",
|
|
2029
|
-
"aria-current": entry.active ? "page" : void 0,
|
|
2030
|
-
"data-testid": entryTestId(entry),
|
|
2031
|
-
onClick: jump(entry),
|
|
2032
|
-
children: (0, react_jsx_runtime.jsx)("span", { children: entry.label })
|
|
2033
|
-
})
|
|
2034
|
-
}) }, entry.key);
|
|
2035
|
-
const [top, ...blocks] = tree;
|
|
2036
|
-
return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [top !== void 0 && top.entries.length > 0 && (0, react_jsx_runtime.jsxs)(SidebarGroup, { children: [topLabel !== null && (0, react_jsx_runtime.jsx)(SidebarGroupLabel, { children: topLabel ?? t("nav.resources") }), (0, react_jsx_runtime.jsx)(SidebarGroupContent, { children: (0, react_jsx_runtime.jsx)(SidebarMenu, { children: top.entries.map(menuItem) }) })] }), blocks.map((block) => {
|
|
2037
|
-
const key = block.key ?? "";
|
|
2038
|
-
if (block.label === null) return (0, react_jsx_runtime.jsx)(SidebarGroup, { children: (0, react_jsx_runtime.jsx)(SidebarGroupContent, { children: (0, react_jsx_runtime.jsx)(SidebarMenu, { children: block.entries.map(menuItem) }) }) }, key);
|
|
2039
|
-
if (block.collapsible) return (0, react_jsx_runtime.jsx)(CollapsibleNavSection, {
|
|
2040
|
-
name: key,
|
|
2041
|
-
label: block.label,
|
|
2042
|
-
icon: sectionIcon(key, block.icon),
|
|
2043
|
-
hasActiveChild: block.active,
|
|
2044
|
-
declaredOpen: block.defaultOpen,
|
|
2045
|
-
children: block.entries.map(subItem)
|
|
2046
|
-
}, key);
|
|
2047
|
-
return (0, react_jsx_runtime.jsxs)(SidebarGroup, {
|
|
2048
|
-
"data-testid": `sidebar-section-group:${key}`,
|
|
2049
|
-
children: [(0, react_jsx_runtime.jsx)(SidebarGroupLabel, {
|
|
2050
|
-
"data-testid": `sidebar-section:${key}`,
|
|
2051
|
-
children: block.label
|
|
2052
|
-
}), (0, react_jsx_runtime.jsx)(SidebarGroupContent, { children: (0, react_jsx_runtime.jsx)(SidebarMenu, { children: block.entries.map(menuItem) }) })]
|
|
2053
|
-
}, key);
|
|
2054
|
-
})] });
|
|
3838
|
+
return (0, react_jsx_runtime.jsx)(RecordRoute, {
|
|
3839
|
+
...route,
|
|
3840
|
+
id
|
|
3841
|
+
});
|
|
2055
3842
|
}
|
|
2056
3843
|
//#endregion
|
|
2057
|
-
//#region src/layout/
|
|
2058
|
-
function
|
|
2059
|
-
const
|
|
2060
|
-
const
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
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",
|
|
2065
3893
|
children: [
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
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
|
+
})
|
|
2069
3906
|
}),
|
|
2070
|
-
(0, react_jsx_runtime.jsx)(
|
|
2071
|
-
|
|
2072
|
-
className: "
|
|
2073
|
-
children:
|
|
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
|
+
})
|
|
2074
3914
|
}),
|
|
2075
|
-
(0, react_jsx_runtime.jsx)(
|
|
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
|
+
})
|
|
2076
3923
|
]
|
|
2077
3924
|
});
|
|
2078
3925
|
}
|
|
2079
3926
|
//#endregion
|
|
2080
|
-
//#region src/layout/
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
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;
|
|
2088
3960
|
const caps = (0, _burojs_react.useI18nCaps)();
|
|
2089
|
-
const
|
|
2090
|
-
const
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
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
|
+
})
|
|
2096
3991
|
});
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
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, {});
|
|
2120
4113
|
}
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
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, {})
|
|
2124
4162
|
});
|
|
2125
4163
|
}
|
|
2126
4164
|
//#endregion
|
|
@@ -2188,7 +4226,7 @@ function Breadcrumbs(input) {
|
|
|
2188
4226
|
});
|
|
2189
4227
|
if (!def) return null;
|
|
2190
4228
|
const { recordId, pageLabel, middleSegments, rootSegments } = props;
|
|
2191
|
-
const resourceKey =
|
|
4229
|
+
const resourceKey = require_record_trail_store.canonicalResourceKey(def);
|
|
2192
4230
|
if (rootSegments !== void 0 && rootSegments.length > 0) return (0, react_jsx_runtime.jsxs)("nav", {
|
|
2193
4231
|
className: navClass,
|
|
2194
4232
|
"aria-label": ariaLabel,
|
|
@@ -2259,20 +4297,23 @@ function Breadcrumbs(input) {
|
|
|
2259
4297
|
//#region src/layout/record-breadcrumbs.tsx
|
|
2260
4298
|
function viewOrigin(ctx, trail, resource) {
|
|
2261
4299
|
if (trail === void 0 || trail.resource === void 0 || trail.segments.length > 0) return void 0;
|
|
2262
|
-
const
|
|
2263
|
-
|
|
2264
|
-
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;
|
|
2265
4306
|
}
|
|
2266
4307
|
function RecordBreadcrumbs() {
|
|
2267
|
-
const ctx =
|
|
2268
|
-
const match =
|
|
4308
|
+
const ctx = useTrailContext();
|
|
4309
|
+
const match = useMatch();
|
|
2269
4310
|
const snapshot = (0, _burojs_react.useApplicationSnapshot)();
|
|
2270
|
-
const route =
|
|
2271
|
-
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}`));
|
|
2272
4313
|
const idTitle = (0, _burojs_react.useRecordTitle)(route?.resource, route?.id);
|
|
2273
4314
|
(0, _burojs_react.usePublishOriginTitle)(published?.title || void 0);
|
|
2274
4315
|
const origin = (0, _burojs_react.useNavigationOrigin)();
|
|
2275
|
-
const rooted = origin === null ? void 0 :
|
|
4316
|
+
const rooted = origin === null ? void 0 : originTrail(ctx, origin);
|
|
2276
4317
|
const view = route === null ? void 0 : viewOrigin(ctx, rooted, route.resource);
|
|
2277
4318
|
const viewScopes = (0, _burojs_react.useDocTrailScopes)(view);
|
|
2278
4319
|
const ownScopes = (0, _burojs_react.useDocTrailScopes)(view === void 0 ? void 0 : route?.resource);
|
|
@@ -2285,7 +4326,7 @@ function RecordBreadcrumbs() {
|
|
|
2285
4326
|
if ((0, _burojs_core.effectiveFlow)(snapshot, match.ref, route.flow) === void 0) return null;
|
|
2286
4327
|
const flowLabel = published?.flowLabel;
|
|
2287
4328
|
if (flowLabel === void 0) return (0, react_jsx_runtime.jsx)(Breadcrumbs, {
|
|
2288
|
-
...
|
|
4329
|
+
...recordTrail(ctx, {
|
|
2289
4330
|
resource,
|
|
2290
4331
|
action: "show",
|
|
2291
4332
|
id,
|
|
@@ -2297,7 +4338,7 @@ function RecordBreadcrumbs() {
|
|
|
2297
4338
|
"data-testid": "record-breadcrumbs"
|
|
2298
4339
|
});
|
|
2299
4340
|
return (0, react_jsx_runtime.jsx)(Breadcrumbs, {
|
|
2300
|
-
...
|
|
4341
|
+
...recordTrail(ctx, {
|
|
2301
4342
|
resource,
|
|
2302
4343
|
action: "edit",
|
|
2303
4344
|
id,
|
|
@@ -2311,7 +4352,7 @@ function RecordBreadcrumbs() {
|
|
|
2311
4352
|
});
|
|
2312
4353
|
}
|
|
2313
4354
|
return (0, react_jsx_runtime.jsx)(Breadcrumbs, {
|
|
2314
|
-
...
|
|
4355
|
+
...recordTrail(ctx, {
|
|
2315
4356
|
resource,
|
|
2316
4357
|
action: route.action,
|
|
2317
4358
|
id,
|
|
@@ -2325,7 +4366,7 @@ function RecordBreadcrumbs() {
|
|
|
2325
4366
|
}
|
|
2326
4367
|
//#endregion
|
|
2327
4368
|
//#region src/layout/default-nav-layouts.ts
|
|
2328
|
-
const defaultNavLayouts = { ...
|
|
4369
|
+
const defaultNavLayouts = { ...BUILTIN_LAYOUTS };
|
|
2329
4370
|
//#endregion
|
|
2330
4371
|
//#region src/layout/context-picker.tsx
|
|
2331
4372
|
const ALL = "\0all";
|
|
@@ -2398,7 +4439,7 @@ function ScopeDimensionPicker(props) {
|
|
|
2398
4439
|
});
|
|
2399
4440
|
}
|
|
2400
4441
|
function ResourceDimension({ resource, labelField, ...rest }) {
|
|
2401
|
-
const options =
|
|
4442
|
+
const options = useResourceDimensionOptions(rest.dimension, resource, labelField);
|
|
2402
4443
|
return (0, react_jsx_runtime.jsx)(DimensionControl, {
|
|
2403
4444
|
...rest,
|
|
2404
4445
|
options
|
|
@@ -2485,10 +4526,10 @@ function LanguageSwitch({ onChange, className }) {
|
|
|
2485
4526
|
//#endregion
|
|
2486
4527
|
//#region src/layout/header-breadcrumbs.tsx
|
|
2487
4528
|
function HeaderBreadcrumbs() {
|
|
2488
|
-
const ctx =
|
|
2489
|
-
const match =
|
|
2490
|
-
if (
|
|
2491
|
-
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);
|
|
2492
4533
|
if (trail === null) return null;
|
|
2493
4534
|
return (0, react_jsx_runtime.jsx)(Breadcrumbs, {
|
|
2494
4535
|
...trail,
|
|
@@ -2636,20 +4677,20 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2636
4677
|
const visibilityCtx = (0, _burojs_react.useVisibilityCtx)();
|
|
2637
4678
|
const t = (0, _burojs_react.useOptionalT)();
|
|
2638
4679
|
const navigate = (0, _burojs_react.useRouteNavigate)();
|
|
2639
|
-
const isVisible =
|
|
2640
|
-
const resolveLayout =
|
|
2641
|
-
const isResourceVisible =
|
|
2642
|
-
const pageAllowed =
|
|
4680
|
+
const isVisible = useNavVisible();
|
|
4681
|
+
const resolveLayout = useLayoutResolver();
|
|
4682
|
+
const isResourceVisible = useResourceVisible();
|
|
4683
|
+
const pageAllowed = usePageAllowed();
|
|
2643
4684
|
const isPageVisible = (p) => (0, _burojs_core.evaluateVisible)(p.visible, visibilityCtx) && pageAllowed(p);
|
|
2644
4685
|
const { topLevelResources, topLevelPages, sectionGroups } = (0, react.useMemo)(() => {
|
|
2645
4686
|
const allResources = app.registry.list();
|
|
2646
4687
|
const allPages = app.registry.customPages.list();
|
|
2647
4688
|
const allSections = app.registry.sections.list();
|
|
2648
|
-
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);
|
|
2649
4690
|
const tlPages = allPages.filter((p) => !p.section && !p.group).filter(isPageVisible);
|
|
2650
4691
|
const groups = [];
|
|
2651
4692
|
for (const section of allSections) {
|
|
2652
|
-
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));
|
|
2653
4694
|
if (children.length === 0) continue;
|
|
2654
4695
|
groups.push({
|
|
2655
4696
|
section,
|
|
@@ -2666,13 +4707,13 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2666
4707
|
onSelect?.();
|
|
2667
4708
|
navigate(href, { origin: "jump" });
|
|
2668
4709
|
};
|
|
2669
|
-
const resourceLabel = (def) => (0, _burojs_core.resolveResourceLabel)(caps,
|
|
2670
|
-
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"));
|
|
2671
4712
|
const groups = [];
|
|
2672
4713
|
if (topLevelResources.length > 0) groups.push((0, react_jsx_runtime.jsx)(require_relation_create.CommandGroup, {
|
|
2673
4714
|
heading: t("commandPalette.resources", { defaultValue: "Resources" }),
|
|
2674
4715
|
children: topLevelResources.map((def) => {
|
|
2675
|
-
const resource =
|
|
4716
|
+
const resource = require_record_trail_store.canonicalResourceKey(def);
|
|
2676
4717
|
const label = resourceLabel(def);
|
|
2677
4718
|
const href = (0, _burojs_core.hrefFor)(app.registry, resource, { isVisible });
|
|
2678
4719
|
return (0, react_jsx_runtime.jsx)(require_relation_create.CommandItem, {
|
|
@@ -2686,7 +4727,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2686
4727
|
if (topLevelPages.length > 0) groups.push((0, react_jsx_runtime.jsx)(require_relation_create.CommandGroup, {
|
|
2687
4728
|
heading: t("commandPalette.pages", { defaultValue: "Pages" }),
|
|
2688
4729
|
children: topLevelPages.map((page) => {
|
|
2689
|
-
const pageKey =
|
|
4730
|
+
const pageKey = require_record_trail_store.canonicalNavKey(page);
|
|
2690
4731
|
const label = pageLabel(page);
|
|
2691
4732
|
const href = page.path;
|
|
2692
4733
|
return (0, react_jsx_runtime.jsx)(require_relation_create.CommandItem, {
|
|
@@ -2698,7 +4739,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2698
4739
|
})
|
|
2699
4740
|
}, "pages"));
|
|
2700
4741
|
for (const { section, children } of sectionGroups) {
|
|
2701
|
-
const sectionKey =
|
|
4742
|
+
const sectionKey = require_record_trail_store.canonicalNavKey(section);
|
|
2702
4743
|
const sectionLabel = (0, _burojs_core.resolveNavLabel)(caps, `sections.${sectionKey}`, (0, _burojs_core.declaredText)("chrome", section, "label"));
|
|
2703
4744
|
groups.push((0, react_jsx_runtime.jsxs)(require_relation_create.CommandGroup, {
|
|
2704
4745
|
heading: sectionLabel,
|
|
@@ -2710,7 +4751,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2710
4751
|
children: sectionLabel
|
|
2711
4752
|
}, `__section_header_${sectionKey}`), children.map((child) => {
|
|
2712
4753
|
if ((0, _burojs_core.isCustomPageDef)(child)) {
|
|
2713
|
-
const pageKey =
|
|
4754
|
+
const pageKey = require_record_trail_store.canonicalNavKey(child);
|
|
2714
4755
|
const href = child.path;
|
|
2715
4756
|
const label = pageLabel(child);
|
|
2716
4757
|
return (0, react_jsx_runtime.jsx)(require_relation_create.CommandItem, {
|
|
@@ -2721,7 +4762,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2721
4762
|
children: label
|
|
2722
4763
|
}, `section:${sectionKey}:page:${pageKey}`);
|
|
2723
4764
|
}
|
|
2724
|
-
const resource =
|
|
4765
|
+
const resource = require_record_trail_store.canonicalResourceKey(child);
|
|
2725
4766
|
const label = resourceLabel(child);
|
|
2726
4767
|
const href = (0, _burojs_core.hrefFor)(app.registry, resource, { isVisible });
|
|
2727
4768
|
return (0, react_jsx_runtime.jsx)(require_relation_create.CommandItem, {
|
|
@@ -2736,10 +4777,10 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2736
4777
|
}
|
|
2737
4778
|
const collectGroupItems = (group, idPath, depth) => {
|
|
2738
4779
|
const items = [];
|
|
2739
|
-
|
|
2740
|
-
|
|
4780
|
+
const href = !!resolveLayout(group.layout) ? groupNavHref(app.registry, require_record_trail_store.canonicalNavKey(group), isVisible) : void 0;
|
|
4781
|
+
if (href !== void 0) {
|
|
4782
|
+
const groupKey = require_record_trail_store.canonicalNavKey(group);
|
|
2741
4783
|
const label = (0, _burojs_core.resolveNavLabel)(caps, `groups.${groupKey}`, (0, _burojs_core.declaredText)("chrome", group, "label"));
|
|
2742
|
-
const href = (0, _burojs_core.navHrefFor)(app.registry, groupKey, { isVisible });
|
|
2743
4784
|
items.push((0, react_jsx_runtime.jsx)(require_relation_create.CommandItem, {
|
|
2744
4785
|
value: `group:${idPath}:${label}`,
|
|
2745
4786
|
onSelect: () => goTo(href),
|
|
@@ -2748,17 +4789,18 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2748
4789
|
children: label
|
|
2749
4790
|
}, `group:${idPath}`));
|
|
2750
4791
|
}
|
|
2751
|
-
for (const child of app.registry.groups.childrenOf(
|
|
4792
|
+
for (const child of app.registry.groups.childrenOf(require_record_trail_store.canonicalNavKey(group))) {
|
|
2752
4793
|
const kind = (0, _burojs_core.nodeKind)(child);
|
|
2753
4794
|
if (kind === "group") {
|
|
2754
4795
|
const sub = child;
|
|
2755
4796
|
if (!isVisible(sub)) continue;
|
|
2756
|
-
items.push(...collectGroupItems(sub, `${idPath}:${
|
|
4797
|
+
items.push(...collectGroupItems(sub, `${idPath}:${require_record_trail_store.canonicalNavKey(sub)}`, depth + 1));
|
|
2757
4798
|
continue;
|
|
2758
4799
|
}
|
|
2759
4800
|
if (kind === "custom-page") {
|
|
2760
4801
|
const page = child;
|
|
2761
|
-
|
|
4802
|
+
if (!isPageVisible(page)) continue;
|
|
4803
|
+
const pageKey = require_record_trail_store.canonicalNavKey(page);
|
|
2762
4804
|
const label = pageLabel(page);
|
|
2763
4805
|
const href = page.path;
|
|
2764
4806
|
items.push((0, react_jsx_runtime.jsx)(require_relation_create.CommandItem, {
|
|
@@ -2773,7 +4815,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2773
4815
|
const resource = child;
|
|
2774
4816
|
if (!(0, _burojs_core.hasListPage)(resource)) continue;
|
|
2775
4817
|
if (!isResourceVisible(resource)) continue;
|
|
2776
|
-
const resourceId =
|
|
4818
|
+
const resourceId = require_record_trail_store.canonicalResourceKey(resource);
|
|
2777
4819
|
const label = resourceLabel(resource);
|
|
2778
4820
|
const href = (0, _burojs_core.hrefFor)(app.registry, resourceId, { isVisible });
|
|
2779
4821
|
items.push((0, react_jsx_runtime.jsx)(require_relation_create.CommandItem, {
|
|
@@ -2789,7 +4831,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2789
4831
|
const rootGroups = app.registry.groups.rootNodes().filter((n) => (0, _burojs_core.nodeKind)(n) === "group");
|
|
2790
4832
|
for (const group of rootGroups) {
|
|
2791
4833
|
if (!isVisible(group)) continue;
|
|
2792
|
-
const groupKey =
|
|
4834
|
+
const groupKey = require_record_trail_store.canonicalNavKey(group);
|
|
2793
4835
|
const items = collectGroupItems(group, groupKey, 0);
|
|
2794
4836
|
if (items.length === 0) continue;
|
|
2795
4837
|
const heading = (0, _burojs_core.resolveNavLabel)(caps, `groups.${groupKey}`, (0, _burojs_core.declaredText)("chrome", group, "label"));
|
|
@@ -2829,7 +4871,7 @@ function CommandPaletteRecentGroup({ onSelect, getTestId, heading, refreshKey, w
|
|
|
2829
4871
|
const navigate = (0, _burojs_react.useRouteNavigate)();
|
|
2830
4872
|
const quick = (0, _burojs_react.useQuick)();
|
|
2831
4873
|
const userId = (0, _burojs_react.useCurrentUserId)();
|
|
2832
|
-
const isResourceVisible =
|
|
4874
|
+
const isResourceVisible = useResourceVisible();
|
|
2833
4875
|
const resolvedHeading = heading ?? t("commandPalette.recent", { defaultValue: "Recent" });
|
|
2834
4876
|
const store = (0, _burojs_react.usePlatformStorage)().local;
|
|
2835
4877
|
const [stored, setStored] = (0, react.useState)([]);
|
|
@@ -2839,7 +4881,7 @@ function CommandPaletteRecentGroup({ onSelect, getTestId, heading, refreshKey, w
|
|
|
2839
4881
|
return;
|
|
2840
4882
|
}
|
|
2841
4883
|
let current = true;
|
|
2842
|
-
const read =
|
|
4884
|
+
const read = readRecentRecords(store, userId);
|
|
2843
4885
|
if (Array.isArray(read)) setStored(read);
|
|
2844
4886
|
else read.then((entries) => {
|
|
2845
4887
|
if (current) setStored(entries);
|
|
@@ -2888,7 +4930,7 @@ function RecentItem({ entry, href, onGo, getTestId }) {
|
|
|
2888
4930
|
const resourceLabel = (0, _burojs_core.resolveResourceLabel)(caps, entry.canonicalRef, "single", def);
|
|
2889
4931
|
const key = `${entry.canonicalRef}:${entry.id}`;
|
|
2890
4932
|
const declared = Object.keys(def?.fields ?? {});
|
|
2891
|
-
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;
|
|
2892
4934
|
const legacyTrusted = entry.label === entry.id || access.status === "ready" && candidates.every((name) => access.fieldVisible(name));
|
|
2893
4935
|
const shown = entry.labelField === void 0 ? legacyTrusted ? entry.label : entry.id : access.status === "ready" && access.fieldVisible(entry.labelField) ? entry.label : entry.id;
|
|
2894
4936
|
return (0, react_jsx_runtime.jsxs)(require_relation_create.CommandItem, {
|
|
@@ -2926,12 +4968,12 @@ function CommandPaletteRecordsGroup({ enabled = true, pageSize = 5, minQueryLeng
|
|
|
2926
4968
|
const t = (0, _burojs_react.useOptionalT)();
|
|
2927
4969
|
const navigate = (0, _burojs_react.useRouteNavigate)();
|
|
2928
4970
|
const quick = (0, _burojs_react.useQuick)();
|
|
2929
|
-
const isResourceVisible =
|
|
4971
|
+
const isResourceVisible = useResourceVisible();
|
|
2930
4972
|
const resolvedHeading = heading ?? t("commandPalette.records", { defaultValue: "Records" });
|
|
2931
4973
|
const liveQuery = (0, cmdk.useCommandState)((state) => state.search) ?? "";
|
|
2932
4974
|
const debouncedQuery = (0, _burojs_react.useDebouncedValue)(liveQuery, debounceMs);
|
|
2933
4975
|
const searchableResources = (0, react.useMemo)(() => {
|
|
2934
|
-
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) => {
|
|
2935
4977
|
const displayField = resolveDisplayField(def);
|
|
2936
4978
|
return displayField ? {
|
|
2937
4979
|
def,
|
|
@@ -2957,12 +4999,12 @@ function CommandPaletteRecordsGroup({ enabled = true, pageSize = 5, minQueryLeng
|
|
|
2957
4999
|
recordHref,
|
|
2958
5000
|
registry: app.registry,
|
|
2959
5001
|
getTestId
|
|
2960
|
-
},
|
|
5002
|
+
}, require_record_trail_store.canonicalResourceKey(def)))
|
|
2961
5003
|
}, "records");
|
|
2962
5004
|
}
|
|
2963
5005
|
function PerResourceSearchHits({ def, displayField, query, pageSize, goTo, recordHref, registry, getTestId }) {
|
|
2964
5006
|
const caps = (0, _burojs_react.useI18nCaps)();
|
|
2965
|
-
const resource =
|
|
5007
|
+
const resource = require_record_trail_store.canonicalResourceKey(def);
|
|
2966
5008
|
const access = (0, _burojs_react.useListAccess)(resource);
|
|
2967
5009
|
const titleVisible = access.status === "ready" && access.fieldVisible(displayField);
|
|
2968
5010
|
const shouldFetch = query.length > 0 && titleVisible;
|
|
@@ -2987,7 +5029,7 @@ function PerResourceSearchHits({ def, displayField, query, pageSize, goTo, recor
|
|
|
2987
5029
|
report(rows.length);
|
|
2988
5030
|
}, [report, rows.length]);
|
|
2989
5031
|
if (rows.length === 0) return null;
|
|
2990
|
-
const resourceLabel = (0, _burojs_core.resolveResourceLabel)(caps,
|
|
5032
|
+
const resourceLabel = (0, _burojs_core.resolveResourceLabel)(caps, require_record_trail_store.canonicalResourceKey(def), "single", def);
|
|
2991
5033
|
const declaredIdField = def.data?.idField;
|
|
2992
5034
|
const idField = typeof declaredIdField === "string" && declaredIdField.length > 0 ? declaredIdField : "id";
|
|
2993
5035
|
return (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: rows.map((row) => {
|
|
@@ -2997,7 +5039,7 @@ function PerResourceSearchHits({ def, displayField, query, pageSize, goTo, recor
|
|
|
2997
5039
|
const display = titleVisible ? row[displayField] : void 0;
|
|
2998
5040
|
const labelText = typeof display === "string" && display.length > 0 ? display : id;
|
|
2999
5041
|
const subtitle = rowSubtitle(row) ?? null;
|
|
3000
|
-
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;
|
|
3001
5043
|
return (0, react_jsx_runtime.jsxs)(require_relation_create.CommandItem, {
|
|
3002
5044
|
value: `record:${resource}:${id}:${labelText}`,
|
|
3003
5045
|
forceMount: true,
|
|
@@ -3076,7 +5118,7 @@ function CommandPaletteActionsGroup({ actions, onSelect, getTestId, heading }) {
|
|
|
3076
5118
|
const propActions = actions ?? EMPTY_ACTIONS;
|
|
3077
5119
|
const resolvedHeading = heading ?? t("commandPalette.actions", { defaultValue: "Actions" });
|
|
3078
5120
|
const { items, collidingIds } = (0, react.useMemo)(() => {
|
|
3079
|
-
return mergeActions(registryEntries.map((entry) => appActionToItem(entry, present, caps)), propActions);
|
|
5121
|
+
return mergeActions(registryEntries.filter((entry) => entry.undecided !== true).map((entry) => appActionToItem(entry, present, caps)), propActions);
|
|
3080
5122
|
}, [
|
|
3081
5123
|
registryEntries,
|
|
3082
5124
|
propActions,
|
|
@@ -3145,7 +5187,7 @@ function CommandPaletteActionsGroup({ actions, onSelect, getTestId, heading }) {
|
|
|
3145
5187
|
function CommandPaletteCreateGroup({ resourceFilter, onSelect, getTestId, heading, createHref, prefix }) {
|
|
3146
5188
|
const caps = (0, _burojs_react.useI18nCaps)();
|
|
3147
5189
|
const app = (0, _burojs_react.useApp)();
|
|
3148
|
-
const isResourceVisible =
|
|
5190
|
+
const isResourceVisible = useResourceVisible();
|
|
3149
5191
|
const gate = (0, _burojs_react.useAvailabilityGate)();
|
|
3150
5192
|
const t = (0, _burojs_react.useOptionalT)();
|
|
3151
5193
|
const navigate = (0, _burojs_react.useRouteNavigate)();
|
|
@@ -3153,7 +5195,7 @@ function CommandPaletteCreateGroup({ resourceFilter, onSelect, getTestId, headin
|
|
|
3153
5195
|
const resolvedHeading = heading ?? t("commandPalette.create", { defaultValue: "Create" });
|
|
3154
5196
|
const resolvedPrefix = prefix ?? t("commandPalette.createNew", { defaultValue: "Create new" });
|
|
3155
5197
|
const visibleResources = (0, react.useMemo)(() => {
|
|
3156
|
-
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);
|
|
3157
5199
|
}, [
|
|
3158
5200
|
app,
|
|
3159
5201
|
gate,
|
|
@@ -3171,13 +5213,13 @@ function CommandPaletteCreateGroup({ resourceFilter, onSelect, getTestId, headin
|
|
|
3171
5213
|
return;
|
|
3172
5214
|
}
|
|
3173
5215
|
onSelect?.();
|
|
3174
|
-
quick.create(
|
|
5216
|
+
quick.create(require_record_trail_store.canonicalResourceKey(def));
|
|
3175
5217
|
};
|
|
3176
|
-
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);
|
|
3177
5219
|
return (0, react_jsx_runtime.jsx)(require_relation_create.CommandGroup, {
|
|
3178
5220
|
heading: resolvedHeading,
|
|
3179
5221
|
children: visibleResources.map((def) => {
|
|
3180
|
-
const resource =
|
|
5222
|
+
const resource = require_record_trail_store.canonicalResourceKey(def);
|
|
3181
5223
|
const label = resourceLabel(def);
|
|
3182
5224
|
const href = createHref?.(def) ?? (0, _burojs_core.resourceCreateHref)(app.registry, def, resource);
|
|
3183
5225
|
const value = `create:${resource}:${resolvedPrefix}:${label}`;
|
|
@@ -3229,19 +5271,21 @@ function AppActions() {
|
|
|
3229
5271
|
className: "flex items-center gap-1",
|
|
3230
5272
|
"data-testid": "app-actions",
|
|
3231
5273
|
children: links.map(({ action, href }) => {
|
|
5274
|
+
const inert = action.disabledReason !== void 0 || action.undecided === true;
|
|
3232
5275
|
const label = (0, _burojs_core.resolveNavLabel)(caps, `appActions.${action.name}`, action.label);
|
|
3233
5276
|
const content = action.icon === void 0 ? label : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(require_check_confirm_dialog.Icon, { name: action.icon }), (0, react_jsx_runtime.jsx)("span", {
|
|
3234
5277
|
className: "max-md:sr-only",
|
|
3235
5278
|
children: label
|
|
3236
5279
|
})] });
|
|
3237
5280
|
return (0, react_jsx_runtime.jsx)(require_button.Button, {
|
|
3238
|
-
asChild:
|
|
5281
|
+
asChild: !inert,
|
|
3239
5282
|
variant: "outline",
|
|
3240
5283
|
size: "sm",
|
|
3241
|
-
disabled:
|
|
5284
|
+
disabled: inert,
|
|
5285
|
+
"aria-busy": action.undecided === true ? "true" : void 0,
|
|
3242
5286
|
title: action.disabledReason === void 0 ? void 0 : require_check_confirm_dialog.reasonText(caps, action.disabledReason),
|
|
3243
5287
|
"data-testid": `app-action:${action.name}`,
|
|
3244
|
-
children:
|
|
5288
|
+
children: !inert ? (0, react_jsx_runtime.jsx)(RouterLink, {
|
|
3245
5289
|
href,
|
|
3246
5290
|
children: content
|
|
3247
5291
|
}) : (0, react_jsx_runtime.jsx)("span", { children: content })
|
|
@@ -3622,6 +5666,7 @@ function EnumChoiceGroup({ control, options, current, settling, value, onChange,
|
|
|
3622
5666
|
//#endregion
|
|
3623
5667
|
//#region src/enum/enum-picker.tsx
|
|
3624
5668
|
const ENUM_PICKER_CLEAR_SENTINEL = "__buro_clear__";
|
|
5669
|
+
const NO_VALUES = Object.freeze([]);
|
|
3625
5670
|
function withSummary(summary) {
|
|
3626
5671
|
return summary === void 0 ? {} : { summary };
|
|
3627
5672
|
}
|
|
@@ -3632,7 +5677,10 @@ function EnumPicker({ enumName: enumInput, value, onChange, control = "select",
|
|
|
3632
5677
|
const def = app.registry.enums.get(enumName);
|
|
3633
5678
|
const caps = (0, _burojs_react.useI18nCaps)();
|
|
3634
5679
|
const ns = def?.i18nNamespace ?? enumName;
|
|
3635
|
-
const
|
|
5680
|
+
const loaderParams = def !== void 0 && def.values === void 0 && use !== void 0 ? (0, _burojs_core_internal.resolveEnumParams)(def.params, use.params, use.sources) : void 0;
|
|
5681
|
+
const unsettledParams = loaderParams !== void 0 && loaderParams.status !== "ready";
|
|
5682
|
+
const { values: loadedValues, isLoading, error } = (0, _burojs_react.useEnumValues)(enumName, loaderParams?.status === "ready" ? loaderParams.params : void 0, { enabled: !unsettledParams });
|
|
5683
|
+
const values = unsettledParams ? NO_VALUES : loadedValues;
|
|
3636
5684
|
const available = (0, _burojs_react.useAvailableEnumValues)({
|
|
3637
5685
|
values: isLoading || values === void 0 ? "pending" : values,
|
|
3638
5686
|
...def === void 0 ? {} : { enum: def },
|
|
@@ -4480,7 +6528,7 @@ function JsonInput({ name, id, value, onChange, testid, disabled, required, aria
|
|
|
4480
6528
|
}
|
|
4481
6529
|
//#endregion
|
|
4482
6530
|
//#region src/fields/lazy-relation-many.tsx
|
|
4483
|
-
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 })));
|
|
4484
6532
|
function LazyRelationManyInput(props) {
|
|
4485
6533
|
return (0, react_jsx_runtime.jsx)(react.Suspense, {
|
|
4486
6534
|
fallback: (0, react_jsx_runtime.jsx)(require_skeleton.Skeleton, {
|
|
@@ -5801,7 +7849,7 @@ function BlockScreen({ block, props, resource, record, label }) {
|
|
|
5801
7849
|
children: (0, react_jsx_runtime.jsx)("div", {
|
|
5802
7850
|
"data-testid": "modal-block",
|
|
5803
7851
|
className: "min-w-0",
|
|
5804
|
-
children: (0, react_jsx_runtime.jsx)(
|
|
7852
|
+
children: (0, react_jsx_runtime.jsx)(PlannedBody, {
|
|
5805
7853
|
screen: compiled,
|
|
5806
7854
|
name: "modal",
|
|
5807
7855
|
label: label ?? "",
|
|
@@ -6327,7 +8375,7 @@ function QuickLoaded({ entry, recordId, typedId, row, isCurrentData }) {
|
|
|
6327
8375
|
const answer = gate(entry.resource, entry.mode === "edit" ? "edit" : "show", row);
|
|
6328
8376
|
const open = answer.state === "open";
|
|
6329
8377
|
const title = (0, _burojs_react.useProjectedTitle)(entry.resource, recordId, row, { placeholder: !isCurrentData });
|
|
6330
|
-
|
|
8378
|
+
useRecordVisit(entry.resource, open && entry.mode === "show" ? row : null, { isCurrentData });
|
|
6331
8379
|
const stack = quick?.stack;
|
|
6332
8380
|
(0, react.useEffect)(() => {
|
|
6333
8381
|
if (open && stack !== void 0) stack.nameTop(title);
|
|
@@ -6413,7 +8461,7 @@ function QuickScreenOf({ entry, route, recordId }) {
|
|
|
6413
8461
|
value: route,
|
|
6414
8462
|
children: (0, react_jsx_runtime.jsx)(require_place_node.QuickScreenClaimContext.Provider, {
|
|
6415
8463
|
value: true,
|
|
6416
|
-
children: (0, react_jsx_runtime.jsx)(
|
|
8464
|
+
children: (0, react_jsx_runtime.jsx)(RecordScreen, {
|
|
6417
8465
|
resource: entry.resource,
|
|
6418
8466
|
mode: entry.mode,
|
|
6419
8467
|
...recordId === void 0 ? {} : { recordId },
|
|
@@ -6922,6 +8970,7 @@ const spacing = {
|
|
|
6922
8970
|
const groupTestId = (role, id) => `command-palette:${role}:${id}`;
|
|
6923
8971
|
function DefaultCommandPalette({ open, onOpenChange, actions, children }) {
|
|
6924
8972
|
const t = (0, _burojs_react.useOptionalT)();
|
|
8973
|
+
const waiting = useShellWaiting();
|
|
6925
8974
|
const locale = (0, _burojs_react.useLocale)();
|
|
6926
8975
|
const canSearchRecords = (0, _burojs_react.useOptionalDataRuntime)() !== null;
|
|
6927
8976
|
const close = () => onOpenChange(false);
|
|
@@ -6960,21 +9009,21 @@ function DefaultCommandPalette({ open, onOpenChange, actions, children }) {
|
|
|
6960
9009
|
locale,
|
|
6961
9010
|
onSelect: close
|
|
6962
9011
|
}),
|
|
6963
|
-
(0, react_jsx_runtime.jsx)(CommandPaletteRecentGroup, {
|
|
9012
|
+
waiting ? null : (0, react_jsx_runtime.jsx)(CommandPaletteRecentGroup, {
|
|
6964
9013
|
onSelect: close,
|
|
6965
9014
|
refreshKey: open,
|
|
6966
9015
|
getTestId: groupTestId
|
|
6967
9016
|
}),
|
|
6968
|
-
canSearchRecords ? (0, react_jsx_runtime.jsx)(CommandPaletteRecordsGroup, {
|
|
9017
|
+
canSearchRecords && !waiting ? (0, react_jsx_runtime.jsx)(CommandPaletteRecordsGroup, {
|
|
6969
9018
|
enabled: open,
|
|
6970
9019
|
onSelect: close,
|
|
6971
9020
|
getTestId: groupTestId
|
|
6972
9021
|
}) : null,
|
|
6973
|
-
(0, react_jsx_runtime.jsx)(CommandPaletteNavigationGroups, {
|
|
9022
|
+
waiting ? null : (0, react_jsx_runtime.jsx)(CommandPaletteNavigationGroups, {
|
|
6974
9023
|
onSelect: close,
|
|
6975
9024
|
getTestId: (role, id) => `command-palette:nav:${role}:${id}`
|
|
6976
9025
|
}),
|
|
6977
|
-
(0, react_jsx_runtime.jsx)(CommandPaletteCreateGroup, {
|
|
9026
|
+
waiting ? null : (0, react_jsx_runtime.jsx)(CommandPaletteCreateGroup, {
|
|
6978
9027
|
onSelect: close,
|
|
6979
9028
|
getTestId: groupTestId
|
|
6980
9029
|
}),
|
|
@@ -6990,6 +9039,10 @@ function DefaultCommandPalette({ open, onOpenChange, actions, children }) {
|
|
|
6990
9039
|
//#region src/shell/app-shell.tsx
|
|
6991
9040
|
function AppShell({ brand, user, loginPath, sidebar, header, palette, docPanel, navChrome, children }) {
|
|
6992
9041
|
const enabled = palette !== false;
|
|
9042
|
+
const waiting = useShellWaiting();
|
|
9043
|
+
const decidedOnce = (0, react.useRef)(false);
|
|
9044
|
+
if (!waiting) decidedOnce.current = true;
|
|
9045
|
+
const holding = waiting && !decidedOnce.current;
|
|
6993
9046
|
const { open, setOpen, toggle } = (0, _burojs_react.useCommandPalette)();
|
|
6994
9047
|
(0, _burojs_react_web.useGlobalShortcut)({
|
|
6995
9048
|
key: "k",
|
|
@@ -7012,7 +9065,7 @@ function AppShell({ brand, user, loginPath, sidebar, header, palette, docPanel,
|
|
|
7012
9065
|
sidebar: fill(sidebar, () => (0, react_jsx_runtime.jsx)(AppSidebar, {})),
|
|
7013
9066
|
header: fill(header, () => (0, react_jsx_runtime.jsx)(AppHeader, {})),
|
|
7014
9067
|
...docPanel !== void 0 ? { docPanel } : {},
|
|
7015
|
-
children: navChrome === false ? children : (0, react_jsx_runtime.jsx)(NavChrome, { children })
|
|
9068
|
+
children: holding ? (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "loading" }) : navChrome === false ? children : (0, react_jsx_runtime.jsx)(NavChrome, { children })
|
|
7016
9069
|
}), paletteNode]
|
|
7017
9070
|
});
|
|
7018
9071
|
}
|
|
@@ -7161,6 +9214,8 @@ exports.Checkbox = require_place_node.Checkbox;
|
|
|
7161
9214
|
exports.Collapsible = Collapsible;
|
|
7162
9215
|
exports.CollapsibleContent = CollapsibleContent;
|
|
7163
9216
|
exports.CollapsibleTrigger = CollapsibleTrigger;
|
|
9217
|
+
exports.CollectionCreatePicker = CollectionCreatePicker;
|
|
9218
|
+
exports.CollectionRecordRoute = CollectionRecordRoute;
|
|
7164
9219
|
exports.ColumnsToggle = require_place_node.ColumnsToggle;
|
|
7165
9220
|
exports.Command = require_relation_create.Command;
|
|
7166
9221
|
exports.CommandDialog = require_relation_create.CommandDialog;
|
|
@@ -7281,7 +9336,8 @@ exports.ListLive = require_place_node.ListLive;
|
|
|
7281
9336
|
exports.ListSavedViews = require_place_node.ListSavedViews;
|
|
7282
9337
|
exports.ListSearchInput = require_place_node.ListSearchInput;
|
|
7283
9338
|
exports.LoginForm = LoginForm;
|
|
7284
|
-
exports.
|
|
9339
|
+
exports.NavAreaNotFound = require_record_trail_store.NavAreaNotFound;
|
|
9340
|
+
exports.NavAreaPage = NavAreaPage;
|
|
7285
9341
|
exports.NavChrome = NavChrome;
|
|
7286
9342
|
exports.NavMain = NavMain;
|
|
7287
9343
|
exports.NavigationGuardDialog = NavigationGuardDialog;
|
|
@@ -7301,8 +9357,8 @@ exports.PresetFilterControls = require_filter_builder.PresetFilterControls;
|
|
|
7301
9357
|
exports.Progress = Progress;
|
|
7302
9358
|
exports.RecordActions = require_place_node.RecordActions;
|
|
7303
9359
|
exports.RecordBreadcrumbs = RecordBreadcrumbs;
|
|
7304
|
-
exports.RecordPage =
|
|
7305
|
-
exports.RecordScreen =
|
|
9360
|
+
exports.RecordPage = RecordPage;
|
|
9361
|
+
exports.RecordScreen = RecordScreen;
|
|
7306
9362
|
exports.RecordTitle = require_place_node.RecordTitle;
|
|
7307
9363
|
exports.RefreshButton = RefreshButton;
|
|
7308
9364
|
exports.RelationDisplay = require_relation_create.RelationDisplay;
|
|
@@ -7312,12 +9368,12 @@ exports.RelationPicker = require_relation_picker.RelationPicker;
|
|
|
7312
9368
|
exports.RelationPickerDialog = require_lazy_relation_picker_dialog.LazyRelationPickerDialog;
|
|
7313
9369
|
exports.RelationPickerInput = require_relation_picker.RelationPickerInput;
|
|
7314
9370
|
exports.ResourceList = require_place_node.ResourceList;
|
|
7315
|
-
exports.ResourceListPage =
|
|
7316
|
-
exports.ResourcePageRouter =
|
|
9371
|
+
exports.ResourceListPage = ResourceListPage;
|
|
9372
|
+
exports.ResourcePageRouter = ResourcePageRouter;
|
|
7317
9373
|
exports.SavedViewsDropdown = require_place_node.SavedViewsDropdown;
|
|
7318
9374
|
exports.ScopeDimensionPicker = ScopeDimensionPicker;
|
|
7319
9375
|
exports.ScopeSwitcher = ScopeSwitcher;
|
|
7320
|
-
exports.SecondarySidebarLayout =
|
|
9376
|
+
exports.SecondarySidebarLayout = SecondarySidebarLayout;
|
|
7321
9377
|
exports.Select = require_filter_builder.Select;
|
|
7322
9378
|
exports.SelectContent = require_filter_builder.SelectContent;
|
|
7323
9379
|
exports.SelectGroup = require_filter_builder.SelectGroup;
|
|
@@ -7377,7 +9433,7 @@ exports.TableHeader = require_filter_builder.TableHeader;
|
|
|
7377
9433
|
exports.TableRow = require_filter_builder.TableRow;
|
|
7378
9434
|
exports.Tabs = require_place_node.Tabs;
|
|
7379
9435
|
exports.TabsContent = require_place_node.TabsContent;
|
|
7380
|
-
exports.TabsLayout =
|
|
9436
|
+
exports.TabsLayout = TabsLayout;
|
|
7381
9437
|
exports.TabsList = require_place_node.TabsList;
|
|
7382
9438
|
exports.TabsTrigger = require_place_node.TabsTrigger;
|
|
7383
9439
|
exports.TaskRunPanel = TaskRunPanel;
|
|
@@ -7393,6 +9449,7 @@ exports.Tooltip = require_check_confirm_dialog.Tooltip;
|
|
|
7393
9449
|
exports.TooltipContent = require_check_confirm_dialog.TooltipContent;
|
|
7394
9450
|
exports.TooltipProvider = require_check_confirm_dialog.TooltipProvider;
|
|
7395
9451
|
exports.TooltipTrigger = require_check_confirm_dialog.TooltipTrigger;
|
|
9452
|
+
exports.UnknownMemberCard = UnknownMemberCard;
|
|
7396
9453
|
exports.UserMenu = UserMenu;
|
|
7397
9454
|
exports.badgeVariants = require_filter_builder.badgeVariants;
|
|
7398
9455
|
exports.buildNavItems = buildNavItems;
|
|
@@ -7406,7 +9463,7 @@ exports.formatOperatorLabel = formatOperatorLabel;
|
|
|
7406
9463
|
exports.hasIcon = require_check_confirm_dialog.hasIcon;
|
|
7407
9464
|
exports.i18nPrefixToRef = _burojs_core.i18nPrefixToRef;
|
|
7408
9465
|
exports.isImage = _burojs_file_storage.isImage;
|
|
7409
|
-
exports.layoutSlot =
|
|
9466
|
+
exports.layoutSlot = layoutSlot;
|
|
7410
9467
|
exports.listSlot = require_check_confirm_dialog.listSlot;
|
|
7411
9468
|
exports.loadLocale = require_filter_builder.loadLocale;
|
|
7412
9469
|
exports.localeLabel = localeLabel;
|
|
@@ -7436,18 +9493,18 @@ exports.useDocumentTitle = require_place_node.useDocumentTitle;
|
|
|
7436
9493
|
exports.useExportRunWatcher = require_place_node.useExportRunWatcher;
|
|
7437
9494
|
exports.useFormControl = require_place_node.useFormControl;
|
|
7438
9495
|
exports.useFormField = useFormField;
|
|
7439
|
-
exports.useHref =
|
|
9496
|
+
exports.useHref = useHref;
|
|
7440
9497
|
exports.useIsMobile = useIsMobile;
|
|
7441
9498
|
exports.useLanguagePaletteActions = useLanguagePaletteActions;
|
|
7442
9499
|
exports.useLanguageSwitch = useLanguageSwitch;
|
|
7443
|
-
exports.useLayout =
|
|
7444
|
-
exports.useLayoutResolver =
|
|
9500
|
+
exports.useLayout = useLayout;
|
|
9501
|
+
exports.useLayoutResolver = useLayoutResolver;
|
|
7445
9502
|
exports.useLinkComponent = require_toaster.useLinkComponent;
|
|
7446
9503
|
exports.useListSlot = require_check_confirm_dialog.useListSlot;
|
|
7447
|
-
exports.useMatch =
|
|
9504
|
+
exports.useMatch = useMatch;
|
|
7448
9505
|
exports.useNavIcon = useNavIcon;
|
|
7449
9506
|
exports.useNavTree = useNavTree;
|
|
7450
|
-
exports.useNavVisible =
|
|
9507
|
+
exports.useNavVisible = useNavVisible;
|
|
7451
9508
|
exports.useOptionalSidebar = useOptionalSidebar;
|
|
7452
9509
|
exports.usePaletteState = require_place_node.usePaletteState;
|
|
7453
9510
|
exports.usePresentationCopy = usePresentationCopy;
|