@burojs/ui-shadcn 0.6.0 → 0.7.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/README.md +9 -0
- package/dist/bulk-summary-BWSAS7k2.js +143 -0
- package/dist/bulk-summary-BWSAS7k2.js.map +1 -0
- package/dist/bulk-summary-CrEij5vq.cjs +143 -0
- package/dist/bulk-summary-CrEij5vq.cjs.map +1 -0
- package/dist/{candidates-relation-picker-B116Bmqi.js → candidates-relation-picker-CS_JZ4Fd.js} +3 -3
- package/dist/{candidates-relation-picker-B116Bmqi.js.map → candidates-relation-picker-CS_JZ4Fd.js.map} +1 -1
- package/dist/{candidates-relation-picker-Cy0rTxvI.cjs → candidates-relation-picker-y5M6_oe4.cjs} +4 -4
- package/dist/{candidates-relation-picker-Cy0rTxvI.cjs.map → candidates-relation-picker-y5M6_oe4.cjs.map} +1 -1
- package/dist/{check-confirm-dialog-bRT8lt0d.js → check-confirm-dialog-2j0gOd7x.js} +384 -108
- package/dist/check-confirm-dialog-2j0gOd7x.js.map +1 -0
- package/dist/{check-confirm-dialog--gPFnEeg.cjs → check-confirm-dialog-C-NHgMST.cjs} +468 -107
- package/dist/check-confirm-dialog-C-NHgMST.cjs.map +1 -0
- package/dist/{dialog-B_rt9S1c.js → dialog-C123sVQ8.js} +4 -4
- package/dist/dialog-C123sVQ8.js.map +1 -0
- package/dist/{dialog-DRNUq9EA.cjs → dialog-vmMdfUWs.cjs} +3 -3
- package/dist/dialog-vmMdfUWs.cjs.map +1 -0
- package/dist/{filter-builder-nXqtM_h4.cjs → filter-builder-DFu0JP-1.cjs} +923 -120
- package/dist/filter-builder-DFu0JP-1.cjs.map +1 -0
- package/dist/{filter-builder-Bhn-dhZV.js → filter-builder-DaWHUZuV.js} +839 -108
- package/dist/filter-builder-DaWHUZuV.js.map +1 -0
- package/dist/{flow-runtime-D3avVH0I.cjs → flow-runtime-BpmrIUb6.cjs} +61 -29
- package/dist/flow-runtime-BpmrIUb6.cjs.map +1 -0
- package/dist/{flow-runtime-s6lkRPKF.js → flow-runtime-DyqTmK3H.js} +62 -30
- package/dist/flow-runtime-DyqTmK3H.js.map +1 -0
- package/dist/{flow-screen-Ci_Sik4Y.cjs → flow-screen-Bcz9NF2V.cjs} +128 -87
- package/dist/flow-screen-Bcz9NF2V.cjs.map +1 -0
- package/dist/{flow-screen-CCvgDI9G.js → flow-screen-DCdli6Ha.js} +128 -87
- package/dist/flow-screen-DCdli6Ha.js.map +1 -0
- package/dist/index.cjs +731 -906
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +455 -247
- package/dist/index.d.ts +455 -247
- package/dist/index.js +647 -828
- package/dist/index.js.map +1 -1
- package/dist/{inline-flow-host-DV1et3c6.cjs → inline-flow-host-3vw7LzzD.cjs} +5 -5
- package/dist/inline-flow-host-3vw7LzzD.cjs.map +1 -0
- package/dist/{inline-flow-host-B6FI0ctQ.js → inline-flow-host-C0rI9B7f.js} +5 -5
- package/dist/inline-flow-host-C0rI9B7f.js.map +1 -0
- package/dist/{candidates-gate-D33jXLHO.cjs → lazy-relation-picker-dialog-Bt8lrEIu.cjs} +10 -10
- package/dist/lazy-relation-picker-dialog-Bt8lrEIu.cjs.map +1 -0
- package/dist/{candidates-gate-Bb70LPAy.js → lazy-relation-picker-dialog-CAScLPb2.js} +11 -11
- package/dist/lazy-relation-picker-dialog-CAScLPb2.js.map +1 -0
- package/dist/{page-flow-route-i3ZfJ1sd.js → page-flow-route-BHUEpn0I.js} +36 -23
- package/dist/page-flow-route-BHUEpn0I.js.map +1 -0
- package/dist/{page-flow-route-hdnULWqd.cjs → page-flow-route-DS8IVTVH.cjs} +41 -28
- package/dist/page-flow-route-DS8IVTVH.cjs.map +1 -0
- package/dist/{place-node-C5SmIAYU.cjs → place-node-CNb3w-c7.cjs} +1869 -947
- package/dist/place-node-CNb3w-c7.cjs.map +1 -0
- package/dist/{place-node-NraNYKPx.js → place-node-CfzQvh4Y.js} +1824 -926
- package/dist/place-node-CfzQvh4Y.js.map +1 -0
- package/dist/{related-list-cards-BWZ9GfOG.js → related-list-cards-BIqqY69Y.js} +9 -4
- package/dist/{related-list-cards-BWZ9GfOG.js.map → related-list-cards-BIqqY69Y.js.map} +1 -1
- package/dist/{related-list-cards-CFq3meUn.cjs → related-list-cards-CelMxl4q.cjs} +9 -4
- package/dist/{related-list-cards-CFq3meUn.cjs.map → related-list-cards-CelMxl4q.cjs.map} +1 -1
- package/dist/{related-list-timeline-yrPsjA3F.js → related-list-timeline-CRh7xwLD.js} +6 -7
- package/dist/related-list-timeline-CRh7xwLD.js.map +1 -0
- package/dist/{related-list-timeline-CCzl71aA.cjs → related-list-timeline-DsLdi8sv.cjs} +5 -6
- package/dist/related-list-timeline-DsLdi8sv.cjs.map +1 -0
- package/dist/{related-rows-o0_t-Yce.js → related-rows--uP2iKQC.js} +25 -14
- package/dist/related-rows--uP2iKQC.js.map +1 -0
- package/dist/{related-rows-ea43qhhy.cjs → related-rows-MPnLCmPF.cjs} +27 -16
- package/dist/related-rows-MPnLCmPF.cjs.map +1 -0
- package/dist/{search-access-CPPmfuvy.js → relation-create-C43cdPQt.js} +595 -13
- package/dist/relation-create-C43cdPQt.js.map +1 -0
- package/dist/{search-access-Dugvttlg.cjs → relation-create-DDEYcKfw.cjs} +633 -14
- package/dist/relation-create-DDEYcKfw.cjs.map +1 -0
- package/dist/{relation-many-picker-bvkjkv-k.js → relation-many-picker-BJhaEqxz.js} +203 -102
- package/dist/relation-many-picker-BJhaEqxz.js.map +1 -0
- package/dist/{relation-many-picker-C8zFEjwd.cjs → relation-many-picker-DzuGJpEl.cjs} +211 -110
- package/dist/relation-many-picker-DzuGJpEl.cjs.map +1 -0
- package/dist/{relation-picker-Z0ZJJ5uS.js → relation-picker-D-tBBZW_.js} +23 -59
- package/dist/relation-picker-D-tBBZW_.js.map +1 -0
- package/dist/{relation-picker-gag0qSR5.cjs → relation-picker-DaIMzf2H.cjs} +29 -71
- package/dist/relation-picker-DaIMzf2H.cjs.map +1 -0
- package/dist/{relation-picker-dialog-0IzkjmiA.cjs → relation-picker-dialog-9Vg5vvR1.cjs} +133 -35
- package/dist/relation-picker-dialog-9Vg5vvR1.cjs.map +1 -0
- package/dist/{relation-picker-dialog-B6nIiJBf.js → relation-picker-dialog-DoEY8EkH.js} +134 -36
- package/dist/relation-picker-dialog-DoEY8EkH.js.map +1 -0
- package/dist/relation-select-B8Fq4o-t.js +48 -0
- package/dist/relation-select-B8Fq4o-t.js.map +1 -0
- package/dist/relation-select-Cr3CfNLy.cjs +55 -0
- package/dist/relation-select-Cr3CfNLy.cjs.map +1 -0
- package/dist/{resource-page-router-PXfMW9nh.cjs → resource-page-router-C_kGW2o_.cjs} +543 -300
- package/dist/resource-page-router-C_kGW2o_.cjs.map +1 -0
- package/dist/{resource-page-router-3RUf9d1j.js → resource-page-router-Diw6S6TK.js} +498 -255
- package/dist/resource-page-router-Diw6S6TK.js.map +1 -0
- package/dist/{rich-text-vTyVjDoa.cjs → rich-text-C_7JCvRo.cjs} +2 -2
- package/dist/{rich-text-vTyVjDoa.cjs.map → rich-text-C_7JCvRo.cjs.map} +1 -1
- package/dist/{rich-text-DFerywgz.js → rich-text-RcPBf6hr.js} +2 -2
- package/dist/{rich-text-DFerywgz.js.map → rich-text-RcPBf6hr.js.map} +1 -1
- package/dist/success-notices-Dl3M1fZP.cjs +46 -0
- package/dist/success-notices-Dl3M1fZP.cjs.map +1 -0
- package/dist/success-notices-LDEgEkc4.js +41 -0
- package/dist/success-notices-LDEgEkc4.js.map +1 -0
- package/dist/{toaster-Cr51X7bz.cjs → toaster-BbByOytP.cjs} +60 -15
- package/dist/toaster-BbByOytP.cjs.map +1 -0
- package/dist/{toaster-C02XbB9r.js → toaster-Ct_YHGs6.js} +43 -16
- package/dist/toaster-Ct_YHGs6.js.map +1 -0
- package/dist/{use-dialog-filter-state-C--oMAZG.js → use-dialog-filter-state-B_MqzHaT.js} +5 -4
- package/dist/use-dialog-filter-state-B_MqzHaT.js.map +1 -0
- package/dist/{use-dialog-filter-state-Dhe8PcB5.cjs → use-dialog-filter-state-tNvqAAjh.cjs} +6 -5
- package/dist/use-dialog-filter-state-tNvqAAjh.cjs.map +1 -0
- package/package.json +11 -11
- package/dist/bulk-summary-CwSd6Yjb.cjs +0 -108
- package/dist/bulk-summary-CwSd6Yjb.cjs.map +0 -1
- package/dist/bulk-summary-GxMDP4bw.js +0 -108
- package/dist/bulk-summary-GxMDP4bw.js.map +0 -1
- package/dist/candidates-gate-Bb70LPAy.js.map +0 -1
- package/dist/candidates-gate-D33jXLHO.cjs.map +0 -1
- package/dist/check-confirm-dialog--gPFnEeg.cjs.map +0 -1
- package/dist/check-confirm-dialog-bRT8lt0d.js.map +0 -1
- package/dist/dialog-B_rt9S1c.js.map +0 -1
- package/dist/dialog-DRNUq9EA.cjs.map +0 -1
- package/dist/filter-builder-Bhn-dhZV.js.map +0 -1
- package/dist/filter-builder-nXqtM_h4.cjs.map +0 -1
- package/dist/flow-runtime-D3avVH0I.cjs.map +0 -1
- package/dist/flow-runtime-s6lkRPKF.js.map +0 -1
- package/dist/flow-screen-CCvgDI9G.js.map +0 -1
- package/dist/flow-screen-Ci_Sik4Y.cjs.map +0 -1
- package/dist/inline-flow-host-B6FI0ctQ.js.map +0 -1
- package/dist/inline-flow-host-DV1et3c6.cjs.map +0 -1
- package/dist/page-flow-route-hdnULWqd.cjs.map +0 -1
- package/dist/page-flow-route-i3ZfJ1sd.js.map +0 -1
- package/dist/place-node-C5SmIAYU.cjs.map +0 -1
- package/dist/place-node-NraNYKPx.js.map +0 -1
- package/dist/related-list-timeline-CCzl71aA.cjs.map +0 -1
- package/dist/related-list-timeline-yrPsjA3F.js.map +0 -1
- package/dist/related-rows-ea43qhhy.cjs.map +0 -1
- package/dist/related-rows-o0_t-Yce.js.map +0 -1
- package/dist/relation-create-IA40t1hi.cjs +0 -364
- package/dist/relation-create-IA40t1hi.cjs.map +0 -1
- package/dist/relation-create-h6F9B4C4.js +0 -339
- package/dist/relation-create-h6F9B4C4.js.map +0 -1
- package/dist/relation-many-picker-C8zFEjwd.cjs.map +0 -1
- package/dist/relation-many-picker-bvkjkv-k.js.map +0 -1
- package/dist/relation-picker-Z0ZJJ5uS.js.map +0 -1
- package/dist/relation-picker-dialog-0IzkjmiA.cjs.map +0 -1
- package/dist/relation-picker-dialog-B6nIiJBf.js.map +0 -1
- package/dist/relation-picker-gag0qSR5.cjs.map +0 -1
- package/dist/resource-page-router-3RUf9d1j.js.map +0 -1
- package/dist/resource-page-router-PXfMW9nh.cjs.map +0 -1
- package/dist/search-access-CPPmfuvy.js.map +0 -1
- package/dist/search-access-Dugvttlg.cjs.map +0 -1
- package/dist/shell-BPlk8hEa.js +0 -205
- package/dist/shell-BPlk8hEa.js.map +0 -1
- package/dist/shell-DxhlsPwm.cjs +0 -271
- package/dist/shell-DxhlsPwm.cjs.map +0 -1
- package/dist/toaster-C02XbB9r.js.map +0 -1
- package/dist/toaster-Cr51X7bz.cjs.map +0 -1
- package/dist/use-dialog-filter-state-C--oMAZG.js.map +0 -1
- package/dist/use-dialog-filter-state-Dhe8PcB5.cjs.map +0 -1
|
@@ -1,64 +1,121 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { l as cn } from "./use-theme-dnE3Od3I.js";
|
|
2
|
+
import { l as useLinkComponent } from "./toaster-Ct_YHGs6.js";
|
|
3
|
+
import { D as loadPageFlowRoute, k as useLoaded, o as canonicalResourceName, t as CheckConfirmDialog, v as FlowBoundary, w as loadFailedText } from "./check-confirm-dialog-2j0gOd7x.js";
|
|
2
4
|
import { t as Button } from "./button-MWVeZaqj.js";
|
|
5
|
+
import { b as RecordState, m as useRowTitle, v as InvalidRouteId, y as LoadError } from "./relation-create-C43cdPQt.js";
|
|
3
6
|
import { t as Skeleton } from "./skeleton-U2noefj5.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
+
import { Ct as recordReturnTarget, Dt as useShownItemActions, G as RouteScreenClaimContext, H as ScreenTree, J as FormControlProvider, K as RouteScreenContext, Pt as FieldDisplay, S as useFrameChrome, St as listTarget, Tt as showTarget, U as useTabsUrlState, W as QuickScreenClaimContext, X as useFormControlOf, d as resolveFrameView, g as UndeclaredTypeNotice, h as TypeChromeDrawnContext, ht as PageHeader, i as RouteListContext, jt as DeepLinkScope, m as HeaderTypeNotice, n as viewOf, p as ChangeTypeButton, q as useIsRouteScreen, t as selectImplementation, u as isBuiltinRecordView, v as FormActions, wt as recordRouteAvailable, x as FrameChromeContext, xt as isShowAvailable } from "./place-node-CfzQvh4Y.js";
|
|
8
|
+
import { t as useNoticeSink } from "./success-notices-LDEgEkc4.js";
|
|
9
|
+
import { FORM_SLOT, addressesCapability, builtinFrames, canonicalEntityNodeKey, compilePageScreen, declaredText, dtoFields, evaluateVisible, fieldSensitivity, formatEntityRef, hasListPage, hrefFor, humanizeKey, isCustomPageDef, isScreenFailure, issueOfInput, matchPath, navHrefFor, normalizeEntityRef, normalizeIssueInputs, pageParamNames, parsePageParams, resolveNavLabel, resourceKey, routeResourceKey, routeServerIssues, scopeColumnOf, snapshotAppFrames, snapshotBlockLookup, snapshotFrameLookup, successNoticesOf } from "@burojs/core";
|
|
10
|
+
import { ActionRouteContext, ComponentsContext, FrameCheckContext, RecordFrameContext, RecordScopeProvider, ResourceContext, RouteSourceContext, ScreenStateProvider, maybeThen, pageAccessFor, policyRecordOf, recordKeyOf, resolveRoute, retryRecordRead, settle, useApp, useApplicationSnapshot, useAvailabilityResolver, useChromeT, useComponent, useCtx, useCurrentUserId, useFieldAccess, useFormController, useFrameImplementations, useFrameT, useI18nCaps, useList, useNavigationGuardText, useOne, useOptionalDataRuntime, useOptionalRouterAdapter, useOptionalT, usePageAccess, usePageScreen, usePermissions, usePlatformStorage, useProjectedRecord, usePublishDocVariant, useQuickEntry, useRecordFrame, useRecordTitle, useRouteListImplementation, useRouteNavigate, useRouteRecordId, useScope, useT, useTestIds, useTranslate, useVisibilityCtx } from "@burojs/react";
|
|
7
11
|
import { Suspense, createContext, useCallback, useContext, useEffect, useId, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
8
12
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
9
13
|
//#region src/resource-key.ts
|
|
10
14
|
function canonicalNavKey(node) {
|
|
11
15
|
return canonicalEntityNodeKey(node);
|
|
12
16
|
}
|
|
13
|
-
function canonicalResourceKey(def) {
|
|
17
|
+
function canonicalResourceKey$1(def) {
|
|
14
18
|
return canonicalNavKey(def);
|
|
15
19
|
}
|
|
16
20
|
//#endregion
|
|
17
|
-
//#region src/layout/
|
|
18
|
-
function
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
21
|
+
//#region src/layout/layouts/secondary-sidebar-layout.tsx
|
|
22
|
+
function Row({ it }) {
|
|
23
|
+
const RouterLink = useLinkComponent();
|
|
24
|
+
return jsx("li", { children: jsxs(RouterLink, {
|
|
25
|
+
href: it.href,
|
|
26
|
+
"data-testid": `nav-secondary-item:${it.name}`,
|
|
27
|
+
"aria-current": it.active ? "page" : void 0,
|
|
28
|
+
className: 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"),
|
|
29
|
+
children: [it.icon != null && jsx("span", {
|
|
30
|
+
className: "inline-flex h-4 w-4 shrink-0 items-center justify-center",
|
|
31
|
+
"aria-hidden": "true",
|
|
32
|
+
children: it.icon
|
|
33
|
+
}), jsx("span", {
|
|
34
|
+
className: "truncate",
|
|
35
|
+
title: it.label,
|
|
36
|
+
children: it.label
|
|
37
|
+
})]
|
|
38
|
+
}) });
|
|
39
|
+
}
|
|
40
|
+
function SecondarySidebarLayout({ group, groupKey, items, children }) {
|
|
41
|
+
const RouterLink = useLinkComponent();
|
|
42
|
+
const caps = useI18nCaps();
|
|
43
|
+
const id = groupKey ?? group.name;
|
|
44
|
+
const label = resolveNavLabel(caps, `groups.${id}`, declaredText("chrome", group, "label"));
|
|
45
|
+
return jsxs("div", {
|
|
46
|
+
className: "md:-m-6 md:flex md:min-h-[calc(100%+3rem)]",
|
|
47
|
+
"data-testid": `nav-secondary:${id}`,
|
|
48
|
+
children: [
|
|
49
|
+
jsx("aside", {
|
|
50
|
+
className: "hidden w-64 shrink-0 border-r bg-background text-foreground md:block",
|
|
51
|
+
children: jsxs("div", {
|
|
52
|
+
className: "space-y-4 p-4",
|
|
53
|
+
children: [jsx("p", {
|
|
54
|
+
className: "px-3 text-base font-semibold tracking-tight",
|
|
55
|
+
children: label
|
|
56
|
+
}), jsx("nav", {
|
|
57
|
+
"aria-label": label,
|
|
58
|
+
children: jsx("ul", {
|
|
59
|
+
className: "space-y-0.5",
|
|
60
|
+
children: items.map((it) => jsx(Row, { it }, it.name))
|
|
61
|
+
})
|
|
62
|
+
})]
|
|
63
|
+
})
|
|
64
|
+
}),
|
|
65
|
+
jsx("nav", {
|
|
66
|
+
"aria-label": label,
|
|
67
|
+
"data-testid": `nav-secondary-select:${id}`,
|
|
68
|
+
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",
|
|
69
|
+
children: items.map((it) => jsx(RouterLink, {
|
|
70
|
+
href: it.href,
|
|
71
|
+
"aria-current": it.active ? "page" : void 0,
|
|
72
|
+
className: 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"),
|
|
73
|
+
children: it.label
|
|
74
|
+
}, it.name))
|
|
75
|
+
}),
|
|
76
|
+
jsx("div", {
|
|
77
|
+
className: "min-w-0 flex-1 md:overflow-x-hidden md:p-6",
|
|
78
|
+
children
|
|
79
|
+
})
|
|
80
|
+
]
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/layout/layouts/tabs-layout.tsx
|
|
85
|
+
function TabsLayout({ group, groupKey, items, children }) {
|
|
86
|
+
const RouterLink = useLinkComponent();
|
|
87
|
+
const caps = useI18nCaps();
|
|
88
|
+
const id = groupKey ?? group.name;
|
|
89
|
+
const label = resolveNavLabel(caps, `groups.${id}`, declaredText("chrome", group, "label"));
|
|
90
|
+
return jsxs("div", {
|
|
91
|
+
className: "flex flex-col gap-4",
|
|
92
|
+
"data-testid": `nav-tabs:${id}`,
|
|
93
|
+
children: [jsx("nav", {
|
|
94
|
+
"aria-label": label,
|
|
95
|
+
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",
|
|
96
|
+
children: items.map((it) => jsxs(RouterLink, {
|
|
97
|
+
href: it.href,
|
|
98
|
+
"aria-current": it.active ? "page" : void 0,
|
|
99
|
+
"data-testid": `nav-tab:${it.name}`,
|
|
100
|
+
className: 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"),
|
|
101
|
+
children: [
|
|
102
|
+
it.icon != null && jsx("span", {
|
|
103
|
+
className: "inline-flex h-4 w-4 shrink-0 items-center justify-center",
|
|
104
|
+
"aria-hidden": "true",
|
|
105
|
+
children: it.icon
|
|
106
|
+
}),
|
|
107
|
+
it.label,
|
|
108
|
+
jsx("span", {
|
|
109
|
+
"aria-hidden": "true",
|
|
110
|
+
className: 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")
|
|
111
|
+
})
|
|
112
|
+
]
|
|
113
|
+
}, it.name))
|
|
114
|
+
}), jsx("div", {
|
|
115
|
+
className: "min-w-0",
|
|
116
|
+
children
|
|
117
|
+
})]
|
|
118
|
+
});
|
|
62
119
|
}
|
|
63
120
|
//#endregion
|
|
64
121
|
//#region src/layout/nav-slots.ts
|
|
@@ -68,9 +125,33 @@ function layoutSlot(key) {
|
|
|
68
125
|
function useLayout(key) {
|
|
69
126
|
return useComponent(layoutSlot(key));
|
|
70
127
|
}
|
|
128
|
+
const BUILTIN_LAYOUTS = {
|
|
129
|
+
[layoutSlot("secondary-sidebar")]: SecondarySidebarLayout,
|
|
130
|
+
[layoutSlot("tabs")]: TabsLayout
|
|
131
|
+
};
|
|
71
132
|
function useLayoutResolver() {
|
|
72
133
|
const components = useContext(ComponentsContext);
|
|
73
|
-
return (key) => components[layoutSlot(key)];
|
|
134
|
+
return (key) => components[layoutSlot(key)] ?? BUILTIN_LAYOUTS[layoutSlot(key)];
|
|
135
|
+
}
|
|
136
|
+
const unresolvedLayoutReported = new WeakMap();
|
|
137
|
+
function useReportUnresolvedLayouts(groups, resolve) {
|
|
138
|
+
const app = useApp();
|
|
139
|
+
useEffect(() => {
|
|
140
|
+
if (process.env.NODE_ENV === "production") return;
|
|
141
|
+
for (const group of groups) {
|
|
142
|
+
const layout = group.layout;
|
|
143
|
+
if (layout === "flat" || layout === "collapsible" || resolve(layout)) continue;
|
|
144
|
+
const key = canonicalNavKey(group);
|
|
145
|
+
let seen = unresolvedLayoutReported.get(app);
|
|
146
|
+
if (!seen) {
|
|
147
|
+
seen = new Set();
|
|
148
|
+
unresolvedLayoutReported.set(app, seen);
|
|
149
|
+
}
|
|
150
|
+
if (seen.has(key)) continue;
|
|
151
|
+
seen.add(key);
|
|
152
|
+
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".`);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
74
155
|
}
|
|
75
156
|
//#endregion
|
|
76
157
|
//#region src/layout/use-nav-routing.ts
|
|
@@ -79,6 +160,10 @@ function useNavVisible() {
|
|
|
79
160
|
const allowed = usePageAllowed();
|
|
80
161
|
return useCallback((node) => evaluateVisible(node.visible, ctx) && (!isCustomPageDef(node) || allowed(node)), [ctx, allowed]);
|
|
81
162
|
}
|
|
163
|
+
function useResourceVisible() {
|
|
164
|
+
const ctx = useVisibilityCtx();
|
|
165
|
+
return useCallback((def) => evaluateVisible(def.visible, ctx), [ctx]);
|
|
166
|
+
}
|
|
82
167
|
function usePageAllowed() {
|
|
83
168
|
const permissions = usePermissions();
|
|
84
169
|
return useCallback((page) => pageAccessFor(page, permissions) === "allowed", [permissions]);
|
|
@@ -98,99 +183,17 @@ function useMatch() {
|
|
|
98
183
|
return path === void 0 ? null : matchPath(app.registry, path, { isVisible });
|
|
99
184
|
}
|
|
100
185
|
//#endregion
|
|
101
|
-
//#region src/layout/nav-chrome-
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
function NavChromeBoundaryProvider({ claim, children }) {
|
|
107
|
-
const parent = useContext(NavChromeBoundaryContext);
|
|
108
|
-
const key = claim.join(" ");
|
|
109
|
-
const merged = useMemo(() => {
|
|
110
|
-
const s = new Set(parent);
|
|
111
|
-
for (const n of claim) s.add(n);
|
|
112
|
-
return s;
|
|
113
|
-
}, [parent, key]);
|
|
114
|
-
return jsx(NavChromeBoundaryContext.Provider, {
|
|
115
|
-
value: merged,
|
|
116
|
-
children
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
//#endregion
|
|
120
|
-
//#region src/layout/nav-chrome.tsx
|
|
121
|
-
const DETAIL_ACTIONS = new Set([
|
|
122
|
-
"show",
|
|
123
|
-
"edit",
|
|
124
|
-
"create"
|
|
125
|
-
]);
|
|
126
|
-
function NavChrome({ children, entryFilter, icons }) {
|
|
127
|
-
const app = useApp();
|
|
128
|
-
const caps = useI18nCaps();
|
|
129
|
-
const isVisible = useNavVisible();
|
|
130
|
-
const match = useMatch();
|
|
131
|
-
const resolveLayout = useLayoutResolver();
|
|
132
|
-
const boundary = useNavChromeBoundary();
|
|
133
|
-
if (!match) return jsx(Fragment$1, { children });
|
|
134
|
-
let content = children;
|
|
135
|
-
for (let i = match.groupChain.length - 1; i >= 0; i--) {
|
|
136
|
-
const group = match.groupChain[i];
|
|
137
|
-
if (!group) continue;
|
|
138
|
-
const groupKey = canonicalNavKey(group);
|
|
139
|
-
if (boundary.has(groupKey)) continue;
|
|
140
|
-
if (group.chromeOn === "list" && match.kind === "resource" && DETAIL_ACTIONS.has(match.action)) continue;
|
|
141
|
-
const Layout = resolveLayout(group.layout);
|
|
142
|
-
if (!Layout) continue;
|
|
143
|
-
const items = buildNavItems({
|
|
144
|
-
registry: app.registry,
|
|
145
|
-
caps,
|
|
146
|
-
groupName: groupKey,
|
|
147
|
-
match,
|
|
148
|
-
isVisible,
|
|
149
|
-
entryFilter,
|
|
150
|
-
icons
|
|
151
|
-
});
|
|
152
|
-
content = jsx(Layout, {
|
|
153
|
-
group,
|
|
154
|
-
groupKey,
|
|
155
|
-
items,
|
|
156
|
-
children: content
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
return jsx(Fragment$1, { children: content });
|
|
160
|
-
}
|
|
161
|
-
//#endregion
|
|
162
|
-
//#region src/record/record-state.tsx
|
|
163
|
-
function RecordState({ state, onRetry }) {
|
|
164
|
-
const t = useT();
|
|
165
|
-
if (state === "loading") return jsx("div", {
|
|
166
|
-
role: "status",
|
|
167
|
-
"aria-busy": "true",
|
|
168
|
-
"data-testid": "record-page:loading",
|
|
169
|
-
className: "p-6 text-sm text-muted-foreground",
|
|
170
|
-
children: t("router.recordLoading")
|
|
171
|
-
});
|
|
172
|
-
const message = state === "not-found" ? t("router.recordNotFound") : state === "session-expired" ? t("router.recordSessionExpired") : t("router.recordError");
|
|
173
|
-
return jsxs("div", {
|
|
174
|
-
role: "alert",
|
|
175
|
-
"data-testid": `record-page:${state}`,
|
|
176
|
-
className: "flex flex-col items-center justify-center gap-3 px-6 py-24 text-center",
|
|
177
|
-
children: [jsx("p", {
|
|
178
|
-
className: "max-w-sm text-sm text-muted-foreground",
|
|
179
|
-
children: message
|
|
180
|
-
}), onRetry ? jsx(Button, {
|
|
181
|
-
type: "button",
|
|
182
|
-
variant: "outline",
|
|
183
|
-
size: "sm",
|
|
184
|
-
"data-testid": "record-page:retry",
|
|
185
|
-
onClick: onRetry,
|
|
186
|
-
children: t("actions.retry")
|
|
187
|
-
}) : null]
|
|
188
|
-
});
|
|
186
|
+
//#region src/layout/nav-chrome-mounted.ts
|
|
187
|
+
const NavChromeMountedContext = createContext(false);
|
|
188
|
+
const NavChromeMountedProvider = NavChromeMountedContext.Provider;
|
|
189
|
+
function useNavChromeMounted() {
|
|
190
|
+
return useContext(NavChromeMountedContext);
|
|
189
191
|
}
|
|
190
192
|
//#endregion
|
|
191
193
|
//#region src/flows/page-flow-loader.tsx
|
|
192
194
|
function PageFlowRouteLoader({ match }) {
|
|
193
195
|
const t = useOptionalT();
|
|
196
|
+
const chromeT = useChromeT();
|
|
194
197
|
const loaded = useLoaded(loadPageFlowRoute);
|
|
195
198
|
const failed = (retry) => jsxs("div", {
|
|
196
199
|
role: "alert",
|
|
@@ -199,7 +202,7 @@ function PageFlowRouteLoader({ match }) {
|
|
|
199
202
|
children: [jsx("p", { children: loadFailedText(t) }), jsx("div", { children: jsx(Button, {
|
|
200
203
|
type: "button",
|
|
201
204
|
onClick: retry,
|
|
202
|
-
children:
|
|
205
|
+
children: chromeT("actions.retry", { defaultValue: "Retry" })
|
|
203
206
|
}) })]
|
|
204
207
|
});
|
|
205
208
|
if (loaded.error !== void 0) return failed(loaded.retry);
|
|
@@ -212,7 +215,8 @@ function PageFlowRouteLoader({ match }) {
|
|
|
212
215
|
}
|
|
213
216
|
//#endregion
|
|
214
217
|
//#region src/list-kit/resource-list-page.tsx
|
|
215
|
-
function ResourceListPage({ resource, meta, renderCell, emptyState }) {
|
|
218
|
+
function ResourceListPage({ resource: resourceInput, meta, renderCell, emptyState }) {
|
|
219
|
+
const resource = routeResourceKey(resourceInput);
|
|
216
220
|
const app = useRouteListImplementation();
|
|
217
221
|
const implementation = selectImplementation("buro:related-list", app);
|
|
218
222
|
const View = implementation === void 0 ? void 0 : viewOf(implementation);
|
|
@@ -311,8 +315,9 @@ function PageRouteScreen({ children }) {
|
|
|
311
315
|
})
|
|
312
316
|
});
|
|
313
317
|
}
|
|
314
|
-
function PlannedBody({ screen, name, label }) {
|
|
315
|
-
const
|
|
318
|
+
function PlannedBody({ screen, name, label, record }) {
|
|
319
|
+
const pageOptions = useMemo(() => record === void 0 ? {} : { record }, [record]);
|
|
320
|
+
const page = usePageScreen(screen, pageOptions);
|
|
316
321
|
const { PlacementScope } = page;
|
|
317
322
|
const route = useContext(RouteSourceContext);
|
|
318
323
|
const catalog = useFrameImplementations();
|
|
@@ -337,27 +342,23 @@ function PlannedBody({ screen, name, label }) {
|
|
|
337
342
|
};
|
|
338
343
|
return jsx(RouteSourceContext.Provider, {
|
|
339
344
|
value: null,
|
|
340
|
-
children: jsx(
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
children: jsx(
|
|
346
|
-
|
|
347
|
-
children: jsx(
|
|
345
|
+
children: jsx(ActionRouteContext.Provider, {
|
|
346
|
+
value: route,
|
|
347
|
+
children: jsx(PlacementScope, { children: jsx(DeepLinkScope, {
|
|
348
|
+
plan: page.plan,
|
|
349
|
+
enabled: true,
|
|
350
|
+
children: jsx("div", {
|
|
351
|
+
"data-buro-region": "page-body",
|
|
352
|
+
children: jsx(Suspense, {
|
|
353
|
+
fallback: null,
|
|
354
|
+
children: jsx(View, { ...viewProps })
|
|
355
|
+
})
|
|
348
356
|
})
|
|
349
|
-
})
|
|
350
|
-
})
|
|
357
|
+
}) })
|
|
358
|
+
})
|
|
351
359
|
});
|
|
352
360
|
}
|
|
353
361
|
//#endregion
|
|
354
|
-
//#region src/resource/form-context.tsx
|
|
355
|
-
const FormControlContext = createContext(null);
|
|
356
|
-
const FormControlProvider = FormControlContext.Provider;
|
|
357
|
-
function useFormControl() {
|
|
358
|
-
return useContext(FormControlContext);
|
|
359
|
-
}
|
|
360
|
-
//#endregion
|
|
361
362
|
//#region src/frames/obligations.tsx
|
|
362
363
|
const SlotMountsContext = createContext(null);
|
|
363
364
|
function useSlotOnce(slot) {
|
|
@@ -487,9 +488,9 @@ function timeAgo(savedAt, t) {
|
|
|
487
488
|
if (diff < 864e5) return t("draft.timeAgoHours", { count: Math.round(diff / 36e5) });
|
|
488
489
|
return t("draft.timeAgoDays", { count: Math.round(diff / 864e5) });
|
|
489
490
|
}
|
|
490
|
-
function frameRecordId(frame) {
|
|
491
|
+
function frameRecordId(frame, def) {
|
|
491
492
|
if (frame.recordId !== void 0) return frame.recordId;
|
|
492
|
-
const id = frame.record
|
|
493
|
+
const id = recordKeyOf(def, frame.record);
|
|
493
494
|
return typeof id === "string" || typeof id === "number" ? String(id) : void 0;
|
|
494
495
|
}
|
|
495
496
|
function BodySlot() {
|
|
@@ -497,7 +498,7 @@ function BodySlot() {
|
|
|
497
498
|
const { resource, mode, controller } = frame;
|
|
498
499
|
const chrome = useFrameChrome();
|
|
499
500
|
const tid = useTestIds();
|
|
500
|
-
const id = frameRecordId(frame);
|
|
501
|
+
const id = frameRecordId(frame, useApp().registry.get(resource));
|
|
501
502
|
const tree = jsx("div", {
|
|
502
503
|
"data-buro-region": "record-body",
|
|
503
504
|
"data-buro-slot": FORM_SLOT,
|
|
@@ -646,7 +647,7 @@ function RecordFrameView({ frame: instance }) {
|
|
|
646
647
|
...policyRecord ?? {},
|
|
647
648
|
id: typeof rowId === "string" || typeof rowId === "number" ? String(rowId) : ""
|
|
648
649
|
}), [policyRecord, rowId]);
|
|
649
|
-
const showItemActions = useShownItemActions(resource, actionRow, "show");
|
|
650
|
+
const showItemActions = useShownItemActions(resource, actionRow, "show", void 0, controller.sources);
|
|
650
651
|
const showActions = mode === "show" && record !== void 0 && showItemActions.length > 0;
|
|
651
652
|
const View = resolved.view;
|
|
652
653
|
const builtin = isBuiltinRecordView(resolved);
|
|
@@ -664,6 +665,156 @@ function RecordFrameView({ frame: instance }) {
|
|
|
664
665
|
})
|
|
665
666
|
})] });
|
|
666
667
|
}
|
|
668
|
+
function useResourceDimensionOptions(dimension, resource, labelField) {
|
|
669
|
+
const def = useApp().registry.get(resource);
|
|
670
|
+
const rowTitle = useRowTitle(resource, labelField ?? def?.displayField);
|
|
671
|
+
const rows = useList(resource, {
|
|
672
|
+
pagination: {
|
|
673
|
+
kind: "offset",
|
|
674
|
+
page: 1,
|
|
675
|
+
pageSize: 100
|
|
676
|
+
},
|
|
677
|
+
total: false,
|
|
678
|
+
scope: {
|
|
679
|
+
default: "session",
|
|
680
|
+
dimensions: { [dimension]: "none" }
|
|
681
|
+
}
|
|
682
|
+
}).data?.data;
|
|
683
|
+
return useMemo(() => (rows ?? []).flatMap((row) => {
|
|
684
|
+
const key = recordKeyOf(def, row);
|
|
685
|
+
return key === null || key === void 0 ? [] : [{
|
|
686
|
+
value: key,
|
|
687
|
+
label: rowTitle(row)
|
|
688
|
+
}];
|
|
689
|
+
}), [
|
|
690
|
+
rows,
|
|
691
|
+
def,
|
|
692
|
+
rowTitle
|
|
693
|
+
]);
|
|
694
|
+
}
|
|
695
|
+
//#endregion
|
|
696
|
+
//#region src/record/scope-mismatch-banner.tsx
|
|
697
|
+
const asList = (value) => value === null ? [] : Array.isArray(value) ? value : [value];
|
|
698
|
+
const isScalar = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
699
|
+
function ScopeMismatchBanner(props) {
|
|
700
|
+
const app = useApp();
|
|
701
|
+
const mapping = app.registry.get(props.resource)?.data?.scope;
|
|
702
|
+
if (app.scope === void 0 || mapping === void 0 || props.record === void 0) return null;
|
|
703
|
+
return jsx(Banner, {
|
|
704
|
+
...props,
|
|
705
|
+
record: props.record,
|
|
706
|
+
mapping
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
function Banner({ record, mapping, kind = "record" }) {
|
|
710
|
+
const scope = useScope();
|
|
711
|
+
const chromeT = useChromeT();
|
|
712
|
+
const differences = useMemo(() => {
|
|
713
|
+
const out = [];
|
|
714
|
+
for (const [dimension, target] of Object.entries(mapping)) {
|
|
715
|
+
const definition = scope.definition?.dimensions[dimension];
|
|
716
|
+
if (definition === void 0 || definition.select === "none") continue;
|
|
717
|
+
const selected = asList(scope.selection[dimension] ?? null);
|
|
718
|
+
if (selected.length === 0) continue;
|
|
719
|
+
const column = scopeColumnOf(target);
|
|
720
|
+
if (!Object.hasOwn(record, column)) continue;
|
|
721
|
+
const held = record[column];
|
|
722
|
+
if (held === null || held === void 0 || held === "") {
|
|
723
|
+
if (kind === "created" || "field" in target && target.empty === "shared") continue;
|
|
724
|
+
out.push({
|
|
725
|
+
dimension,
|
|
726
|
+
value: null,
|
|
727
|
+
selected,
|
|
728
|
+
select: definition.select
|
|
729
|
+
});
|
|
730
|
+
continue;
|
|
731
|
+
}
|
|
732
|
+
if (!isScalar(held)) continue;
|
|
733
|
+
if (selected.some((value) => String(value) === String(held))) continue;
|
|
734
|
+
out.push({
|
|
735
|
+
dimension,
|
|
736
|
+
value: held,
|
|
737
|
+
selected,
|
|
738
|
+
select: definition.select
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
return out;
|
|
742
|
+
}, [
|
|
743
|
+
mapping,
|
|
744
|
+
record,
|
|
745
|
+
scope.definition,
|
|
746
|
+
scope.selection,
|
|
747
|
+
kind
|
|
748
|
+
]);
|
|
749
|
+
if (differences.length === 0) return null;
|
|
750
|
+
const apply = () => {
|
|
751
|
+
for (const difference of differences) scope.select(difference.dimension, difference.value === null ? null : difference.select === "multiple" ? [difference.value] : difference.value);
|
|
752
|
+
};
|
|
753
|
+
return jsxs("div", {
|
|
754
|
+
role: "status",
|
|
755
|
+
"data-testid": "scope-mismatch:banner",
|
|
756
|
+
className: "flex flex-wrap items-center justify-between gap-3 rounded-md border bg-muted/50 px-3 py-2 text-sm",
|
|
757
|
+
children: [jsxs("div", {
|
|
758
|
+
className: "space-y-1",
|
|
759
|
+
children: [jsx("p", {
|
|
760
|
+
className: "font-medium",
|
|
761
|
+
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" })
|
|
762
|
+
}), jsx("ul", {
|
|
763
|
+
className: "text-muted-foreground",
|
|
764
|
+
children: differences.map((difference) => jsx(DifferenceLine, {
|
|
765
|
+
difference,
|
|
766
|
+
definition: scope.definition.dimensions[difference.dimension]
|
|
767
|
+
}, difference.dimension))
|
|
768
|
+
})]
|
|
769
|
+
}), jsx(Button, {
|
|
770
|
+
type: "button",
|
|
771
|
+
size: "sm",
|
|
772
|
+
"data-testid": "scope-mismatch:switch",
|
|
773
|
+
onClick: apply,
|
|
774
|
+
children: chromeT("scope.mismatch.switch", { defaultValue: "Switch" })
|
|
775
|
+
})]
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
function DifferenceLine(props) {
|
|
779
|
+
const source = props.definition.values;
|
|
780
|
+
if (source !== void 0 && !Array.isArray(source)) {
|
|
781
|
+
const { resource, label } = source;
|
|
782
|
+
return jsx(ResourceLine, {
|
|
783
|
+
...props,
|
|
784
|
+
resource,
|
|
785
|
+
...label ? { labelField: label } : {}
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
return jsx(LineText, {
|
|
789
|
+
difference: props.difference,
|
|
790
|
+
options: source ?? []
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
function ResourceLine({ difference, resource, labelField }) {
|
|
794
|
+
const options = useResourceDimensionOptions(difference.dimension, resource, labelField);
|
|
795
|
+
return jsx(LineText, {
|
|
796
|
+
difference,
|
|
797
|
+
options
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
function LineText({ difference, options }) {
|
|
801
|
+
const chromeT = useChromeT();
|
|
802
|
+
const labelOf = (value) => options.find((option) => String(option.value) === String(value))?.label ?? String(value);
|
|
803
|
+
const field = humanizeKey(difference.dimension);
|
|
804
|
+
const item = difference.value === null ? chromeT("scope.mismatch.empty", { defaultValue: "not set" }) : labelOf(difference.value);
|
|
805
|
+
const items = difference.selected.map(labelOf).join(", ");
|
|
806
|
+
return jsx("li", {
|
|
807
|
+
"data-testid": `scope-mismatch:line:${difference.dimension}`,
|
|
808
|
+
children: chromeT("scope.mismatch.line", {
|
|
809
|
+
params: {
|
|
810
|
+
field,
|
|
811
|
+
item,
|
|
812
|
+
items
|
|
813
|
+
},
|
|
814
|
+
defaultValue: `${field}: ${item} (selected: ${items})`
|
|
815
|
+
})
|
|
816
|
+
});
|
|
817
|
+
}
|
|
667
818
|
//#endregion
|
|
668
819
|
//#region src/record/type-offer.tsx
|
|
669
820
|
function TypeOffer({ resource, offer, onChoose }) {
|
|
@@ -726,18 +877,41 @@ function isAbort(error) {
|
|
|
726
877
|
return false;
|
|
727
878
|
}
|
|
728
879
|
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
880
|
+
const NO_ISSUES = Object.freeze([]);
|
|
881
|
+
const APPLIED_UNREADABLE = Object.freeze({
|
|
882
|
+
code: "applied-unreadable",
|
|
883
|
+
message: Object.freeze({
|
|
884
|
+
key: "errors.appliedUnreadable",
|
|
885
|
+
default: "Saved. The server's answer could not be read, so the screen may not show the latest values."
|
|
886
|
+
}),
|
|
887
|
+
path: Object.freeze([]),
|
|
888
|
+
source: "server",
|
|
889
|
+
severity: "info"
|
|
890
|
+
});
|
|
891
|
+
function issuesOf(error) {
|
|
892
|
+
if (error === null || typeof error !== "object") return void 0;
|
|
893
|
+
try {
|
|
894
|
+
const descriptor = Object.getOwnPropertyDescriptor(error, "issues");
|
|
895
|
+
return descriptor !== void 0 && "value" in descriptor ? descriptor.value : void 0;
|
|
896
|
+
} catch {
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
735
899
|
}
|
|
736
|
-
|
|
737
|
-
|
|
900
|
+
const NO_EDITED = new Set();
|
|
901
|
+
function sameValue(a, b) {
|
|
902
|
+
if (Object.is(a, b)) return true;
|
|
903
|
+
try {
|
|
904
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
905
|
+
} catch {
|
|
906
|
+
return false;
|
|
907
|
+
}
|
|
738
908
|
}
|
|
739
909
|
function RecordFrameHost(props) {
|
|
740
910
|
const { resource, mode } = props;
|
|
911
|
+
const [failed, setFailed] = useState(NO_ISSUES);
|
|
912
|
+
const named = useMemo(() => failed.length === 0 ? NO_ISSUES : routeServerIssues({ issues: failed }, (segment) => segment, (field) => field !== "_form").fields, [failed]);
|
|
913
|
+
const atFailure = useRef({});
|
|
914
|
+
const [edited, setEdited] = useState(NO_EDITED);
|
|
741
915
|
const controller = useFormController({
|
|
742
916
|
resource,
|
|
743
917
|
mode,
|
|
@@ -746,7 +920,8 @@ function RecordFrameHost(props) {
|
|
|
746
920
|
...props.record === void 0 ? {} : { record: props.record },
|
|
747
921
|
...props.defaults === void 0 ? {} : { defaults: props.defaults },
|
|
748
922
|
...props.onSubmit === void 0 ? {} : { onSubmit: props.onSubmit },
|
|
749
|
-
...props.hostTitle ? { entry: "quick" } : {}
|
|
923
|
+
...props.hostTitle ? { entry: "quick" } : {},
|
|
924
|
+
serverIssues: named
|
|
750
925
|
});
|
|
751
926
|
const inputApplied = useRef(false);
|
|
752
927
|
const { input } = props;
|
|
@@ -765,13 +940,26 @@ function RecordFrameHost(props) {
|
|
|
765
940
|
const formId = `record-form-${useId()}`;
|
|
766
941
|
const root = useRef(null);
|
|
767
942
|
const [submitError, setSubmitError] = useState(void 0);
|
|
943
|
+
const [submitApplied, setSubmitApplied] = useState(void 0);
|
|
944
|
+
useEffect(() => {
|
|
945
|
+
if (plan === null) return;
|
|
946
|
+
const now = Object.keys(atFailure.current).filter((name) => !edited.has(name) && plan.fields[name] === "active" && !sameValue(controller.field(name).value, atFailure.current[name]));
|
|
947
|
+
if (now.length > 0) setEdited((previous) => new Set([...previous, ...now]));
|
|
948
|
+
}, [
|
|
949
|
+
plan,
|
|
950
|
+
controller,
|
|
951
|
+
edited
|
|
952
|
+
]);
|
|
953
|
+
const notify = useNoticeSink(resource);
|
|
768
954
|
const latest = useRef({
|
|
769
955
|
controller,
|
|
770
|
-
onSuccess: props.onSuccess
|
|
956
|
+
onSuccess: props.onSuccess,
|
|
957
|
+
notify
|
|
771
958
|
});
|
|
772
959
|
latest.current = {
|
|
773
960
|
controller,
|
|
774
|
-
onSuccess: props.onSuccess
|
|
961
|
+
onSuccess: props.onSuccess,
|
|
962
|
+
notify
|
|
775
963
|
};
|
|
776
964
|
const mounted = useRef(true);
|
|
777
965
|
useEffect(() => {
|
|
@@ -782,21 +970,45 @@ function RecordFrameHost(props) {
|
|
|
782
970
|
}, []);
|
|
783
971
|
const submit = useCallback(async () => {
|
|
784
972
|
setSubmitError(void 0);
|
|
973
|
+
setSubmitApplied(void 0);
|
|
974
|
+
setFailed(NO_ISSUES);
|
|
975
|
+
setEdited(NO_EDITED);
|
|
976
|
+
atFailure.current = {};
|
|
785
977
|
const outcome = await latest.current.controller.submit();
|
|
786
978
|
if (!mounted.current) return;
|
|
787
|
-
if (outcome.status === "submitted")
|
|
788
|
-
|
|
979
|
+
if (outcome.status === "submitted") {
|
|
980
|
+
const notices = successNoticesOf(outcome.result);
|
|
981
|
+
if (notices.length > 0) latest.current.notify(notices);
|
|
982
|
+
latest.current.onSuccess?.(outcome.result);
|
|
983
|
+
} else if (outcome.status === "failed" && outcome.applied === "yes") {
|
|
984
|
+
latest.current.notify([APPLIED_UNREADABLE]);
|
|
985
|
+
latest.current.onSuccess?.(void 0);
|
|
986
|
+
} else if (outcome.status === "failed" && !isAbort(outcome.error)) {
|
|
987
|
+
setSubmitError(outcome.error ?? null);
|
|
988
|
+
setSubmitApplied(outcome.applied);
|
|
989
|
+
const issues = normalizeIssueInputs(issuesOf(outcome.error)).issues;
|
|
990
|
+
const next = issues.length === 0 ? NO_ISSUES : Object.freeze(issues.map(issueOfInput));
|
|
991
|
+
const held = {};
|
|
992
|
+
const now = latest.current.controller;
|
|
993
|
+
for (const issue of next) {
|
|
994
|
+
const head = issue.path[0];
|
|
995
|
+
if (typeof head === "string" && head !== "_form" && now.plan?.fields[head] === "active") held[head] = now.field(head).value;
|
|
996
|
+
}
|
|
997
|
+
atFailure.current = held;
|
|
998
|
+
setFailed(next);
|
|
999
|
+
}
|
|
789
1000
|
}, []);
|
|
790
1001
|
const record = controller.record;
|
|
1002
|
+
const recordText = props.recordId === void 0 ? void 0 : String(props.recordId);
|
|
791
1003
|
const frame = useMemo(() => ({
|
|
792
1004
|
resource,
|
|
793
|
-
recordId:
|
|
1005
|
+
recordId: recordText,
|
|
794
1006
|
mode,
|
|
795
1007
|
record,
|
|
796
1008
|
controller
|
|
797
1009
|
}), [
|
|
798
1010
|
resource,
|
|
799
|
-
|
|
1011
|
+
recordText,
|
|
800
1012
|
mode,
|
|
801
1013
|
record,
|
|
802
1014
|
controller
|
|
@@ -817,7 +1029,8 @@ function RecordFrameHost(props) {
|
|
|
817
1029
|
guardText.title,
|
|
818
1030
|
guardText.body
|
|
819
1031
|
]);
|
|
820
|
-
const
|
|
1032
|
+
const app = useApp();
|
|
1033
|
+
const typesDecl = app.registry.get(resource)?.types;
|
|
821
1034
|
const loaded = controller.record;
|
|
822
1035
|
const unsupportedType = useMemo(() => {
|
|
823
1036
|
if (mode === "create" || typesDecl === void 0 || loaded === void 0) return void 0;
|
|
@@ -829,6 +1042,10 @@ function RecordFrameHost(props) {
|
|
|
829
1042
|
typesDecl,
|
|
830
1043
|
loaded
|
|
831
1044
|
]);
|
|
1045
|
+
const shownFailed = useMemo(() => edited.size === 0 ? failed : Object.freeze(failed.filter((issue) => {
|
|
1046
|
+
const head = issue.path[0];
|
|
1047
|
+
return typeof head !== "string" || !edited.has(head);
|
|
1048
|
+
})), [failed, edited]);
|
|
832
1049
|
const chrome = useMemo(() => ({
|
|
833
1050
|
...props.onCancel === void 0 ? {} : { onCancel: props.onCancel },
|
|
834
1051
|
...props.submitLabel === void 0 ? {} : { submitLabel: props.submitLabel },
|
|
@@ -838,6 +1055,8 @@ function RecordFrameHost(props) {
|
|
|
838
1055
|
...props.hostTitle ? { hostTitle: true } : {},
|
|
839
1056
|
formId,
|
|
840
1057
|
submitError,
|
|
1058
|
+
...submitApplied === void 0 ? {} : { submitApplied },
|
|
1059
|
+
serverIssues: shownFailed,
|
|
841
1060
|
submit,
|
|
842
1061
|
root
|
|
843
1062
|
}), [
|
|
@@ -849,6 +1068,8 @@ function RecordFrameHost(props) {
|
|
|
849
1068
|
props.hostTitle,
|
|
850
1069
|
formId,
|
|
851
1070
|
submitError,
|
|
1071
|
+
submitApplied,
|
|
1072
|
+
shownFailed,
|
|
852
1073
|
submit
|
|
853
1074
|
]);
|
|
854
1075
|
usePublishDocVariant(mode === "show" ? resource : void 0, record);
|
|
@@ -863,45 +1084,51 @@ function RecordFrameHost(props) {
|
|
|
863
1084
|
resource,
|
|
864
1085
|
mode
|
|
865
1086
|
]);
|
|
866
|
-
const
|
|
867
|
-
|
|
868
|
-
}, []);
|
|
869
|
-
const formControl = useMemo(() => ({ setValues }), [setValues]);
|
|
870
|
-
const id = frameId(frame);
|
|
1087
|
+
const formControl = useFormControlOf(controller);
|
|
1088
|
+
const id = frameRecordId(frame, app.registry.get(frame.resource));
|
|
871
1089
|
const rootId = mode === "show" ? tid.pageShow(resource, id ?? "") : mode === "edit" ? tid.pageEdit(resource, id ?? "") : tid.pageCreate(resource);
|
|
1090
|
+
const claimedRoute = useContext(RouteSourceContext);
|
|
872
1091
|
const scopeValues = mode === "show" ? controller.record : controller.values;
|
|
873
1092
|
return jsx(RecordScopeProvider, {
|
|
874
1093
|
resource,
|
|
875
|
-
...
|
|
1094
|
+
...recordText === void 0 ? {} : { recordId: recordText },
|
|
876
1095
|
values: scopeValues,
|
|
1096
|
+
create: mode === "create",
|
|
877
1097
|
children: jsx(RouteSourceContext.Provider, {
|
|
878
1098
|
value: null,
|
|
879
|
-
children: jsx(
|
|
880
|
-
value:
|
|
881
|
-
children: jsx(
|
|
882
|
-
value:
|
|
883
|
-
children:
|
|
884
|
-
value:
|
|
885
|
-
children:
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
"
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
1099
|
+
children: jsx(ActionRouteContext.Provider, {
|
|
1100
|
+
value: claimedRoute,
|
|
1101
|
+
children: jsx(RecordFrameContext.Provider, {
|
|
1102
|
+
value: frame,
|
|
1103
|
+
children: jsx(FrameChromeContext.Provider, {
|
|
1104
|
+
value: chrome,
|
|
1105
|
+
children: jsxs(FormControlProvider, {
|
|
1106
|
+
value: formControl,
|
|
1107
|
+
children: [jsx(DeepLinkScope, {
|
|
1108
|
+
plan: controller.plan,
|
|
1109
|
+
enabled: routeScreen && mode !== "create",
|
|
1110
|
+
children: jsx("div", {
|
|
1111
|
+
ref: root,
|
|
1112
|
+
"data-testid": rootId,
|
|
1113
|
+
className: "flex flex-col gap-[var(--buro-section-gap)]",
|
|
1114
|
+
children: offering && controller.typeOffer !== null ? jsx(TypeOffer, {
|
|
1115
|
+
resource,
|
|
1116
|
+
offer: controller.typeOffer,
|
|
1117
|
+
onChoose: (type) => chooseType(type)
|
|
1118
|
+
}) : failure !== null ? jsxs(Fragment$1, { children: [jsx(RecordState, { state: "error" }), jsx(FormActions, {})] }) : mode === "edit" && unsupportedType !== void 0 ? jsx(UndeclaredTypeNotice, {
|
|
1119
|
+
resource,
|
|
1120
|
+
typeValue: unsupportedType
|
|
1121
|
+
}) : jsxs(Fragment$1, { children: [jsx(ScopeMismatchBanner, {
|
|
1122
|
+
resource,
|
|
1123
|
+
record: mode === "create" ? controller.trustedSeeds : controller.record,
|
|
1124
|
+
kind: mode === "create" ? "created" : "record"
|
|
1125
|
+
}), jsx(RecordFrameView, { ...props.frame === void 0 ? {} : { frame: props.frame } })] })
|
|
1126
|
+
})
|
|
1127
|
+
}), controller.checkGate === null ? null : jsx(CheckConfirmDialog, {
|
|
1128
|
+
state: controller.checkGate,
|
|
1129
|
+
testid: `${tid.form(resource, mode, id)}:checks`
|
|
1130
|
+
})]
|
|
1131
|
+
})
|
|
905
1132
|
})
|
|
906
1133
|
})
|
|
907
1134
|
})
|
|
@@ -913,7 +1140,8 @@ function RecordScreen(props) {
|
|
|
913
1140
|
const routeScreen = useContext(RouteScreenClaimContext);
|
|
914
1141
|
const quickScreen = useContext(QuickScreenClaimContext);
|
|
915
1142
|
const route = useContext(RouteSourceContext);
|
|
916
|
-
const
|
|
1143
|
+
const resourceInput = props.resource;
|
|
1144
|
+
const resource = resourceKey(resourceInput);
|
|
917
1145
|
const tabs = useTabsUrlState(props.mode, routeScreen);
|
|
918
1146
|
const adapter = useOptionalRouterAdapter();
|
|
919
1147
|
const router = routeScreen ? adapter : null;
|
|
@@ -1175,24 +1403,18 @@ function parse(raw) {
|
|
|
1175
1403
|
return [];
|
|
1176
1404
|
}
|
|
1177
1405
|
}
|
|
1178
|
-
function readRecentRecords(userId) {
|
|
1179
|
-
|
|
1180
|
-
try {
|
|
1181
|
-
return parse(window.localStorage.getItem(recentStorageKey(userId)));
|
|
1182
|
-
} catch {
|
|
1183
|
-
return [];
|
|
1184
|
-
}
|
|
1406
|
+
function readRecentRecords(store, userId) {
|
|
1407
|
+
return maybeThen(settle(() => store.get(recentStorageKey(userId)), null), parse);
|
|
1185
1408
|
}
|
|
1186
|
-
function writeRecentRecord(userId, entry) {
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
const key = recentStorageKey(userId);
|
|
1409
|
+
function writeRecentRecord(store, userId, entry) {
|
|
1410
|
+
const key = recentStorageKey(userId);
|
|
1411
|
+
return maybeThen(settle(() => store.get(key), null), (raw) => {
|
|
1190
1412
|
const envelope = {
|
|
1191
1413
|
version: 2,
|
|
1192
|
-
items: [entry, ...parse(
|
|
1414
|
+
items: [entry, ...parse(raw).filter((item) => !(item.canonicalRef === entry.canonicalRef && item.id === entry.id))].slice(0, 5)
|
|
1193
1415
|
};
|
|
1194
|
-
|
|
1195
|
-
}
|
|
1416
|
+
return settle(() => store.set(key, JSON.stringify(envelope)), void 0);
|
|
1417
|
+
});
|
|
1196
1418
|
}
|
|
1197
1419
|
function text(value) {
|
|
1198
1420
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
@@ -1218,10 +1440,12 @@ function recentLabel(record, id, isGuarded = () => false) {
|
|
|
1218
1440
|
//#region src/layout/use-record-visit.ts
|
|
1219
1441
|
function useRecordVisit(resource, record, opts) {
|
|
1220
1442
|
const userId = useCurrentUserId();
|
|
1221
|
-
const
|
|
1222
|
-
const id = typeof raw === "string" || typeof raw === "number" ? String(raw) : void 0;
|
|
1443
|
+
const store = usePlatformStorage().local;
|
|
1223
1444
|
const app = useApp();
|
|
1224
|
-
const
|
|
1445
|
+
const def = app.registry.get(resource);
|
|
1446
|
+
const raw = recordKeyOf(def, record);
|
|
1447
|
+
const id = typeof raw === "string" || typeof raw === "number" ? String(raw) : void 0;
|
|
1448
|
+
const fields = def?.fields;
|
|
1225
1449
|
const rules = app.ruleSource?.rules(resource) ?? [];
|
|
1226
1450
|
const isGuarded = (field) => fields !== void 0 && Object.hasOwn(fields, field) && fieldSensitivity(fields[field]) !== void 0 || addressesCapability(rules, "view", {
|
|
1227
1451
|
kind: "field",
|
|
@@ -1235,7 +1459,7 @@ function useRecordVisit(resource, record, opts) {
|
|
|
1235
1459
|
useEffect(() => {
|
|
1236
1460
|
if (userId === null || !isCurrentData || id === void 0 || id === "") return;
|
|
1237
1461
|
if (label === void 0) return;
|
|
1238
|
-
writeRecentRecord(userId, {
|
|
1462
|
+
writeRecentRecord(store, userId, {
|
|
1239
1463
|
canonicalRef,
|
|
1240
1464
|
id,
|
|
1241
1465
|
label,
|
|
@@ -1243,6 +1467,7 @@ function useRecordVisit(resource, record, opts) {
|
|
|
1243
1467
|
at: new Date().toISOString()
|
|
1244
1468
|
});
|
|
1245
1469
|
}, [
|
|
1470
|
+
store,
|
|
1246
1471
|
userId,
|
|
1247
1472
|
isCurrentData,
|
|
1248
1473
|
canonicalRef,
|
|
@@ -1253,12 +1478,6 @@ function useRecordVisit(resource, record, opts) {
|
|
|
1253
1478
|
}
|
|
1254
1479
|
//#endregion
|
|
1255
1480
|
//#region src/layout/record-page.tsx
|
|
1256
|
-
function recordErrorState(error) {
|
|
1257
|
-
const { kind } = normalizeDataError(error);
|
|
1258
|
-
if (kind === "not-found" || kind === "forbidden") return "not-found";
|
|
1259
|
-
if (kind === "auth") return "session-expired";
|
|
1260
|
-
return "error";
|
|
1261
|
-
}
|
|
1262
1481
|
function useMountedRef() {
|
|
1263
1482
|
const mounted = useRef(true);
|
|
1264
1483
|
useEffect(() => {
|
|
@@ -1281,7 +1500,7 @@ function RecordRouteHeader({ resource, action, id, record }) {
|
|
|
1281
1500
|
...action === "create" ? {} : { recordName }
|
|
1282
1501
|
});
|
|
1283
1502
|
}
|
|
1284
|
-
function RecordShow({ resource, id, record, shown }) {
|
|
1503
|
+
function RecordShow({ resource, id, recordId, record, shown }) {
|
|
1285
1504
|
return jsxs("div", { children: [jsx(RecordRouteHeader, {
|
|
1286
1505
|
resource,
|
|
1287
1506
|
action: "show",
|
|
@@ -1290,11 +1509,11 @@ function RecordShow({ resource, id, record, shown }) {
|
|
|
1290
1509
|
}), jsx(RecordScreen, {
|
|
1291
1510
|
resource,
|
|
1292
1511
|
mode: "show",
|
|
1293
|
-
recordId
|
|
1512
|
+
recordId,
|
|
1294
1513
|
record
|
|
1295
1514
|
})] });
|
|
1296
1515
|
}
|
|
1297
|
-
function RecordEdit({ resource, id, record, shown }) {
|
|
1516
|
+
function RecordEdit({ resource, id, recordId, record, shown }) {
|
|
1298
1517
|
const app = useApp();
|
|
1299
1518
|
const navigate = useRouteNavigate();
|
|
1300
1519
|
const mounted = useMountedRef();
|
|
@@ -1307,7 +1526,7 @@ function RecordEdit({ resource, id, record, shown }) {
|
|
|
1307
1526
|
}), jsx(RecordScreen, {
|
|
1308
1527
|
resource,
|
|
1309
1528
|
mode: "edit",
|
|
1310
|
-
recordId
|
|
1529
|
+
recordId,
|
|
1311
1530
|
record,
|
|
1312
1531
|
onCancel: () => navigate(back),
|
|
1313
1532
|
onSuccess: () => {
|
|
@@ -1346,12 +1565,12 @@ function RecordCreate({ resource, defaults }) {
|
|
|
1346
1565
|
})
|
|
1347
1566
|
})] });
|
|
1348
1567
|
}
|
|
1349
|
-
function RecordRead({ resource, action, id }) {
|
|
1568
|
+
function RecordRead({ resource, action, id, recordId }) {
|
|
1350
1569
|
const app = useApp();
|
|
1351
1570
|
const def = app.registry.get(resource);
|
|
1352
1571
|
const projection = useMemo(() => def === void 0 ? void 0 : dtoFields(def, "record"), [def]);
|
|
1353
1572
|
const query = useOne(resource, {
|
|
1354
|
-
id,
|
|
1573
|
+
id: recordId,
|
|
1355
1574
|
retry: retryRecordRead,
|
|
1356
1575
|
...projection === void 0 ? {} : { projection }
|
|
1357
1576
|
});
|
|
@@ -1391,30 +1610,39 @@ function RecordRead({ resource, action, id }) {
|
|
|
1391
1610
|
children: action === "edit" ? jsx(RecordEdit, {
|
|
1392
1611
|
resource,
|
|
1393
1612
|
id,
|
|
1613
|
+
recordId,
|
|
1394
1614
|
record: loaded,
|
|
1395
1615
|
shown
|
|
1396
1616
|
}) : jsx(RecordShow, {
|
|
1397
1617
|
resource,
|
|
1398
1618
|
id,
|
|
1619
|
+
recordId,
|
|
1399
1620
|
record: loaded,
|
|
1400
1621
|
shown
|
|
1401
1622
|
})
|
|
1402
1623
|
})
|
|
1403
1624
|
});
|
|
1404
1625
|
}
|
|
1405
|
-
if (query.error != null) {
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
}
|
|
1626
|
+
if (query.error != null) return jsx(LoadError, {
|
|
1627
|
+
surface: "record",
|
|
1628
|
+
resource,
|
|
1629
|
+
error: query.error,
|
|
1630
|
+
retry: () => void query.refetch()
|
|
1631
|
+
});
|
|
1412
1632
|
return jsx(RecordState, { state: "loading" });
|
|
1413
1633
|
}
|
|
1414
1634
|
function RecordRouteBody(props) {
|
|
1415
1635
|
if (props.action === "create") return jsx(RecordCreate, { ...props });
|
|
1416
1636
|
if (props.id === "") return jsx(RecordState, { state: "not-found" });
|
|
1417
|
-
return jsx(
|
|
1637
|
+
return jsx(RecordReadRoute, { ...props });
|
|
1638
|
+
}
|
|
1639
|
+
function RecordReadRoute(props) {
|
|
1640
|
+
const recordId = useRouteRecordId(props.resource, props.id);
|
|
1641
|
+
if (recordId === void 0) return jsx(InvalidRouteId, { resource: props.resource });
|
|
1642
|
+
return jsx(RecordRead, {
|
|
1643
|
+
...props,
|
|
1644
|
+
recordId
|
|
1645
|
+
});
|
|
1418
1646
|
}
|
|
1419
1647
|
function RecordRoute(props) {
|
|
1420
1648
|
const missingRuntime = useOptionalDataRuntime() === null;
|
|
@@ -1437,7 +1665,8 @@ function RecordPage(props) {
|
|
|
1437
1665
|
const app = useApp();
|
|
1438
1666
|
const match = useMatch();
|
|
1439
1667
|
const id = match === null ? null : match.id ?? "";
|
|
1440
|
-
const {
|
|
1668
|
+
const { action } = props;
|
|
1669
|
+
const resource = props.resource === void 0 ? void 0 : routeResourceKey(props.resource);
|
|
1441
1670
|
const onRecordRoute = recordActionOf(match) !== void 0;
|
|
1442
1671
|
const problem = recordPageProblem({
|
|
1443
1672
|
props,
|
|
@@ -1567,10 +1796,24 @@ function NavAreaNotFound() {
|
|
|
1567
1796
|
});
|
|
1568
1797
|
}
|
|
1569
1798
|
const adapterNoticeGiven = new WeakSet();
|
|
1799
|
+
const chromeNoticeGiven = new WeakSet();
|
|
1570
1800
|
function NavAreaPage() {
|
|
1571
1801
|
const match = useMatch();
|
|
1572
1802
|
const app = useApp();
|
|
1573
1803
|
const noAdapter = useOptionalRouterAdapter() === null;
|
|
1804
|
+
const chromeMounted = useNavChromeMounted();
|
|
1805
|
+
const resolveLayout = useLayoutResolver();
|
|
1806
|
+
const chromeGroup = match?.groupChain.find((g) => resolveLayout(g.layout)) ?? null;
|
|
1807
|
+
useEffect(() => {
|
|
1808
|
+
if (process.env.NODE_ENV === "production") return;
|
|
1809
|
+
if (chromeMounted || !chromeGroup || chromeNoticeGiven.has(app)) return;
|
|
1810
|
+
chromeNoticeGiven.add(app);
|
|
1811
|
+
console.error(`[burojs] <NavAreaPage> is inside the nav group "${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>.`);
|
|
1812
|
+
}, [
|
|
1813
|
+
app,
|
|
1814
|
+
chromeMounted,
|
|
1815
|
+
chromeGroup
|
|
1816
|
+
]);
|
|
1574
1817
|
useEffect(() => {
|
|
1575
1818
|
if (!noAdapter || process.env.NODE_ENV === "production") return;
|
|
1576
1819
|
if (adapterNoticeGiven.has(app)) return;
|
|
@@ -1579,10 +1822,10 @@ function NavAreaPage() {
|
|
|
1579
1822
|
}, [app, noAdapter]);
|
|
1580
1823
|
return jsx(Suspense, {
|
|
1581
1824
|
fallback: jsx(NavAreaPageSkeleton, {}),
|
|
1582
|
-
children: match ? jsx(
|
|
1825
|
+
children: match ? jsx(ResourcePageRouter, { match }) : jsx(NavAreaNotFound, {})
|
|
1583
1826
|
});
|
|
1584
1827
|
}
|
|
1585
1828
|
//#endregion
|
|
1586
|
-
export {
|
|
1829
|
+
export { TabsLayout as A, usePageAllowed as C, useLayout as D, layoutSlot as E, canonicalNavKey as M, canonicalResourceKey$1 as N, useLayoutResolver as O, useNavVisible as S, BUILTIN_LAYOUTS as T, PlannedBody as _, useRecordVisit as a, useHref as b, headerTrail as c, useTrailContext as d, recordTrailKey as f, useResourceDimensionOptions as g, RecordScreen as h, RecordPage as i, SecondarySidebarLayout as j, useReportUnresolvedLayouts as k, recordTrail as l, usePublishedRecordTrail as m, NavAreaPage as n, RECENT_LABEL_KEYS as o, usePublishRecordTrail as p, ResourcePageRouter as r, readRecentRecords as s, NavAreaNotFound as t, recordTrailRoute as u, ResourceListPage as v, useResourceVisible as w, useMatch as x, NavChromeMountedProvider as y };
|
|
1587
1830
|
|
|
1588
|
-
//# sourceMappingURL=resource-page-router-
|
|
1831
|
+
//# sourceMappingURL=resource-page-router-Diw6S6TK.js.map
|