@burojs/ui-shadcn 0.6.0 → 0.8.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-2HLgz7Il.cjs +169 -0
- package/dist/bulk-summary-2HLgz7Il.cjs.map +1 -0
- package/dist/bulk-summary-D6A0ua21.js +169 -0
- package/dist/bulk-summary-D6A0ua21.js.map +1 -0
- package/dist/{candidates-relation-picker-Cy0rTxvI.cjs → candidates-relation-picker-C47mF260.cjs} +4 -4
- package/dist/{candidates-relation-picker-Cy0rTxvI.cjs.map → candidates-relation-picker-C47mF260.cjs.map} +1 -1
- package/dist/{candidates-relation-picker-B116Bmqi.js → candidates-relation-picker-CGXItMN0.js} +3 -3
- package/dist/{candidates-relation-picker-B116Bmqi.js.map → candidates-relation-picker-CGXItMN0.js.map} +1 -1
- package/dist/{check-confirm-dialog--gPFnEeg.cjs → check-confirm-dialog-BT04Mieo.cjs} +475 -107
- package/dist/check-confirm-dialog-BT04Mieo.cjs.map +1 -0
- package/dist/{check-confirm-dialog-bRT8lt0d.js → check-confirm-dialog-CtiRzOAt.js} +391 -108
- package/dist/check-confirm-dialog-CtiRzOAt.js.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-ByGhxLf_.cjs} +1021 -154
- package/dist/filter-builder-ByGhxLf_.cjs.map +1 -0
- package/dist/{filter-builder-Bhn-dhZV.js → filter-builder-z3Axzf9Y.js} +929 -140
- package/dist/filter-builder-z3Axzf9Y.js.map +1 -0
- package/dist/{flow-runtime-D3avVH0I.cjs → flow-runtime-BVFjMU5-.cjs} +64 -29
- package/dist/flow-runtime-BVFjMU5-.cjs.map +1 -0
- package/dist/{flow-runtime-s6lkRPKF.js → flow-runtime-DrUWyTS0.js} +65 -30
- package/dist/flow-runtime-DrUWyTS0.js.map +1 -0
- package/dist/{flow-screen-CCvgDI9G.js → flow-screen-3fk6J33y.js} +130 -87
- package/dist/flow-screen-3fk6J33y.js.map +1 -0
- package/dist/{flow-screen-Ci_Sik4Y.cjs → flow-screen-6y5E_HT6.cjs} +130 -87
- package/dist/flow-screen-6y5E_HT6.cjs.map +1 -0
- package/dist/index.cjs +1186 -950
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +631 -322
- package/dist/index.d.ts +631 -322
- package/dist/index.js +1100 -870
- package/dist/index.js.map +1 -1
- package/dist/{inline-flow-host-DV1et3c6.cjs → inline-flow-host-C4KmZIYE.cjs} +5 -5
- package/dist/inline-flow-host-C4KmZIYE.cjs.map +1 -0
- package/dist/{inline-flow-host-B6FI0ctQ.js → inline-flow-host-YnnvWjdU.js} +5 -5
- package/dist/inline-flow-host-YnnvWjdU.js.map +1 -0
- package/dist/{candidates-gate-D33jXLHO.cjs → lazy-relation-picker-dialog-BAKBRn3V.cjs} +10 -10
- package/dist/lazy-relation-picker-dialog-BAKBRn3V.cjs.map +1 -0
- package/dist/{candidates-gate-Bb70LPAy.js → lazy-relation-picker-dialog-DN4bvQfg.js} +11 -11
- package/dist/lazy-relation-picker-dialog-DN4bvQfg.js.map +1 -0
- package/dist/{page-flow-route-i3ZfJ1sd.js → page-flow-route-CtEfqAvU.js} +35 -23
- package/dist/page-flow-route-CtEfqAvU.js.map +1 -0
- package/dist/{page-flow-route-hdnULWqd.cjs → page-flow-route-DEjAxHe3.cjs} +42 -30
- package/dist/page-flow-route-DEjAxHe3.cjs.map +1 -0
- package/dist/{place-node-NraNYKPx.js → place-node-BdxT-30h.js} +1980 -1041
- package/dist/place-node-BdxT-30h.js.map +1 -0
- package/dist/{place-node-C5SmIAYU.cjs → place-node-Bhl8B3fF.cjs} +2038 -1087
- package/dist/place-node-Bhl8B3fF.cjs.map +1 -0
- package/dist/{related-list-cards-CFq3meUn.cjs → related-list-cards-Bc_vfCE_.cjs} +9 -4
- package/dist/{related-list-cards-CFq3meUn.cjs.map → related-list-cards-Bc_vfCE_.cjs.map} +1 -1
- package/dist/{related-list-cards-BWZ9GfOG.js → related-list-cards-BvkD5OcC.js} +9 -4
- package/dist/{related-list-cards-BWZ9GfOG.js.map → related-list-cards-BvkD5OcC.js.map} +1 -1
- package/dist/related-list-timeline-DCrwN9oO.js +167 -0
- package/dist/related-list-timeline-DCrwN9oO.js.map +1 -0
- package/dist/related-list-timeline-k0DtnxTs.cjs +167 -0
- package/dist/related-list-timeline-k0DtnxTs.cjs.map +1 -0
- package/dist/{related-rows-ea43qhhy.cjs → related-rows-BW9Jr07T.cjs} +27 -16
- package/dist/related-rows-BW9Jr07T.cjs.map +1 -0
- package/dist/{related-rows-o0_t-Yce.js → related-rows-CPE-9FFr.js} +25 -14
- package/dist/related-rows-CPE-9FFr.js.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-BlrGRwMV.js} +210 -104
- package/dist/relation-many-picker-BlrGRwMV.js.map +1 -0
- package/dist/{relation-many-picker-C8zFEjwd.cjs → relation-many-picker-Br-zBHxT.cjs} +218 -112
- package/dist/relation-many-picker-Br-zBHxT.cjs.map +1 -0
- package/dist/{relation-picker-gag0qSR5.cjs → relation-picker-ADjxI_TI.cjs} +36 -73
- package/dist/relation-picker-ADjxI_TI.cjs.map +1 -0
- package/dist/{relation-picker-dialog-B6nIiJBf.js → relation-picker-dialog-CyKliBkN.js} +134 -36
- package/dist/relation-picker-dialog-CyKliBkN.js.map +1 -0
- package/dist/{relation-picker-dialog-0IzkjmiA.cjs → relation-picker-dialog-DimVQF9Y.cjs} +133 -35
- package/dist/relation-picker-dialog-DimVQF9Y.cjs.map +1 -0
- package/dist/{relation-picker-Z0ZJJ5uS.js → relation-picker-x7P5HKie.js} +30 -61
- package/dist/relation-picker-x7P5HKie.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-3RUf9d1j.js → resource-page-router-BRpUnhay.js} +634 -264
- package/dist/resource-page-router-BRpUnhay.js.map +1 -0
- package/dist/{resource-page-router-PXfMW9nh.cjs → resource-page-router-qEd2xb55.cjs} +694 -312
- package/dist/resource-page-router-qEd2xb55.cjs.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/dist/use-record-subtitle-bfwIoUme.cjs +70 -0
- package/dist/use-record-subtitle-bfwIoUme.cjs.map +1 -0
- package/dist/use-record-subtitle-gIaCGgbI.js +53 -0
- package/dist/use-record-subtitle-gIaCGgbI.js.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 +0 -142
- package/dist/related-list-timeline-CCzl71aA.cjs.map +0 -1
- package/dist/related-list-timeline-yrPsjA3F.js +0 -142
- 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
package/dist/index.js
CHANGED
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
import { c as scrollToDocAnchor, l as cn, n as useTheme, s as readDocHash, t as THEME_CHOICES } from "./use-theme-dnE3Od3I.js";
|
|
2
|
-
import { a as
|
|
3
|
-
import { A as
|
|
2
|
+
import { a as technicalText, c as LinkComponentProvider, d as PopoverAnchor, f as PopoverClose, l as useLinkComponent, m as PopoverTrigger, n as toast, p as PopoverContent, r as friendlyStringsFrom, s as toFriendlyError, t as Toaster, u as Popover } from "./toaster-Ct_YHGs6.js";
|
|
3
|
+
import { $ as Tooltip, A as OwnTitleHeading, B as DropdownMenuContent, F as Icon, G as DropdownMenuRadioGroup, H as DropdownMenuItem, I as hasIcon, J as DropdownMenuShortcut, K as DropdownMenuRadioItem, L as registerIcons, M as DialogPresentationShell, N as OwnTitleContext, P as SheetPresentationShell, Q as DropdownMenuTrigger, R as DropdownMenu, T as loadFlowScreen, U as DropdownMenuLabel, V as DropdownMenuGroup, W as DropdownMenuPortal, X as DropdownMenuSubContent, Y as DropdownMenuSub, Z as DropdownMenuSubTrigger, _ as reasonText, a as modeForSurface, at as SheetContent, c as useListSlot, ct as SheetHeader, dt as DocInfo, et as TooltipContent, f as FlowActionButton, it as SheetClose, k as useLoaded, l as isExternalHref, lt as SheetTitle, n as ActionButton, nt as TooltipTrigger, o as canonicalResourceName, ot as SheetDescription, q as DropdownMenuSeparator, r as DisabledAction, rt as Sheet, s as listSlot, st as SheetFooter, t as CheckConfirmDialog, tt as TooltipProvider, u as openExternal, ut as SheetTrigger, v as FlowBoundary, y as FlowLoadFailed, z as DropdownMenuCheckboxItem } from "./check-confirm-dialog-CtiRzOAt.js";
|
|
4
4
|
import { n as buttonVariants, t as Button } from "./button-MWVeZaqj.js";
|
|
5
5
|
import { t as Input } from "./input-CUPStzZO.js";
|
|
6
|
-
import { a as DialogFooter, c as DialogTrigger, i as DialogDescription, n as DialogClose, o as DialogHeader, r as DialogContent, s as DialogTitle, t as Dialog } from "./dialog-
|
|
7
|
-
import { C as
|
|
8
|
-
import { a as SheetClose, c as SheetFooter, d as SheetTrigger, i as Sheet, l as SheetHeader, n as OwnTitleContext, o as SheetContent, r as SheetPresentationShell, s as SheetDescription, t as DialogPresentationShell, u as SheetTitle } from "./shell-BPlk8hEa.js";
|
|
6
|
+
import { a as DialogFooter, c as DialogTrigger, i as DialogDescription, n as DialogClose, o as DialogHeader, r as DialogContent, s as DialogTitle, t as Dialog } from "./dialog-C123sVQ8.js";
|
|
7
|
+
import { C as CommandEmpty, D as CommandList, E as CommandItem, O as CommandLoading, S as CommandDialog, T as CommandInput, b as RecordState, c as RelationField, d as peekAnchorOpener, f as PeekContext, h as recordDisplayName, k as CommandSeparator, l as relationLinkClassName, p as PeekHostContext, s as RelationDisplay, u as focusWithoutPeek, v as InvalidRouteId, w as CommandGroup, x as Command, y as LoadError } from "./relation-create-C43cdPQt.js";
|
|
9
8
|
import { t as Skeleton } from "./skeleton-U2noefj5.js";
|
|
10
|
-
import { $ as
|
|
9
|
+
import { $ as CursorLoadMore, A as ListSearchInput, At as AppFlowButton, B as ExportDialog, C as ListControls, D as ListFlows, Dt as EnumSettlingRow, E as ListLive, Et as EnumBadge, F as ListColumns, Ft as toDisplayText, H as ScreenTree, I as ColumnsToggle, It as ShellProvider, L as DataTableViewOptions, Lt as defaultUserMapper, M as ExportButton, Mt as FieldDisplay, N as ListCreate, Nt as i18nPrefixToRef, O as ListFilters, Ot as unknownEnumValueLabel, P as CreateButton, Pt as FieldValueFrame, Q as ResourceList, R as ListBulkBar, Rt as usePaletteState, St as ActionOverflow, T as SavedViewsDropdown, Tt as downloadArtifact, V as DeclarativeForm, W as QuickScreenClaimContext, Y as useFormControl, Z as ListBody, _ as CopyId, _t as ShowPageHeader, a as peekFieldDefinition, at as DataTable, b as RecordTitle, bt as useDocumentTitle, c as peekRow, ct as TabsContent, d as resolveFrameView, et as ListErrorState, f as shadcnFrameViews, gt as PageHeader, ht as EditPageHeader, it as useBuroDataTable, j as ListExport, jt as Field, k as FilterRegion, l as useRelationPicker, lt as TabsList, nt as resolveUpdater, o as peekLeafAllowed, ot as Checkbox, r as shadcnBlockImplementations, rt as tanStackSortingToBuro, s as peekRecord, st as Tabs, tt as buroSortingToTanStack, ut as TabsTrigger, v as FormActions, vt as resolveResourceTitle, w as ListSavedViews, wt as useExportRunWatcher, xt as typography, y as RecordActions, yt as DocumentTitleProvider, z as BulkActionToolbar, zt as useShell } from "./place-node-BdxT-30h.js";
|
|
11
10
|
import { THEME_STORAGE_KEY } from "./layout/theme-storage-key.js";
|
|
12
|
-
import {
|
|
13
|
-
import { A as useLayoutResolver, C as
|
|
11
|
+
import { A as TableHeader, B as DEFAULT_LANGUAGE_STORAGE_KEY, C as SelectTrigger, D as TableCaption, E as TableBody, F as ResolvedFieldDisplay, H as saveLocale, M as Badge, N as badgeVariants, O as TableCell, S as SelectSeparator, T as Table, V as loadLocale, _ as SelectGroup, a as PinnedFilterControls, b as SelectScrollDownButton, c as fromLocalDateTimeText, d as useFieldTimeZone, f as FilterBadges, g as SelectContent, h as Select, i as FacetedFilterPicker, j as TableRow, k as TableHead, l as toLocalDateTimeText, m as localeTag, n as PresetFilterControls, o as FilterPanel, p as formatNumber, r as DataTableFacetedFilter, s as FilterValueControl, t as FilterBuilder, u as dateDisplayParams, v as SelectItem, w as SelectValue, x as SelectScrollUpButton, y as SelectLabel, z as lowerLegacyField } from "./filter-builder-z3Axzf9Y.js";
|
|
12
|
+
import { A as useLayoutResolver, C as useMatch, D as BUILTIN_LAYOUTS, E as useResourceVisible, F as canonicalResourceKey$1, M as TabsLayout, N as SecondarySidebarLayout, O as layoutSlot, P as canonicalNavKey, S as useHref, T as usePageAllowed, _ as RecordScreen, a as useRecordVisit, b as ResourceListPage, c as headerTrail, d as recordTrailRoute, f as useTrailContext, g as usePublishedRecordTrail, i as RecordPage, j as useReportUnresolvedLayouts, k as useLayout, l as originTrail, m as recordTrailKey, n as NavAreaPage, o as RECENT_LABEL_KEYS, p as isShowAvailable, r as ResourcePageRouter, s as readRecentRecords, u as recordTrail, v as useResourceDimensionOptions, w as useNavVisible, x as NavChromeMountedProvider, y as PlannedBody } from "./resource-page-router-BRpUnhay.js";
|
|
14
13
|
import { t as Label } from "./label-66W1qbke.js";
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
14
|
+
import { t as LazyRelationPickerDialog } from "./lazy-relation-picker-dialog-DN4bvQfg.js";
|
|
15
|
+
import { n as useRecordSubtitle, r as useRowSubtitle } from "./use-record-subtitle-gIaCGgbI.js";
|
|
16
|
+
import { n as RelationPicker, r as RelationPickerInput } from "./relation-picker-x7P5HKie.js";
|
|
17
|
+
import { t as useDialogFilterState } from "./use-dialog-filter-state-B_MqzHaT.js";
|
|
18
|
+
import { useGlobalShortcut, webPlatform } from "@burojs/react/web";
|
|
19
|
+
import { ENUM_CONTROLS, builtinFrames, canonicalInstant, columnName, compilePageScreen, compiledScreenFor, declaredField, declaredText, dtoFields, effectiveFlow, enumFallbackKey, enumFallbackText, enumNamespaceOf, enumValueText, epochMsToInstant, evaluateVisible, fieldOptionText, formatEntityRef, formatTimeValue, hasListPage, hasRecordPage, hrefFor, humanizeKey, isCalendarDate, isCustomPageDef, isEnumControl, isRelationField, isScreenFailure, linkOf, navHrefFor, nodeKind, normalizeDataError, normalizeEntityRef, projectDto, recordEntries, relationAmbiguousError, resolveConceptLabel, resolveContentSlot, resolveDoc, resolveEnumLabel, resolveFieldLabel, resolveNavLabel, resolveResourceLabel, resolveResourceNavLabel, resolveStaticAvailability, resourceCreateHref, resourceKey, resourceShowHref, routeResourceKey, snapshotAppFrames, snapshotBlockLookup, snapshotFrameLookup, taskRunFraction, taskRunOutcome, zoneShortName } from "@burojs/core";
|
|
20
|
+
import { ComponentsContext, DispatcherProvider, I18nContext, NO_RECORD_SCOPE_FRAMES, QUICK_ANCHOR_ATTRIBUTE, QuickEntryContext, RecordScopeChain, RouteSourceContext, ScreenStateProvider, formatBytes, optionFieldName, recordRouteAvailable, resolveErrorText, resolveOptionLabel, retryRecordRead, useApp, useAppActions, useApplicationSnapshot, useAvailabilityGate, useAvailableEnumValues, useBoundEnum, useCapabilityResolver, useChangeLocale, useChromeT, useCommandPalette, useCurrentUserId, useDebouncedValue, useDispatcherEffects, useDocPanel, useDocScopes, useDocTopics, useDocTrailScopes, useDocsConfig, useDocumentedScopes, useEntryGate, useEnumValues, useFieldAccess, useFieldMetaSources, useFileField, useFileUrls, useFormController, useFrameImplementations, useFrameT, useI18nCaps, useIdentity, useLanguageStorageKey, useLinkKeys, useList, useListAccess, useLocale, useLogout, useNavigationGuardText, useNavigationOrigin, useOne, useOptionCaps, useOptionalApp, useOptionalAuthController, useOptionalDataRuntime, useOptionalFileStorage, useOptionalLocale, useOptionalRouterAdapter, useOptionalT, useOriginIntent, usePlatformStorage, usePresentBlock, useProjectedRecord, useProjectedTitle, usePublishOriginTitle, useQuick, useQuickEntry, useQuickEntryValue, useQuickOpener, useRecordTitle, useRefresh, useRegisterNavigationGuardDialog, useRelatedRecord, useRouteNavigate, useRouteRecordId, useRouterAdapter, useScope, useT, useTestIds, useTimeZone, useUIInstance, useUIPresentationRuntime, useVisibilityCtx } from "@burojs/react";
|
|
21
|
+
import { IconAlertCircle, IconArrowDown, IconArrowLeft, IconArrowUp, IconArrowUpRight, IconBook2, IconCheck, IconChevronDown, IconChevronRight, IconDeviceDesktop, IconDots, IconExternalLink, IconHelp, IconHelpHexagon, IconLayoutSidebar, IconLoader2, IconLogin, IconLogout, IconMaximize, IconMinimize, IconMoon, IconPlus, IconRefresh, IconRotate, IconSearch, IconSelector, IconSun, IconTrash, IconUpload, IconUser, IconX } from "@tabler/icons-react";
|
|
21
22
|
import * as React from "react";
|
|
22
23
|
import { Children, Fragment, Suspense, cloneElement, createContext, createElement, isValidElement, lazy, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
23
24
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -29,6 +30,7 @@ import * as SeparatorPrimitive from "@radix-ui/react-separator";
|
|
|
29
30
|
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
|
|
30
31
|
import * as AvatarPrimitive from "@radix-ui/react-avatar";
|
|
31
32
|
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
|
|
33
|
+
import { enumBindingKey, enumParamsOf, narrowEntriesOf } from "@burojs/core/internal";
|
|
32
34
|
import { Controller, FormProvider, useForm, useFormContext } from "react-hook-form";
|
|
33
35
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
34
36
|
import { z } from "zod";
|
|
@@ -489,7 +491,7 @@ function ScopeSummary({ scope, summary }) {
|
|
|
489
491
|
const caps = useI18nCaps();
|
|
490
492
|
const t = useOptionalT();
|
|
491
493
|
const links = (scope !== void 0 ? resolveDoc(caps, scope) : void 0)?.links ?? [];
|
|
492
|
-
const newTabNote = t("docPanel.
|
|
494
|
+
const newTabNote = t("docPanel.opensInNewTab", { defaultValue: "(opens in a new tab)" });
|
|
493
495
|
if (summary === void 0 && links.length === 0) return null;
|
|
494
496
|
return jsxs("div", {
|
|
495
497
|
className: "mt-2 flex flex-col items-start gap-3",
|
|
@@ -1111,7 +1113,7 @@ AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
|
|
|
1111
1113
|
function NavigationGuardDialog() {
|
|
1112
1114
|
const prompt = useRegisterNavigationGuardDialog();
|
|
1113
1115
|
const text = useNavigationGuardText();
|
|
1114
|
-
const unsavedAction = useOptionalT()("navigation.unsavedAction");
|
|
1116
|
+
const unsavedAction = useOptionalT()("navigation.unsavedAction", { defaultValue: "An action on this screen has unsaved input" });
|
|
1115
1117
|
const returnFocus = useRef(null);
|
|
1116
1118
|
const wasOpen = useRef(false);
|
|
1117
1119
|
const open = prompt !== null;
|
|
@@ -1134,7 +1136,7 @@ function NavigationGuardDialog() {
|
|
|
1134
1136
|
event.preventDefault();
|
|
1135
1137
|
element.focus();
|
|
1136
1138
|
},
|
|
1137
|
-
children: [jsxs(AlertDialogHeader, { children: [jsx(AlertDialogTitle, { children: text.title }), jsxs(AlertDialogDescription, { children: [text.body, prompt !== null && prompt.labels.length > 0 ? ` ${unsavedAction
|
|
1139
|
+
children: [jsxs(AlertDialogHeader, { children: [jsx(AlertDialogTitle, { children: text.title }), jsxs(AlertDialogDescription, { children: [text.body, prompt !== null && prompt.labels.length > 0 ? ` ${unsavedAction}: ${prompt.labels.join(", ")}.` : null] })] }), jsxs(AlertDialogFooter, { children: [jsx(AlertDialogCancel, {
|
|
1138
1140
|
"data-testid": "nav-guard-stay",
|
|
1139
1141
|
children: text.stay
|
|
1140
1142
|
}), jsx(AlertDialogAction, {
|
|
@@ -1694,14 +1696,14 @@ const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger;
|
|
|
1694
1696
|
const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent;
|
|
1695
1697
|
//#endregion
|
|
1696
1698
|
//#region src/shell/use-nav-icon.tsx
|
|
1697
|
-
const warned = new Set();
|
|
1699
|
+
const warned$1 = new Set();
|
|
1698
1700
|
function resolveNavIcon(name, components) {
|
|
1699
1701
|
if (name === void 0 || name === "") return void 0;
|
|
1700
1702
|
const slot = components(name);
|
|
1701
1703
|
if (typeof slot === "function" || typeof slot === "object" && slot !== null) return jsx(slot, { className: "h-4 w-4" });
|
|
1702
1704
|
if (hasIcon(name)) return jsx(Icon, { name });
|
|
1703
|
-
if (process.env.NODE_ENV !== "production" && !warned.has(name)) {
|
|
1704
|
-
warned.add(name);
|
|
1705
|
+
if (process.env.NODE_ENV !== "production" && !warned$1.has(name)) {
|
|
1706
|
+
warned$1.add(name);
|
|
1705
1707
|
console.warn(`[buro] unknown nav icon "${name}"`);
|
|
1706
1708
|
}
|
|
1707
1709
|
}
|
|
@@ -1710,6 +1712,53 @@ function useNavIcon() {
|
|
|
1710
1712
|
return useCallback((name) => resolveNavIcon(name, (key) => components[key]), [components]);
|
|
1711
1713
|
}
|
|
1712
1714
|
//#endregion
|
|
1715
|
+
//#region src/layout/build-nav-items.ts
|
|
1716
|
+
function buildNavItems(args) {
|
|
1717
|
+
const { registry, caps, groupName, match, isVisible, entryFilter, icons } = args;
|
|
1718
|
+
const chain = match?.groupChain ?? [];
|
|
1719
|
+
const qualifiedMatch = match;
|
|
1720
|
+
const activeLeaf = qualifiedMatch == null ? void 0 : qualifiedMatch.kind === "group-index" ? canonicalNavKey({
|
|
1721
|
+
name: qualifiedMatch.target ?? qualifiedMatch.name,
|
|
1722
|
+
ref: qualifiedMatch.targetRef
|
|
1723
|
+
}) : canonicalNavKey(qualifiedMatch);
|
|
1724
|
+
const isEligible = (node) => isVisible(node) && (entryFilter ? entryFilter(node) : true);
|
|
1725
|
+
const out = [];
|
|
1726
|
+
for (const child of registry.groups.childrenOf(groupName)) {
|
|
1727
|
+
if (!isEligible(child)) continue;
|
|
1728
|
+
const kind = nodeKind(child);
|
|
1729
|
+
const childKey = canonicalNavKey(child);
|
|
1730
|
+
const href = navHrefFor(registry, childKey, { isVisible: isEligible });
|
|
1731
|
+
if (kind === "group") {
|
|
1732
|
+
const label = resolveNavLabel(caps, `groups.${childKey}`, declaredText("chrome", child, "label"));
|
|
1733
|
+
const active = chain.some((g) => canonicalNavKey(g) === childKey);
|
|
1734
|
+
out.push({
|
|
1735
|
+
kind: "group",
|
|
1736
|
+
name: childKey,
|
|
1737
|
+
label,
|
|
1738
|
+
href,
|
|
1739
|
+
icon: icons?.group?.(childKey),
|
|
1740
|
+
active
|
|
1741
|
+
});
|
|
1742
|
+
} else if (kind === "custom-page") out.push({
|
|
1743
|
+
kind: "custom-page",
|
|
1744
|
+
name: childKey,
|
|
1745
|
+
label: resolveNavLabel(caps, `pages.${childKey}`, declaredText("chrome", child, "label")),
|
|
1746
|
+
href,
|
|
1747
|
+
icon: icons?.page?.(childKey),
|
|
1748
|
+
active: activeLeaf === childKey
|
|
1749
|
+
});
|
|
1750
|
+
else out.push({
|
|
1751
|
+
kind: "resource",
|
|
1752
|
+
name: childKey,
|
|
1753
|
+
label: resolveResourceNavLabel(caps, childKey, child),
|
|
1754
|
+
href,
|
|
1755
|
+
icon: icons?.resource?.(childKey),
|
|
1756
|
+
active: activeLeaf === childKey
|
|
1757
|
+
});
|
|
1758
|
+
}
|
|
1759
|
+
return out;
|
|
1760
|
+
}
|
|
1761
|
+
//#endregion
|
|
1713
1762
|
//#region src/layout/use-nav-tree.ts
|
|
1714
1763
|
function isActiveHref(href, currentPath) {
|
|
1715
1764
|
if (!currentPath) return false;
|
|
@@ -1723,8 +1772,7 @@ function useNavTree(opts = {}) {
|
|
|
1723
1772
|
const passesEntryFilter = (entry) => entryFilter ? entryFilter(entry) : true;
|
|
1724
1773
|
const app = useApp();
|
|
1725
1774
|
const caps = useI18nCaps();
|
|
1726
|
-
const
|
|
1727
|
-
const isResourceVisible = (r) => evaluateVisible(r.visible, visibilityCtx);
|
|
1775
|
+
const isResourceVisible = useResourceVisible();
|
|
1728
1776
|
const resolveLayout = useLayoutResolver();
|
|
1729
1777
|
const match = useMatch();
|
|
1730
1778
|
const isVisible = useNavVisible();
|
|
@@ -1734,6 +1782,7 @@ function useNavTree(opts = {}) {
|
|
|
1734
1782
|
const allCustomPages = app.registry.customPages.list();
|
|
1735
1783
|
const sections = app.registry.sections.list();
|
|
1736
1784
|
const groups = app.registry.groups.rootNodes().filter((n) => nodeKind(n) === "group");
|
|
1785
|
+
useReportUnresolvedLayouts(app.registry.groups.list(), resolveLayout);
|
|
1737
1786
|
const topLevelResources = allResources.filter((r) => hasListPage(r)).filter(isResourceVisible).filter(passesEntryFilter).filter((r) => !r.section && !r.group).map((r, idx) => ({
|
|
1738
1787
|
r,
|
|
1739
1788
|
idx
|
|
@@ -1743,8 +1792,8 @@ function useNavTree(opts = {}) {
|
|
|
1743
1792
|
return ao !== bo ? ao - bo : a.idx - b.idx;
|
|
1744
1793
|
}).map((x) => x.r);
|
|
1745
1794
|
const topLevelCustomPages = allCustomPages.filter((p) => !p.section && !p.group).filter(pageAllowed).filter(passesEntryFilter);
|
|
1746
|
-
const resourceHref = (def) => hrefFor(app.registry, canonicalResourceKey(def));
|
|
1747
|
-
const resourceLabel = (def) => resolveResourceNavLabel(caps, canonicalResourceKey(def), def);
|
|
1795
|
+
const resourceHref = (def) => hrefFor(app.registry, canonicalResourceKey$1(def));
|
|
1796
|
+
const resourceLabel = (def) => resolveResourceNavLabel(caps, canonicalResourceKey$1(def), def);
|
|
1748
1797
|
const pageLabel = (page) => resolveNavLabel(caps, `pages.${canonicalNavKey(page)}`, declaredText("chrome", page, "label"));
|
|
1749
1798
|
const sectionLabel = (section) => resolveNavLabel(caps, `sections.${canonicalNavKey(section)}`, declaredText("chrome", section, "label"));
|
|
1750
1799
|
const groupLabel = (group) => resolveNavLabel(caps, `groups.${canonicalNavKey(group)}`, declaredText("chrome", group, "label"));
|
|
@@ -1763,7 +1812,7 @@ function useNavTree(opts = {}) {
|
|
|
1763
1812
|
const href = resourceHref(def);
|
|
1764
1813
|
return {
|
|
1765
1814
|
kind: "resource",
|
|
1766
|
-
key: canonicalResourceKey(def),
|
|
1815
|
+
key: canonicalResourceKey$1(def),
|
|
1767
1816
|
label: resourceLabel(def),
|
|
1768
1817
|
href,
|
|
1769
1818
|
icon: def.icon,
|
|
@@ -1926,6 +1975,10 @@ function NavMain({ topLabel, iconForResource, iconForCustomPage, iconForSection,
|
|
|
1926
1975
|
const t = useT();
|
|
1927
1976
|
const RouterLink = useLinkComponent();
|
|
1928
1977
|
const navIcon = useNavIcon();
|
|
1978
|
+
const intent = useOriginIntent();
|
|
1979
|
+
const jump = (entry) => () => {
|
|
1980
|
+
if (entry.href !== void 0) intent(entry.href, "jump");
|
|
1981
|
+
};
|
|
1929
1982
|
const ownOr = (own, name) => own !== void 0 ? own : navIcon(name);
|
|
1930
1983
|
const groupAsSection = (key) => app.registry.sections.get(key) ?? app.registry.groups.get(key);
|
|
1931
1984
|
const sectionIcon = (key, name) => {
|
|
@@ -1952,6 +2005,7 @@ function NavMain({ topLabel, iconForResource, iconForCustomPage, iconForSection,
|
|
|
1952
2005
|
href: entry.href ?? "",
|
|
1953
2006
|
"aria-current": entry.active ? "page" : void 0,
|
|
1954
2007
|
"data-testid": entryTestId(entry),
|
|
2008
|
+
onClick: jump(entry),
|
|
1955
2009
|
children: [icon != null && jsx("span", {
|
|
1956
2010
|
className: "inline-flex h-4 w-4 items-center justify-center",
|
|
1957
2011
|
"aria-hidden": "true",
|
|
@@ -1967,11 +2021,12 @@ function NavMain({ topLabel, iconForResource, iconForCustomPage, iconForSection,
|
|
|
1967
2021
|
href: entry.href ?? "",
|
|
1968
2022
|
"aria-current": entry.active ? "page" : void 0,
|
|
1969
2023
|
"data-testid": entryTestId(entry),
|
|
2024
|
+
onClick: jump(entry),
|
|
1970
2025
|
children: jsx("span", { children: entry.label })
|
|
1971
2026
|
})
|
|
1972
2027
|
}) }, entry.key);
|
|
1973
2028
|
const [top, ...blocks] = tree;
|
|
1974
|
-
return jsxs(Fragment$1, { children: [jsxs(SidebarGroup, { children: [topLabel !== null && jsx(SidebarGroupLabel, { children: topLabel ?? t("nav.resources") }), jsx(SidebarGroupContent, { children: jsx(SidebarMenu, { children: top
|
|
2029
|
+
return jsxs(Fragment$1, { children: [top !== void 0 && top.entries.length > 0 && jsxs(SidebarGroup, { children: [topLabel !== null && jsx(SidebarGroupLabel, { children: topLabel ?? t("nav.resources") }), jsx(SidebarGroupContent, { children: jsx(SidebarMenu, { children: top.entries.map(menuItem) }) })] }), blocks.map((block) => {
|
|
1975
2030
|
const key = block.key ?? "";
|
|
1976
2031
|
if (block.label === null) return jsx(SidebarGroup, { children: jsx(SidebarGroupContent, { children: jsx(SidebarMenu, { children: block.entries.map(menuItem) }) }) }, key);
|
|
1977
2032
|
if (block.collapsible) return jsx(CollapsibleNavSection, {
|
|
@@ -2015,126 +2070,31 @@ function AppSidebar({ header, filters, nav, footer }) {
|
|
|
2015
2070
|
});
|
|
2016
2071
|
}
|
|
2017
2072
|
//#endregion
|
|
2018
|
-
//#region src/layout/
|
|
2019
|
-
function Row({ it }) {
|
|
2020
|
-
const RouterLink = useLinkComponent();
|
|
2021
|
-
return jsx("li", { children: jsxs(RouterLink, {
|
|
2022
|
-
href: it.href,
|
|
2023
|
-
"data-testid": `nav-secondary-item:${it.name}`,
|
|
2024
|
-
"aria-current": it.active ? "page" : void 0,
|
|
2025
|
-
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"),
|
|
2026
|
-
children: [it.icon != null && jsx("span", {
|
|
2027
|
-
className: "inline-flex h-4 w-4 shrink-0 items-center justify-center",
|
|
2028
|
-
"aria-hidden": "true",
|
|
2029
|
-
children: it.icon
|
|
2030
|
-
}), jsx("span", {
|
|
2031
|
-
className: "truncate",
|
|
2032
|
-
title: it.label,
|
|
2033
|
-
children: it.label
|
|
2034
|
-
})]
|
|
2035
|
-
}) });
|
|
2036
|
-
}
|
|
2037
|
-
function SecondarySidebarLayout({ group, groupKey, items, children }) {
|
|
2038
|
-
const RouterLink = useLinkComponent();
|
|
2039
|
-
const caps = useI18nCaps();
|
|
2040
|
-
const id = groupKey ?? group.name;
|
|
2041
|
-
const label = resolveNavLabel(caps, `groups.${id}`, declaredText("chrome", group, "label"));
|
|
2042
|
-
return jsxs("div", {
|
|
2043
|
-
className: "md:-m-6 md:flex md:min-h-[calc(100%+3rem)]",
|
|
2044
|
-
"data-testid": `nav-secondary:${id}`,
|
|
2045
|
-
children: [
|
|
2046
|
-
jsx("aside", {
|
|
2047
|
-
className: "hidden w-64 shrink-0 border-r bg-background text-foreground md:block",
|
|
2048
|
-
children: jsxs("div", {
|
|
2049
|
-
className: "space-y-4 p-4",
|
|
2050
|
-
children: [jsx("p", {
|
|
2051
|
-
className: "px-3 text-base font-semibold tracking-tight",
|
|
2052
|
-
children: label
|
|
2053
|
-
}), jsx("nav", {
|
|
2054
|
-
"aria-label": label,
|
|
2055
|
-
children: jsx("ul", {
|
|
2056
|
-
className: "space-y-0.5",
|
|
2057
|
-
children: items.map((it) => jsx(Row, { it }, it.name))
|
|
2058
|
-
})
|
|
2059
|
-
})]
|
|
2060
|
-
})
|
|
2061
|
-
}),
|
|
2062
|
-
jsx("nav", {
|
|
2063
|
-
"aria-label": label,
|
|
2064
|
-
"data-testid": `nav-secondary-select:${id}`,
|
|
2065
|
-
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",
|
|
2066
|
-
children: items.map((it) => jsx(RouterLink, {
|
|
2067
|
-
href: it.href,
|
|
2068
|
-
"aria-current": it.active ? "page" : void 0,
|
|
2069
|
-
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"),
|
|
2070
|
-
children: it.label
|
|
2071
|
-
}, it.name))
|
|
2072
|
-
}),
|
|
2073
|
-
jsx("div", {
|
|
2074
|
-
className: "min-w-0 flex-1 md:overflow-x-hidden md:p-6",
|
|
2075
|
-
children
|
|
2076
|
-
})
|
|
2077
|
-
]
|
|
2078
|
-
});
|
|
2079
|
-
}
|
|
2080
|
-
//#endregion
|
|
2081
|
-
//#region src/layout/layouts/tabs-layout.tsx
|
|
2082
|
-
function TabsLayout({ group, groupKey, items, children }) {
|
|
2083
|
-
const RouterLink = useLinkComponent();
|
|
2084
|
-
const caps = useI18nCaps();
|
|
2085
|
-
const id = groupKey ?? group.name;
|
|
2086
|
-
const label = resolveNavLabel(caps, `groups.${id}`, declaredText("chrome", group, "label"));
|
|
2087
|
-
return jsxs("div", {
|
|
2088
|
-
className: "flex flex-col gap-4",
|
|
2089
|
-
"data-testid": `nav-tabs:${id}`,
|
|
2090
|
-
children: [jsx("nav", {
|
|
2091
|
-
"aria-label": label,
|
|
2092
|
-
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",
|
|
2093
|
-
children: items.map((it) => jsxs(RouterLink, {
|
|
2094
|
-
href: it.href,
|
|
2095
|
-
"aria-current": it.active ? "page" : void 0,
|
|
2096
|
-
"data-testid": `nav-tab:${it.name}`,
|
|
2097
|
-
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"),
|
|
2098
|
-
children: [
|
|
2099
|
-
it.icon != null && jsx("span", {
|
|
2100
|
-
className: "inline-flex h-4 w-4 shrink-0 items-center justify-center",
|
|
2101
|
-
"aria-hidden": "true",
|
|
2102
|
-
children: it.icon
|
|
2103
|
-
}),
|
|
2104
|
-
it.label,
|
|
2105
|
-
jsx("span", {
|
|
2106
|
-
"aria-hidden": "true",
|
|
2107
|
-
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")
|
|
2108
|
-
})
|
|
2109
|
-
]
|
|
2110
|
-
}, it.name))
|
|
2111
|
-
}), jsx("div", {
|
|
2112
|
-
className: "min-w-0",
|
|
2113
|
-
children
|
|
2114
|
-
})]
|
|
2115
|
-
});
|
|
2116
|
-
}
|
|
2117
|
-
//#endregion
|
|
2118
|
-
//#region src/layout/nav-area-layout.tsx
|
|
2073
|
+
//#region src/layout/nav-chrome.tsx
|
|
2119
2074
|
const DETAIL_ACTIONS = new Set([
|
|
2120
2075
|
"show",
|
|
2121
2076
|
"edit",
|
|
2122
2077
|
"create"
|
|
2123
2078
|
]);
|
|
2124
|
-
function
|
|
2079
|
+
function NavChrome({ children, entryFilter, icons }) {
|
|
2125
2080
|
const app = useApp();
|
|
2126
2081
|
const caps = useI18nCaps();
|
|
2127
2082
|
const isVisible = useNavVisible();
|
|
2128
2083
|
const match = useMatch();
|
|
2129
2084
|
const resolveLayout = useLayoutResolver();
|
|
2130
|
-
|
|
2131
|
-
if (!
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
const Layout = resolveLayout(group.layout);
|
|
2085
|
+
useReportUnresolvedLayouts(match?.groupChain ?? [], resolveLayout);
|
|
2086
|
+
if (!match) return jsx(NavChromeMountedProvider, {
|
|
2087
|
+
value: true,
|
|
2088
|
+
children
|
|
2089
|
+
});
|
|
2136
2090
|
let content = children;
|
|
2137
|
-
|
|
2091
|
+
for (let i = match.groupChain.length - 1; i >= 0; i--) {
|
|
2092
|
+
const group = match.groupChain[i];
|
|
2093
|
+
if (!group) continue;
|
|
2094
|
+
const groupKey = canonicalNavKey(group);
|
|
2095
|
+
if (group.chromeOn === "list" && match.kind === "resource" && DETAIL_ACTIONS.has(match.action)) continue;
|
|
2096
|
+
const Layout = resolveLayout(group.layout);
|
|
2097
|
+
if (!Layout) continue;
|
|
2138
2098
|
const items = buildNavItems({
|
|
2139
2099
|
registry: app.registry,
|
|
2140
2100
|
caps,
|
|
@@ -2148,11 +2108,11 @@ function NavAreaLayout({ groupName, children, entryFilter, icons }) {
|
|
|
2148
2108
|
group,
|
|
2149
2109
|
groupKey,
|
|
2150
2110
|
items,
|
|
2151
|
-
children
|
|
2111
|
+
children: content
|
|
2152
2112
|
});
|
|
2153
2113
|
}
|
|
2154
|
-
return jsx(
|
|
2155
|
-
|
|
2114
|
+
return jsx(NavChromeMountedProvider, {
|
|
2115
|
+
value: true,
|
|
2156
2116
|
children: content
|
|
2157
2117
|
});
|
|
2158
2118
|
}
|
|
@@ -2165,19 +2125,27 @@ function Chevron() {
|
|
|
2165
2125
|
"aria-hidden": "true"
|
|
2166
2126
|
});
|
|
2167
2127
|
}
|
|
2168
|
-
function Breadcrumbs(
|
|
2128
|
+
function Breadcrumbs(input) {
|
|
2129
|
+
const props = input;
|
|
2169
2130
|
const { leadingSegments, className, docScopes, "data-testid": testId } = props;
|
|
2170
2131
|
const app = useApp();
|
|
2171
|
-
const
|
|
2132
|
+
const resource = props.resource === void 0 ? void 0 : routeResourceKey(props.resource);
|
|
2133
|
+
const def = resource === void 0 ? void 0 : app.registry.get(resource);
|
|
2172
2134
|
const tid = useTestIds();
|
|
2173
2135
|
const t = useOptionalT();
|
|
2174
2136
|
const RouterLink = useLinkComponent();
|
|
2175
2137
|
const caps = useI18nCaps(def?.name);
|
|
2138
|
+
const intent = useOriginIntent();
|
|
2139
|
+
const onJump = (seg) => {
|
|
2140
|
+
const href = seg.href;
|
|
2141
|
+
return seg.jump === true && href !== void 0 ? () => intent(href, "jump") : void 0;
|
|
2142
|
+
};
|
|
2176
2143
|
const trailScopes = useDocTrailScopes(def?.name);
|
|
2177
2144
|
const leading = (name) => leadingSegments?.map((seg, i) => jsxs("span", {
|
|
2178
2145
|
className: "flex min-w-0 items-center gap-1",
|
|
2179
2146
|
children: [seg.href ? jsx(RouterLink, {
|
|
2180
2147
|
href: seg.href,
|
|
2148
|
+
onClick: onJump(seg),
|
|
2181
2149
|
"data-testid": `${tid.navBreadcrumb(name)}:lead:${i}`,
|
|
2182
2150
|
className: cn(LINK_CLASS, "truncate"),
|
|
2183
2151
|
title: seg.label,
|
|
@@ -2212,9 +2180,34 @@ function Breadcrumbs(props) {
|
|
|
2212
2180
|
]
|
|
2213
2181
|
});
|
|
2214
2182
|
if (!def) return null;
|
|
2215
|
-
const { recordId, pageLabel, middleSegments } = props;
|
|
2216
|
-
const resourceKey = canonicalResourceKey(def);
|
|
2217
|
-
|
|
2183
|
+
const { recordId, pageLabel, middleSegments, rootSegments } = props;
|
|
2184
|
+
const resourceKey = canonicalResourceKey$1(def);
|
|
2185
|
+
if (rootSegments !== void 0 && rootSegments.length > 0) return jsxs("nav", {
|
|
2186
|
+
className: navClass,
|
|
2187
|
+
"aria-label": ariaLabel,
|
|
2188
|
+
"data-testid": testId,
|
|
2189
|
+
children: [
|
|
2190
|
+
rootSegments.map((seg, i) => jsxs("span", {
|
|
2191
|
+
className: "flex min-w-0 items-center gap-1",
|
|
2192
|
+
children: [i > 0 && jsx(Chevron, {}), seg.href ? jsx(RouterLink, {
|
|
2193
|
+
href: seg.href,
|
|
2194
|
+
onClick: onJump(seg),
|
|
2195
|
+
"data-testid": `${tid.navBreadcrumb(resourceKey)}:root:${i}`,
|
|
2196
|
+
className: cn(LINK_CLASS, "truncate"),
|
|
2197
|
+
title: seg.label,
|
|
2198
|
+
children: seg.label
|
|
2199
|
+
}) : jsx("span", {
|
|
2200
|
+
"data-testid": `${tid.navBreadcrumb(resourceKey)}:root:${i}`,
|
|
2201
|
+
className: "truncate",
|
|
2202
|
+
title: seg.label,
|
|
2203
|
+
children: seg.label
|
|
2204
|
+
})]
|
|
2205
|
+
}, `root:${i}:${seg.label}`)),
|
|
2206
|
+
pageLabel && jsxs(Fragment$1, { children: [jsx(Chevron, {}), current(tid.navBreadcrumb(resourceKey, recordId), pageLabel)] }),
|
|
2207
|
+
help
|
|
2208
|
+
]
|
|
2209
|
+
});
|
|
2210
|
+
const listHref = props.resourceHref ?? hrefFor(app.registry, resourceKey);
|
|
2218
2211
|
const resourceLabel = resolveResourceLabel(caps, resourceKey, "plural", def);
|
|
2219
2212
|
const resourceIsCurrent = !pageLabel && !(middleSegments && middleSegments.length > 0);
|
|
2220
2213
|
return jsxs("nav", {
|
|
@@ -2223,7 +2216,12 @@ function Breadcrumbs(props) {
|
|
|
2223
2216
|
"data-testid": testId,
|
|
2224
2217
|
children: [
|
|
2225
2218
|
leading(resourceKey),
|
|
2226
|
-
resourceIsCurrent ? current(tid.navBreadcrumb(resourceKey), resourceLabel) : jsx(
|
|
2219
|
+
resourceIsCurrent ? current(tid.navBreadcrumb(resourceKey), resourceLabel) : !hasListPage(def) ? jsx("span", {
|
|
2220
|
+
"data-testid": tid.navBreadcrumb(resourceKey),
|
|
2221
|
+
className: "truncate",
|
|
2222
|
+
title: resourceLabel,
|
|
2223
|
+
children: resourceLabel
|
|
2224
|
+
}) : jsx(RouterLink, {
|
|
2227
2225
|
href: listHref,
|
|
2228
2226
|
"data-testid": tid.navBreadcrumb(resourceKey),
|
|
2229
2227
|
className: cn(LINK_CLASS, "truncate"),
|
|
@@ -2234,6 +2232,7 @@ function Breadcrumbs(props) {
|
|
|
2234
2232
|
className: "flex min-w-0 items-center gap-1",
|
|
2235
2233
|
children: [jsx(Chevron, {}), seg.href ? jsx(RouterLink, {
|
|
2236
2234
|
href: seg.href,
|
|
2235
|
+
onClick: onJump(seg),
|
|
2237
2236
|
"data-testid": `${tid.navBreadcrumb(resourceKey)}:mid:${i}`,
|
|
2238
2237
|
className: cn(LINK_CLASS, "truncate"),
|
|
2239
2238
|
title: seg.label,
|
|
@@ -2251,6 +2250,12 @@ function Breadcrumbs(props) {
|
|
|
2251
2250
|
}
|
|
2252
2251
|
//#endregion
|
|
2253
2252
|
//#region src/layout/record-breadcrumbs.tsx
|
|
2253
|
+
function viewOrigin(ctx, trail, resource) {
|
|
2254
|
+
if (trail === void 0 || trail.resource === void 0 || trail.segments.length > 0) return void 0;
|
|
2255
|
+
const target = ctx.registry.get(trail.resource)?.routesTo?.show;
|
|
2256
|
+
if (target === void 0 || ctx.registry.get(target) !== ctx.registry.get(resource)) return void 0;
|
|
2257
|
+
return trail.resource;
|
|
2258
|
+
}
|
|
2254
2259
|
function RecordBreadcrumbs() {
|
|
2255
2260
|
const ctx = useTrailContext();
|
|
2256
2261
|
const match = useMatch();
|
|
@@ -2258,9 +2263,17 @@ function RecordBreadcrumbs() {
|
|
|
2258
2263
|
const route = recordTrailRoute(ctx.registry, match);
|
|
2259
2264
|
const published = usePublishedRecordTrail(route === null ? "" : recordTrailKey(route.resource, route.id, route.flow === void 0 ? route.action : `flow:${route.flow}`));
|
|
2260
2265
|
const idTitle = useRecordTitle(route?.resource, route?.id);
|
|
2266
|
+
usePublishOriginTitle(published?.title || void 0);
|
|
2267
|
+
const origin = useNavigationOrigin();
|
|
2268
|
+
const rooted = origin === null ? void 0 : originTrail(ctx, origin);
|
|
2269
|
+
const view = route === null ? void 0 : viewOrigin(ctx, rooted, route.resource);
|
|
2270
|
+
const viewScopes = useDocTrailScopes(view);
|
|
2271
|
+
const ownScopes = useDocTrailScopes(view === void 0 ? void 0 : route?.resource);
|
|
2272
|
+
const docScopes = view === void 0 ? {} : { docScopes: [...new Set([...viewScopes, ...ownScopes])] };
|
|
2261
2273
|
if (route === null || match === null) return null;
|
|
2262
2274
|
const { resource, id, groupChain } = route;
|
|
2263
2275
|
const title = published?.title ?? idTitle;
|
|
2276
|
+
const withOrigin = rooted === void 0 ? {} : { origin: rooted };
|
|
2264
2277
|
if (route.flow !== void 0) {
|
|
2265
2278
|
if (effectiveFlow(snapshot, match.ref, route.flow) === void 0) return null;
|
|
2266
2279
|
const flowLabel = published?.flowLabel;
|
|
@@ -2270,8 +2283,10 @@ function RecordBreadcrumbs() {
|
|
|
2270
2283
|
action: "show",
|
|
2271
2284
|
id,
|
|
2272
2285
|
title: idTitle,
|
|
2273
|
-
groupChain
|
|
2286
|
+
groupChain,
|
|
2287
|
+
...withOrigin
|
|
2274
2288
|
}),
|
|
2289
|
+
...docScopes,
|
|
2275
2290
|
"data-testid": "record-breadcrumbs"
|
|
2276
2291
|
});
|
|
2277
2292
|
return jsx(Breadcrumbs, {
|
|
@@ -2280,8 +2295,10 @@ function RecordBreadcrumbs() {
|
|
|
2280
2295
|
action: "edit",
|
|
2281
2296
|
id,
|
|
2282
2297
|
title,
|
|
2283
|
-
groupChain
|
|
2298
|
+
groupChain,
|
|
2299
|
+
...withOrigin
|
|
2284
2300
|
}),
|
|
2301
|
+
...docScopes,
|
|
2285
2302
|
pageLabel: flowLabel,
|
|
2286
2303
|
"data-testid": "record-breadcrumbs"
|
|
2287
2304
|
});
|
|
@@ -2292,22 +2309,24 @@ function RecordBreadcrumbs() {
|
|
|
2292
2309
|
action: route.action,
|
|
2293
2310
|
id,
|
|
2294
2311
|
title,
|
|
2295
|
-
groupChain
|
|
2312
|
+
groupChain,
|
|
2313
|
+
...withOrigin
|
|
2296
2314
|
}),
|
|
2315
|
+
...docScopes,
|
|
2297
2316
|
"data-testid": "record-breadcrumbs"
|
|
2298
2317
|
});
|
|
2299
2318
|
}
|
|
2300
2319
|
//#endregion
|
|
2301
2320
|
//#region src/layout/default-nav-layouts.ts
|
|
2302
|
-
const defaultNavLayouts = {
|
|
2303
|
-
[layoutSlot("secondary-sidebar")]: SecondarySidebarLayout,
|
|
2304
|
-
[layoutSlot("tabs")]: TabsLayout
|
|
2305
|
-
};
|
|
2321
|
+
const defaultNavLayouts = { ...BUILTIN_LAYOUTS };
|
|
2306
2322
|
//#endregion
|
|
2307
2323
|
//#region src/layout/context-picker.tsx
|
|
2308
|
-
|
|
2324
|
+
const ALL = "\0all";
|
|
2325
|
+
function ContextPicker({ sliceName, label, options, value, onChange, placeholder, disabled, className, hideLabel, allOption }) {
|
|
2309
2326
|
const tid = useTestIds();
|
|
2310
2327
|
const t = useOptionalT();
|
|
2328
|
+
const chromeT = useChromeT();
|
|
2329
|
+
const allLabel = typeof allOption === "string" ? allOption : chromeT("scope.all", { defaultValue: "All" });
|
|
2311
2330
|
const displayLabel = label ?? humanizeKey(sliceName);
|
|
2312
2331
|
return jsxs("div", {
|
|
2313
2332
|
className: cn("space-y-1", className),
|
|
@@ -2316,21 +2335,112 @@ function ContextPicker({ sliceName, label, options, value, onChange, placeholder
|
|
|
2316
2335
|
className: hideLabel ? "sr-only" : "text-xs font-medium text-muted-foreground uppercase tracking-wide",
|
|
2317
2336
|
children: displayLabel
|
|
2318
2337
|
}), jsxs(Select, {
|
|
2319
|
-
value: value ?? "",
|
|
2320
|
-
onValueChange:
|
|
2338
|
+
value: value ?? (allOption === void 0 ? "" : ALL),
|
|
2339
|
+
onValueChange: (next) => {
|
|
2340
|
+
if (allOption === void 0) onChange(next);
|
|
2341
|
+
else onChange(next === ALL ? null : next);
|
|
2342
|
+
},
|
|
2321
2343
|
disabled,
|
|
2322
2344
|
children: [jsx(SelectTrigger, {
|
|
2323
2345
|
id: `context-picker:${sliceName}`,
|
|
2324
2346
|
"data-testid": tid.contextPicker(sliceName),
|
|
2325
2347
|
className: cn("w-full", hideLabel ? "h-8 text-xs" : void 0),
|
|
2326
2348
|
children: jsx(SelectValue, { placeholder: placeholder ?? t("field.select", { defaultValue: "Select…" }) })
|
|
2327
|
-
}),
|
|
2349
|
+
}), jsxs(SelectContent, { children: [allOption === void 0 ? null : jsx(SelectItem, {
|
|
2350
|
+
value: ALL,
|
|
2351
|
+
"data-testid": tid.contextPickerOption(sliceName, "all"),
|
|
2352
|
+
children: allLabel
|
|
2353
|
+
}), options.map((o) => jsx(SelectItem, {
|
|
2328
2354
|
value: o.value,
|
|
2329
2355
|
"data-testid": tid.contextPickerOption(sliceName, o.value),
|
|
2330
2356
|
children: o.label
|
|
2331
|
-
}, o.value)) })]
|
|
2357
|
+
}, o.value))] })]
|
|
2358
|
+
})]
|
|
2359
|
+
});
|
|
2360
|
+
}
|
|
2361
|
+
//#endregion
|
|
2362
|
+
//#region src/layout/scope-dimension-picker.tsx
|
|
2363
|
+
function ScopeDimensionPicker(props) {
|
|
2364
|
+
const scope = useScope();
|
|
2365
|
+
const definition = scope.definition?.dimensions[props.dimension];
|
|
2366
|
+
if (definition === void 0) throw new Error(`ScopeDimensionPicker: '${props.dimension}' is not a dimension of the app's defineScope(...)`);
|
|
2367
|
+
if (definition.select === "none") return null;
|
|
2368
|
+
const source = definition.values;
|
|
2369
|
+
if (source === void 0) throw new Error(`ScopeDimensionPicker: dimension '${props.dimension}' declares no values; add values: { resource } or a { value, label } list`);
|
|
2370
|
+
const allowed = scope.access[props.dimension]?.allowed;
|
|
2371
|
+
const permitted = Array.isArray(allowed) ? allowed : void 0;
|
|
2372
|
+
const common = {
|
|
2373
|
+
...props,
|
|
2374
|
+
multiple: definition.select === "multiple",
|
|
2375
|
+
all: definition.all,
|
|
2376
|
+
selected: scope.selection[props.dimension] ?? null,
|
|
2377
|
+
select: (value) => scope.select(props.dimension, value)
|
|
2378
|
+
};
|
|
2379
|
+
if (Array.isArray(source)) {
|
|
2380
|
+
const options = source.filter((option) => permitted === void 0 || permitted.includes(option.value));
|
|
2381
|
+
return jsx(DimensionControl, {
|
|
2382
|
+
...common,
|
|
2383
|
+
options
|
|
2384
|
+
});
|
|
2385
|
+
}
|
|
2386
|
+
const { resource, label } = source;
|
|
2387
|
+
return jsx(ResourceDimension, {
|
|
2388
|
+
...common,
|
|
2389
|
+
resource,
|
|
2390
|
+
...label ? { labelField: label } : {}
|
|
2391
|
+
});
|
|
2392
|
+
}
|
|
2393
|
+
function ResourceDimension({ resource, labelField, ...rest }) {
|
|
2394
|
+
const options = useResourceDimensionOptions(rest.dimension, resource, labelField);
|
|
2395
|
+
return jsx(DimensionControl, {
|
|
2396
|
+
...rest,
|
|
2397
|
+
options
|
|
2398
|
+
});
|
|
2399
|
+
}
|
|
2400
|
+
function DimensionControl({ dimension, label, hideLabel, className, multiple, all, selected, select, options }) {
|
|
2401
|
+
const tid = useTestIds();
|
|
2402
|
+
const chromeT = useChromeT();
|
|
2403
|
+
const byText = useMemo(() => new Map(options.map((option) => [String(option.value), option.value])), [options]);
|
|
2404
|
+
const textOptions = useMemo(() => options.map((option) => ({
|
|
2405
|
+
value: String(option.value),
|
|
2406
|
+
label: option.label
|
|
2407
|
+
})), [options]);
|
|
2408
|
+
const picked = (Array.isArray(selected) ? selected : selected === null ? [] : [selected]).map(String);
|
|
2409
|
+
const text = label ?? humanizeKey(dimension);
|
|
2410
|
+
if (multiple) return jsxs("div", {
|
|
2411
|
+
className: cn("space-y-1", className),
|
|
2412
|
+
children: [jsx("span", {
|
|
2413
|
+
className: hideLabel ? "sr-only" : "text-xs font-medium text-muted-foreground uppercase tracking-wide",
|
|
2414
|
+
children: text
|
|
2415
|
+
}), jsx(FacetedFilterPicker, {
|
|
2416
|
+
title: text,
|
|
2417
|
+
options: textOptions,
|
|
2418
|
+
selected: picked,
|
|
2419
|
+
...all ? { emptyLabel: chromeT("scope.all", { defaultValue: "All" }) } : { clearable: false },
|
|
2420
|
+
onChange: (next) => {
|
|
2421
|
+
if (next.length === 0 && !all) return;
|
|
2422
|
+
select(next.length === 0 ? null : next.map((value) => byText.get(value) ?? value));
|
|
2423
|
+
},
|
|
2424
|
+
getTestId: (role, value) => role === "trigger" ? tid.contextPicker(dimension) : role === "option" ? tid.contextPickerOption(dimension, value ?? "") : role === "clear" ? tid.contextPickerOption(dimension, "all") : void 0
|
|
2332
2425
|
})]
|
|
2333
2426
|
});
|
|
2427
|
+
const common = {
|
|
2428
|
+
sliceName: dimension,
|
|
2429
|
+
...label === void 0 ? {} : { label },
|
|
2430
|
+
options: textOptions,
|
|
2431
|
+
value: picked[0] ?? null,
|
|
2432
|
+
...hideLabel === void 0 ? {} : { hideLabel },
|
|
2433
|
+
...className === void 0 ? {} : { className }
|
|
2434
|
+
};
|
|
2435
|
+
const choose = (value) => select(value === null ? null : byText.get(value) ?? value);
|
|
2436
|
+
return all ? jsx(ContextPicker, {
|
|
2437
|
+
...common,
|
|
2438
|
+
allOption: true,
|
|
2439
|
+
onChange: choose
|
|
2440
|
+
}) : jsx(ContextPicker, {
|
|
2441
|
+
...common,
|
|
2442
|
+
onChange: choose
|
|
2443
|
+
});
|
|
2334
2444
|
}
|
|
2335
2445
|
//#endregion
|
|
2336
2446
|
//#region src/layout/language-switch.tsx
|
|
@@ -2521,7 +2631,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2521
2631
|
const navigate = useRouteNavigate();
|
|
2522
2632
|
const isVisible = useNavVisible();
|
|
2523
2633
|
const resolveLayout = useLayoutResolver();
|
|
2524
|
-
const isResourceVisible = (
|
|
2634
|
+
const isResourceVisible = useResourceVisible();
|
|
2525
2635
|
const pageAllowed = usePageAllowed();
|
|
2526
2636
|
const isPageVisible = (p) => evaluateVisible(p.visible, visibilityCtx) && pageAllowed(p);
|
|
2527
2637
|
const { topLevelResources, topLevelPages, sectionGroups } = useMemo(() => {
|
|
@@ -2547,15 +2657,15 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2547
2657
|
}, [app, visibilityCtx]);
|
|
2548
2658
|
const goTo = (href) => {
|
|
2549
2659
|
onSelect?.();
|
|
2550
|
-
navigate(href);
|
|
2660
|
+
navigate(href, { origin: "jump" });
|
|
2551
2661
|
};
|
|
2552
|
-
const resourceLabel = (def) => resolveResourceLabel(caps, canonicalResourceKey(def), "plural", def);
|
|
2662
|
+
const resourceLabel = (def) => resolveResourceLabel(caps, canonicalResourceKey$1(def), "plural", def);
|
|
2553
2663
|
const pageLabel = (def) => resolveNavLabel(caps, `pages.${canonicalNavKey(def)}`, declaredText("chrome", def, "label"));
|
|
2554
2664
|
const groups = [];
|
|
2555
2665
|
if (topLevelResources.length > 0) groups.push(jsx(CommandGroup, {
|
|
2556
2666
|
heading: t("commandPalette.resources", { defaultValue: "Resources" }),
|
|
2557
2667
|
children: topLevelResources.map((def) => {
|
|
2558
|
-
const resource = canonicalResourceKey(def);
|
|
2668
|
+
const resource = canonicalResourceKey$1(def);
|
|
2559
2669
|
const label = resourceLabel(def);
|
|
2560
2670
|
const href = hrefFor(app.registry, resource, { isVisible });
|
|
2561
2671
|
return jsx(CommandItem, {
|
|
@@ -2604,7 +2714,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2604
2714
|
children: label
|
|
2605
2715
|
}, `section:${sectionKey}:page:${pageKey}`);
|
|
2606
2716
|
}
|
|
2607
|
-
const resource = canonicalResourceKey(child);
|
|
2717
|
+
const resource = canonicalResourceKey$1(child);
|
|
2608
2718
|
const label = resourceLabel(child);
|
|
2609
2719
|
const href = hrefFor(app.registry, resource, { isVisible });
|
|
2610
2720
|
return jsx(CommandItem, {
|
|
@@ -2656,7 +2766,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
|
|
|
2656
2766
|
const resource = child;
|
|
2657
2767
|
if (!hasListPage(resource)) continue;
|
|
2658
2768
|
if (!isResourceVisible(resource)) continue;
|
|
2659
|
-
const resourceId = canonicalResourceKey(resource);
|
|
2769
|
+
const resourceId = canonicalResourceKey$1(resource);
|
|
2660
2770
|
const label = resourceLabel(resource);
|
|
2661
2771
|
const href = hrefFor(app.registry, resourceId, { isVisible });
|
|
2662
2772
|
items.push(jsx(CommandItem, {
|
|
@@ -2695,10 +2805,10 @@ function opensInQuick(registry, resource, mode) {
|
|
|
2695
2805
|
}
|
|
2696
2806
|
//#endregion
|
|
2697
2807
|
//#region src/layout/command-palette-recent-group.tsx
|
|
2698
|
-
function entryHref(registry, entry,
|
|
2808
|
+
function entryHref(registry, entry, isResourceVisible) {
|
|
2699
2809
|
const def = registry.get(entry.canonicalRef);
|
|
2700
2810
|
if (def === void 0) return void 0;
|
|
2701
|
-
if (!
|
|
2811
|
+
if (!isResourceVisible(def)) return void 0;
|
|
2702
2812
|
for (const action of ["show", "edit"]) if (recordRouteAvailable(registry, entry.canonicalRef, action)) return hrefFor(registry, entry.canonicalRef, {
|
|
2703
2813
|
action,
|
|
2704
2814
|
id: entry.id
|
|
@@ -2712,34 +2822,46 @@ function CommandPaletteRecentGroup({ onSelect, getTestId, heading, refreshKey, w
|
|
|
2712
2822
|
const navigate = useRouteNavigate();
|
|
2713
2823
|
const quick = useQuick();
|
|
2714
2824
|
const userId = useCurrentUserId();
|
|
2715
|
-
const
|
|
2825
|
+
const isResourceVisible = useResourceVisible();
|
|
2716
2826
|
const resolvedHeading = heading ?? t("commandPalette.recent", { defaultValue: "Recent" });
|
|
2717
|
-
const
|
|
2827
|
+
const store = usePlatformStorage().local;
|
|
2828
|
+
const [stored, setStored] = useState([]);
|
|
2718
2829
|
useEffect(() => {
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2830
|
+
if (userId === null) {
|
|
2831
|
+
setStored([]);
|
|
2832
|
+
return;
|
|
2833
|
+
}
|
|
2834
|
+
let current = true;
|
|
2835
|
+
const read = readRecentRecords(store, userId);
|
|
2836
|
+
if (Array.isArray(read)) setStored(read);
|
|
2837
|
+
else read.then((entries) => {
|
|
2838
|
+
if (current) setStored(entries);
|
|
2839
|
+
}, () => void 0);
|
|
2840
|
+
return () => {
|
|
2841
|
+
current = false;
|
|
2842
|
+
};
|
|
2730
2843
|
}, [
|
|
2731
|
-
|
|
2844
|
+
store,
|
|
2732
2845
|
userId,
|
|
2733
|
-
refreshKey
|
|
2846
|
+
refreshKey
|
|
2847
|
+
]);
|
|
2848
|
+
const recents = useMemo(() => stored.flatMap((entry) => {
|
|
2849
|
+
const href = entryHref(app.registry, entry, isResourceVisible);
|
|
2850
|
+
return href === void 0 ? [] : [{
|
|
2851
|
+
entry,
|
|
2852
|
+
href
|
|
2853
|
+
}];
|
|
2854
|
+
}), [
|
|
2855
|
+
stored,
|
|
2734
2856
|
app.registry,
|
|
2735
|
-
|
|
2857
|
+
isResourceVisible
|
|
2736
2858
|
]);
|
|
2737
2859
|
if ((useCommandState((state) => state.search) ?? "").length > 0) return null;
|
|
2738
2860
|
if (recents.length === 0) return null;
|
|
2739
2861
|
const goTo = (href, entry) => {
|
|
2740
2862
|
onSelect?.();
|
|
2741
2863
|
if (href === null) quick.show(entry.canonicalRef, entry.id);
|
|
2742
|
-
else navigate(href);
|
|
2864
|
+
else navigate(href, { origin: "jump" });
|
|
2743
2865
|
};
|
|
2744
2866
|
return jsxs(Fragment, { children: [jsx(CommandGroup, {
|
|
2745
2867
|
heading: resolvedHeading,
|
|
@@ -2797,23 +2919,24 @@ function CommandPaletteRecordsGroup({ enabled = true, pageSize = 5, minQueryLeng
|
|
|
2797
2919
|
const t = useOptionalT();
|
|
2798
2920
|
const navigate = useRouteNavigate();
|
|
2799
2921
|
const quick = useQuick();
|
|
2922
|
+
const isResourceVisible = useResourceVisible();
|
|
2800
2923
|
const resolvedHeading = heading ?? t("commandPalette.records", { defaultValue: "Records" });
|
|
2801
2924
|
const liveQuery = useCommandState((state) => state.search) ?? "";
|
|
2802
2925
|
const debouncedQuery = useDebouncedValue(liveQuery, debounceMs);
|
|
2803
2926
|
const searchableResources = useMemo(() => {
|
|
2804
|
-
return app.registry.list().filter((r) => isShowAvailable(app.registry, canonicalResourceKey(r)) || opensInQuick(app.registry, canonicalResourceKey(r), "show")).map((def) => {
|
|
2927
|
+
return app.registry.list().filter((r) => isShowAvailable(app.registry, canonicalResourceKey$1(r)) || opensInQuick(app.registry, canonicalResourceKey$1(r), "show")).filter(isResourceVisible).map((def) => {
|
|
2805
2928
|
const displayField = resolveDisplayField(def);
|
|
2806
2929
|
return displayField ? {
|
|
2807
2930
|
def,
|
|
2808
2931
|
displayField
|
|
2809
2932
|
} : null;
|
|
2810
2933
|
}).filter((entry) => entry !== null);
|
|
2811
|
-
}, [app.registry]);
|
|
2934
|
+
}, [app.registry, isResourceVisible]);
|
|
2812
2935
|
if (!(enabled && debouncedQuery.length >= minQueryLength && searchableResources.length > 0)) return null;
|
|
2813
2936
|
const goTo = (href, resource, id) => {
|
|
2814
2937
|
onSelect?.();
|
|
2815
2938
|
if (href === null) quick.show(resource, id);
|
|
2816
|
-
else navigate(href);
|
|
2939
|
+
else navigate(href, { origin: "jump" });
|
|
2817
2940
|
};
|
|
2818
2941
|
return jsx(CommandGroup, {
|
|
2819
2942
|
heading: resolvedHeading,
|
|
@@ -2827,12 +2950,12 @@ function CommandPaletteRecordsGroup({ enabled = true, pageSize = 5, minQueryLeng
|
|
|
2827
2950
|
recordHref,
|
|
2828
2951
|
registry: app.registry,
|
|
2829
2952
|
getTestId
|
|
2830
|
-
}, canonicalResourceKey(def)))
|
|
2953
|
+
}, canonicalResourceKey$1(def)))
|
|
2831
2954
|
}, "records");
|
|
2832
2955
|
}
|
|
2833
2956
|
function PerResourceSearchHits({ def, displayField, query, pageSize, goTo, recordHref, registry, getTestId }) {
|
|
2834
2957
|
const caps = useI18nCaps();
|
|
2835
|
-
const resource = canonicalResourceKey(def);
|
|
2958
|
+
const resource = canonicalResourceKey$1(def);
|
|
2836
2959
|
const access = useListAccess(resource);
|
|
2837
2960
|
const titleVisible = access.status === "ready" && access.fieldVisible(displayField);
|
|
2838
2961
|
const shouldFetch = query.length > 0 && titleVisible;
|
|
@@ -2851,28 +2974,40 @@ function PerResourceSearchHits({ def, displayField, query, pageSize, goTo, recor
|
|
|
2851
2974
|
enabled: shouldFetch
|
|
2852
2975
|
});
|
|
2853
2976
|
const report = useCommandPaletteResults(`records:${resource}`);
|
|
2977
|
+
const rowSubtitle = useRowSubtitle(resource);
|
|
2854
2978
|
const rows = !shouldFetch || q.isLoading || q.isError ? [] : q.data?.data ?? [];
|
|
2855
2979
|
useEffect(() => {
|
|
2856
2980
|
report(rows.length);
|
|
2857
2981
|
}, [report, rows.length]);
|
|
2858
2982
|
if (rows.length === 0) return null;
|
|
2859
|
-
const resourceLabel = resolveResourceLabel(caps, canonicalResourceKey(def), "single", def);
|
|
2983
|
+
const resourceLabel = resolveResourceLabel(caps, canonicalResourceKey$1(def), "single", def);
|
|
2984
|
+
const declaredIdField = def.data?.idField;
|
|
2985
|
+
const idField = typeof declaredIdField === "string" && declaredIdField.length > 0 ? declaredIdField : "id";
|
|
2860
2986
|
return jsx(Fragment$1, { children: rows.map((row) => {
|
|
2861
|
-
const idVal = row.id ?? row.event_id ?? row.job_id;
|
|
2987
|
+
const idVal = row[idField] ?? row.id ?? row.event_id ?? row.job_id;
|
|
2862
2988
|
const id = idVal == null ? "" : String(idVal);
|
|
2863
2989
|
if (!id) return null;
|
|
2864
2990
|
const display = titleVisible ? row[displayField] : void 0;
|
|
2865
2991
|
const labelText = typeof display === "string" && display.length > 0 ? display : id;
|
|
2992
|
+
const subtitle = rowSubtitle(row) ?? null;
|
|
2866
2993
|
const href = recordHref ? recordHref(resource, id) : isShowAvailable(registry, resource) ? resourceShowHref(registry, def, resource, id) : null;
|
|
2867
2994
|
return jsxs(CommandItem, {
|
|
2868
2995
|
value: `record:${resource}:${id}:${labelText}`,
|
|
2869
2996
|
forceMount: true,
|
|
2870
2997
|
onSelect: () => goTo(href, resource, id),
|
|
2871
2998
|
"data-testid": getTestId?.("records-record", `${resource}:${id}`),
|
|
2872
|
-
children: [
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2999
|
+
children: [
|
|
3000
|
+
jsxs("span", {
|
|
3001
|
+
className: "text-muted-foreground group-data-[selected=true]:text-accent-foreground mr-2",
|
|
3002
|
+
children: [resourceLabel, ":"]
|
|
3003
|
+
}),
|
|
3004
|
+
labelText,
|
|
3005
|
+
subtitle === null ? null : jsx("span", {
|
|
3006
|
+
"data-buro-region": "record-subtitle",
|
|
3007
|
+
className: "ml-auto truncate pl-2 text-xs text-muted-foreground group-data-[selected=true]:text-accent-foreground",
|
|
3008
|
+
children: subtitle
|
|
3009
|
+
})
|
|
3010
|
+
]
|
|
2876
3011
|
}, `record:${resource}:${id}`);
|
|
2877
3012
|
}) });
|
|
2878
3013
|
}
|
|
@@ -3003,7 +3138,7 @@ function CommandPaletteActionsGroup({ actions, onSelect, getTestId, heading }) {
|
|
|
3003
3138
|
function CommandPaletteCreateGroup({ resourceFilter, onSelect, getTestId, heading, createHref, prefix }) {
|
|
3004
3139
|
const caps = useI18nCaps();
|
|
3005
3140
|
const app = useApp();
|
|
3006
|
-
const
|
|
3141
|
+
const isResourceVisible = useResourceVisible();
|
|
3007
3142
|
const gate = useAvailabilityGate();
|
|
3008
3143
|
const t = useOptionalT();
|
|
3009
3144
|
const navigate = useRouteNavigate();
|
|
@@ -3011,16 +3146,16 @@ function CommandPaletteCreateGroup({ resourceFilter, onSelect, getTestId, headin
|
|
|
3011
3146
|
const resolvedHeading = heading ?? t("commandPalette.create", { defaultValue: "Create" });
|
|
3012
3147
|
const resolvedPrefix = prefix ?? t("commandPalette.createNew", { defaultValue: "Create new" });
|
|
3013
3148
|
const visibleResources = useMemo(() => {
|
|
3014
|
-
return app.registry.list().filter((r) => hasListPage(r)).filter((r) => gate(canonicalResourceKey(r), "create").state === "available").filter((r) => hasRecordPage(r, "create") || opensInQuick(app.registry, canonicalResourceKey(r), "create")).filter(
|
|
3149
|
+
return app.registry.list().filter((r) => hasListPage(r)).filter((r) => gate(canonicalResourceKey$1(r), "create").state === "available").filter((r) => hasRecordPage(r, "create") || opensInQuick(app.registry, canonicalResourceKey$1(r), "create")).filter(isResourceVisible).filter((r) => resourceFilter ? resourceFilter(r) : true);
|
|
3015
3150
|
}, [
|
|
3016
3151
|
app,
|
|
3017
3152
|
gate,
|
|
3018
|
-
|
|
3153
|
+
isResourceVisible,
|
|
3019
3154
|
resourceFilter
|
|
3020
3155
|
]);
|
|
3021
3156
|
if (visibleResources.length === 0) return null;
|
|
3022
3157
|
const goTo = (href) => {
|
|
3023
|
-
navigate(href);
|
|
3158
|
+
navigate(href, { origin: "jump" });
|
|
3024
3159
|
onSelect?.();
|
|
3025
3160
|
};
|
|
3026
3161
|
const createIn = (def, href) => {
|
|
@@ -3029,13 +3164,13 @@ function CommandPaletteCreateGroup({ resourceFilter, onSelect, getTestId, headin
|
|
|
3029
3164
|
return;
|
|
3030
3165
|
}
|
|
3031
3166
|
onSelect?.();
|
|
3032
|
-
quick.create(canonicalResourceKey(def));
|
|
3167
|
+
quick.create(canonicalResourceKey$1(def));
|
|
3033
3168
|
};
|
|
3034
|
-
const resourceLabel = (def) => resolveResourceLabel(caps, canonicalResourceKey(def), "single", def);
|
|
3169
|
+
const resourceLabel = (def) => resolveResourceLabel(caps, canonicalResourceKey$1(def), "single", def);
|
|
3035
3170
|
return jsx(CommandGroup, {
|
|
3036
3171
|
heading: resolvedHeading,
|
|
3037
3172
|
children: visibleResources.map((def) => {
|
|
3038
|
-
const resource = canonicalResourceKey(def);
|
|
3173
|
+
const resource = canonicalResourceKey$1(def);
|
|
3039
3174
|
const label = resourceLabel(def);
|
|
3040
3175
|
const href = createHref?.(def) ?? resourceCreateHref(app.registry, def, resource);
|
|
3041
3176
|
const value = `create:${resource}:${resolvedPrefix}:${label}`;
|
|
@@ -3097,7 +3232,7 @@ function AppActions() {
|
|
|
3097
3232
|
variant: "outline",
|
|
3098
3233
|
size: "sm",
|
|
3099
3234
|
disabled: action.disabledReason !== void 0,
|
|
3100
|
-
title: action.disabledReason,
|
|
3235
|
+
title: action.disabledReason === void 0 ? void 0 : reasonText(caps, action.disabledReason),
|
|
3101
3236
|
"data-testid": `app-action:${action.name}`,
|
|
3102
3237
|
children: action.disabledReason === void 0 ? jsx(RouterLink, {
|
|
3103
3238
|
href,
|
|
@@ -3219,6 +3354,7 @@ function localizedSchema(t) {
|
|
|
3219
3354
|
function LoginForm({ onSubmit, title, description, className }) {
|
|
3220
3355
|
const tid = useTestIds();
|
|
3221
3356
|
const t = useOptionalT();
|
|
3357
|
+
const caps = useI18nCaps();
|
|
3222
3358
|
const resolvedTitle = title ?? t("auth.signIn", { defaultValue: "Sign in" });
|
|
3223
3359
|
const { register, handleSubmit, formState: { errors, isSubmitting } } = useForm({
|
|
3224
3360
|
resolver: zodResolver(localizedSchema(t)),
|
|
@@ -3233,9 +3369,11 @@ function LoginForm({ onSubmit, title, description, className }) {
|
|
|
3233
3369
|
try {
|
|
3234
3370
|
await onSubmit(values);
|
|
3235
3371
|
} catch (e) {
|
|
3236
|
-
const
|
|
3372
|
+
const dataCode = e !== null && typeof e === "object" && !(e instanceof Error) ? e.code : void 0;
|
|
3373
|
+
const raw = e instanceof Error ? e.message : technicalText(e) ?? (dataCode === void 0 ? String(e) : "");
|
|
3237
3374
|
const friendly = toFriendlyError(raw, "", friendlyStringsFrom(t));
|
|
3238
|
-
|
|
3375
|
+
const credentials = credentialsMessage(raw, t);
|
|
3376
|
+
setSubmitError(friendly.replaced ? `${friendly.title}. ${friendly.detail}` : typeof dataCode === "string" && credentials === raw ? resolveErrorText(e, caps) : credentials);
|
|
3239
3377
|
}
|
|
3240
3378
|
});
|
|
3241
3379
|
return jsxs(Card, {
|
|
@@ -3360,15 +3498,139 @@ function AuthPage({ children, brand, footer, className }) {
|
|
|
3360
3498
|
});
|
|
3361
3499
|
}
|
|
3362
3500
|
//#endregion
|
|
3501
|
+
//#region src/enum/enum-choice-group.tsx
|
|
3502
|
+
const NONE = "__none__";
|
|
3503
|
+
function isEmpty$1(value) {
|
|
3504
|
+
return value === null || value === void 0 || value === "";
|
|
3505
|
+
}
|
|
3506
|
+
function EnumChoiceGroup({ control, options, current, settling, value, onChange, testid, name, id, required, disabled, ariaInvalid, ariaDescribedBy, ariaErrorMessage, ariaLabelledBy, className }) {
|
|
3507
|
+
const t = useOptionalT();
|
|
3508
|
+
const generatedName = React.useId();
|
|
3509
|
+
const groupName = name ?? generatedName;
|
|
3510
|
+
const empty = isEmpty$1(value);
|
|
3511
|
+
const noneLabel = t("field.none", { defaultValue: "None" });
|
|
3512
|
+
const pick = (next) => {
|
|
3513
|
+
if (!disabled) onChange(next);
|
|
3514
|
+
};
|
|
3515
|
+
const ariaProps = {
|
|
3516
|
+
"aria-invalid": ariaInvalid || void 0,
|
|
3517
|
+
"aria-describedby": ariaDescribedBy,
|
|
3518
|
+
...ariaErrorMessage ? { "aria-errormessage": ariaErrorMessage } : {}
|
|
3519
|
+
};
|
|
3520
|
+
if (control === "segmented") {
|
|
3521
|
+
const segmentLabel = (option) => jsxs(Fragment$1, { children: [option.icon ? jsx("span", {
|
|
3522
|
+
"data-testid": `${testid}:option:${option.value}:icon`,
|
|
3523
|
+
className: "contents",
|
|
3524
|
+
children: jsx(Icon, {
|
|
3525
|
+
name: option.icon,
|
|
3526
|
+
className: "size-3.5 shrink-0"
|
|
3527
|
+
})
|
|
3528
|
+
}) : null, option.label] });
|
|
3529
|
+
const segment = (key, label, active, select, currentItem = false) => jsx("button", {
|
|
3530
|
+
type: "button",
|
|
3531
|
+
"aria-pressed": active,
|
|
3532
|
+
"data-state": active ? "active" : "inactive",
|
|
3533
|
+
"data-testid": currentItem ? `${testid}:current` : `${testid}:option:${key}`,
|
|
3534
|
+
...currentItem ? { "data-current": "" } : {},
|
|
3535
|
+
disabled: disabled || currentItem,
|
|
3536
|
+
onClick: select,
|
|
3537
|
+
className: cn("inline-flex items-center justify-center gap-1.5 whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium transition-all", "data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-xs", "disabled:pointer-events-none disabled:opacity-50", "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"),
|
|
3538
|
+
children: label
|
|
3539
|
+
}, currentItem ? `current:${key}` : key);
|
|
3540
|
+
return jsxs("div", {
|
|
3541
|
+
role: "group",
|
|
3542
|
+
id,
|
|
3543
|
+
"aria-labelledby": ariaLabelledBy,
|
|
3544
|
+
"data-testid": testid,
|
|
3545
|
+
className: cn("inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground", className),
|
|
3546
|
+
...ariaProps,
|
|
3547
|
+
children: [
|
|
3548
|
+
current === void 0 ? null : segment(current.value, segmentLabel(current), true, () => void 0, true),
|
|
3549
|
+
required || settling !== void 0 ? null : segment(NONE, noneLabel, empty, () => pick(void 0)),
|
|
3550
|
+
settling === void 0 ? null : jsx(EnumSettlingRow, {
|
|
3551
|
+
status: settling,
|
|
3552
|
+
testid
|
|
3553
|
+
}),
|
|
3554
|
+
options.map((option) => segment(option.value, segmentLabel(option), value === option.value, () => pick(option.value)))
|
|
3555
|
+
]
|
|
3556
|
+
});
|
|
3557
|
+
}
|
|
3558
|
+
const cards = control === "cards";
|
|
3559
|
+
const choice = (key, option, label, checked, select, currentItem = false) => {
|
|
3560
|
+
const inputId = `${id ?? groupName}:${currentItem ? "current:" : ""}${key}`;
|
|
3561
|
+
const inert = disabled || currentItem;
|
|
3562
|
+
return jsxs("label", {
|
|
3563
|
+
htmlFor: inputId,
|
|
3564
|
+
className: cn("flex items-start gap-2.5", cards && "cursor-pointer rounded-lg border px-3 py-2.5 transition-colors hover:bg-accent/50 has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-ring", cards && (checked ? "border-primary" : "border-input"), inert && "cursor-not-allowed opacity-60"),
|
|
3565
|
+
children: [jsx("input", {
|
|
3566
|
+
type: "radio",
|
|
3567
|
+
id: inputId,
|
|
3568
|
+
name: groupName,
|
|
3569
|
+
value: key,
|
|
3570
|
+
checked,
|
|
3571
|
+
onChange: select,
|
|
3572
|
+
disabled: inert,
|
|
3573
|
+
...ariaProps,
|
|
3574
|
+
"data-testid": currentItem ? `${testid}:current` : `${testid}:option:${key}`,
|
|
3575
|
+
...currentItem ? { "data-current": "" } : {},
|
|
3576
|
+
className: cn("h-4 w-4 shrink-0 accent-primary", cards ? "mt-0.5" : "mt-1")
|
|
3577
|
+
}), jsxs("span", {
|
|
3578
|
+
className: "flex min-w-0 flex-col gap-0.5",
|
|
3579
|
+
children: [jsxs("span", {
|
|
3580
|
+
className: cn("flex items-center gap-1.5", cards && "font-medium"),
|
|
3581
|
+
children: [option?.icon ? jsx("span", {
|
|
3582
|
+
"data-testid": `${testid}:option:${key}:icon`,
|
|
3583
|
+
className: "contents",
|
|
3584
|
+
children: jsx(Icon, {
|
|
3585
|
+
name: option.icon,
|
|
3586
|
+
className: "size-4 shrink-0"
|
|
3587
|
+
})
|
|
3588
|
+
}) : null, jsx("span", { children: label })]
|
|
3589
|
+
}), option?.summary === void 0 || option.summary === "" ? null : jsx("span", {
|
|
3590
|
+
"data-testid": `${testid}:option:${key}:doc`,
|
|
3591
|
+
className: "text-sm text-muted-foreground",
|
|
3592
|
+
children: option.summary
|
|
3593
|
+
})]
|
|
3594
|
+
})]
|
|
3595
|
+
}, currentItem ? `current:${key}` : key);
|
|
3596
|
+
};
|
|
3597
|
+
return jsxs("div", {
|
|
3598
|
+
role: "radiogroup",
|
|
3599
|
+
id,
|
|
3600
|
+
"aria-labelledby": ariaLabelledBy,
|
|
3601
|
+
"data-testid": testid,
|
|
3602
|
+
"aria-required": required,
|
|
3603
|
+
className: cn("flex flex-col", cards ? "gap-2" : "gap-1.5", className),
|
|
3604
|
+
children: [
|
|
3605
|
+
current === void 0 ? null : choice(current.value, current, current.label, true, () => void 0, true),
|
|
3606
|
+
required || settling !== void 0 ? null : choice(NONE, void 0, noneLabel, empty, () => pick(void 0)),
|
|
3607
|
+
settling === void 0 ? null : jsx(EnumSettlingRow, {
|
|
3608
|
+
status: settling,
|
|
3609
|
+
testid
|
|
3610
|
+
}),
|
|
3611
|
+
options.map((option) => choice(option.value, option, option.label, value === option.value, () => pick(option.value)))
|
|
3612
|
+
]
|
|
3613
|
+
});
|
|
3614
|
+
}
|
|
3615
|
+
//#endregion
|
|
3363
3616
|
//#region src/enum/enum-picker.tsx
|
|
3364
3617
|
const ENUM_PICKER_CLEAR_SENTINEL = "__buro_clear__";
|
|
3365
|
-
function
|
|
3618
|
+
function withSummary(summary) {
|
|
3619
|
+
return summary === void 0 ? {} : { summary };
|
|
3620
|
+
}
|
|
3621
|
+
function EnumPicker({ enumName: enumInput, value, onChange, control = "select", name, id, testid, placeholder, disabled, required, ariaInvalid, ariaDescribedBy, ariaErrorMessage, ariaLabelledBy, className, clearable = false, clearLabel = "All", use }) {
|
|
3622
|
+
const enumName = enumBindingKey(enumInput) ?? "";
|
|
3366
3623
|
const app = useApp();
|
|
3367
3624
|
const t = useOptionalT();
|
|
3368
3625
|
const def = app.registry.enums.get(enumName);
|
|
3369
3626
|
const caps = useI18nCaps();
|
|
3370
3627
|
const ns = def?.i18nNamespace ?? enumName;
|
|
3371
3628
|
const { values, isLoading, error } = useEnumValues(enumName);
|
|
3629
|
+
const available = useAvailableEnumValues({
|
|
3630
|
+
values: isLoading || values === void 0 ? "pending" : values,
|
|
3631
|
+
...def === void 0 ? {} : { enum: def },
|
|
3632
|
+
...use === void 0 ? {} : { use }
|
|
3633
|
+
});
|
|
3372
3634
|
const tid = testid ?? `enum-picker:${enumName}`;
|
|
3373
3635
|
if (!def) return jsxs("span", {
|
|
3374
3636
|
"data-testid": `${tid}:unregistered`,
|
|
@@ -3393,63 +3655,56 @@ function EnumPicker({ enumName, value, onChange, renderAs = "select", name, id,
|
|
|
3393
3655
|
children: jsx(SelectValue, { placeholder: t("field.loading", { defaultValue: "Loading…" }) })
|
|
3394
3656
|
}), jsx(SelectContent, {})]
|
|
3395
3657
|
});
|
|
3396
|
-
if (error || !values) return jsxs(
|
|
3397
|
-
"
|
|
3658
|
+
if (error || !values) return jsxs(LoadError, {
|
|
3659
|
+
surface: "picker",
|
|
3660
|
+
error,
|
|
3661
|
+
testId: `${tid}:error`,
|
|
3398
3662
|
className: "text-muted-foreground",
|
|
3399
|
-
|
|
3663
|
+
fallback: {
|
|
3664
|
+
key: "relation.failed",
|
|
3665
|
+
default: "Failed to load options."
|
|
3666
|
+
},
|
|
3400
3667
|
children: [
|
|
3401
3668
|
"(failed to load enum ‘",
|
|
3402
3669
|
enumName,
|
|
3403
3670
|
"’)"
|
|
3404
3671
|
]
|
|
3405
3672
|
});
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
const isActive = value === entry.value;
|
|
3442
|
-
return jsx("button", {
|
|
3443
|
-
type: "button",
|
|
3444
|
-
"aria-pressed": isActive,
|
|
3445
|
-
"data-state": isActive ? "active" : "inactive",
|
|
3446
|
-
"data-testid": `${tid}:option:${entry.value}`,
|
|
3447
|
-
disabled,
|
|
3448
|
-
onClick: () => onChange(entry.value),
|
|
3449
|
-
className: cn("inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium transition-all", "data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-xs", "disabled:pointer-events-none disabled:opacity-50", "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"),
|
|
3450
|
-
children: resolveEnumLabel(caps, ns, entry.value, enumValueText(def, entry.value) ?? entry.label)
|
|
3451
|
-
}, entry.value);
|
|
3452
|
-
})
|
|
3673
|
+
const labelOf = (entry) => resolveEnumLabel(caps, ns, entry.value, enumValueText(def, entry.value) ?? entry.label);
|
|
3674
|
+
const summaryOf = (entry) => resolveDoc(caps, `enum/${ns}/${entry.value}`)?.summary || void 0;
|
|
3675
|
+
const settling = available.status === "ready" ? void 0 : available.status;
|
|
3676
|
+
const offered = settling === void 0 ? available.values : [];
|
|
3677
|
+
const known = value == null ? void 0 : values.find((entry) => entry.value === value);
|
|
3678
|
+
const current = value == null || value === "" || offered.some((entry) => entry.value === value) ? void 0 : known === void 0 ? {
|
|
3679
|
+
value,
|
|
3680
|
+
label: unknownEnumValueLabel(caps, def, ns, value).label
|
|
3681
|
+
} : {
|
|
3682
|
+
value,
|
|
3683
|
+
label: labelOf(known),
|
|
3684
|
+
...known.icon === void 0 ? {} : { icon: known.icon }
|
|
3685
|
+
};
|
|
3686
|
+
if (control !== "select") return jsx(EnumChoiceGroup, {
|
|
3687
|
+
control,
|
|
3688
|
+
...current === void 0 ? {} : { current },
|
|
3689
|
+
...settling === void 0 ? {} : { settling },
|
|
3690
|
+
options: offered.map((entry) => ({
|
|
3691
|
+
value: entry.value,
|
|
3692
|
+
label: labelOf(entry),
|
|
3693
|
+
...entry.icon === void 0 ? {} : { icon: entry.icon },
|
|
3694
|
+
...withSummary(summaryOf(entry))
|
|
3695
|
+
})),
|
|
3696
|
+
value,
|
|
3697
|
+
onChange,
|
|
3698
|
+
testid: tid,
|
|
3699
|
+
name,
|
|
3700
|
+
id,
|
|
3701
|
+
required,
|
|
3702
|
+
disabled,
|
|
3703
|
+
ariaInvalid,
|
|
3704
|
+
ariaDescribedBy,
|
|
3705
|
+
ariaErrorMessage,
|
|
3706
|
+
ariaLabelledBy,
|
|
3707
|
+
className
|
|
3453
3708
|
});
|
|
3454
3709
|
const selectValue = value == null ? clearable ? ENUM_PICKER_CLEAR_SENTINEL : "" : value;
|
|
3455
3710
|
const handleValueChange = (next) => {
|
|
@@ -3469,46 +3724,74 @@ function EnumPicker({ enumName, value, onChange, renderAs = "select", name, id,
|
|
|
3469
3724
|
name,
|
|
3470
3725
|
id,
|
|
3471
3726
|
"aria-required": required,
|
|
3727
|
+
"aria-busy": settling === "pending" || void 0,
|
|
3472
3728
|
"aria-invalid": ariaInvalid || void 0,
|
|
3473
3729
|
"aria-describedby": ariaDescribedBy,
|
|
3474
3730
|
...ariaErrorMessage ? { "aria-errormessage": ariaErrorMessage } : {},
|
|
3475
3731
|
className,
|
|
3476
3732
|
children: jsx(SelectValue, { placeholder: placeholder ?? t("field.select", { defaultValue: "Select…" }) })
|
|
3477
|
-
}), jsxs(SelectContent, { children: [
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
"data-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3733
|
+
}), jsxs(SelectContent, { children: [
|
|
3734
|
+
clearable && jsx(SelectItem, {
|
|
3735
|
+
value: "__buro_clear__",
|
|
3736
|
+
"data-testid": `${tid}:option:__clear__`,
|
|
3737
|
+
children: clearLabel
|
|
3738
|
+
}),
|
|
3739
|
+
current === void 0 ? null : jsx(SelectItem, {
|
|
3740
|
+
value: current.value,
|
|
3741
|
+
disabled: true,
|
|
3742
|
+
"data-current": "",
|
|
3743
|
+
"data-testid": `${tid}:current`,
|
|
3744
|
+
children: current.label
|
|
3745
|
+
}),
|
|
3746
|
+
settling === void 0 ? null : jsx(EnumSettlingRow, {
|
|
3747
|
+
status: settling,
|
|
3748
|
+
testid: tid
|
|
3749
|
+
}),
|
|
3750
|
+
offered.map((entry) => {
|
|
3751
|
+
const optionLabel = labelOf(entry);
|
|
3752
|
+
const optionDoc = summaryOf(entry);
|
|
3753
|
+
return jsx(SelectItem, {
|
|
3754
|
+
value: entry.value,
|
|
3755
|
+
"data-testid": `${tid}:option:${entry.value}`,
|
|
3756
|
+
description: optionDoc === void 0 ? void 0 : jsx("span", {
|
|
3491
3757
|
"data-testid": `${tid}:option:${entry.value}:doc`,
|
|
3492
3758
|
children: optionDoc
|
|
3493
|
-
})
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3759
|
+
}),
|
|
3760
|
+
children: optionLabel
|
|
3761
|
+
}, entry.value);
|
|
3762
|
+
})
|
|
3763
|
+
] })]
|
|
3497
3764
|
});
|
|
3498
3765
|
}
|
|
3499
3766
|
//#endregion
|
|
3767
|
+
//#region src/enum/resolve-enum-control.ts
|
|
3768
|
+
const warned = new Set();
|
|
3769
|
+
function resolveEnumControl(fieldControl, enumDef, where) {
|
|
3770
|
+
if (isEnumControl(fieldControl)) return fieldControl;
|
|
3771
|
+
if (fieldControl !== void 0) {
|
|
3772
|
+
const shown = typeof fieldControl === "string" ? `'${fieldControl}'` : String(fieldControl);
|
|
3773
|
+
const key = `${where}\u0000${shown}`;
|
|
3774
|
+
if (!warned.has(key)) {
|
|
3775
|
+
warned.add(key);
|
|
3776
|
+
console.warn(`[buro/ui-shadcn] ${where}: unknown enum control ${shown}; expected one of ${ENUM_CONTROLS.map((control) => `'${control}'`).join(", ")}. Using the enum's control, else 'select'.`);
|
|
3777
|
+
}
|
|
3778
|
+
}
|
|
3779
|
+
return enumDef?.control ?? "select";
|
|
3780
|
+
}
|
|
3781
|
+
//#endregion
|
|
3500
3782
|
//#region src/forms/issue-severity.ts
|
|
3501
3783
|
function isErrorIssue(issue) {
|
|
3502
3784
|
return issue.severity === "error";
|
|
3503
3785
|
}
|
|
3504
3786
|
//#endregion
|
|
3505
3787
|
//#region src/fields/boolean.tsx
|
|
3506
|
-
function BooleanDisplay({ value }) {
|
|
3788
|
+
function BooleanDisplay({ value, text }) {
|
|
3507
3789
|
const t = useOptionalT();
|
|
3508
3790
|
if (value == null) return jsx("span", {
|
|
3509
3791
|
className: "text-muted-foreground",
|
|
3510
3792
|
children: "—"
|
|
3511
3793
|
});
|
|
3794
|
+
if (text !== void 0) return jsx("span", { children: text });
|
|
3512
3795
|
return jsx("span", { children: value ? t("boolean.yes", { defaultValue: "Yes" }) : t("boolean.no", { defaultValue: "No" }) });
|
|
3513
3796
|
}
|
|
3514
3797
|
function BooleanInput({ name, id, value, onChange, testid, disabled, required, ariaInvalid, ariaDescribedBy, ariaErrorMessage }) {
|
|
@@ -3527,34 +3810,113 @@ function BooleanInput({ name, id, value, onChange, testid, disabled, required, a
|
|
|
3527
3810
|
}
|
|
3528
3811
|
//#endregion
|
|
3529
3812
|
//#region src/fields/date.tsx
|
|
3530
|
-
function DateDisplay(
|
|
3813
|
+
function DateDisplay(props) {
|
|
3814
|
+
return jsx(TemporalDisplay, {
|
|
3815
|
+
kind: "date",
|
|
3816
|
+
...props
|
|
3817
|
+
});
|
|
3818
|
+
}
|
|
3819
|
+
function DateTimeDisplay(props) {
|
|
3820
|
+
return jsx(TemporalDisplay, {
|
|
3821
|
+
kind: "dateTime",
|
|
3822
|
+
...props
|
|
3823
|
+
});
|
|
3824
|
+
}
|
|
3825
|
+
function TimeDisplay(props) {
|
|
3826
|
+
return jsx(TemporalDisplay, {
|
|
3827
|
+
kind: "time",
|
|
3828
|
+
...props
|
|
3829
|
+
});
|
|
3830
|
+
}
|
|
3831
|
+
function storedText(value) {
|
|
3832
|
+
return value instanceof Date && !Number.isNaN(value.getTime()) ? value.toISOString() : String(value);
|
|
3833
|
+
}
|
|
3834
|
+
function TemporalDisplay({ kind, value, text, field, record }) {
|
|
3531
3835
|
const locale = useOptionalLocale();
|
|
3836
|
+
const zone = useFieldTimeZone(field?.zone, record);
|
|
3837
|
+
const viewer = useTimeZone();
|
|
3532
3838
|
if (value == null || value === "") return jsx("span", {
|
|
3533
3839
|
className: "text-muted-foreground",
|
|
3534
3840
|
children: "—"
|
|
3535
3841
|
});
|
|
3536
|
-
|
|
3537
|
-
|
|
3842
|
+
if (zone.status === "pending" || viewer.status === "pending") return jsx(Skeleton, {
|
|
3843
|
+
className: "h-4 w-24",
|
|
3844
|
+
"aria-busy": "true"
|
|
3845
|
+
});
|
|
3846
|
+
const raw = storedText(value);
|
|
3847
|
+
const formatted = formatTimeValue(kind, raw, {
|
|
3848
|
+
zone: zone.zone,
|
|
3849
|
+
viewerZone: viewer.zone,
|
|
3850
|
+
locale: localeTag(locale),
|
|
3851
|
+
params: {
|
|
3852
|
+
...kind === "time" && field?.ui?.seconds === true ? { timeStyle: "medium" } : {},
|
|
3853
|
+
...dateDisplayParams(field?.ui)
|
|
3854
|
+
}
|
|
3855
|
+
});
|
|
3856
|
+
if (text !== void 0) return jsx("span", {
|
|
3857
|
+
title: formatted,
|
|
3858
|
+
children: text
|
|
3859
|
+
});
|
|
3860
|
+
if (formatted === void 0) return jsx("span", { children: raw });
|
|
3538
3861
|
return jsx("span", {
|
|
3539
3862
|
className: "whitespace-nowrap",
|
|
3540
|
-
children:
|
|
3863
|
+
children: formatted
|
|
3541
3864
|
});
|
|
3542
3865
|
}
|
|
3543
3866
|
function toIsoDate(v) {
|
|
3544
3867
|
if (v == null || v === "") return "";
|
|
3545
3868
|
const s = String(v);
|
|
3546
|
-
|
|
3547
|
-
const d = new Date(s);
|
|
3548
|
-
if (Number.isNaN(d.getTime())) return "";
|
|
3549
|
-
return d.toISOString().slice(0, 10);
|
|
3869
|
+
return isCalendarDate(s) ? s : "";
|
|
3550
3870
|
}
|
|
3551
|
-
function DateInput(
|
|
3552
|
-
return jsx(
|
|
3871
|
+
function DateInput(props) {
|
|
3872
|
+
return jsx(TemporalInput, {
|
|
3873
|
+
...props,
|
|
3874
|
+
type: "date",
|
|
3875
|
+
toText: toIsoDate,
|
|
3876
|
+
fromText: (text) => text || null
|
|
3877
|
+
});
|
|
3878
|
+
}
|
|
3879
|
+
function DateTimeInput(props) {
|
|
3880
|
+
const locale = useOptionalLocale();
|
|
3881
|
+
const zone = useFieldTimeZone(props.field?.zone, props.values === void 0 ? props.record : {
|
|
3882
|
+
...props.record,
|
|
3883
|
+
...props.values
|
|
3884
|
+
});
|
|
3885
|
+
const viewer = useTimeZone();
|
|
3886
|
+
const pending = zone.status === "pending";
|
|
3887
|
+
const fieldZone = zone.status === "ready" ? zone.zone : void 0;
|
|
3888
|
+
const named = fieldZone !== void 0 && viewer.status === "ready" && fieldZone !== viewer.zone ? zoneShortName(canonicalInstant(String(props.value ?? "")) ?? epochMsToInstant(Date.now()), fieldZone, localeTag(locale)) : void 0;
|
|
3889
|
+
return jsx(TemporalInput, {
|
|
3890
|
+
...props,
|
|
3891
|
+
type: "datetime-local",
|
|
3892
|
+
disabled: props.disabled || pending,
|
|
3893
|
+
toText: (value) => fieldZone === void 0 ? "" : toLocalDateTimeText(value, fieldZone),
|
|
3894
|
+
fromText: (text) => fieldZone === void 0 ? null : fromLocalDateTimeText(text, fieldZone) ?? null,
|
|
3895
|
+
...named === void 0 ? {} : { zoneName: named }
|
|
3896
|
+
});
|
|
3897
|
+
}
|
|
3898
|
+
function TimeInput(props) {
|
|
3899
|
+
const seconds = props.field?.ui?.seconds === true;
|
|
3900
|
+
return jsx(TemporalInput, {
|
|
3901
|
+
...props,
|
|
3902
|
+
type: "time",
|
|
3903
|
+
step: seconds ? 1 : 60,
|
|
3904
|
+
toText: (value) => value == null ? "" : String(value),
|
|
3905
|
+
fromText: (text) => {
|
|
3906
|
+
if (text === "") return null;
|
|
3907
|
+
if (seconds) return text.length === 5 ? `${text}:00` : text;
|
|
3908
|
+
return text.slice(0, 5);
|
|
3909
|
+
}
|
|
3910
|
+
});
|
|
3911
|
+
}
|
|
3912
|
+
function TemporalInput({ type, step, toText, fromText, name, id, value, onChange, testid, disabled, required, ariaInvalid, ariaDescribedBy, ariaErrorMessage, zoneName }) {
|
|
3913
|
+
const input = jsx(Input, {
|
|
3553
3914
|
name,
|
|
3554
3915
|
id,
|
|
3555
|
-
type
|
|
3556
|
-
|
|
3557
|
-
|
|
3916
|
+
type,
|
|
3917
|
+
...step === void 0 ? {} : { step },
|
|
3918
|
+
value: toText(value),
|
|
3919
|
+
onChange: (e) => onChange(fromText(e.target.value)),
|
|
3558
3920
|
"data-testid": testid,
|
|
3559
3921
|
disabled,
|
|
3560
3922
|
required,
|
|
@@ -3563,25 +3925,18 @@ function DateInput({ name, id, value, onChange, testid, disabled, required, aria
|
|
|
3563
3925
|
"aria-describedby": ariaDescribedBy,
|
|
3564
3926
|
...ariaErrorMessage ? { "aria-errormessage": ariaErrorMessage } : {}
|
|
3565
3927
|
});
|
|
3928
|
+
if (zoneName === void 0) return input;
|
|
3929
|
+
return jsxs("div", {
|
|
3930
|
+
className: "flex items-center gap-2",
|
|
3931
|
+
children: [input, jsx("span", {
|
|
3932
|
+
className: "whitespace-nowrap text-xs text-muted-foreground",
|
|
3933
|
+
"data-testid": testid === void 0 ? void 0 : `${testid}:zone`,
|
|
3934
|
+
children: zoneName
|
|
3935
|
+
})]
|
|
3936
|
+
});
|
|
3566
3937
|
}
|
|
3567
3938
|
//#endregion
|
|
3568
3939
|
//#region src/fields/enum.tsx
|
|
3569
|
-
function optionLabel(caps, field, value, inline) {
|
|
3570
|
-
const ns = enumNamespaceOf(field);
|
|
3571
|
-
if (ns) return resolveEnumLabel(caps, ns, value, inline);
|
|
3572
|
-
return field ? resolveFieldOptionLabel(caps, field.name, value, inline) : inline;
|
|
3573
|
-
}
|
|
3574
|
-
function declaredOptionLabel(option, value, enumDef) {
|
|
3575
|
-
return (enumDef === void 0 ? void 0 : enumValueText(enumDef, value)) ?? (typeof option?.label === "string" ? option.label : value);
|
|
3576
|
-
}
|
|
3577
|
-
function useBoundEnum(field) {
|
|
3578
|
-
const app = useOptionalApp();
|
|
3579
|
-
const namespace = enumNamespaceOf(field);
|
|
3580
|
-
return namespace === void 0 ? void 0 : app?.registry.enums.get(namespace);
|
|
3581
|
-
}
|
|
3582
|
-
function useOptionCaps(resource) {
|
|
3583
|
-
return useI18nCaps(useContext(ResourceContext).resource ?? resource);
|
|
3584
|
-
}
|
|
3585
3940
|
function EnumDisplay({ value, options, field, resource }) {
|
|
3586
3941
|
const caps = useOptionCaps(resource);
|
|
3587
3942
|
const enumDef = useBoundEnum(field);
|
|
@@ -3590,7 +3945,7 @@ function EnumDisplay({ value, options, field, resource }) {
|
|
|
3590
3945
|
children: "—"
|
|
3591
3946
|
});
|
|
3592
3947
|
const opt = options?.find((o) => o.value === String(value));
|
|
3593
|
-
const label =
|
|
3948
|
+
const label = resolveOptionLabel(caps, field, String(value), opt, enumDef);
|
|
3594
3949
|
return jsxs("span", {
|
|
3595
3950
|
className: "inline-flex items-center gap-1",
|
|
3596
3951
|
children: [opt?.icon ? jsx(Icon, {
|
|
@@ -3599,10 +3954,62 @@ function EnumDisplay({ value, options, field, resource }) {
|
|
|
3599
3954
|
}) : null, label]
|
|
3600
3955
|
});
|
|
3601
3956
|
}
|
|
3602
|
-
function EnumInput({ name, id, value, onChange, testid, options, field, placeholder, disabled, required, ariaInvalid, ariaDescribedBy, ariaErrorMessage, resource }) {
|
|
3957
|
+
function EnumInput({ name, id, value, onChange, testid, options, field, placeholder, disabled, required, ariaInvalid, ariaDescribedBy, ariaErrorMessage, ariaLabelledBy, resource, record, values, metaSources, baseline }) {
|
|
3603
3958
|
const t = useOptionalT();
|
|
3604
3959
|
const caps = useOptionCaps(resource);
|
|
3605
3960
|
const enumDef = useBoundEnum(field);
|
|
3961
|
+
const ns = enumNamespaceOf(field);
|
|
3962
|
+
const control = resolveEnumControl(field?.ui?.control, enumDef, `field ${field?.name ?? name}`);
|
|
3963
|
+
const sources = useFieldMetaSources({
|
|
3964
|
+
record,
|
|
3965
|
+
values,
|
|
3966
|
+
extra: metaSources
|
|
3967
|
+
});
|
|
3968
|
+
const available = useAvailableEnumValues({
|
|
3969
|
+
values: options ?? [],
|
|
3970
|
+
use: {
|
|
3971
|
+
narrow: narrowEntriesOf(field?.meta?.narrow),
|
|
3972
|
+
sources,
|
|
3973
|
+
mode: record === void 0 ? "create" : "edit",
|
|
3974
|
+
baseline: baseline ?? record
|
|
3975
|
+
}
|
|
3976
|
+
});
|
|
3977
|
+
const settling = available.status === "ready" ? void 0 : available.status;
|
|
3978
|
+
const offered = settling === void 0 ? available.values : [];
|
|
3979
|
+
const tid = testid ?? name;
|
|
3980
|
+
const resolved = offered.map((o) => {
|
|
3981
|
+
const summary = ns === void 0 ? void 0 : resolveDoc(caps, `enum/${ns}/${o.value}`)?.summary;
|
|
3982
|
+
return {
|
|
3983
|
+
value: o.value,
|
|
3984
|
+
label: resolveOptionLabel(caps, field, o.value, o, enumDef),
|
|
3985
|
+
...o.icon === void 0 ? {} : { icon: o.icon },
|
|
3986
|
+
...summary === void 0 ? {} : { summary }
|
|
3987
|
+
};
|
|
3988
|
+
});
|
|
3989
|
+
const raw = value == null || value === "" ? void 0 : String(value);
|
|
3990
|
+
const known = raw === void 0 ? void 0 : options?.find((o) => o.value === raw);
|
|
3991
|
+
const current = raw === void 0 || resolved.some((o) => o.value === raw) ? void 0 : {
|
|
3992
|
+
value: raw,
|
|
3993
|
+
label: resolveOptionLabel(caps, field, raw, known, enumDef),
|
|
3994
|
+
...known?.icon === void 0 ? {} : { icon: known.icon }
|
|
3995
|
+
};
|
|
3996
|
+
if (control !== "select") return jsx(EnumChoiceGroup, {
|
|
3997
|
+
control,
|
|
3998
|
+
options: resolved,
|
|
3999
|
+
...current === void 0 ? {} : { current },
|
|
4000
|
+
...settling === void 0 ? {} : { settling },
|
|
4001
|
+
value,
|
|
4002
|
+
onChange,
|
|
4003
|
+
testid: tid,
|
|
4004
|
+
name,
|
|
4005
|
+
id,
|
|
4006
|
+
required,
|
|
4007
|
+
disabled,
|
|
4008
|
+
ariaInvalid,
|
|
4009
|
+
ariaDescribedBy,
|
|
4010
|
+
ariaErrorMessage,
|
|
4011
|
+
ariaLabelledBy
|
|
4012
|
+
});
|
|
3606
4013
|
return jsxs(Select, {
|
|
3607
4014
|
value: value ?? "",
|
|
3608
4015
|
onValueChange: onChange,
|
|
@@ -3613,20 +4020,39 @@ function EnumInput({ name, id, value, onChange, testid, options, field, placehol
|
|
|
3613
4020
|
name,
|
|
3614
4021
|
id,
|
|
3615
4022
|
"aria-required": required,
|
|
4023
|
+
"aria-busy": settling === "pending" || void 0,
|
|
3616
4024
|
"aria-invalid": ariaInvalid || void 0,
|
|
3617
4025
|
"aria-describedby": ariaDescribedBy,
|
|
3618
4026
|
...ariaErrorMessage ? { "aria-errormessage": ariaErrorMessage } : {},
|
|
3619
4027
|
children: jsx(SelectValue, { placeholder: placeholder ?? t("field.select", { defaultValue: "Select…" }) })
|
|
3620
|
-
}),
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
4028
|
+
}), jsxs(SelectContent, { children: [
|
|
4029
|
+
current === void 0 ? null : jsx(SelectItem, {
|
|
4030
|
+
value: current.value,
|
|
4031
|
+
disabled: true,
|
|
4032
|
+
"data-current": "",
|
|
4033
|
+
"data-testid": `${tid}:current`,
|
|
4034
|
+
children: current.label
|
|
4035
|
+
}),
|
|
4036
|
+
settling === void 0 ? null : jsx(EnumSettlingRow, {
|
|
4037
|
+
status: settling,
|
|
4038
|
+
testid: tid
|
|
4039
|
+
}),
|
|
4040
|
+
resolved.map((o) => jsx(SelectItem, {
|
|
4041
|
+
value: o.value,
|
|
4042
|
+
"data-testid": testid === void 0 ? void 0 : `${testid}:option:${o.value}`,
|
|
4043
|
+
description: o.summary === void 0 ? void 0 : jsx("span", {
|
|
4044
|
+
"data-testid": testid === void 0 ? void 0 : `${testid}:option:${o.value}:doc`,
|
|
4045
|
+
children: o.summary
|
|
4046
|
+
}),
|
|
4047
|
+
children: jsxs("span", {
|
|
4048
|
+
className: "inline-flex items-center gap-1.5",
|
|
4049
|
+
children: [o.icon ? jsx(Icon, {
|
|
4050
|
+
name: o.icon,
|
|
4051
|
+
className: "size-3.5 shrink-0 text-muted-foreground"
|
|
4052
|
+
}) : null, o.label]
|
|
4053
|
+
})
|
|
4054
|
+
}, o.value))
|
|
4055
|
+
] })]
|
|
3630
4056
|
});
|
|
3631
4057
|
}
|
|
3632
4058
|
//#endregion
|
|
@@ -4047,7 +4473,7 @@ function JsonInput({ name, id, value, onChange, testid, disabled, required, aria
|
|
|
4047
4473
|
}
|
|
4048
4474
|
//#endregion
|
|
4049
4475
|
//#region src/fields/lazy-relation-many.tsx
|
|
4050
|
-
const RelationManyPickerInput = lazy(() => import("./relation-many-picker-
|
|
4476
|
+
const RelationManyPickerInput = lazy(() => import("./relation-many-picker-BlrGRwMV.js").then((module) => ({ default: module.RelationManyPickerInput })));
|
|
4051
4477
|
function LazyRelationManyInput(props) {
|
|
4052
4478
|
return jsx(Suspense, {
|
|
4053
4479
|
fallback: jsx(Skeleton, {
|
|
@@ -4060,8 +4486,8 @@ function LazyRelationManyInput(props) {
|
|
|
4060
4486
|
}
|
|
4061
4487
|
//#endregion
|
|
4062
4488
|
//#region src/fields/lazy-rich-text.tsx
|
|
4063
|
-
const RichTextDisplay = lazy(() => import("./rich-text-
|
|
4064
|
-
const RichTextInput = lazy(() => import("./rich-text-
|
|
4489
|
+
const RichTextDisplay = lazy(() => import("./rich-text-RcPBf6hr.js").then((module) => ({ default: module.RichTextDisplay })));
|
|
4490
|
+
const RichTextInput = lazy(() => import("./rich-text-RcPBf6hr.js").then((module) => ({ default: module.RichTextInput })));
|
|
4065
4491
|
function RichTextDisplayLoading() {
|
|
4066
4492
|
const t = useOptionalT();
|
|
4067
4493
|
return jsx("div", {
|
|
@@ -4118,12 +4544,13 @@ function isIdentifier(field) {
|
|
|
4118
4544
|
const n = field?.name;
|
|
4119
4545
|
return n === "id" || typeof n === "string" && n.endsWith("_id");
|
|
4120
4546
|
}
|
|
4121
|
-
function NumberDisplay({ value, field }) {
|
|
4547
|
+
function NumberDisplay({ value, field, text }) {
|
|
4122
4548
|
const locale = useOptionalLocale();
|
|
4123
4549
|
if (value == null || value === "") return jsx("span", {
|
|
4124
4550
|
className: "text-muted-foreground",
|
|
4125
4551
|
children: "—"
|
|
4126
4552
|
});
|
|
4553
|
+
if (text !== void 0) return jsx("span", { children: text });
|
|
4127
4554
|
let raw = value;
|
|
4128
4555
|
if (typeof raw === "string") raw = unquote(raw);
|
|
4129
4556
|
const n = typeof raw === "number" ? raw : Number(raw);
|
|
@@ -4158,12 +4585,149 @@ function NumberInput({ name, id, value, onChange, testid, placeholder, disabled,
|
|
|
4158
4585
|
});
|
|
4159
4586
|
}
|
|
4160
4587
|
//#endregion
|
|
4588
|
+
//#region src/fields/object-group.tsx
|
|
4589
|
+
const GROUP = "rounded-md border border-input p-3";
|
|
4590
|
+
function ObjectGroupInput(props) {
|
|
4591
|
+
const { testIds, accessibility, children } = props;
|
|
4592
|
+
return jsx("div", {
|
|
4593
|
+
role: "group",
|
|
4594
|
+
"data-buro-object-group": "input",
|
|
4595
|
+
className: cn(GROUP, "space-y-3"),
|
|
4596
|
+
"data-testid": testIds.input,
|
|
4597
|
+
id: accessibility.input,
|
|
4598
|
+
"aria-labelledby": accessibility.label,
|
|
4599
|
+
"aria-describedby": accessibility.description,
|
|
4600
|
+
"aria-invalid": props.issues.some((issue) => issue.severity === "error" && issue.path.length === 0) || void 0,
|
|
4601
|
+
"aria-errormessage": accessibility.error,
|
|
4602
|
+
children
|
|
4603
|
+
});
|
|
4604
|
+
}
|
|
4605
|
+
function ObjectGroupDisplay(props) {
|
|
4606
|
+
const { testIds, children } = props;
|
|
4607
|
+
return jsx("div", {
|
|
4608
|
+
role: "group",
|
|
4609
|
+
"data-buro-object-group": "display",
|
|
4610
|
+
className: cn(GROUP, "space-y-2"),
|
|
4611
|
+
"data-testid": testIds.display,
|
|
4612
|
+
children
|
|
4613
|
+
});
|
|
4614
|
+
}
|
|
4615
|
+
//#endregion
|
|
4616
|
+
//#region src/fields/repeater.tsx
|
|
4617
|
+
function useRepeaterTexts() {
|
|
4618
|
+
const t = useChromeT();
|
|
4619
|
+
return {
|
|
4620
|
+
add: t("field.repeater.add", { defaultValue: "Add" }),
|
|
4621
|
+
empty: t("field.repeater.empty", { defaultValue: "No items yet" }),
|
|
4622
|
+
remove: (position) => t("field.repeater.remove", {
|
|
4623
|
+
params: { position },
|
|
4624
|
+
defaultValue: "Remove item {{position}}"
|
|
4625
|
+
}),
|
|
4626
|
+
moveUp: (position) => t("field.repeater.moveUp", {
|
|
4627
|
+
params: { position },
|
|
4628
|
+
defaultValue: "Move item {{position}} up"
|
|
4629
|
+
}),
|
|
4630
|
+
moveDown: (position) => t("field.repeater.moveDown", {
|
|
4631
|
+
params: { position },
|
|
4632
|
+
defaultValue: "Move item {{position}} down"
|
|
4633
|
+
})
|
|
4634
|
+
};
|
|
4635
|
+
}
|
|
4636
|
+
function RepeaterInput(props) {
|
|
4637
|
+
const texts = useRepeaterTexts();
|
|
4638
|
+
const { value, renderElement, elementKeys, onAdd, onRemove, onMove, testIds, accessibility } = props;
|
|
4639
|
+
const root = testIds.input;
|
|
4640
|
+
const at = (suffix) => root === void 0 ? void 0 : `${root}:${suffix}`;
|
|
4641
|
+
const editable = props.disabled !== true && props.readOnly !== true;
|
|
4642
|
+
const canAdd = editable && onAdd !== void 0 && props.canAdd !== false;
|
|
4643
|
+
const canRemove = editable && onRemove !== void 0 && props.canRemove !== false;
|
|
4644
|
+
const last = value.length - 1;
|
|
4645
|
+
return jsxs("div", {
|
|
4646
|
+
role: "group",
|
|
4647
|
+
className: "space-y-2",
|
|
4648
|
+
"data-testid": root,
|
|
4649
|
+
id: accessibility.input,
|
|
4650
|
+
"aria-labelledby": accessibility.label,
|
|
4651
|
+
"aria-describedby": accessibility.description,
|
|
4652
|
+
"aria-errormessage": accessibility.error,
|
|
4653
|
+
children: [value.length === 0 ? jsx("p", {
|
|
4654
|
+
className: "text-sm text-muted-foreground",
|
|
4655
|
+
"data-testid": at("empty"),
|
|
4656
|
+
children: texts.empty
|
|
4657
|
+
}) : jsx("ol", {
|
|
4658
|
+
className: "space-y-2",
|
|
4659
|
+
children: value.map((_, index) => jsxs("li", {
|
|
4660
|
+
className: "flex items-start gap-2 rounded-md border border-input p-3",
|
|
4661
|
+
"data-testid": at(`item:${index}`),
|
|
4662
|
+
children: [jsx("div", {
|
|
4663
|
+
className: "min-w-0 flex-1",
|
|
4664
|
+
children: renderElement?.(index)
|
|
4665
|
+
}), onMove === void 0 && onRemove === void 0 ? null : jsxs("div", {
|
|
4666
|
+
className: "flex shrink-0 gap-1",
|
|
4667
|
+
children: [onMove === void 0 ? null : jsxs(Fragment$1, { children: [jsx(Button, {
|
|
4668
|
+
type: "button",
|
|
4669
|
+
variant: "ghost",
|
|
4670
|
+
size: "icon",
|
|
4671
|
+
"aria-label": texts.moveUp(index + 1),
|
|
4672
|
+
disabled: !editable || index === 0,
|
|
4673
|
+
"data-testid": at(`up:${index}`),
|
|
4674
|
+
onClick: () => onMove(index, index - 1),
|
|
4675
|
+
children: jsx(IconArrowUp, { "aria-hidden": "true" })
|
|
4676
|
+
}), jsx(Button, {
|
|
4677
|
+
type: "button",
|
|
4678
|
+
variant: "ghost",
|
|
4679
|
+
size: "icon",
|
|
4680
|
+
"aria-label": texts.moveDown(index + 1),
|
|
4681
|
+
disabled: !editable || index === last,
|
|
4682
|
+
"data-testid": at(`down:${index}`),
|
|
4683
|
+
onClick: () => onMove(index, index + 1),
|
|
4684
|
+
children: jsx(IconArrowDown, { "aria-hidden": "true" })
|
|
4685
|
+
})] }), onRemove === void 0 ? null : jsx(Button, {
|
|
4686
|
+
type: "button",
|
|
4687
|
+
variant: "ghost",
|
|
4688
|
+
size: "icon",
|
|
4689
|
+
"aria-label": texts.remove(index + 1),
|
|
4690
|
+
disabled: !canRemove,
|
|
4691
|
+
"data-testid": at(`remove:${index}`),
|
|
4692
|
+
onClick: () => onRemove(index),
|
|
4693
|
+
children: jsx(IconTrash, { "aria-hidden": "true" })
|
|
4694
|
+
})]
|
|
4695
|
+
})]
|
|
4696
|
+
}, elementKeys?.[index] ?? index))
|
|
4697
|
+
}), onAdd === void 0 ? null : jsxs(Button, {
|
|
4698
|
+
type: "button",
|
|
4699
|
+
variant: "outline",
|
|
4700
|
+
size: "sm",
|
|
4701
|
+
disabled: !canAdd,
|
|
4702
|
+
"data-testid": at("add"),
|
|
4703
|
+
onClick: onAdd,
|
|
4704
|
+
children: [jsx(IconPlus, { "aria-hidden": "true" }), texts.add]
|
|
4705
|
+
})]
|
|
4706
|
+
});
|
|
4707
|
+
}
|
|
4708
|
+
function RepeaterDisplay(props) {
|
|
4709
|
+
const texts = useRepeaterTexts();
|
|
4710
|
+
const { value, renderElement, testIds } = props;
|
|
4711
|
+
if (value.length === 0) return jsx("span", {
|
|
4712
|
+
className: "text-muted-foreground",
|
|
4713
|
+
"data-testid": testIds.display,
|
|
4714
|
+
children: texts.empty
|
|
4715
|
+
});
|
|
4716
|
+
return jsx("ol", {
|
|
4717
|
+
className: "space-y-2",
|
|
4718
|
+
"data-testid": testIds.display,
|
|
4719
|
+
children: value.map((_, index) => jsx("li", {
|
|
4720
|
+
className: "rounded-md border border-input p-3",
|
|
4721
|
+
children: renderElement?.(index)
|
|
4722
|
+
}, index))
|
|
4723
|
+
});
|
|
4724
|
+
}
|
|
4725
|
+
//#endregion
|
|
4161
4726
|
//#region src/fields/link-keys-display.tsx
|
|
4162
4727
|
const isRecord$1 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4163
|
-
function qualify(name
|
|
4728
|
+
function qualify(name) {
|
|
4164
4729
|
try {
|
|
4165
|
-
const
|
|
4166
|
-
const ref = normalizeEntityRef(name, { defaultNamespace: namespace });
|
|
4730
|
+
const ref = normalizeEntityRef(name);
|
|
4167
4731
|
return ref.namespace === "default" ? ref.id : `${ref.namespace}:${ref.id}`;
|
|
4168
4732
|
} catch {
|
|
4169
4733
|
return;
|
|
@@ -4188,7 +4752,7 @@ function LinkKeysDisplay(props) {
|
|
|
4188
4752
|
const ownerDef = owner === "" ? void 0 : app.registry.get(owner);
|
|
4189
4753
|
const declaration = ownerDef === void 0 ? void 0 : declaredField(ownerDef, name);
|
|
4190
4754
|
const link = isRecord$1(declaration) ? linkOf(declaration) : void 0;
|
|
4191
|
-
const junctionName = link === void 0 ? void 0 : qualify(link.junction
|
|
4755
|
+
const junctionName = link === void 0 ? void 0 : qualify(link.junction);
|
|
4192
4756
|
const junctionDef = junctionName === void 0 ? void 0 : app.registry.get(junctionName);
|
|
4193
4757
|
const junctionField = (key) => junctionDef === void 0 ? void 0 : declaredField(junctionDef, key);
|
|
4194
4758
|
const ownerField = link === void 0 ? idFieldOf(ownerDef) : byOf(junctionField(link.sourceKey)) ?? idFieldOf(ownerDef);
|
|
@@ -4196,11 +4760,11 @@ function LinkKeysDisplay(props) {
|
|
|
4196
4760
|
const ownerKey = record?.[ownerField];
|
|
4197
4761
|
const { keys, complete, isLoading, error } = useLinkKeys(owner, name, ownerKey);
|
|
4198
4762
|
const [missed, setMissed] = useState(() => new Set());
|
|
4199
|
-
const onMiss = useCallback((key,
|
|
4763
|
+
const onMiss = useCallback((key, isMiss) => {
|
|
4200
4764
|
setMissed((current) => {
|
|
4201
|
-
if (current.has(key) ===
|
|
4765
|
+
if (current.has(key) === isMiss) return current;
|
|
4202
4766
|
const next = new Set(current);
|
|
4203
|
-
if (
|
|
4767
|
+
if (isMiss) next.add(key);
|
|
4204
4768
|
else next.delete(key);
|
|
4205
4769
|
return next;
|
|
4206
4770
|
});
|
|
@@ -4220,12 +4784,17 @@ function LinkKeysDisplay(props) {
|
|
|
4220
4784
|
targetBy
|
|
4221
4785
|
]);
|
|
4222
4786
|
const chipsId = tid.linkChips(owner, name);
|
|
4223
|
-
if (error) return jsx(
|
|
4224
|
-
"
|
|
4225
|
-
|
|
4787
|
+
if (error) return jsx(LoadError, {
|
|
4788
|
+
surface: "relation",
|
|
4789
|
+
error,
|
|
4790
|
+
...typeof target === "string" ? { resource: target } : {},
|
|
4791
|
+
testId: tid.linkError(owner, name),
|
|
4226
4792
|
className: "text-destructive text-xs",
|
|
4227
|
-
|
|
4228
|
-
|
|
4793
|
+
attributes: { role: "status" },
|
|
4794
|
+
fallback: {
|
|
4795
|
+
key: "field.link.failed",
|
|
4796
|
+
default: "Links could not be loaded"
|
|
4797
|
+
}
|
|
4229
4798
|
});
|
|
4230
4799
|
if (keys === void 0) {
|
|
4231
4800
|
if (!isLoading) return jsx("span", {
|
|
@@ -4245,7 +4814,7 @@ function LinkKeysDisplay(props) {
|
|
|
4245
4814
|
children: jsx("span", {
|
|
4246
4815
|
"data-testid": tid.linkIncomplete(owner, name),
|
|
4247
4816
|
className: "text-muted-foreground",
|
|
4248
|
-
children: t("
|
|
4817
|
+
children: t("field.link.incomplete", {
|
|
4249
4818
|
count: keys.length,
|
|
4250
4819
|
defaultValue: "More than {{count}} links"
|
|
4251
4820
|
})
|
|
@@ -4267,7 +4836,7 @@ function LinkKeysDisplay(props) {
|
|
|
4267
4836
|
}, String(key))), hidden > 0 ? jsx("span", {
|
|
4268
4837
|
"data-testid": tid.linkHidden(owner, name),
|
|
4269
4838
|
className: `${chipClassName} text-muted-foreground`,
|
|
4270
|
-
children: t("
|
|
4839
|
+
children: t("field.link.hidden", {
|
|
4271
4840
|
count: hidden,
|
|
4272
4841
|
defaultValue: "{{count}} not visible"
|
|
4273
4842
|
})
|
|
@@ -4355,7 +4924,7 @@ const relationMetaSchema = Object.freeze({ "~standard": Object.freeze({
|
|
|
4355
4924
|
path: []
|
|
4356
4925
|
}] };
|
|
4357
4926
|
const issues = [];
|
|
4358
|
-
const { to, by, resolve, searchField, candidates } = value;
|
|
4927
|
+
const { to, by, resolve, searchField, candidates, scope } = value;
|
|
4359
4928
|
if (to !== void 0 && !(typeof to === "string" && to.length > 0) && !(isRecord(to) && (typeof to.id === "string" || isRecord(to.ref)))) issues.push({
|
|
4360
4929
|
message: "must be a resource name or reference",
|
|
4361
4930
|
path: ["to"]
|
|
@@ -4376,16 +4945,21 @@ const relationMetaSchema = Object.freeze({ "~standard": Object.freeze({
|
|
|
4376
4945
|
message: "must be an array of conditions",
|
|
4377
4946
|
path: ["candidates"]
|
|
4378
4947
|
});
|
|
4948
|
+
if (scope !== void 0 && scope !== "context" && scope !== "session" && scope !== "none") issues.push({
|
|
4949
|
+
message: "must be 'context', 'session' or 'none'",
|
|
4950
|
+
path: ["scope"]
|
|
4951
|
+
});
|
|
4379
4952
|
return issues.length > 0 ? { issues } : { value };
|
|
4380
4953
|
}
|
|
4381
4954
|
}) });
|
|
4382
4955
|
//#endregion
|
|
4383
4956
|
//#region src/fields/text.tsx
|
|
4384
|
-
function TextDisplay({ value }) {
|
|
4957
|
+
function TextDisplay({ value, text: formatted }) {
|
|
4385
4958
|
if (value == null || value === "") return jsx("span", {
|
|
4386
4959
|
className: "text-muted-foreground",
|
|
4387
4960
|
children: "—"
|
|
4388
4961
|
});
|
|
4962
|
+
if (formatted !== void 0) return jsx("span", { children: formatted });
|
|
4389
4963
|
const { text, isStructured } = toDisplayText(value);
|
|
4390
4964
|
return isStructured ? jsx("span", {
|
|
4391
4965
|
className: "font-mono text-xs break-all",
|
|
@@ -4414,23 +4988,26 @@ function TextInput({ name, id, value, onChange, testid, placeholder, disabled, r
|
|
|
4414
4988
|
}
|
|
4415
4989
|
//#endregion
|
|
4416
4990
|
//#region src/fields/textarea.tsx
|
|
4417
|
-
function TextareaDisplay({ value }) {
|
|
4991
|
+
function TextareaDisplay({ value, text: formatted }) {
|
|
4418
4992
|
if (value == null || value === "") return jsx("span", {
|
|
4419
4993
|
className: "text-muted-foreground",
|
|
4420
4994
|
children: "—"
|
|
4421
4995
|
});
|
|
4422
|
-
const { text, isStructured } = toDisplayText(value)
|
|
4996
|
+
const { text, isStructured } = formatted === void 0 ? toDisplayText(value) : {
|
|
4997
|
+
text: formatted,
|
|
4998
|
+
isStructured: false
|
|
4999
|
+
};
|
|
4423
5000
|
return jsx("pre", {
|
|
4424
5001
|
className: isStructured ? "whitespace-pre-wrap break-all font-mono text-xs" : "whitespace-pre-wrap font-sans text-sm",
|
|
4425
5002
|
children: text
|
|
4426
5003
|
});
|
|
4427
5004
|
}
|
|
4428
|
-
function CodeDisplay({ value, presentation, testid }) {
|
|
5005
|
+
function CodeDisplay({ value, text: formatted, presentation, testid }) {
|
|
4429
5006
|
if (value == null || value === "") return jsx("span", {
|
|
4430
5007
|
className: "text-muted-foreground",
|
|
4431
5008
|
children: "—"
|
|
4432
5009
|
});
|
|
4433
|
-
const
|
|
5010
|
+
const text = formatted ?? toDisplayText(value).text;
|
|
4434
5011
|
return jsx("pre", {
|
|
4435
5012
|
"data-testid": testid,
|
|
4436
5013
|
className: presentation === "plain" ? "overflow-x-auto whitespace-pre font-mono text-xs leading-relaxed" : "overflow-x-auto whitespace-pre rounded-md border bg-muted/40 p-3 font-mono text-xs leading-relaxed",
|
|
@@ -4474,14 +5051,14 @@ function TextareaInput({ name, id, value, onChange, testid, placeholder, disable
|
|
|
4474
5051
|
//#endregion
|
|
4475
5052
|
//#region src/fields/default-renderers.ts
|
|
4476
5053
|
function legacyField(props) {
|
|
4477
|
-
const name =
|
|
4478
|
-
const texts = props.field
|
|
5054
|
+
const name = optionFieldName(props.path);
|
|
5055
|
+
const { texts, zone } = props.field;
|
|
4479
5056
|
return Object.freeze({
|
|
4480
5057
|
name,
|
|
4481
5058
|
meta: props.meta,
|
|
4482
5059
|
ui: props.ui,
|
|
4483
|
-
|
|
4484
|
-
...
|
|
5060
|
+
...texts === void 0 ? {} : { texts },
|
|
5061
|
+
...zone === void 0 ? {} : { zone }
|
|
4485
5062
|
});
|
|
4486
5063
|
}
|
|
4487
5064
|
function legacyOptions(options, field) {
|
|
@@ -4502,6 +5079,7 @@ function display(renderer) {
|
|
|
4502
5079
|
return function ShadcnDisplay(props) {
|
|
4503
5080
|
return createElement(renderer, {
|
|
4504
5081
|
value: props.value,
|
|
5082
|
+
...props.text === void 0 ? {} : { text: props.text },
|
|
4505
5083
|
multiple: props.multiple,
|
|
4506
5084
|
field: legacyField(props),
|
|
4507
5085
|
options: legacyOptions(props.options, props.field),
|
|
@@ -4539,12 +5117,17 @@ function input(renderer) {
|
|
|
4539
5117
|
ariaInvalid: props.issues.some(isErrorIssue),
|
|
4540
5118
|
ariaDescribedBy: props.accessibility.description,
|
|
4541
5119
|
ariaErrorMessage: props.accessibility.error,
|
|
5120
|
+
ariaLabelledBy: props.accessibility.label,
|
|
4542
5121
|
field: legacyField(props),
|
|
4543
5122
|
resource: props.resource.id,
|
|
4544
5123
|
record: props.record,
|
|
5124
|
+
values: props.form,
|
|
4545
5125
|
relationSeeds: props.relationSeeds,
|
|
4546
5126
|
fixedFilters: props.fixedFilters,
|
|
4547
|
-
|
|
5127
|
+
optionSubtitle: props.optionSubtitle,
|
|
5128
|
+
metaSources: props.metaSources,
|
|
5129
|
+
...props.baseline === void 0 ? {} : { baseline: props.baseline },
|
|
5130
|
+
link: props.link
|
|
4548
5131
|
});
|
|
4549
5132
|
};
|
|
4550
5133
|
}
|
|
@@ -4592,9 +5175,40 @@ function scalarOrCollection(renderer, layout) {
|
|
|
4592
5175
|
});
|
|
4593
5176
|
}
|
|
4594
5177
|
function enumName(ui) {
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
5178
|
+
return enumBindingKey(ui.enum);
|
|
5179
|
+
}
|
|
5180
|
+
function RegistryEnumInput(props) {
|
|
5181
|
+
const app = useOptionalApp();
|
|
5182
|
+
const meta = props.field.meta;
|
|
5183
|
+
const sources = useFieldMetaSources({
|
|
5184
|
+
record: props.record,
|
|
5185
|
+
values: props.form,
|
|
5186
|
+
extra: props.metaSources
|
|
5187
|
+
});
|
|
5188
|
+
const control = resolveEnumControl(props.ui.control, app?.registry.enums.get(props.enumName), `field ${typeof props.path.at(-1) === "string" ? String(props.path.at(-1)) : props.enumName}`);
|
|
5189
|
+
return createElement(EnumPicker, {
|
|
5190
|
+
enumName: props.enumName,
|
|
5191
|
+
control,
|
|
5192
|
+
value: props.value == null ? void 0 : String(props.value),
|
|
5193
|
+
onChange: props.onChange ?? (() => void 0),
|
|
5194
|
+
name: props.accessibility.input,
|
|
5195
|
+
id: props.accessibility.input,
|
|
5196
|
+
testid: props.testIds.input,
|
|
5197
|
+
placeholder: typeof props.ui.placeholder === "string" ? props.ui.placeholder : void 0,
|
|
5198
|
+
disabled: props.disabled,
|
|
5199
|
+
required: props.field.required === true,
|
|
5200
|
+
ariaInvalid: props.issues.some(isErrorIssue),
|
|
5201
|
+
ariaDescribedBy: props.accessibility.description,
|
|
5202
|
+
ariaErrorMessage: props.accessibility.error,
|
|
5203
|
+
ariaLabelledBy: props.accessibility.label,
|
|
5204
|
+
use: {
|
|
5205
|
+
params: enumParamsOf(meta?.enumParams),
|
|
5206
|
+
narrow: narrowEntriesOf(meta?.narrow),
|
|
5207
|
+
sources,
|
|
5208
|
+
mode: props.record === void 0 ? "create" : "edit",
|
|
5209
|
+
baseline: props.baseline ?? props.record
|
|
5210
|
+
}
|
|
5211
|
+
});
|
|
4598
5212
|
}
|
|
4599
5213
|
function enumAware(renderer, layout) {
|
|
4600
5214
|
const FallbackInput = input(renderer.Input);
|
|
@@ -4604,19 +5218,9 @@ function enumAware(renderer, layout) {
|
|
|
4604
5218
|
return Object.freeze({
|
|
4605
5219
|
Input: (props) => {
|
|
4606
5220
|
const name = enumName(props.ui);
|
|
4607
|
-
if (name !== void 0) return createElement(
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
onChange: props.onChange ?? (() => void 0),
|
|
4611
|
-
name: props.accessibility.input,
|
|
4612
|
-
id: props.accessibility.input,
|
|
4613
|
-
testid: props.testIds.input,
|
|
4614
|
-
placeholder: typeof props.ui.placeholder === "string" ? props.ui.placeholder : void 0,
|
|
4615
|
-
disabled: props.disabled,
|
|
4616
|
-
required: props.field.required === true,
|
|
4617
|
-
ariaInvalid: props.issues.some(isErrorIssue),
|
|
4618
|
-
ariaDescribedBy: props.accessibility.description,
|
|
4619
|
-
ariaErrorMessage: props.accessibility.error
|
|
5221
|
+
if (name !== void 0) return createElement(RegistryEnumInput, {
|
|
5222
|
+
...props,
|
|
5223
|
+
enumName: name
|
|
4620
5224
|
});
|
|
4621
5225
|
if (props.options.length > 0) return createElement(OptionedInput, props);
|
|
4622
5226
|
return createElement(FallbackInput, props);
|
|
@@ -4651,6 +5255,14 @@ const date = {
|
|
|
4651
5255
|
Display: DateDisplay,
|
|
4652
5256
|
Input: DateInput
|
|
4653
5257
|
};
|
|
5258
|
+
const dateTime = {
|
|
5259
|
+
Display: DateTimeDisplay,
|
|
5260
|
+
Input: DateTimeInput
|
|
5261
|
+
};
|
|
5262
|
+
const time = {
|
|
5263
|
+
Display: TimeDisplay,
|
|
5264
|
+
Input: TimeInput
|
|
5265
|
+
};
|
|
4654
5266
|
const en = {
|
|
4655
5267
|
Display: EnumDisplay,
|
|
4656
5268
|
Input: EnumInput
|
|
@@ -4686,9 +5298,11 @@ const shadcnFieldImplementations = Object.freeze({
|
|
|
4686
5298
|
number: scalar(num),
|
|
4687
5299
|
boolean: scalar(bool),
|
|
4688
5300
|
date: scalar(date),
|
|
4689
|
-
dateTime: scalar(
|
|
4690
|
-
"date-time": scalar(
|
|
4691
|
-
"default:date-time": scalar(
|
|
5301
|
+
dateTime: scalar(dateTime),
|
|
5302
|
+
"date-time": scalar(dateTime),
|
|
5303
|
+
"default:date-time": scalar(dateTime),
|
|
5304
|
+
time: scalar(time),
|
|
5305
|
+
"default:time": scalar(time),
|
|
4692
5306
|
enum: enumAware(en),
|
|
4693
5307
|
json: scalar({
|
|
4694
5308
|
Display: JsonDisplay,
|
|
@@ -4702,316 +5316,19 @@ const shadcnFieldImplementations = Object.freeze({
|
|
|
4702
5316
|
richText: scalar(rich, { size: "full" }),
|
|
4703
5317
|
"rich-text": scalar(rich, { size: "full" }),
|
|
4704
5318
|
"default:rich-text": scalar(rich, { size: "full" }),
|
|
4705
|
-
file: scalarOrCollection(file, { size: "full" })
|
|
5319
|
+
file: scalarOrCollection(file, { size: "full" }),
|
|
5320
|
+
object: Object.freeze({
|
|
5321
|
+
Input: ObjectGroupInput,
|
|
5322
|
+
Display: ObjectGroupDisplay,
|
|
5323
|
+
chrome: true
|
|
5324
|
+
}),
|
|
5325
|
+
array: Object.freeze({
|
|
5326
|
+
CollectionInput: RepeaterInput,
|
|
5327
|
+
CollectionDisplay: RepeaterDisplay,
|
|
5328
|
+
chrome: true
|
|
5329
|
+
})
|
|
4706
5330
|
});
|
|
4707
5331
|
//#endregion
|
|
4708
|
-
//#region src/fields/use-relation-picker.tsx
|
|
4709
|
-
const noop = () => void 0;
|
|
4710
|
-
function safeKey(input) {
|
|
4711
|
-
if (input === void 0 || input === null) return void 0;
|
|
4712
|
-
try {
|
|
4713
|
-
return resourceKey(input);
|
|
4714
|
-
} catch {
|
|
4715
|
-
return;
|
|
4716
|
-
}
|
|
4717
|
-
}
|
|
4718
|
-
function sessionIdentity(runtime) {
|
|
4719
|
-
const state = runtime.dataSession.getState();
|
|
4720
|
-
const snapshot = state.status === "ready" ? state.snapshot : state.target;
|
|
4721
|
-
let scopeKey;
|
|
4722
|
-
try {
|
|
4723
|
-
scopeKey = JSON.stringify(snapshot.scopeKey) ?? "";
|
|
4724
|
-
} catch {
|
|
4725
|
-
scopeKey = String(snapshot.scopeKey);
|
|
4726
|
-
}
|
|
4727
|
-
return {
|
|
4728
|
-
sessionKey: snapshot.sessionKey,
|
|
4729
|
-
scopeKey
|
|
4730
|
-
};
|
|
4731
|
-
}
|
|
4732
|
-
function PickerHost(props) {
|
|
4733
|
-
const { register } = props;
|
|
4734
|
-
React.useEffect(() => register(), [register]);
|
|
4735
|
-
return jsx(Fragment$1, { children: props.children });
|
|
4736
|
-
}
|
|
4737
|
-
function useRelationPicker(options) {
|
|
4738
|
-
const app = useApp();
|
|
4739
|
-
const runtime = useDataRuntime();
|
|
4740
|
-
const frame = useOptionalRecordFrame();
|
|
4741
|
-
const frames = useRecordScopeFrames();
|
|
4742
|
-
const multiple = options.multiple === true;
|
|
4743
|
-
const fieldName = options.field;
|
|
4744
|
-
let to;
|
|
4745
|
-
let declaredBy;
|
|
4746
|
-
let declaredCandidates;
|
|
4747
|
-
if (fieldName !== void 0) {
|
|
4748
|
-
const meta = ((frame === null ? void 0 : app.registry.get(frame.resource)?.fields)?.[fieldName])?.meta;
|
|
4749
|
-
to = safeKey(meta?.to);
|
|
4750
|
-
declaredBy = typeof meta?.by === "string" ? meta.by : void 0;
|
|
4751
|
-
declaredCandidates = Array.isArray(meta?.candidates) ? meta.candidates : void 0;
|
|
4752
|
-
} else to = safeKey(options.to);
|
|
4753
|
-
const target = to ?? "";
|
|
4754
|
-
const by = options.valueField ?? declaredBy;
|
|
4755
|
-
const scope = options.scope ?? "context";
|
|
4756
|
-
const selection = useCandidateSelection({
|
|
4757
|
-
to,
|
|
4758
|
-
candidates: options.candidates ?? declaredCandidates,
|
|
4759
|
-
sources: frame?.controller.sources,
|
|
4760
|
-
resource: frame?.resource ?? "",
|
|
4761
|
-
fieldName: fieldName ?? target,
|
|
4762
|
-
fixedFilters: options.fixedFilters
|
|
4763
|
-
});
|
|
4764
|
-
const held = selection.gate !== void 0;
|
|
4765
|
-
const pendingRef = React.useRef(null);
|
|
4766
|
-
const [active, setActive] = React.useState(null);
|
|
4767
|
-
const activeRef = React.useRef(null);
|
|
4768
|
-
activeRef.current = active;
|
|
4769
|
-
const rowsRef = React.useRef(new Map());
|
|
4770
|
-
const createdRowRef = React.useRef(void 0);
|
|
4771
|
-
const alive = React.useRef(true);
|
|
4772
|
-
const mounts = React.useRef(0);
|
|
4773
|
-
const sequence = React.useRef(0);
|
|
4774
|
-
const latest = React.useRef({
|
|
4775
|
-
multiple,
|
|
4776
|
-
select: options.select,
|
|
4777
|
-
idField: "id",
|
|
4778
|
-
valueField: "id",
|
|
4779
|
-
available: false,
|
|
4780
|
-
frames
|
|
4781
|
-
});
|
|
4782
|
-
const project = React.useCallback((row) => {
|
|
4783
|
-
const select = latest.current.select;
|
|
4784
|
-
if (select === void 0) return { ...row };
|
|
4785
|
-
const out = {};
|
|
4786
|
-
const key = row.id !== void 0 ? row.id : row[latest.current.idField];
|
|
4787
|
-
if (key !== void 0) out.id = key;
|
|
4788
|
-
const { valueField } = latest.current;
|
|
4789
|
-
if (Object.hasOwn(row, valueField)) out[valueField] = row[valueField];
|
|
4790
|
-
for (const name of select) if (Object.hasOwn(row, name)) out[name] = row[name];
|
|
4791
|
-
return out;
|
|
4792
|
-
}, []);
|
|
4793
|
-
const settle = React.useCallback((result) => {
|
|
4794
|
-
const pending = pendingRef.current;
|
|
4795
|
-
if (pending === null) return;
|
|
4796
|
-
pendingRef.current = null;
|
|
4797
|
-
pending.detach();
|
|
4798
|
-
if (alive.current) setActive(null);
|
|
4799
|
-
pending.resolve(result);
|
|
4800
|
-
}, []);
|
|
4801
|
-
const toggle = React.useCallback((key, row) => {
|
|
4802
|
-
setActive((current) => {
|
|
4803
|
-
if (current === null) return current;
|
|
4804
|
-
const has = current.selected.some((k) => String(k) === String(key));
|
|
4805
|
-
if (has) rowsRef.current.delete(String(key));
|
|
4806
|
-
else if (row !== void 0) rowsRef.current.set(String(key), row);
|
|
4807
|
-
const selected = has ? current.selected.filter((k) => String(k) !== String(key)) : [...current.selected, key];
|
|
4808
|
-
const next = {
|
|
4809
|
-
...current,
|
|
4810
|
-
selected
|
|
4811
|
-
};
|
|
4812
|
-
activeRef.current = next;
|
|
4813
|
-
return next;
|
|
4814
|
-
});
|
|
4815
|
-
}, []);
|
|
4816
|
-
const onValue = React.useCallback((value) => {
|
|
4817
|
-
const row = createdRowRef.current;
|
|
4818
|
-
createdRowRef.current = void 0;
|
|
4819
|
-
if (latest.current.multiple) {
|
|
4820
|
-
const current = activeRef.current;
|
|
4821
|
-
if (current !== null && !current.selected.some((k) => String(k) === String(value))) toggle(value, row);
|
|
4822
|
-
return;
|
|
4823
|
-
}
|
|
4824
|
-
settle({
|
|
4825
|
-
kind: "selected",
|
|
4826
|
-
keys: [value],
|
|
4827
|
-
rows: row === void 0 ? [] : [project(row)]
|
|
4828
|
-
});
|
|
4829
|
-
}, [
|
|
4830
|
-
project,
|
|
4831
|
-
settle,
|
|
4832
|
-
toggle
|
|
4833
|
-
]);
|
|
4834
|
-
const wiring = useRelationSelect({
|
|
4835
|
-
to: target,
|
|
4836
|
-
by,
|
|
4837
|
-
fixedFilters: selection.fixedFilters,
|
|
4838
|
-
scope,
|
|
4839
|
-
...fieldName === void 0 ? {} : { scopeField: fieldName },
|
|
4840
|
-
held,
|
|
4841
|
-
onValue
|
|
4842
|
-
});
|
|
4843
|
-
latest.current = {
|
|
4844
|
-
multiple,
|
|
4845
|
-
select: options.select,
|
|
4846
|
-
idField: wiring.idField,
|
|
4847
|
-
valueField: wiring.valueField,
|
|
4848
|
-
available: to !== void 0 && wiring.targetDef !== void 0 && !held,
|
|
4849
|
-
frames
|
|
4850
|
-
};
|
|
4851
|
-
const { create: shared } = wiring;
|
|
4852
|
-
const create = React.useMemo(() => ({
|
|
4853
|
-
...shared,
|
|
4854
|
-
start: (openCreate) => shared.start(() => {
|
|
4855
|
-
const opened = openCreate();
|
|
4856
|
-
opened.then((row) => {
|
|
4857
|
-
createdRowRef.current = row === null ? void 0 : { ...row };
|
|
4858
|
-
}, noop);
|
|
4859
|
-
return opened;
|
|
4860
|
-
})
|
|
4861
|
-
}), [shared]);
|
|
4862
|
-
React.useEffect(() => runtime.dataSession.subscribe(() => {
|
|
4863
|
-
const pending = pendingRef.current;
|
|
4864
|
-
if (pending === null) return;
|
|
4865
|
-
const now = sessionIdentity(runtime);
|
|
4866
|
-
if (now.sessionKey !== pending.sessionKey || now.scopeKey !== pending.scopeKey) settle({
|
|
4867
|
-
kind: "cancelled",
|
|
4868
|
-
reason: "session-changed"
|
|
4869
|
-
});
|
|
4870
|
-
}), [runtime, settle]);
|
|
4871
|
-
React.useEffect(() => {
|
|
4872
|
-
alive.current = true;
|
|
4873
|
-
return () => {
|
|
4874
|
-
alive.current = false;
|
|
4875
|
-
settle({
|
|
4876
|
-
kind: "cancelled",
|
|
4877
|
-
reason: "unmounted"
|
|
4878
|
-
});
|
|
4879
|
-
};
|
|
4880
|
-
}, [settle]);
|
|
4881
|
-
React.useEffect(() => {
|
|
4882
|
-
if (held) settle({
|
|
4883
|
-
kind: "cancelled",
|
|
4884
|
-
reason: "unavailable"
|
|
4885
|
-
});
|
|
4886
|
-
}, [held, settle]);
|
|
4887
|
-
const register = React.useCallback(() => {
|
|
4888
|
-
mounts.current += 1;
|
|
4889
|
-
return () => {
|
|
4890
|
-
mounts.current -= 1;
|
|
4891
|
-
if (mounts.current === 0) settle({
|
|
4892
|
-
kind: "cancelled",
|
|
4893
|
-
reason: "unmounted"
|
|
4894
|
-
});
|
|
4895
|
-
};
|
|
4896
|
-
}, [settle]);
|
|
4897
|
-
const open = React.useCallback((opts = {}) => new Promise((resolve) => {
|
|
4898
|
-
settle({
|
|
4899
|
-
kind: "cancelled",
|
|
4900
|
-
reason: "superseded"
|
|
4901
|
-
});
|
|
4902
|
-
if (mounts.current === 0) {
|
|
4903
|
-
if (process.env.NODE_ENV !== "production") console.error("[burojs] useRelationPicker: open() was called but its element is not rendered — render `handle.element` once in your tree.");
|
|
4904
|
-
resolve({
|
|
4905
|
-
kind: "cancelled",
|
|
4906
|
-
reason: "not-mounted"
|
|
4907
|
-
});
|
|
4908
|
-
return;
|
|
4909
|
-
}
|
|
4910
|
-
const { signal } = opts;
|
|
4911
|
-
if (signal?.aborted === true) {
|
|
4912
|
-
resolve({
|
|
4913
|
-
kind: "cancelled",
|
|
4914
|
-
reason: "aborted"
|
|
4915
|
-
});
|
|
4916
|
-
return;
|
|
4917
|
-
}
|
|
4918
|
-
if (!latest.current.available) {
|
|
4919
|
-
resolve({
|
|
4920
|
-
kind: "cancelled",
|
|
4921
|
-
reason: "unavailable"
|
|
4922
|
-
});
|
|
4923
|
-
return;
|
|
4924
|
-
}
|
|
4925
|
-
sequence.current += 1;
|
|
4926
|
-
const id = sequence.current;
|
|
4927
|
-
const onAbort = () => {
|
|
4928
|
-
if (pendingRef.current?.id === id) settle({
|
|
4929
|
-
kind: "cancelled",
|
|
4930
|
-
reason: "aborted"
|
|
4931
|
-
});
|
|
4932
|
-
};
|
|
4933
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
4934
|
-
pendingRef.current = {
|
|
4935
|
-
id,
|
|
4936
|
-
...sessionIdentity(runtime),
|
|
4937
|
-
resolve,
|
|
4938
|
-
detach: () => signal?.removeEventListener("abort", onAbort)
|
|
4939
|
-
};
|
|
4940
|
-
rowsRef.current = new Map();
|
|
4941
|
-
createdRowRef.current = void 0;
|
|
4942
|
-
const next = {
|
|
4943
|
-
id,
|
|
4944
|
-
frames: latest.current.frames,
|
|
4945
|
-
selected: opts.selected ?? []
|
|
4946
|
-
};
|
|
4947
|
-
activeRef.current = next;
|
|
4948
|
-
setActive(next);
|
|
4949
|
-
}), [runtime, settle]);
|
|
4950
|
-
const onSelectRow = React.useCallback((row) => {
|
|
4951
|
-
const field = wiring.valueField;
|
|
4952
|
-
const value = field === "id" ? row.id : row[field];
|
|
4953
|
-
if (typeof value !== "string" && typeof value !== "number") return;
|
|
4954
|
-
settle({
|
|
4955
|
-
kind: "selected",
|
|
4956
|
-
keys: [value],
|
|
4957
|
-
rows: [project(row)]
|
|
4958
|
-
});
|
|
4959
|
-
}, [
|
|
4960
|
-
wiring.valueField,
|
|
4961
|
-
settle,
|
|
4962
|
-
project
|
|
4963
|
-
]);
|
|
4964
|
-
const onDone = React.useCallback(() => {
|
|
4965
|
-
const keys = activeRef.current?.selected ?? [];
|
|
4966
|
-
const rows = keys.flatMap((key) => {
|
|
4967
|
-
const row = rowsRef.current.get(String(key));
|
|
4968
|
-
return row === void 0 ? [] : [project(row)];
|
|
4969
|
-
});
|
|
4970
|
-
settle({
|
|
4971
|
-
kind: "selected",
|
|
4972
|
-
keys,
|
|
4973
|
-
rows
|
|
4974
|
-
});
|
|
4975
|
-
}, [settle, project]);
|
|
4976
|
-
const onOpenChange = React.useCallback((next) => {
|
|
4977
|
-
if (!next) settle({
|
|
4978
|
-
kind: "cancelled",
|
|
4979
|
-
reason: "dismissed"
|
|
4980
|
-
});
|
|
4981
|
-
}, [settle]);
|
|
4982
|
-
return {
|
|
4983
|
-
open,
|
|
4984
|
-
element: jsx(PickerHost, {
|
|
4985
|
-
register,
|
|
4986
|
-
children: active === null || held ? null : jsxs(RecordScopeChain, {
|
|
4987
|
-
frames: active.frames,
|
|
4988
|
-
children: [jsx(LazyRelationPickerDialog, {
|
|
4989
|
-
to: target,
|
|
4990
|
-
open: true,
|
|
4991
|
-
onOpenChange,
|
|
4992
|
-
onSelect: noop,
|
|
4993
|
-
onSelectRow,
|
|
4994
|
-
valueField: wiring.valueField,
|
|
4995
|
-
...selection.fixedFilters === void 0 ? {} : { fixedFilters: selection.fixedFilters },
|
|
4996
|
-
scope,
|
|
4997
|
-
...fieldName === void 0 ? {} : { scopeField: fieldName },
|
|
4998
|
-
...options.create === void 0 ? {} : {
|
|
4999
|
-
create,
|
|
5000
|
-
...options.create.seeds === void 0 ? {} : { createSeeds: options.create.seeds }
|
|
5001
|
-
},
|
|
5002
|
-
fieldName: fieldName ?? target,
|
|
5003
|
-
...multiple ? {
|
|
5004
|
-
multiple: true,
|
|
5005
|
-
selected: active.selected,
|
|
5006
|
-
onToggle: (value, row) => toggle(value, row),
|
|
5007
|
-
onDone
|
|
5008
|
-
} : {}
|
|
5009
|
-
}), wiring.reader]
|
|
5010
|
-
}, active.id)
|
|
5011
|
-
})
|
|
5012
|
-
};
|
|
5013
|
-
}
|
|
5014
|
-
//#endregion
|
|
5015
5332
|
//#region src/forms/declarative-display.tsx
|
|
5016
5333
|
function DeclarativeDisplay(props) {
|
|
5017
5334
|
return jsx(ScreenStateProvider, { children: jsx(DisplayBody, { ...props }) });
|
|
@@ -5037,7 +5354,8 @@ function DisplayBody(props) {
|
|
|
5037
5354
|
}
|
|
5038
5355
|
//#endregion
|
|
5039
5356
|
//#region src/enum/enum-display.tsx
|
|
5040
|
-
function EnumDisplay$1({ enumName, value, variant = "badge", testid, className }) {
|
|
5357
|
+
function EnumDisplay$1({ enumName: enumInput, value, variant = "badge", testid, className }) {
|
|
5358
|
+
const enumName = enumBindingKey(enumInput) ?? "";
|
|
5041
5359
|
const app = useApp();
|
|
5042
5360
|
const caps = useI18nCaps();
|
|
5043
5361
|
const def = app.registry.enums.get(enumName);
|
|
@@ -5085,159 +5403,6 @@ function EnumDisplay$1({ enumName, value, variant = "badge", testid, className }
|
|
|
5085
5403
|
});
|
|
5086
5404
|
}
|
|
5087
5405
|
//#endregion
|
|
5088
|
-
//#region src/data-table/data-table-faceted-filter.tsx
|
|
5089
|
-
function DataTableFacetedFilter({ column, title, options = [], loadOptions, selectedLabelFor, searchPlaceholder, emptyText, getTestId, className }) {
|
|
5090
|
-
const t = useOptionalT();
|
|
5091
|
-
const filterValue = column.getFilterValue();
|
|
5092
|
-
const selected = useMemo(() => {
|
|
5093
|
-
if (Array.isArray(filterValue)) return new Set(filterValue.map(String));
|
|
5094
|
-
return new Set();
|
|
5095
|
-
}, [filterValue]);
|
|
5096
|
-
const [search, setSearch] = useState("");
|
|
5097
|
-
const [asyncOptions, setAsyncOptions] = useState([]);
|
|
5098
|
-
const [loading, setLoading] = useState(false);
|
|
5099
|
-
const debounceRef = useRef(null);
|
|
5100
|
-
const loadOptionsRef = useRef(loadOptions);
|
|
5101
|
-
useEffect(() => {
|
|
5102
|
-
loadOptionsRef.current = loadOptions;
|
|
5103
|
-
});
|
|
5104
|
-
useEffect(() => {
|
|
5105
|
-
if (!loadOptionsRef.current) return;
|
|
5106
|
-
setLoading(true);
|
|
5107
|
-
if (debounceRef.current !== null) clearTimeout(debounceRef.current);
|
|
5108
|
-
let cancelled = false;
|
|
5109
|
-
debounceRef.current = setTimeout(() => {
|
|
5110
|
-
const loader = loadOptionsRef.current;
|
|
5111
|
-
if (!loader) return;
|
|
5112
|
-
loader(search).then((results) => {
|
|
5113
|
-
if (!cancelled) {
|
|
5114
|
-
setAsyncOptions(results);
|
|
5115
|
-
setLoading(false);
|
|
5116
|
-
}
|
|
5117
|
-
}).catch(() => {
|
|
5118
|
-
if (!cancelled) setLoading(false);
|
|
5119
|
-
});
|
|
5120
|
-
}, 250);
|
|
5121
|
-
return () => {
|
|
5122
|
-
cancelled = true;
|
|
5123
|
-
if (debounceRef.current !== null) clearTimeout(debounceRef.current);
|
|
5124
|
-
};
|
|
5125
|
-
}, [search]);
|
|
5126
|
-
const effectiveOptions = loadOptions ? asyncOptions : options;
|
|
5127
|
-
const labelFor = (value) => {
|
|
5128
|
-
const opt = effectiveOptions.find((o) => o.value === value);
|
|
5129
|
-
if (opt) return opt.label;
|
|
5130
|
-
return selectedLabelFor?.(value) ?? value;
|
|
5131
|
-
};
|
|
5132
|
-
const toggle = (value) => {
|
|
5133
|
-
const next = new Set(selected);
|
|
5134
|
-
if (next.has(value)) next.delete(value);
|
|
5135
|
-
else next.add(value);
|
|
5136
|
-
column.setFilterValue(next.size === 0 ? void 0 : Array.from(next));
|
|
5137
|
-
};
|
|
5138
|
-
const selectedValues = Array.from(selected);
|
|
5139
|
-
return jsxs(Popover, { children: [jsx(PopoverTrigger, {
|
|
5140
|
-
asChild: true,
|
|
5141
|
-
children: jsxs(Button, {
|
|
5142
|
-
type: "button",
|
|
5143
|
-
variant: "outline",
|
|
5144
|
-
size: "sm",
|
|
5145
|
-
"data-testid": getTestId?.("trigger"),
|
|
5146
|
-
className: cn("h-8 border-dashed", className),
|
|
5147
|
-
children: [
|
|
5148
|
-
jsx(IconCirclePlus, {
|
|
5149
|
-
className: "mr-2 h-4 w-4",
|
|
5150
|
-
"aria-hidden": "true"
|
|
5151
|
-
}),
|
|
5152
|
-
title,
|
|
5153
|
-
selected.size > 0 && jsxs(Fragment$1, { children: [
|
|
5154
|
-
jsx("span", {
|
|
5155
|
-
className: "mx-2 h-4 w-px bg-border",
|
|
5156
|
-
"aria-hidden": "true"
|
|
5157
|
-
}),
|
|
5158
|
-
jsx(Badge, {
|
|
5159
|
-
variant: "secondary",
|
|
5160
|
-
className: "rounded-sm px-1 font-normal lg:hidden",
|
|
5161
|
-
children: selected.size
|
|
5162
|
-
}),
|
|
5163
|
-
jsx("div", {
|
|
5164
|
-
className: "hidden gap-1 lg:flex",
|
|
5165
|
-
children: selected.size > 2 ? jsx(Badge, {
|
|
5166
|
-
variant: "secondary",
|
|
5167
|
-
className: "rounded-sm px-1 font-normal",
|
|
5168
|
-
children: t("table.selectedCount", {
|
|
5169
|
-
count: selected.size,
|
|
5170
|
-
defaultValue: "{{count}} selected"
|
|
5171
|
-
})
|
|
5172
|
-
}) : selectedValues.map((value) => jsx(Badge, {
|
|
5173
|
-
variant: "secondary",
|
|
5174
|
-
className: "rounded-sm px-1 font-normal",
|
|
5175
|
-
children: labelFor(value)
|
|
5176
|
-
}, value))
|
|
5177
|
-
})
|
|
5178
|
-
] })
|
|
5179
|
-
]
|
|
5180
|
-
})
|
|
5181
|
-
}), jsx(PopoverContent, {
|
|
5182
|
-
className: "w-[220px] p-0",
|
|
5183
|
-
align: "start",
|
|
5184
|
-
children: jsxs(Command, {
|
|
5185
|
-
shouldFilter: !loadOptions,
|
|
5186
|
-
children: [
|
|
5187
|
-
jsx(CommandInput, {
|
|
5188
|
-
placeholder: searchPlaceholder ?? title,
|
|
5189
|
-
"data-testid": getTestId?.("search"),
|
|
5190
|
-
...loadOptions ? {
|
|
5191
|
-
value: search,
|
|
5192
|
-
onValueChange: setSearch
|
|
5193
|
-
} : {}
|
|
5194
|
-
}),
|
|
5195
|
-
jsxs(CommandList, { children: [
|
|
5196
|
-
loading && jsx("div", {
|
|
5197
|
-
className: "py-6 text-center text-sm text-muted-foreground",
|
|
5198
|
-
children: t("list.loadingShort", { defaultValue: "Loading…" })
|
|
5199
|
-
}),
|
|
5200
|
-
jsx(CommandEmpty, { children: emptyText ?? t("relation.noResults", { defaultValue: "No results." }) }),
|
|
5201
|
-
jsx(CommandGroup, { children: effectiveOptions.map((opt) => {
|
|
5202
|
-
const isSelected = selected.has(opt.value);
|
|
5203
|
-
const Icon = opt.icon;
|
|
5204
|
-
return jsxs(CommandItem, {
|
|
5205
|
-
value: opt.label,
|
|
5206
|
-
"data-testid": getTestId?.("option", opt.value),
|
|
5207
|
-
role: "option",
|
|
5208
|
-
"aria-selected": isSelected,
|
|
5209
|
-
"aria-checked": isSelected,
|
|
5210
|
-
onSelect: () => toggle(opt.value),
|
|
5211
|
-
children: [
|
|
5212
|
-
jsx("span", {
|
|
5213
|
-
className: cn("mr-2 flex h-4 w-4 shrink-0 items-center justify-center rounded-sm border", isSelected ? "border-primary bg-primary text-primary-foreground" : "border-input opacity-50"),
|
|
5214
|
-
"aria-hidden": "true",
|
|
5215
|
-
children: isSelected && jsx(IconCheck, { className: "h-3.5 w-3.5" })
|
|
5216
|
-
}),
|
|
5217
|
-
Icon && jsx(Icon, {
|
|
5218
|
-
className: "mr-2 h-4 w-4 text-muted-foreground",
|
|
5219
|
-
"aria-hidden": "true"
|
|
5220
|
-
}),
|
|
5221
|
-
jsx("span", {
|
|
5222
|
-
className: "flex-1 text-left",
|
|
5223
|
-
children: opt.label
|
|
5224
|
-
})
|
|
5225
|
-
]
|
|
5226
|
-
}, opt.value);
|
|
5227
|
-
}) })
|
|
5228
|
-
] }),
|
|
5229
|
-
selected.size > 0 && jsx("button", {
|
|
5230
|
-
type: "button",
|
|
5231
|
-
"data-testid": getTestId?.("clear"),
|
|
5232
|
-
onClick: () => column.setFilterValue(void 0),
|
|
5233
|
-
className: "flex w-full items-center justify-center border-t px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground",
|
|
5234
|
-
children: t("filters.clearAll", { defaultValue: "Clear filters" })
|
|
5235
|
-
})
|
|
5236
|
-
]
|
|
5237
|
-
})
|
|
5238
|
-
})] });
|
|
5239
|
-
}
|
|
5240
|
-
//#endregion
|
|
5241
5406
|
//#region src/data-table/data-table-text-filter.tsx
|
|
5242
5407
|
function DataTableTextFilter({ column, placeholder, testid, className }) {
|
|
5243
5408
|
const external = column.getFilterValue() ?? "";
|
|
@@ -5391,14 +5556,15 @@ const OPERATOR_LABELS = {
|
|
|
5391
5556
|
has: "has",
|
|
5392
5557
|
hasAny: "has any of",
|
|
5393
5558
|
hasAll: "has all of",
|
|
5394
|
-
hasNone: "has none of"
|
|
5559
|
+
hasNone: "has none of",
|
|
5560
|
+
some: "has an item where"
|
|
5395
5561
|
};
|
|
5396
|
-
function formatOperatorLabel(op,
|
|
5397
|
-
return
|
|
5562
|
+
function formatOperatorLabel(op, chromeT) {
|
|
5563
|
+
return chromeT ? chromeT(`filters.operators.${op}`, { defaultValue: OPERATOR_LABELS[op] }) : OPERATOR_LABELS[op];
|
|
5398
5564
|
}
|
|
5399
5565
|
function useOperatorLabel() {
|
|
5400
|
-
const
|
|
5401
|
-
return (op) => formatOperatorLabel(op,
|
|
5566
|
+
const chromeT = useChromeT();
|
|
5567
|
+
return (op) => formatOperatorLabel(op, chromeT);
|
|
5402
5568
|
}
|
|
5403
5569
|
function isEmpty(v) {
|
|
5404
5570
|
return v === void 0 || v === null || v === "";
|
|
@@ -5492,7 +5658,7 @@ function DataTableOperatorFilter({ column, operators, defaultOperator, valueKind
|
|
|
5492
5658
|
//#region src/data-table/data-table-row-actions.tsx
|
|
5493
5659
|
function DataTableRowActions({ row, actions, getTestId, className }) {
|
|
5494
5660
|
const [open, setOpen] = useState(false);
|
|
5495
|
-
const
|
|
5661
|
+
const chromeT = useChromeT();
|
|
5496
5662
|
if (actions.length === 0) return null;
|
|
5497
5663
|
return jsxs(Popover, {
|
|
5498
5664
|
open,
|
|
@@ -5510,7 +5676,7 @@ function DataTableRowActions({ row, actions, getTestId, className }) {
|
|
|
5510
5676
|
"aria-hidden": "true"
|
|
5511
5677
|
}), jsx("span", {
|
|
5512
5678
|
className: "sr-only",
|
|
5513
|
-
children:
|
|
5679
|
+
children: chromeT("actions.openMenu", { defaultValue: "Open row actions menu" })
|
|
5514
5680
|
})]
|
|
5515
5681
|
})
|
|
5516
5682
|
}), jsx(PopoverContent, {
|
|
@@ -5631,7 +5797,8 @@ function BlockScreen({ block, props, resource, record, label }) {
|
|
|
5631
5797
|
children: jsx(PlannedBody, {
|
|
5632
5798
|
screen: compiled,
|
|
5633
5799
|
name: "modal",
|
|
5634
|
-
label: label ?? ""
|
|
5800
|
+
label: label ?? "",
|
|
5801
|
+
...needsRow && row !== null ? { record: row } : {}
|
|
5635
5802
|
})
|
|
5636
5803
|
})
|
|
5637
5804
|
});
|
|
@@ -5640,13 +5807,20 @@ function relation(field) {
|
|
|
5640
5807
|
if (field === null || typeof field !== "object") return false;
|
|
5641
5808
|
return isRelationField(field);
|
|
5642
5809
|
}
|
|
5810
|
+
const resolveOf = (bag) => bag !== null && typeof bag === "object" ? bag.resolve : void 0;
|
|
5811
|
+
function lazyToOne(field) {
|
|
5812
|
+
const entry = field;
|
|
5813
|
+
if (entry.kind === "relationMany" || entry.type === "array") return false;
|
|
5814
|
+
return (resolveOf(entry.meta) ?? resolveOf(entry.opts)) === "lazy";
|
|
5815
|
+
}
|
|
5643
5816
|
function peekFields(def, columns, capabilityFor, fieldVisible = () => true) {
|
|
5644
5817
|
const record = new Set(dtoFields(def, "record"));
|
|
5645
5818
|
const out = [];
|
|
5646
5819
|
for (const name of columns) {
|
|
5647
5820
|
if (out.length === 5) break;
|
|
5648
5821
|
if (name === def.displayField || out.includes(name) || !record.has(name)) continue;
|
|
5649
|
-
|
|
5822
|
+
const field = peekFieldDefinition(def, name);
|
|
5823
|
+
if (!peekLeafAllowed(def, name, capabilityFor, fieldVisible) || relation(field) && !lazyToOne(field)) continue;
|
|
5650
5824
|
out.push(name);
|
|
5651
5825
|
}
|
|
5652
5826
|
return Object.freeze(out);
|
|
@@ -5729,7 +5903,7 @@ function PeekByKey({ target, by }) {
|
|
|
5729
5903
|
} else if (query.error != null) read = failure(query.error, () => void query.refetch());
|
|
5730
5904
|
else read = { state: "pending" };
|
|
5731
5905
|
useEffect(() => {
|
|
5732
|
-
if (read.state === "ambiguous" && process.env.NODE_ENV !== "production") console.error(`[burojs] ${relationAmbiguousError(target, by.field, by.key)
|
|
5906
|
+
if (read.state === "ambiguous" && process.env.NODE_ENV !== "production") console.error(`[burojs] ${technicalText(relationAmbiguousError(target, by.field, by.key))}`);
|
|
5733
5907
|
}, [
|
|
5734
5908
|
read.state,
|
|
5735
5909
|
target,
|
|
@@ -5745,6 +5919,7 @@ function PeekByKey({ target, by }) {
|
|
|
5745
5919
|
function PeekBody({ target, peekKey, read }) {
|
|
5746
5920
|
const tid = useTestIds();
|
|
5747
5921
|
const t = useOptionalT();
|
|
5922
|
+
const chromeT = useChromeT();
|
|
5748
5923
|
const testid = tid.peek(target, peekKey);
|
|
5749
5924
|
if (read.state === "pending") return jsx("div", {
|
|
5750
5925
|
"data-testid": testid,
|
|
@@ -5772,7 +5947,7 @@ function PeekBody({ target, peekKey, read }) {
|
|
|
5772
5947
|
variant: "outline",
|
|
5773
5948
|
"data-testid": `${testid}:retry`,
|
|
5774
5949
|
onClick: read.retry,
|
|
5775
|
-
children:
|
|
5950
|
+
children: chromeT("actions.retry", { defaultValue: "Retry" })
|
|
5776
5951
|
})]
|
|
5777
5952
|
});
|
|
5778
5953
|
if (read.state === "unavailable") return jsx("p", {
|
|
@@ -5916,6 +6091,7 @@ function PeekRecord({ target, testid, row }) {
|
|
|
5916
6091
|
function DeclaredPeekBody({ target, testid, record, frameRecord, def, capabilityFor, fieldVisible, view: View, builtin, open, openable, t }) {
|
|
5917
6092
|
const host = useContext(PeekHostContext);
|
|
5918
6093
|
const title = recordDisplayName(record, def?.displayField);
|
|
6094
|
+
const subtitle = useRecordSubtitle(target)(record) ?? void 0;
|
|
5919
6095
|
const setLabel = host?.setLabel;
|
|
5920
6096
|
useEffect(() => setLabel?.(title), [setLabel, title]);
|
|
5921
6097
|
const controller = useFormController({
|
|
@@ -5951,6 +6127,7 @@ function DeclaredPeekBody({ target, testid, record, frameRecord, def, capability
|
|
|
5951
6127
|
children: [builtin ? jsx(PeekTitle, {
|
|
5952
6128
|
testid,
|
|
5953
6129
|
title,
|
|
6130
|
+
subtitle,
|
|
5954
6131
|
open: openable ? open : void 0
|
|
5955
6132
|
}) : null, jsx(Suspense, {
|
|
5956
6133
|
fallback: null,
|
|
@@ -5963,11 +6140,26 @@ function DeclaredPeekBody({ target, testid, record, frameRecord, def, capability
|
|
|
5963
6140
|
})]
|
|
5964
6141
|
});
|
|
5965
6142
|
}
|
|
5966
|
-
function PeekTitle({ testid, title, open }) {
|
|
5967
|
-
|
|
6143
|
+
function PeekTitle({ testid, title, subtitle, open }) {
|
|
6144
|
+
const heading = open === void 0 ? jsx("p", {
|
|
5968
6145
|
className: "text-sm font-semibold",
|
|
5969
6146
|
children: title
|
|
6147
|
+
}) : jsx(PeekTitleButton, {
|
|
6148
|
+
testid,
|
|
6149
|
+
title,
|
|
6150
|
+
open
|
|
6151
|
+
});
|
|
6152
|
+
if (subtitle === void 0) return heading;
|
|
6153
|
+
return jsxs("div", {
|
|
6154
|
+
className: "flex flex-col gap-0.5",
|
|
6155
|
+
children: [heading, jsx("p", {
|
|
6156
|
+
"data-testid": `${testid}:subtitle`,
|
|
6157
|
+
className: "text-xs text-muted-foreground",
|
|
6158
|
+
children: subtitle
|
|
6159
|
+
})]
|
|
5970
6160
|
});
|
|
6161
|
+
}
|
|
6162
|
+
function PeekTitleButton({ testid, title, open }) {
|
|
5971
6163
|
return jsx("button", {
|
|
5972
6164
|
type: "button",
|
|
5973
6165
|
"data-testid": `${testid}:title`,
|
|
@@ -5995,12 +6187,14 @@ function DefaultPeekBody({ target, testid, row, open }) {
|
|
|
5995
6187
|
const projected = useProjectedRecord(target, dtoRow);
|
|
5996
6188
|
const record = projected.value ?? {};
|
|
5997
6189
|
const title = recordDisplayName(record, def?.displayField);
|
|
6190
|
+
const subtitleOf = useRecordSubtitle(target);
|
|
6191
|
+
const subtitle = projected.status === "ready" ? subtitleOf(record) ?? void 0 : void 0;
|
|
5998
6192
|
const setLabel = host?.setLabel;
|
|
5999
6193
|
useEffect(() => setLabel?.(title), [setLabel, title]);
|
|
6000
6194
|
const columns = useMemo(() => {
|
|
6001
6195
|
if (def === void 0) return [];
|
|
6002
6196
|
const listed = def.views?.list?.columns;
|
|
6003
|
-
return peekFields(def, listed ?? Object.keys(def.fields), capabilityFor, (name) => access[name]?.view === "visible");
|
|
6197
|
+
return peekFields(def, listed?.map(columnName) ?? Object.keys(def.fields), capabilityFor, (name) => access[name]?.view === "visible");
|
|
6004
6198
|
}, [
|
|
6005
6199
|
def,
|
|
6006
6200
|
capabilityFor,
|
|
@@ -6026,6 +6220,7 @@ function DefaultPeekBody({ target, testid, row, open }) {
|
|
|
6026
6220
|
children: [jsx(PeekTitle, {
|
|
6027
6221
|
testid,
|
|
6028
6222
|
title,
|
|
6223
|
+
subtitle,
|
|
6029
6224
|
open
|
|
6030
6225
|
}), columns.length === 0 ? null : jsx("dl", {
|
|
6031
6226
|
className: "grid gap-1.5",
|
|
@@ -6040,13 +6235,21 @@ function DefaultPeekBody({ target, testid, row, open }) {
|
|
|
6040
6235
|
children: resolveFieldLabel(caps, name, declaredText("field", field, "label"))
|
|
6041
6236
|
}), jsx("dd", {
|
|
6042
6237
|
className: "min-w-0 break-words",
|
|
6043
|
-
children: jsx(
|
|
6044
|
-
|
|
6045
|
-
|
|
6046
|
-
|
|
6238
|
+
children: jsx(FieldValueFrame, {
|
|
6239
|
+
field: {
|
|
6240
|
+
...field,
|
|
6241
|
+
name
|
|
6242
|
+
},
|
|
6047
6243
|
value,
|
|
6048
|
-
|
|
6049
|
-
|
|
6244
|
+
surface: "display",
|
|
6245
|
+
children: jsx(ResolvedFieldDisplay, {
|
|
6246
|
+
resource: ref,
|
|
6247
|
+
name,
|
|
6248
|
+
field,
|
|
6249
|
+
value,
|
|
6250
|
+
record,
|
|
6251
|
+
fallback: toDisplayText(value).text
|
|
6252
|
+
})
|
|
6050
6253
|
})
|
|
6051
6254
|
})]
|
|
6052
6255
|
}, name);
|
|
@@ -6069,16 +6272,25 @@ function QuickBodyOf({ entry }) {
|
|
|
6069
6272
|
route: EMPTY_ROUTE
|
|
6070
6273
|
});
|
|
6071
6274
|
if (entry.recordId === void 0 || entry.recordId === "") return jsx(RecordState, { state: "not-found" });
|
|
6072
|
-
return jsx(
|
|
6275
|
+
return jsx(QuickReadRoute, {
|
|
6073
6276
|
entry,
|
|
6074
6277
|
recordId: entry.recordId
|
|
6075
6278
|
});
|
|
6076
6279
|
}
|
|
6077
|
-
function
|
|
6280
|
+
function QuickReadRoute({ entry, recordId }) {
|
|
6281
|
+
const typed = useRouteRecordId(entry.resource, recordId);
|
|
6282
|
+
if (typed === void 0) return jsx(InvalidRouteId, { resource: entry.resource });
|
|
6283
|
+
return jsx(QuickRead, {
|
|
6284
|
+
entry,
|
|
6285
|
+
recordId,
|
|
6286
|
+
typedId: typed
|
|
6287
|
+
});
|
|
6288
|
+
}
|
|
6289
|
+
function QuickRead({ entry, recordId, typedId }) {
|
|
6078
6290
|
const def = useApp().registry.get(entry.resource);
|
|
6079
6291
|
const projection = useMemo(() => def === void 0 ? void 0 : dtoFields(def, "record"), [def]);
|
|
6080
6292
|
const query = useOne(entry.resource, {
|
|
6081
|
-
id:
|
|
6293
|
+
id: typedId,
|
|
6082
6294
|
retry: retryRecordRead,
|
|
6083
6295
|
...projection === void 0 ? {} : { projection }
|
|
6084
6296
|
});
|
|
@@ -6089,20 +6301,20 @@ function QuickRead({ entry, recordId }) {
|
|
|
6089
6301
|
return jsx(QuickLoaded, {
|
|
6090
6302
|
entry,
|
|
6091
6303
|
recordId,
|
|
6304
|
+
typedId,
|
|
6092
6305
|
row,
|
|
6093
6306
|
isCurrentData: !query.isPlaceholderData
|
|
6094
6307
|
});
|
|
6095
6308
|
}
|
|
6096
|
-
if (query.error != null) {
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
}
|
|
6309
|
+
if (query.error != null) return jsx(LoadError, {
|
|
6310
|
+
surface: "record",
|
|
6311
|
+
resource: entry.resource,
|
|
6312
|
+
error: query.error,
|
|
6313
|
+
retry: () => void query.refetch()
|
|
6314
|
+
});
|
|
6103
6315
|
return jsx(RecordState, { state: "loading" });
|
|
6104
6316
|
}
|
|
6105
|
-
function QuickLoaded({ entry, recordId, row, isCurrentData }) {
|
|
6317
|
+
function QuickLoaded({ entry, recordId, typedId, row, isCurrentData }) {
|
|
6106
6318
|
const gate = useEntryGate();
|
|
6107
6319
|
const quick = useQuickEntry();
|
|
6108
6320
|
const answer = gate(entry.resource, entry.mode === "edit" ? "edit" : "show", row);
|
|
@@ -6122,16 +6334,16 @@ function QuickLoaded({ entry, recordId, row, isCurrentData }) {
|
|
|
6122
6334
|
if (!open) return jsx(RecordState, { state: "not-found" });
|
|
6123
6335
|
return jsx(QuickScreenOf, {
|
|
6124
6336
|
entry,
|
|
6125
|
-
route
|
|
6337
|
+
route,
|
|
6338
|
+
recordId: typedId
|
|
6126
6339
|
});
|
|
6127
6340
|
}
|
|
6128
6341
|
function canonicalOrNull(name) {
|
|
6129
|
-
if (typeof name !== "string") return null;
|
|
6130
6342
|
try {
|
|
6131
|
-
return canonicalResourceName(name);
|
|
6132
|
-
|
|
6133
|
-
|
|
6134
|
-
|
|
6343
|
+
if (typeof name === "string") return canonicalResourceName(name);
|
|
6344
|
+
if (name !== null && typeof name === "object") return routeResourceKey(name);
|
|
6345
|
+
} catch {}
|
|
6346
|
+
return null;
|
|
6135
6347
|
}
|
|
6136
6348
|
function absorbedRedirect(to, entry) {
|
|
6137
6349
|
if (typeof to !== "object" || to === null) return null;
|
|
@@ -6145,7 +6357,7 @@ function closeEntry(quick, dismiss) {
|
|
|
6145
6357
|
if (quick.stack.entries.length > 1) quick.stack.pop();
|
|
6146
6358
|
else dismiss(quick.presentationId);
|
|
6147
6359
|
}
|
|
6148
|
-
function QuickScreenOf({ entry, route }) {
|
|
6360
|
+
function QuickScreenOf({ entry, route, recordId }) {
|
|
6149
6361
|
const quick = useQuickEntry();
|
|
6150
6362
|
const instance = useUIInstance();
|
|
6151
6363
|
const runtime = useUIPresentationRuntime();
|
|
@@ -6197,7 +6409,7 @@ function QuickScreenOf({ entry, route }) {
|
|
|
6197
6409
|
children: jsx(RecordScreen, {
|
|
6198
6410
|
resource: entry.resource,
|
|
6199
6411
|
mode: entry.mode,
|
|
6200
|
-
...
|
|
6412
|
+
...recordId === void 0 ? {} : { recordId },
|
|
6201
6413
|
...entry.defaults === void 0 ? {} : { defaults: entry.defaults },
|
|
6202
6414
|
...entry.input === void 0 ? {} : { input: entry.input },
|
|
6203
6415
|
...callbacks
|
|
@@ -6219,7 +6431,7 @@ function useEntryTitle(entry) {
|
|
|
6219
6431
|
const caps = useI18nCaps(entry.resource);
|
|
6220
6432
|
const t = useOptionalT();
|
|
6221
6433
|
if (entry.mode !== "create") return entry.title ?? "";
|
|
6222
|
-
return t
|
|
6434
|
+
return resolveResourceTitle(caps, t, entry.resource, "createTitle", { label: resolveResourceLabel(caps, entry.resource, "single", app.registry.get(entry.resource)) });
|
|
6223
6435
|
}
|
|
6224
6436
|
const HEADING_CLASS = "min-w-0 flex-1 break-words text-lg font-semibold tracking-tight focus-visible:outline-hidden";
|
|
6225
6437
|
function QuickHeader({ entries }) {
|
|
@@ -6476,11 +6688,25 @@ SheetPresentationHost.optionsSchema = Object.freeze({
|
|
|
6476
6688
|
//#region src/ui-presentations/index.tsx
|
|
6477
6689
|
function FlowScreen(props) {
|
|
6478
6690
|
const loaded = useLoaded(loadFlowScreen);
|
|
6479
|
-
if (loaded.error !== void 0) return jsx(FlowLoadFailed, {
|
|
6480
|
-
|
|
6691
|
+
if (loaded.error !== void 0) return jsx(FlowLoadFailed, {
|
|
6692
|
+
label: props.label,
|
|
6693
|
+
onRetry: loaded.retry
|
|
6694
|
+
});
|
|
6695
|
+
if (loaded.module === void 0) return jsxs("div", {
|
|
6696
|
+
"data-buro-flow-step": "loading",
|
|
6697
|
+
"aria-busy": "true",
|
|
6698
|
+
className: "flex flex-col gap-4",
|
|
6699
|
+
children: [jsx(OwnTitleHeading, { label: props.label }), jsx(IconLoader2, {
|
|
6700
|
+
className: "h-5 w-5 animate-spin self-center",
|
|
6701
|
+
"aria-hidden": "true"
|
|
6702
|
+
})]
|
|
6703
|
+
});
|
|
6481
6704
|
const Screen = loaded.module.FlowScreen;
|
|
6482
6705
|
return jsx(FlowBoundary, {
|
|
6483
|
-
fallback: (_error, reset) => jsx(FlowLoadFailed, {
|
|
6706
|
+
fallback: (_error, reset) => jsx(FlowLoadFailed, {
|
|
6707
|
+
label: props.label,
|
|
6708
|
+
onRetry: reset
|
|
6709
|
+
}),
|
|
6484
6710
|
children: jsx(Screen, { ...props })
|
|
6485
6711
|
});
|
|
6486
6712
|
}
|
|
@@ -6755,9 +6981,13 @@ function DefaultCommandPalette({ open, onOpenChange, actions, children }) {
|
|
|
6755
6981
|
}
|
|
6756
6982
|
//#endregion
|
|
6757
6983
|
//#region src/shell/app-shell.tsx
|
|
6758
|
-
function AppShell({ brand, user, loginPath, sidebar, header, palette, docPanel, children }) {
|
|
6984
|
+
function AppShell({ brand, user, loginPath, sidebar, header, palette, docPanel, navChrome, children }) {
|
|
6759
6985
|
const enabled = palette !== false;
|
|
6760
|
-
const { open, setOpen } = useCommandPalette(
|
|
6986
|
+
const { open, setOpen, toggle } = useCommandPalette();
|
|
6987
|
+
useGlobalShortcut({
|
|
6988
|
+
key: "k",
|
|
6989
|
+
mod: true
|
|
6990
|
+
}, toggle, { enabled });
|
|
6761
6991
|
const paletteState = useMemo(() => ({
|
|
6762
6992
|
open,
|
|
6763
6993
|
setOpen
|
|
@@ -6775,7 +7005,7 @@ function AppShell({ brand, user, loginPath, sidebar, header, palette, docPanel,
|
|
|
6775
7005
|
sidebar: fill(sidebar, () => jsx(AppSidebar, {})),
|
|
6776
7006
|
header: fill(header, () => jsx(AppHeader, {})),
|
|
6777
7007
|
...docPanel !== void 0 ? { docPanel } : {},
|
|
6778
|
-
children
|
|
7008
|
+
children: navChrome === false ? children : jsx(NavChrome, { children })
|
|
6779
7009
|
}), paletteNode]
|
|
6780
7010
|
});
|
|
6781
7011
|
}
|
|
@@ -6883,6 +7113,6 @@ function ScopeSwitcher({ options, value, onChange, label, extra, placeholder })
|
|
|
6883
7113
|
const PACKAGE_NAME = "@burojs/ui-shadcn";
|
|
6884
7114
|
const PACKAGE_VERSION = "0.0.0";
|
|
6885
7115
|
//#endregion
|
|
6886
|
-
export { ActionButton, ActionOverflow, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AppActions, AppFlowButton, AppHeader, AppLayout, AppShell, AppSidebar, AuthPage, Avatar, AvatarFallback, AvatarImage, Badge, BooleanDisplay, BooleanInput, BrandMark, Breadcrumbs, BulkActionToolbar, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CheckConfirmDialog, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, ColumnsToggle, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandLoading, CommandPalette, CommandPaletteActionsGroup, CommandPaletteCreateGroup, CommandPaletteDocsGroup, CommandPaletteNavigationGroups, CommandPaletteRecentGroup, CommandPaletteRecordsGroup, CommandPaletteTrigger, CommandSeparator, ContextPicker, CopyId, CreateButton, CursorLoadMore, DEFAULT_LANGUAGE_STORAGE_KEY, DataTable, DataTableDateRangeFilter, DataTableEnumFilter, DataTableFacetedFilter, DataTableNumRangeFilter, DataTableOperatorFilter, DataTableRowActions, DataTableTextFilter, DataTableToolbar, DataTableViewOptions, DateDisplay, DateInput, DeclarativeDisplay, DeclarativeForm, DefaultCommandPalette, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogPresentationHost, DialogPresentationShell, DialogTitle, DialogTrigger, DisabledAction, DocBrowser, DocInfo, DocPanel, DocTrailHelp, DocumentTitleProvider, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, ENUM_PICKER_CLEAR_SENTINEL, EditPageHeader, EnumBadge, EnumDisplay, EnumInput, EnumPicker, EnumDisplay$1 as EnumValueDisplay, ExportButton, ExportDialog, Field, FieldDisplay, FileDisplay, FileField, FileInput, FilterBadges, FilterBuilder, FilterPanel, FilterRegion, FilterValueControl, FlowActionButton, Form, FormActions, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, HeaderBreadcrumbs, HelpButton, Icon, Input, Label, LanguageSubmenu, LanguageSwitch, LinkComponentProvider, LinkKeysDisplay, ListBody, ListBulkBar, ListColumns, ListControls, ListCreate, ListErrorState, ListExport, ListFilters, ListFlows, ListLive, ListSavedViews, ListSearchInput, LoginForm,
|
|
7116
|
+
export { ActionButton, ActionOverflow, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AppActions, AppFlowButton, AppHeader, AppLayout, AppShell, AppSidebar, AuthPage, Avatar, AvatarFallback, AvatarImage, Badge, BooleanDisplay, BooleanInput, BrandMark, Breadcrumbs, BulkActionToolbar, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CheckConfirmDialog, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, ColumnsToggle, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandLoading, CommandPalette, CommandPaletteActionsGroup, CommandPaletteCreateGroup, CommandPaletteDocsGroup, CommandPaletteNavigationGroups, CommandPaletteRecentGroup, CommandPaletteRecordsGroup, CommandPaletteTrigger, CommandSeparator, ContextPicker, CopyId, CreateButton, CursorLoadMore, DEFAULT_LANGUAGE_STORAGE_KEY, DataTable, DataTableDateRangeFilter, DataTableEnumFilter, DataTableFacetedFilter, DataTableNumRangeFilter, DataTableOperatorFilter, DataTableRowActions, DataTableTextFilter, DataTableToolbar, DataTableViewOptions, DateDisplay, DateInput, DeclarativeDisplay, DeclarativeForm, DefaultCommandPalette, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogPresentationHost, DialogPresentationShell, DialogTitle, DialogTrigger, DisabledAction, DocBrowser, DocInfo, DocPanel, DocTrailHelp, DocumentTitleProvider, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, ENUM_PICKER_CLEAR_SENTINEL, EditPageHeader, EnumBadge, EnumDisplay, EnumInput, EnumPicker, EnumDisplay$1 as EnumValueDisplay, ExportButton, ExportDialog, FacetedFilterPicker, Field, FieldDisplay, FileDisplay, FileField, FileInput, FilterBadges, FilterBuilder, FilterPanel, FilterRegion, FilterValueControl, FlowActionButton, Form, FormActions, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, HeaderBreadcrumbs, HelpButton, Icon, Input, Label, LanguageSubmenu, LanguageSwitch, LinkComponentProvider, LinkKeysDisplay, ListBody, ListBulkBar, ListColumns, ListControls, ListCreate, ListErrorState, ListExport, ListFilters, ListFlows, ListLive, ListSavedViews, ListSearchInput, LoginForm, NavAreaPage, NavChrome, NavMain, NavigationGuardDialog, NumberDisplay, NumberInput, PACKAGE_NAME, PACKAGE_VERSION, PageHeader, PinnedFilterControls, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverPresentationHost, PopoverTrigger, PresetFilterControls, Progress, RecordActions, RecordBreadcrumbs, RecordPage, RecordScreen, RecordTitle, RefreshButton, RelationDisplay, RelationField, RelationManyDisplay, RelationPicker, LazyRelationPickerDialog as RelationPickerDialog, RelationPickerInput, ResourceList, ResourceListPage, ResourcePageRouter, SavedViewsDropdown, ScopeDimensionPicker, ScopeSwitcher, SecondarySidebarLayout, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetPresentationHost, SheetPresentationShell, SheetTitle, SheetTrigger, ShellProvider, ShowPageHeader, Sidebar, SidebarBrand, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, THEME_CHOICES, THEME_STORAGE_KEY, Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsLayout, TabsList, TabsTrigger, TaskRunPanel, TextDisplay, TextInput, Textarea, TextareaDisplay, TextareaInput, ThemeSubmenu, ThemeToggle, Toaster, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserMenu, badgeVariants, buildNavItems, buroSortingToTanStack, buttonVariants, cn, defaultNavLayouts, defaultUserMapper, downloadArtifact, formatOperatorLabel, hasIcon, i18nPrefixToRef, isImage, layoutSlot, listSlot, loadLocale, localeLabel, modeForSurface, recordDisplayName, registerIcons, relationLinkClassName, resolveNavIcon, resolveUpdater, saveLocale, shadcnBlockImplementations, shadcnFieldImplementations, shadcnPresentationHosts, spacing, tanStackSortingToBuro, toast, typography, useBuroDataTable, useCurrentUser, useDialogFilterState, useDocumentTitle, useExportRunWatcher, useFormControl, useFormField, useHref, useIsMobile, useLanguagePaletteActions, useLanguageSwitch, useLayout, useLayoutResolver, useLinkComponent, useListSlot, useMatch, useNavIcon, useNavTree, useNavVisible, useOptionalSidebar, usePaletteState, usePresentationCopy, useRelationPicker, useShell, useSidebar, useTheme, useThemePaletteActions, webPlatform, wrapperEnabled };
|
|
6887
7117
|
|
|
6888
7118
|
//# sourceMappingURL=index.js.map
|