@burojs/ui-shadcn 0.3.0 → 0.5.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 +26 -7
- package/dist/bulk-summary-CwSd6Yjb.cjs +108 -0
- package/dist/bulk-summary-CwSd6Yjb.cjs.map +1 -0
- package/dist/bulk-summary-GxMDP4bw.js +108 -0
- package/dist/bulk-summary-GxMDP4bw.js.map +1 -0
- package/dist/button-BxnnE28H.cjs +55 -0
- package/dist/button-BxnnE28H.cjs.map +1 -0
- package/dist/button-MWVeZaqj.js +44 -0
- package/dist/button-MWVeZaqj.js.map +1 -0
- package/dist/candidates-gate-CX2PBu6l.js +63 -0
- package/dist/candidates-gate-CX2PBu6l.js.map +1 -0
- package/dist/candidates-gate-DiFI52r7.cjs +70 -0
- package/dist/candidates-gate-DiFI52r7.cjs.map +1 -0
- package/dist/candidates-relation-picker-CBsVcnPR.js +82 -0
- package/dist/candidates-relation-picker-CBsVcnPR.js.map +1 -0
- package/dist/candidates-relation-picker-Dd_GVLlu.cjs +84 -0
- package/dist/candidates-relation-picker-Dd_GVLlu.cjs.map +1 -0
- package/dist/check-confirm-dialog-BRByTFpg.cjs +1534 -0
- package/dist/check-confirm-dialog-BRByTFpg.cjs.map +1 -0
- package/dist/check-confirm-dialog-CkaVTPT9.js +1232 -0
- package/dist/check-confirm-dialog-CkaVTPT9.js.map +1 -0
- package/dist/dialog-B_rt9S1c.js +63 -0
- package/dist/dialog-B_rt9S1c.js.map +1 -0
- package/dist/dialog-DRNUq9EA.cjs +112 -0
- package/dist/dialog-DRNUq9EA.cjs.map +1 -0
- package/dist/filter-builder-B3mZFL-K.cjs +1761 -0
- package/dist/filter-builder-B3mZFL-K.cjs.map +1 -0
- package/dist/filter-builder-DOnaXNfP.js +1605 -0
- package/dist/filter-builder-DOnaXNfP.js.map +1 -0
- package/dist/flow-runtime-B6zOHYqI.cjs +255 -0
- package/dist/flow-runtime-B6zOHYqI.cjs.map +1 -0
- package/dist/flow-runtime-D8h99FSg.js +252 -0
- package/dist/flow-runtime-D8h99FSg.js.map +1 -0
- package/dist/flow-screen-CX05b3G9.cjs +705 -0
- package/dist/flow-screen-CX05b3G9.cjs.map +1 -0
- package/dist/flow-screen-CmbARSqg.js +701 -0
- package/dist/flow-screen-CmbARSqg.js.map +1 -0
- package/dist/index.cjs +6453 -17494
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3754 -3621
- package/dist/index.d.ts +3754 -3621
- package/dist/index.js +6217 -17219
- package/dist/index.js.map +1 -1
- package/dist/inline-flow-host-B7U1OJUe.cjs +112 -0
- package/dist/inline-flow-host-B7U1OJUe.cjs.map +1 -0
- package/dist/inline-flow-host-C3H2UpSA.js +112 -0
- package/dist/inline-flow-host-C3H2UpSA.js.map +1 -0
- package/dist/input-BI0czGyI.cjs +23 -0
- package/dist/input-BI0czGyI.cjs.map +1 -0
- package/dist/input-CUPStzZO.js +17 -0
- package/dist/input-CUPStzZO.js.map +1 -0
- package/dist/label-66W1qbke.js +29 -0
- package/dist/label-66W1qbke.js.map +1 -0
- package/dist/label-w6JYf2cF.cjs +36 -0
- package/dist/label-w6JYf2cF.cjs.map +1 -0
- package/dist/layout/theme-storage-key.cjs +5 -10
- package/dist/layout/theme-storage-key.cjs.map +1 -1
- package/dist/layout/theme-storage-key.d.cts +2 -23
- package/dist/layout/theme-storage-key.d.ts +2 -23
- package/dist/layout/theme-storage-key.js +5 -2
- package/dist/layout/theme-storage-key.js.map +1 -1
- package/dist/lazy-relation-picker-dialog-2oxnA6IR.js +14 -0
- package/dist/lazy-relation-picker-dialog-2oxnA6IR.js.map +1 -0
- package/dist/lazy-relation-picker-dialog-BfAGKzUG.cjs +19 -0
- package/dist/lazy-relation-picker-dialog-BfAGKzUG.cjs.map +1 -0
- package/dist/markdown/index.cjs +424 -511
- package/dist/markdown/index.cjs.map +1 -1
- package/dist/markdown/index.d.cts +1072 -34
- package/dist/markdown/index.d.ts +1072 -34
- package/dist/markdown/index.js +411 -459
- package/dist/markdown/index.js.map +1 -1
- package/dist/page-flow-route-CQ7HsbBm.cjs +277 -0
- package/dist/page-flow-route-CQ7HsbBm.cjs.map +1 -0
- package/dist/page-flow-route-CyXSvXSE.js +277 -0
- package/dist/page-flow-route-CyXSvXSE.js.map +1 -0
- package/dist/peek-filter-CnqHwTMU.cjs +51 -0
- package/dist/peek-filter-CnqHwTMU.cjs.map +1 -0
- package/dist/peek-filter-ErLfO153.js +28 -0
- package/dist/peek-filter-ErLfO153.js.map +1 -0
- package/dist/place-node--GdsP688.js +7315 -0
- package/dist/place-node--GdsP688.js.map +1 -0
- package/dist/place-node-SIp4XYQH.cjs +7833 -0
- package/dist/place-node-SIp4XYQH.cjs.map +1 -0
- package/dist/related-list-cards-B6x9HQQp.js +42 -0
- package/dist/related-list-cards-B6x9HQQp.js.map +1 -0
- package/dist/related-list-cards-nxuODlIA.cjs +42 -0
- package/dist/related-list-cards-nxuODlIA.cjs.map +1 -0
- package/dist/related-list-timeline-BYJKEbmA.cjs +142 -0
- package/dist/related-list-timeline-BYJKEbmA.cjs.map +1 -0
- package/dist/related-list-timeline-DEdfd-rr.js +142 -0
- package/dist/related-list-timeline-DEdfd-rr.js.map +1 -0
- package/dist/related-rows-B4levHcR.js +186 -0
- package/dist/related-rows-B4levHcR.js.map +1 -0
- package/dist/related-rows-zh5f_4QR.cjs +209 -0
- package/dist/related-rows-zh5f_4QR.cjs.map +1 -0
- package/dist/relation-create-BOaUe12G.cjs +362 -0
- package/dist/relation-create-BOaUe12G.cjs.map +1 -0
- package/dist/relation-create-Bg-eEJLs.js +337 -0
- package/dist/relation-create-Bg-eEJLs.js.map +1 -0
- package/dist/relation-many-picker-B-NCEUgX.cjs +465 -0
- package/dist/relation-many-picker-B-NCEUgX.cjs.map +1 -0
- package/dist/relation-many-picker-gdAOD-qK.js +464 -0
- package/dist/relation-many-picker-gdAOD-qK.js.map +1 -0
- package/dist/relation-picker-BAY77ivO.js +462 -0
- package/dist/relation-picker-BAY77ivO.js.map +1 -0
- package/dist/relation-picker-Da_uhFvA.cjs +479 -0
- package/dist/relation-picker-Da_uhFvA.cjs.map +1 -0
- package/dist/relation-picker-dialog-M0pQaWlp.cjs +300 -0
- package/dist/relation-picker-dialog-M0pQaWlp.cjs.map +1 -0
- package/dist/relation-picker-dialog-hA9rYrZB.js +299 -0
- package/dist/relation-picker-dialog-hA9rYrZB.js.map +1 -0
- package/dist/resource-page-router-OSQyRA5b.cjs +1779 -0
- package/dist/resource-page-router-OSQyRA5b.cjs.map +1 -0
- package/dist/resource-page-router-T4vS5gbJ.js +1582 -0
- package/dist/resource-page-router-T4vS5gbJ.js.map +1 -0
- package/dist/rich-text-DFerywgz.js +457 -0
- package/dist/rich-text-DFerywgz.js.map +1 -0
- package/dist/rich-text-vTyVjDoa.cjs +460 -0
- package/dist/rich-text-vTyVjDoa.cjs.map +1 -0
- package/dist/search-access-B7G5oR8n.cjs +812 -0
- package/dist/search-access-B7G5oR8n.cjs.map +1 -0
- package/dist/search-access-CURsWn-U.js +669 -0
- package/dist/search-access-CURsWn-U.js.map +1 -0
- package/dist/shell-BPlk8hEa.js +205 -0
- package/dist/shell-BPlk8hEa.js.map +1 -0
- package/dist/shell-DxhlsPwm.cjs +271 -0
- package/dist/shell-DxhlsPwm.cjs.map +1 -0
- package/dist/skeleton-U2noefj5.js +13 -0
- package/dist/skeleton-U2noefj5.js.map +1 -0
- package/dist/skeleton-_1gP7wan.cjs +18 -0
- package/dist/skeleton-_1gP7wan.cjs.map +1 -0
- package/dist/styles.css +255 -17
- package/dist/theme/theme-css.cjs +95 -96
- package/dist/theme/theme-css.cjs.map +1 -1
- package/dist/theme/theme-css.d.cts +10 -8
- package/dist/theme/theme-css.d.ts +10 -8
- package/dist/theme/theme-css.js +94 -94
- package/dist/theme/theme-css.js.map +1 -1
- package/dist/theme/theme-storage.cjs +34 -39
- package/dist/theme/theme-storage.cjs.map +1 -1
- package/dist/theme/theme-storage.d.cts +3 -1
- package/dist/theme/theme-storage.d.ts +3 -1
- package/dist/theme/theme-storage.js +33 -37
- package/dist/theme/theme-storage.js.map +1 -1
- package/dist/theme-storage-key-pYlp4aDS.d.cts +31 -0
- package/dist/theme-storage-key-pYlp4aDS.d.ts +31 -0
- package/dist/toaster-C7CiYA4Z.cjs +248 -0
- package/dist/toaster-C7CiYA4Z.cjs.map +1 -0
- package/dist/toaster-CfCRLgR-.js +164 -0
- package/dist/toaster-CfCRLgR-.js.map +1 -0
- package/dist/use-dialog-filter-state-BBCC0OEK.cjs +92 -0
- package/dist/use-dialog-filter-state-BBCC0OEK.cjs.map +1 -0
- package/dist/use-dialog-filter-state-BDcgS5Oz.js +87 -0
- package/dist/use-dialog-filter-state-BDcgS5Oz.js.map +1 -0
- package/dist/use-theme-DFlpXils.cjs +257 -0
- package/dist/use-theme-DFlpXils.cjs.map +1 -0
- package/dist/use-theme-dnE3Od3I.js +175 -0
- package/dist/use-theme-dnE3Od3I.js.map +1 -0
- package/package.json +18 -17
- package/dist/chunk-ABUQPOOE.js +0 -11
- package/dist/chunk-ABUQPOOE.js.map +0 -1
- package/dist/chunk-DBGGWBFG.cjs +0 -199
- package/dist/chunk-DBGGWBFG.cjs.map +0 -1
- package/dist/chunk-FMX4GLCQ.js +0 -6
- package/dist/chunk-FMX4GLCQ.js.map +0 -1
- package/dist/chunk-UC57Z243.js +0 -143
- package/dist/chunk-UC57Z243.js.map +0 -1
- package/dist/chunk-UPGPO75B.js +0 -164
- package/dist/chunk-UPGPO75B.js.map +0 -1
- package/dist/chunk-VXJAXJ3U.cjs +0 -8
- package/dist/chunk-VXJAXJ3U.cjs.map +0 -1
- package/dist/chunk-W7AEYE7A.cjs +0 -13
- package/dist/chunk-W7AEYE7A.cjs.map +0 -1
- package/dist/chunk-YF5IW525.cjs +0 -155
- package/dist/chunk-YF5IW525.cjs.map +0 -1
- package/dist/rich-text-6V7WZ3WV.cjs +0 -518
- package/dist/rich-text-6V7WZ3WV.cjs.map +0 -1
- package/dist/rich-text-N2FZEJJV.js +0 -491
- package/dist/rich-text-N2FZEJJV.js.map +0 -1
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
const require_toaster = require("./toaster-C7CiYA4Z.cjs");
|
|
2
|
+
const require_search_access = require("./search-access-B7G5oR8n.cjs");
|
|
3
|
+
const require_place_node = require("./place-node-SIp4XYQH.cjs");
|
|
4
|
+
const require_peek_filter = require("./peek-filter-CnqHwTMU.cjs");
|
|
5
|
+
let _burojs_core = require("@burojs/core");
|
|
6
|
+
let _burojs_react = require("@burojs/react");
|
|
7
|
+
let react = require("react");
|
|
8
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
9
|
+
//#region src/blocks/default-item.tsx
|
|
10
|
+
const isNumeric = (field) => field?.kind === "number";
|
|
11
|
+
function DefaultItem({ resource, row, raw, columns, variant = "card" }) {
|
|
12
|
+
const def = (0, _burojs_react.useApp)().registry.get(resource);
|
|
13
|
+
const caps = (0, _burojs_react.useI18nCaps)(resource);
|
|
14
|
+
const access = useRowAccess(resource)(raw);
|
|
15
|
+
const viewVisible = useViewVisible(resource);
|
|
16
|
+
const fields = def === void 0 ? [] : (columns ?? def.views?.list?.columns ?? Object.keys(def.fields)).filter((name, index, names) => name !== def.displayField && names.indexOf(name) === index && require_peek_filter.peekLeafAllowed(def, name, access, viewVisible));
|
|
17
|
+
const ref = def?.ref ?? {
|
|
18
|
+
namespace: "default",
|
|
19
|
+
id: resource
|
|
20
|
+
};
|
|
21
|
+
const definition = (name) => require_peek_filter.peekFieldDefinition(def, name);
|
|
22
|
+
const value = (name) => (0, react_jsx_runtime.jsx)(require_place_node.ResolvedFieldDisplay, {
|
|
23
|
+
resource: ref,
|
|
24
|
+
name,
|
|
25
|
+
field: definition(name),
|
|
26
|
+
value: row[name],
|
|
27
|
+
record: row,
|
|
28
|
+
fallback: require_place_node.toDisplayText(row[name]).text
|
|
29
|
+
});
|
|
30
|
+
const title = (0, react_jsx_runtime.jsx)("p", {
|
|
31
|
+
className: "truncate text-sm font-medium",
|
|
32
|
+
children: require_search_access.recordDisplayName(row, def?.displayField)
|
|
33
|
+
});
|
|
34
|
+
if (variant === "entry") {
|
|
35
|
+
const shown = fields.filter((name) => row[name] != null && row[name] !== "");
|
|
36
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
37
|
+
className: "flex min-w-0 flex-col gap-0.5",
|
|
38
|
+
"data-buro-default-item": "",
|
|
39
|
+
children: [title, shown.length === 0 ? null : (0, react_jsx_runtime.jsx)("div", {
|
|
40
|
+
"data-buro-item-meta": "",
|
|
41
|
+
className: "truncate text-xs text-muted-foreground",
|
|
42
|
+
children: shown.map((name, index) => (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [index > 0 ? " · " : null, value(name)] }, name))
|
|
43
|
+
})]
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
const numbers = fields.filter((name) => isNumeric(definition(name)));
|
|
47
|
+
const pairs = fields.filter((name) => !isNumeric(definition(name)));
|
|
48
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
49
|
+
className: "flex min-w-0 items-start gap-3",
|
|
50
|
+
"data-buro-default-item": "",
|
|
51
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
52
|
+
className: "flex min-w-0 flex-1 flex-col gap-2",
|
|
53
|
+
children: [title, pairs.length === 0 ? null : (0, react_jsx_runtime.jsx)("dl", {
|
|
54
|
+
className: "grid gap-1.5",
|
|
55
|
+
children: pairs.map((name) => (0, react_jsx_runtime.jsxs)("div", {
|
|
56
|
+
className: "flex min-w-0 items-baseline gap-2 text-sm",
|
|
57
|
+
children: [(0, react_jsx_runtime.jsx)("dt", {
|
|
58
|
+
className: "w-24 shrink-0 truncate text-xs text-muted-foreground",
|
|
59
|
+
children: (0, _burojs_core.resolveFieldLabel)(caps, name, definition(name)?.label)
|
|
60
|
+
}), (0, react_jsx_runtime.jsx)("dd", {
|
|
61
|
+
className: "min-w-0 break-words",
|
|
62
|
+
children: value(name)
|
|
63
|
+
})]
|
|
64
|
+
}, name))
|
|
65
|
+
})]
|
|
66
|
+
}), numbers.length === 0 ? null : (0, react_jsx_runtime.jsx)("div", {
|
|
67
|
+
"data-buro-item-trailing": "",
|
|
68
|
+
className: "flex shrink-0 flex-col items-end gap-1 border-l pl-3 text-sm tabular-nums",
|
|
69
|
+
children: numbers.map((name) => (0, react_jsx_runtime.jsx)("span", {
|
|
70
|
+
title: (0, _burojs_core.resolveFieldLabel)(caps, name, definition(name)?.label),
|
|
71
|
+
children: value(name)
|
|
72
|
+
}, name))
|
|
73
|
+
})]
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/blocks/related-rows.tsx
|
|
78
|
+
function useRowAccess(resource) {
|
|
79
|
+
const app = (0, _burojs_react.useApp)();
|
|
80
|
+
const scope = (0, _burojs_react.useCtx)((c) => c.scope);
|
|
81
|
+
const user = (0, _burojs_react.useCtx)((c) => c.user);
|
|
82
|
+
const permissions = (0, _burojs_react.useCtx)((c) => c.permissions);
|
|
83
|
+
return (0, react.useCallback)((row) => (capability, target, defaultAllowed = true) => {
|
|
84
|
+
const rules = app.ruleSource.rules(resource);
|
|
85
|
+
if (rules.length === 0) return { allowed: defaultAllowed };
|
|
86
|
+
const ctx = (0, _burojs_core.ruleContextFor)({
|
|
87
|
+
user,
|
|
88
|
+
scope,
|
|
89
|
+
permissions,
|
|
90
|
+
record: row,
|
|
91
|
+
mode: "show",
|
|
92
|
+
resource
|
|
93
|
+
});
|
|
94
|
+
return (0, _burojs_core.resolveCapability)(rules, capability, target, ctx, defaultAllowed);
|
|
95
|
+
}, [
|
|
96
|
+
app.ruleSource,
|
|
97
|
+
resource,
|
|
98
|
+
scope,
|
|
99
|
+
user,
|
|
100
|
+
permissions
|
|
101
|
+
]);
|
|
102
|
+
}
|
|
103
|
+
function useViewVisible(resource) {
|
|
104
|
+
const access = (0, _burojs_react.useFieldAccess)(resource, "every");
|
|
105
|
+
return (0, react.useCallback)((field) => {
|
|
106
|
+
const decision = access[field];
|
|
107
|
+
return decision === void 0 || decision.view === "visible";
|
|
108
|
+
}, [access]);
|
|
109
|
+
}
|
|
110
|
+
function useProjectedRows(resource, rows, item) {
|
|
111
|
+
const def = (0, _burojs_react.useApp)().registry.get(resource);
|
|
112
|
+
const accessOf = useRowAccess(resource);
|
|
113
|
+
const viewRow = (0, _burojs_react.useViewRow)(resource);
|
|
114
|
+
const viewVisible = useViewVisible(resource);
|
|
115
|
+
const idField = (def?.data)?.idField ?? "id";
|
|
116
|
+
const project = (0, react.useCallback)((row) => def === void 0 ? viewRow(row) : require_peek_filter.peekRow(def, viewRow(row), idField, accessOf(row), viewVisible), [
|
|
117
|
+
def,
|
|
118
|
+
idField,
|
|
119
|
+
accessOf,
|
|
120
|
+
viewRow,
|
|
121
|
+
viewVisible
|
|
122
|
+
]);
|
|
123
|
+
const hidden = (0, react.useCallback)((field) => field !== idField && (def === void 0 || !require_peek_filter.peekLeafAllowed(def, field, accessOf(_burojs_core.RECORD_PROBE), viewVisible)), [
|
|
124
|
+
def,
|
|
125
|
+
idField,
|
|
126
|
+
accessOf,
|
|
127
|
+
viewVisible
|
|
128
|
+
]);
|
|
129
|
+
const probe = (0, react.useMemo)(() => rows[0] === void 0 ? void 0 : project(rows[0]), [rows, project]);
|
|
130
|
+
return {
|
|
131
|
+
def,
|
|
132
|
+
project,
|
|
133
|
+
drawn: require_place_node.useItemDrawn(item, hidden, probe),
|
|
134
|
+
title: (0, react.useCallback)((row) => require_search_access.recordDisplayName(project(row), def?.displayField), [project, def])
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function RowContent({ resource, raw, row, item, drawn, columns, variant }) {
|
|
138
|
+
const fallback = (0, react_jsx_runtime.jsx)(DefaultItem, {
|
|
139
|
+
resource,
|
|
140
|
+
row,
|
|
141
|
+
raw,
|
|
142
|
+
columns,
|
|
143
|
+
...variant === void 0 ? {} : { variant }
|
|
144
|
+
});
|
|
145
|
+
if (item === void 0 || !drawn) return fallback;
|
|
146
|
+
return (0, react_jsx_runtime.jsx)(require_place_node.RelatedItem, {
|
|
147
|
+
handle: item,
|
|
148
|
+
row,
|
|
149
|
+
fallback
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
function RowOpener({ title, href, quick }) {
|
|
153
|
+
const RouterLink = require_toaster.useLinkComponent();
|
|
154
|
+
const className = "outline-none after:absolute after:inset-0 after:rounded-[inherit] focus-visible:after:ring-2 focus-visible:after:ring-ring";
|
|
155
|
+
const name = (0, react_jsx_runtime.jsx)("span", {
|
|
156
|
+
className: "sr-only",
|
|
157
|
+
children: title
|
|
158
|
+
});
|
|
159
|
+
if (quick !== null) return href ? (0, react_jsx_runtime.jsx)(require_search_access.ClaimedQuickLink, {
|
|
160
|
+
href,
|
|
161
|
+
className,
|
|
162
|
+
onOpen: quick,
|
|
163
|
+
children: name
|
|
164
|
+
}) : (0, react_jsx_runtime.jsx)("button", {
|
|
165
|
+
type: "button",
|
|
166
|
+
role: "link",
|
|
167
|
+
[_burojs_react.QUICK_ANCHOR_ATTRIBUTE]: "",
|
|
168
|
+
className: `${className} block size-0 p-0`,
|
|
169
|
+
onClick: (event) => {
|
|
170
|
+
if (!require_search_access.isPlainLeftClick(event)) return;
|
|
171
|
+
quick();
|
|
172
|
+
},
|
|
173
|
+
children: name
|
|
174
|
+
});
|
|
175
|
+
if (href) return (0, react_jsx_runtime.jsx)(RouterLink, {
|
|
176
|
+
href,
|
|
177
|
+
className,
|
|
178
|
+
children: name
|
|
179
|
+
});
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
const ITEM_LAYER_CLASS = "relative z-[1] pointer-events-none [&_a]:pointer-events-auto [&_button]:pointer-events-auto [&_input]:pointer-events-auto [&_select]:pointer-events-auto [&_textarea]:pointer-events-auto [&_summary]:pointer-events-auto [&_[role=button]]:pointer-events-auto [&_[role=link]]:pointer-events-auto [&_[role=checkbox]]:pointer-events-auto [&_[role=switch]]:pointer-events-auto";
|
|
183
|
+
//#endregion
|
|
184
|
+
Object.defineProperty(exports, "ITEM_LAYER_CLASS", {
|
|
185
|
+
enumerable: true,
|
|
186
|
+
get: function() {
|
|
187
|
+
return ITEM_LAYER_CLASS;
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
Object.defineProperty(exports, "RowContent", {
|
|
191
|
+
enumerable: true,
|
|
192
|
+
get: function() {
|
|
193
|
+
return RowContent;
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
Object.defineProperty(exports, "RowOpener", {
|
|
197
|
+
enumerable: true,
|
|
198
|
+
get: function() {
|
|
199
|
+
return RowOpener;
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
Object.defineProperty(exports, "useProjectedRows", {
|
|
203
|
+
enumerable: true,
|
|
204
|
+
get: function() {
|
|
205
|
+
return useProjectedRows;
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
//# sourceMappingURL=related-rows-zh5f_4QR.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"related-rows-zh5f_4QR.cjs","names":["useApp","useI18nCaps","peekLeafAllowed","peekFieldDefinition","ResolvedFieldDisplay","toDisplayText","recordDisplayName","Fragment","resolveFieldLabel","useApp","useCtx","useCallback","ruleContextFor","resolveCapability","useFieldAccess","useViewRow","peekRow","peekLeafAllowed","RECORD_PROBE","useMemo","useItemDrawn","recordDisplayName","RelatedItem","useLinkComponent","ClaimedQuickLink","QUICK_ANCHOR_ATTRIBUTE","isPlainLeftClick"],"sources":["../src/blocks/default-item.tsx","../src/blocks/related-rows.tsx"],"sourcesContent":["'use client';\nimport { type EntityRef, resolveFieldLabel } from '@burojs/core';\nimport { useApp, useI18nCaps } from '@burojs/react';\nimport { Fragment, type ReactElement } from 'react';\nimport { toDisplayText } from '../fields/display-value.js';\nimport { ResolvedFieldDisplay } from '../fields/resolved-field.js';\nimport {\n type PeekFieldSource,\n peekFieldDefinition,\n peekLeafAllowed,\n} from '../quick/peek-filter.js';\nimport { recordDisplayName } from '../resource/record-display-name.js';\nimport { type ListRow, useRowAccess, useViewVisible } from './related-rows.js';\n\n/** What a default item reads of the target's definition. */\ninterface TargetDefinition extends PeekFieldSource {\n readonly views?: { readonly list?: { readonly columns?: readonly string[] } };\n readonly ref?: EntityRef;\n}\n\n/** A field the default item puts in its trailing part: a number reads best right-aligned. */\nconst isNumeric = (field: { readonly kind?: unknown } | undefined) => field?.kind === 'number';\n\n/**\n * The item of a related list that names none (P6 3.13). As a card: the row's title (weight 500),\n * its other fields as muted label / value pairs, and its numbers in a trailing part set off by a\n * rule. As a timeline entry (`variant: 'entry'`): the title and the field values on one muted\n * meta line. `row` is the projected row, so a field the viewer may not see is already `null` and\n * is not listed.\n */\nexport function DefaultItem({\n resource,\n row,\n raw,\n columns,\n variant = 'card',\n}: {\n readonly resource: string;\n readonly row: Readonly<Record<string, unknown>>;\n /** The row as the list read it: column rules resolve over it. */\n readonly raw: ListRow;\n readonly columns?: readonly string[] | undefined;\n readonly variant?: 'card' | 'entry';\n}): ReactElement {\n const app = useApp();\n const def = app.registry.get(resource) as TargetDefinition | undefined;\n const caps = useI18nCaps(resource);\n const access = useRowAccess(resource)(raw);\n const viewVisible = useViewVisible(resource);\n const fields =\n def === undefined\n ? []\n : (columns ?? def.views?.list?.columns ?? Object.keys(def.fields)).filter(\n (name, index, names) =>\n name !== def.displayField &&\n names.indexOf(name) === index &&\n peekLeafAllowed(def, name, access, viewVisible),\n );\n const ref = def?.ref ?? { namespace: 'default', id: resource };\n const definition = (name: string) =>\n peekFieldDefinition(def!, name) as { readonly label?: string; readonly kind?: unknown };\n const value = (name: string) => (\n <ResolvedFieldDisplay\n resource={ref}\n name={name}\n field={definition(name) as never}\n value={row[name]}\n record={row}\n fallback={toDisplayText(row[name]).text}\n />\n );\n const title = (\n <p className=\"truncate text-sm font-medium\">{recordDisplayName(row, def?.displayField)}</p>\n );\n if (variant === 'entry') {\n const shown = fields.filter((name) => row[name] != null && row[name] !== '');\n return (\n <div className=\"flex min-w-0 flex-col gap-0.5\" data-buro-default-item=\"\">\n {title}\n {shown.length === 0 ? null : (\n <div data-buro-item-meta=\"\" className=\"truncate text-xs text-muted-foreground\">\n {shown.map((name, index) => (\n <Fragment key={name}>\n {index > 0 ? ' · ' : null}\n {value(name)}\n </Fragment>\n ))}\n </div>\n )}\n </div>\n );\n }\n const numbers = fields.filter((name) => isNumeric(definition(name)));\n const pairs = fields.filter((name) => !isNumeric(definition(name)));\n return (\n <div className=\"flex min-w-0 items-start gap-3\" data-buro-default-item=\"\">\n <div className=\"flex min-w-0 flex-1 flex-col gap-2\">\n {title}\n {pairs.length === 0 ? null : (\n <dl className=\"grid gap-1.5\">\n {pairs.map((name) => (\n <div key={name} className=\"flex min-w-0 items-baseline gap-2 text-sm\">\n <dt className=\"w-24 shrink-0 truncate text-xs text-muted-foreground\">\n {resolveFieldLabel(caps, name, definition(name)?.label)}\n </dt>\n <dd className=\"min-w-0 break-words\">{value(name)}</dd>\n </div>\n ))}\n </dl>\n )}\n </div>\n {numbers.length === 0 ? null : (\n <div\n data-buro-item-trailing=\"\"\n className=\"flex shrink-0 flex-col items-end gap-1 border-l pl-3 text-sm tabular-nums\"\n >\n {numbers.map((name) => (\n <span key={name} title={resolveFieldLabel(caps, name, definition(name)?.label)}>\n {value(name)}\n </span>\n ))}\n </div>\n )}\n </div>\n );\n}\n","'use client';\nimport { type AppContext, RECORD_PROBE, resolveCapability, ruleContextFor } from '@burojs/core';\nimport { type CapabilityResolver, useApp, useCtx, useFieldAccess, useViewRow } from '@burojs/react';\nimport { type ReactElement, type ReactNode, useCallback, useMemo } from 'react';\nimport { QUICK_ANCHOR_ATTRIBUTE } from '@burojs/react';\nimport { ClaimedQuickLink, isPlainLeftClick } from '../fields/claimed-quick-link.js';\nimport { useLinkComponent } from '../layout/link-component.js';\nimport { type PeekFieldSource, peekLeafAllowed, peekRow } from '../quick/peek-filter.js';\nimport { recordDisplayName } from '../resource/record-display-name.js';\nimport { DefaultItem } from './default-item.js';\nimport { type ItemHandle, RelatedItem, useItemDrawn } from './related-item.js';\n\nexport type ListRow = { readonly id: string } & Readonly<Record<string, unknown>>;\n\n/** What `related-list` hands a rows view: the list's rows and how a row opens. */\nexport interface RelatedRowsProps {\n /** The target resource. */\n readonly resource: string;\n /** The placement's key (test ids). */\n readonly placementKey: string;\n readonly rows: readonly ListRow[];\n readonly item?: ItemHandle | undefined;\n /** The placement's `columns`, for the default item. */\n readonly columns?: readonly string[] | undefined;\n readonly rowQuick?: ((row: ListRow) => (() => void) | null) | undefined;\n readonly rowHref?: ((row: ListRow) => string | undefined) | undefined;\n}\n\n/**\n * A capability resolver per row: column rules resolve over the row they hide a field of, as the\n * peek's do (P6-B review), so a rule reading the record sees this row.\n */\nexport function useRowAccess(resource: string): (row: ListRow) => CapabilityResolver {\n const app = useApp();\n const scope = useCtx((c: AppContext) => c.scope);\n const user = useCtx((c: AppContext) => c.user);\n const permissions = useCtx((c: AppContext) => c.permissions);\n return useCallback(\n (row) =>\n (capability, target, defaultAllowed = true) => {\n const rules = app.ruleSource.rules(resource);\n if (rules.length === 0) return { allowed: defaultAllowed };\n const ctx = ruleContextFor({\n user,\n scope,\n permissions,\n record: row,\n mode: 'show',\n resource,\n });\n return resolveCapability(rules, capability, target, ctx, defaultAllowed);\n },\n [app.ruleSource, resource, scope, user, permissions],\n );\n}\n\n/**\n * Whether a field may be drawn on every row by its P5 view (P5 spec 3.6.6): a decision that is\n * not `visible` (`hidden`, `restricted`, `failed` and `pending` alike, so nothing is drawn while\n * the permission map loads) withholds it. A field the map does not decide is not withheld here. The decision\n * is the any-record one ({@link RECORD_PROBE}), so a rule reading the record counts as hiding.\n */\nexport function useViewVisible(resource: string): (field: string) => boolean {\n const access = useFieldAccess(resource, 'every');\n return useCallback(\n (field) => {\n const decision = access[field];\n return decision === undefined || decision.view === 'visible';\n },\n [access],\n );\n}\n\ninterface ProjectedRows {\n readonly def:\n | (PeekFieldSource & { readonly displayField?: string; readonly data?: unknown })\n | undefined;\n /** The row a card or an entry sees: the id and what the viewer may see; the rest read `null`. */\n readonly project: (row: ListRow) => ListRow;\n /** Whether the item block is drawn (decided once for the list), else the default item. */\n readonly drawn: boolean;\n readonly title: (row: ListRow) => string;\n}\n\n/**\n * The rows of a cards or timeline view, projected once and the item decided once per list.\n *\n * The rows arrive as the list read them (policy). A row is first projected by P5's field view\n * (`viewRow`: a field its user may not view for every row is left out) and then by the peek's\n * rule ({@link peekRow}): the id field and every field that is not `sensitive`, not withheld by\n * a field `requires.view` and not hidden by a `column` rule keep their values; every other\n * field reads `null`. It is the one place a row's fields are filtered before an item block or\n * the default item sees them (P6-66), and the timeline's axis reads the same row.\n */\nexport function useProjectedRows(\n resource: string,\n rows: readonly ListRow[],\n item: ItemHandle | undefined,\n): ProjectedRows {\n const app = useApp();\n const def = app.registry.get(resource) as ProjectedRows['def'];\n const accessOf = useRowAccess(resource);\n const viewRow = useViewRow(resource);\n const viewVisible = useViewVisible(resource);\n const idField = (def?.data as { readonly idField?: string } | undefined)?.idField ?? 'id';\n const project = useCallback(\n (row: ListRow): ListRow =>\n (def === undefined\n ? viewRow(row)\n : peekRow(def, viewRow(row), idField, accessOf(row), viewVisible)) as ListRow,\n [def, idField, accessOf, viewRow, viewVisible],\n );\n const hidden = useCallback(\n (field: string) =>\n field !== idField &&\n (def === undefined ||\n !peekLeafAllowed(def, field, accessOf(RECORD_PROBE as ListRow), viewVisible)),\n [def, idField, accessOf, viewVisible],\n );\n const probe = useMemo(\n () => (rows[0] === undefined ? undefined : project(rows[0])),\n [rows, project],\n );\n const drawn = useItemDrawn(item, hidden, probe);\n const title = useCallback(\n (row: ListRow) => recordDisplayName(project(row), def?.displayField),\n [project, def],\n );\n return { def, project, drawn, title };\n}\n\n/** The item block (or the default item) of one row. */\nexport function RowContent({\n resource,\n raw,\n row,\n item,\n drawn,\n columns,\n variant,\n}: {\n readonly resource: string;\n /** The row as the list read it (column rules resolve over it). */\n readonly raw: ListRow;\n /** The projected row. */\n readonly row: ListRow;\n readonly item: ItemHandle | undefined;\n readonly drawn: boolean;\n readonly columns?: readonly string[] | undefined;\n /** How the default item lays the row out: a card's, or a timeline entry's. */\n readonly variant?: 'card' | 'entry';\n}): ReactElement {\n const fallback = (\n <DefaultItem\n resource={resource}\n row={row}\n raw={raw}\n columns={columns}\n {...(variant === undefined ? {} : { variant })}\n />\n );\n if (item === undefined || !drawn) return fallback;\n return <RelatedItem handle={item} row={row} fallback={fallback} />;\n}\n\n/**\n * A card's or an entry's one opener (P6-74): the row's title as the accessible name of a single\n * anchor whose `::after` covers the positioned parent. A quick row is the page anchor claimed\n * for the opener (a modified click follows the `href`), or a link-role button without a page.\n * `open: 'none'` draws nothing.\n */\nexport function RowOpener({\n title,\n href,\n quick,\n}: {\n readonly title: string;\n readonly href: string | undefined;\n readonly quick: (() => void) | null;\n}): ReactElement | null {\n const RouterLink = useLinkComponent();\n const className =\n 'outline-none after:absolute after:inset-0 after:rounded-[inherit] focus-visible:after:ring-2 focus-visible:after:ring-ring';\n const name: ReactNode = <span className=\"sr-only\">{title}</span>;\n if (quick !== null)\n return href ? (\n <ClaimedQuickLink href={href} className={className} onOpen={quick}>\n {name}\n </ClaimedQuickLink>\n ) : (\n <button\n type=\"button\"\n role=\"link\"\n {...{ [QUICK_ANCHOR_ATTRIBUTE]: '' }}\n // A button is inline-block, so even with only an `sr-only` name it took a line of the\n // card and pushed the content down (REF-40). Zero-size and unpositioned, its `::after`\n // still covers the card.\n className={`${className} block size-0 p-0`}\n onClick={(event) => {\n if (!isPlainLeftClick(event)) return;\n quick();\n }}\n >\n {name}\n </button>\n );\n if (href)\n return (\n <RouterLink href={href} className={className}>\n {name}\n </RouterLink>\n );\n return null;\n}\n\n/**\n * The wrapper that raises an item's interactive descendants above the opener's cover (P6-74):\n * the wrapper itself lets clicks through to the opener, its controls take them.\n */\nexport const ITEM_LAYER_CLASS =\n 'relative z-[1] pointer-events-none [&_a]:pointer-events-auto [&_button]:pointer-events-auto [&_input]:pointer-events-auto [&_select]:pointer-events-auto [&_textarea]:pointer-events-auto [&_summary]:pointer-events-auto [&_[role=button]]:pointer-events-auto [&_[role=link]]:pointer-events-auto [&_[role=checkbox]]:pointer-events-auto [&_[role=switch]]:pointer-events-auto';\n"],"mappings":"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"}
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
const require_use_theme = require("./use-theme-DFlpXils.cjs");
|
|
2
|
+
const require_toaster = require("./toaster-C7CiYA4Z.cjs");
|
|
3
|
+
const require_button = require("./button-BxnnE28H.cjs");
|
|
4
|
+
const require_search_access = require("./search-access-B7G5oR8n.cjs");
|
|
5
|
+
let _burojs_core = require("@burojs/core");
|
|
6
|
+
let _burojs_react = require("@burojs/react");
|
|
7
|
+
let _tabler_icons_react = require("@tabler/icons-react");
|
|
8
|
+
let react = require("react");
|
|
9
|
+
react = require_use_theme.__toESM(react, 1);
|
|
10
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
11
|
+
let sonner = require("sonner");
|
|
12
|
+
//#region src/fields/relation-hand-back.tsx
|
|
13
|
+
function createdOptionFilter(input) {
|
|
14
|
+
const own = createdOptionScope(input);
|
|
15
|
+
const byId = {
|
|
16
|
+
field: input.idField,
|
|
17
|
+
op: "eq",
|
|
18
|
+
value: input.id
|
|
19
|
+
};
|
|
20
|
+
return own === void 0 ? byId : { and: [own, byId] };
|
|
21
|
+
}
|
|
22
|
+
function createdOptionScope(input) {
|
|
23
|
+
return (0, _burojs_core.composeListFilter)({
|
|
24
|
+
fixed: (0, _burojs_core.normalizeFixedFilters)(input.fixed),
|
|
25
|
+
search: "",
|
|
26
|
+
...input.searchDecl === void 0 ? {} : { searchDecl: input.searchDecl },
|
|
27
|
+
...input.searchContext === void 0 ? {} : { searchContext: input.searchContext }
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function CreatedOptionRead({ to, filter, ignoreScope, by, idField, onSettled }) {
|
|
31
|
+
const query = (0, _burojs_react.useList)(to, {
|
|
32
|
+
filter,
|
|
33
|
+
pagination: {
|
|
34
|
+
kind: "offset",
|
|
35
|
+
page: 1,
|
|
36
|
+
pageSize: 1
|
|
37
|
+
},
|
|
38
|
+
...ignoreScope ? { providerOptionsOverride: { ignoreScope: true } } : {},
|
|
39
|
+
retry: false
|
|
40
|
+
});
|
|
41
|
+
const settled = react.useRef(false);
|
|
42
|
+
const latest = react.useRef(onSettled);
|
|
43
|
+
latest.current = onSettled;
|
|
44
|
+
const rows = query.data?.data;
|
|
45
|
+
const answered = rows !== void 0 && query.isCurrentData && !query.isFetching;
|
|
46
|
+
const failed = query.isError && !query.isFetching;
|
|
47
|
+
react.useEffect(() => {
|
|
48
|
+
if (settled.current) return;
|
|
49
|
+
if (failed) {
|
|
50
|
+
settled.current = true;
|
|
51
|
+
latest.current({ kind: "failed" });
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (!answered) return;
|
|
55
|
+
settled.current = true;
|
|
56
|
+
const value = rows[0]?.[by ?? idField];
|
|
57
|
+
latest.current(typeof value === "string" || typeof value === "number" ? {
|
|
58
|
+
kind: "fits",
|
|
59
|
+
value
|
|
60
|
+
} : { kind: "does-not-fit" });
|
|
61
|
+
}, [
|
|
62
|
+
answered,
|
|
63
|
+
failed,
|
|
64
|
+
rows,
|
|
65
|
+
by,
|
|
66
|
+
idField
|
|
67
|
+
]);
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/fields/relation-view-button.tsx
|
|
72
|
+
function selectKey(value) {
|
|
73
|
+
if (typeof value === "string") return value.length === 0 ? null : value;
|
|
74
|
+
if (typeof value === "number") return Number.isFinite(value) ? String(value) : null;
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
const VIEW_CLASS = require_use_theme.cn(require_button.buttonVariants({
|
|
78
|
+
variant: "outline",
|
|
79
|
+
size: "icon"
|
|
80
|
+
}), "shrink-0");
|
|
81
|
+
function RelationViewButton(props) {
|
|
82
|
+
const gate = (0, _burojs_react.useEntryGate)();
|
|
83
|
+
const { to, value, by } = props;
|
|
84
|
+
const access = (0, _burojs_react.useListAccess)(to);
|
|
85
|
+
const key = selectKey(value);
|
|
86
|
+
if (key === null || props.open === "none") return null;
|
|
87
|
+
if (by !== void 0 && !(access.status === "ready" && access.fieldVisible(by))) return null;
|
|
88
|
+
if (gate(to, "show").state !== "open") return null;
|
|
89
|
+
return (0, react_jsx_runtime.jsx)(ViewButton, {
|
|
90
|
+
...props,
|
|
91
|
+
keyString: key
|
|
92
|
+
}, key);
|
|
93
|
+
}
|
|
94
|
+
function ViewButton({ to, by, ignoreScope, fieldName, keyString, beforeOpen, open: openMode = "quick" }) {
|
|
95
|
+
const app = (0, _burojs_react.useApp)();
|
|
96
|
+
const t = (0, _burojs_react.useOptionalT)();
|
|
97
|
+
const tid = (0, _burojs_react.useTestIds)();
|
|
98
|
+
const quick = (0, _burojs_react.useQuick)();
|
|
99
|
+
const navigate = (0, _burojs_react.useRouteNavigate)();
|
|
100
|
+
const RouterLink = require_toaster.useLinkComponent();
|
|
101
|
+
const [asked, setAsked] = react.useState(false);
|
|
102
|
+
const requested = react.useRef(false);
|
|
103
|
+
const targetDef = app.registry.get(to);
|
|
104
|
+
const rawIdField = (targetDef?.data)?.idField;
|
|
105
|
+
const idField = typeof rawIdField === "string" && rawIdField.length > 0 ? rawIdField : "id";
|
|
106
|
+
const read = (0, _burojs_react.useList)(to, {
|
|
107
|
+
...asked && by !== void 0 ? {
|
|
108
|
+
filter: {
|
|
109
|
+
field: by,
|
|
110
|
+
op: "eq",
|
|
111
|
+
value: keyString
|
|
112
|
+
},
|
|
113
|
+
pagination: {
|
|
114
|
+
kind: "offset",
|
|
115
|
+
page: 1,
|
|
116
|
+
pageSize: 2
|
|
117
|
+
}
|
|
118
|
+
} : {},
|
|
119
|
+
...ignoreScope === true ? { providerOptionsOverride: { ignoreScope: true } } : {},
|
|
120
|
+
enabled: asked && by !== void 0,
|
|
121
|
+
retry: false
|
|
122
|
+
});
|
|
123
|
+
const rows = read.isCurrentData && !read.isPlaceholderData && !read.isFetching ? read.data?.data : void 0;
|
|
124
|
+
const open = react.useCallback((id) => {
|
|
125
|
+
beforeOpen();
|
|
126
|
+
if (openMode === "page") {
|
|
127
|
+
if (targetDef !== void 0 && require_search_access.linksToPage(app, targetDef)) navigate((0, _burojs_core.resourceShowHref)(app.registry, targetDef, to, id));
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
quick.show(to, id);
|
|
131
|
+
}, [
|
|
132
|
+
beforeOpen,
|
|
133
|
+
quick,
|
|
134
|
+
to,
|
|
135
|
+
openMode,
|
|
136
|
+
navigate,
|
|
137
|
+
app,
|
|
138
|
+
targetDef
|
|
139
|
+
]);
|
|
140
|
+
react.useEffect(() => {
|
|
141
|
+
if (by === void 0 || !asked || rows === void 0 || !requested.current) return;
|
|
142
|
+
requested.current = false;
|
|
143
|
+
if (rows.length !== 1) {
|
|
144
|
+
if (rows.length > 1 && process.env.NODE_ENV !== "production") console.error(`[burojs] ${to}: more than one row has ${by} ${keyString}; "view" opened nothing.`);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const id = rows[0]?.[idField];
|
|
148
|
+
const next = selectKey(id);
|
|
149
|
+
if (next !== null) open(next);
|
|
150
|
+
}, [
|
|
151
|
+
by,
|
|
152
|
+
asked,
|
|
153
|
+
rows,
|
|
154
|
+
idField,
|
|
155
|
+
keyString,
|
|
156
|
+
to,
|
|
157
|
+
open
|
|
158
|
+
]);
|
|
159
|
+
const label = t("relationPicker.view", { defaultValue: "View" });
|
|
160
|
+
const icon = (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconEye, {
|
|
161
|
+
className: "h-4 w-4",
|
|
162
|
+
"aria-hidden": true
|
|
163
|
+
});
|
|
164
|
+
const testid = tid.relationView(to, fieldName);
|
|
165
|
+
if (openMode === "page" && (targetDef === void 0 || !require_search_access.linksToPage(app, targetDef))) return null;
|
|
166
|
+
if (openMode === "page" && by === void 0 && targetDef !== void 0) return (0, react_jsx_runtime.jsxs)(RouterLink, {
|
|
167
|
+
href: (0, _burojs_core.resourceShowHref)(app.registry, targetDef, to, keyString),
|
|
168
|
+
"data-testid": testid,
|
|
169
|
+
className: VIEW_CLASS,
|
|
170
|
+
onClick: () => beforeOpen(),
|
|
171
|
+
children: [icon, (0, react_jsx_runtime.jsx)("span", {
|
|
172
|
+
className: "sr-only",
|
|
173
|
+
children: label
|
|
174
|
+
})]
|
|
175
|
+
});
|
|
176
|
+
if (by === void 0 && targetDef !== void 0 && require_search_access.linksToPage(app, targetDef)) return (0, react_jsx_runtime.jsxs)(require_search_access.ClaimedQuickLink, {
|
|
177
|
+
href: (0, _burojs_core.resourceShowHref)(app.registry, targetDef, to, keyString),
|
|
178
|
+
testid,
|
|
179
|
+
className: VIEW_CLASS,
|
|
180
|
+
onOpen: () => open(keyString),
|
|
181
|
+
children: [icon, (0, react_jsx_runtime.jsx)("span", {
|
|
182
|
+
className: "sr-only",
|
|
183
|
+
children: label
|
|
184
|
+
})]
|
|
185
|
+
});
|
|
186
|
+
return (0, react_jsx_runtime.jsx)("button", {
|
|
187
|
+
type: "button",
|
|
188
|
+
className: VIEW_CLASS,
|
|
189
|
+
"data-testid": testid,
|
|
190
|
+
"aria-label": label,
|
|
191
|
+
[_burojs_react.QUICK_ANCHOR_ATTRIBUTE]: "",
|
|
192
|
+
onClick: (event) => {
|
|
193
|
+
event.preventDefault();
|
|
194
|
+
event.stopPropagation();
|
|
195
|
+
if (!require_search_access.isPlainLeftClick(event)) return;
|
|
196
|
+
if (by === void 0) {
|
|
197
|
+
open(keyString);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
requested.current = true;
|
|
201
|
+
setAsked(true);
|
|
202
|
+
if (rows !== void 0 && rows.length === 1) {
|
|
203
|
+
const next = selectKey(rows[0]?.[idField]);
|
|
204
|
+
requested.current = false;
|
|
205
|
+
if (next !== null) open(next);
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
children: icon
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
//#endregion
|
|
212
|
+
//#region src/fields/relation-create.tsx
|
|
213
|
+
function useSelectCreate(input) {
|
|
214
|
+
const t = (0, _burojs_react.useOptionalT)();
|
|
215
|
+
const { to: target } = input;
|
|
216
|
+
const [pending, setPending] = react.useState(false);
|
|
217
|
+
const [created, setCreated] = react.useState(null);
|
|
218
|
+
const latch = react.useRef(false);
|
|
219
|
+
const mounted = react.useRef(true);
|
|
220
|
+
react.useEffect(() => {
|
|
221
|
+
mounted.current = true;
|
|
222
|
+
return () => {
|
|
223
|
+
mounted.current = false;
|
|
224
|
+
};
|
|
225
|
+
}, []);
|
|
226
|
+
const latest = react.useRef(input);
|
|
227
|
+
latest.current = input;
|
|
228
|
+
const access = (0, _burojs_react.useListAccess)(target);
|
|
229
|
+
const blocked = input.held === true || access.status !== "ready" || require_search_access.namesHiddenField(createdOptionScope({
|
|
230
|
+
fixed: input.fixedFilters,
|
|
231
|
+
searchDecl: input.searchDecl,
|
|
232
|
+
searchContext: input.searchContext
|
|
233
|
+
}), (name) => access.fieldVisible(name));
|
|
234
|
+
const blockedRef = react.useRef(blocked);
|
|
235
|
+
blockedRef.current = blocked;
|
|
236
|
+
const release = react.useCallback(() => {
|
|
237
|
+
latch.current = false;
|
|
238
|
+
if (mounted.current) {
|
|
239
|
+
setPending(false);
|
|
240
|
+
setCreated(null);
|
|
241
|
+
}
|
|
242
|
+
}, []);
|
|
243
|
+
const start = react.useCallback((open) => {
|
|
244
|
+
if (latch.current || !mounted.current || blockedRef.current) return;
|
|
245
|
+
latch.current = true;
|
|
246
|
+
setPending(true);
|
|
247
|
+
let opened;
|
|
248
|
+
try {
|
|
249
|
+
opened = open();
|
|
250
|
+
} catch (error) {
|
|
251
|
+
release();
|
|
252
|
+
throw error;
|
|
253
|
+
}
|
|
254
|
+
opened.then((row) => {
|
|
255
|
+
if (!mounted.current) {
|
|
256
|
+
latch.current = false;
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
const id = row === null ? null : selectKey(row[latest.current.idField]) ?? selectKey(row.id);
|
|
260
|
+
if (id === null) release();
|
|
261
|
+
else setCreated({ id });
|
|
262
|
+
}, () => release());
|
|
263
|
+
}, [release]);
|
|
264
|
+
const settle = react.useCallback((result) => {
|
|
265
|
+
if (mounted.current) {
|
|
266
|
+
if (result.kind === "fits") latest.current.onValue(result.value);
|
|
267
|
+
else if (result.kind === "does-not-fit") (0, sonner.toast)(t("relationPicker.createdNotFitting", { defaultValue: "The record was created but does not fit this field" }));
|
|
268
|
+
else sonner.toast.error(t("relationPicker.createdNotSelected", { defaultValue: "The record was created but could not be selected" }));
|
|
269
|
+
}
|
|
270
|
+
release();
|
|
271
|
+
}, [release, t]);
|
|
272
|
+
return {
|
|
273
|
+
create: react.useMemo(() => ({
|
|
274
|
+
pending,
|
|
275
|
+
blocked,
|
|
276
|
+
start
|
|
277
|
+
}), [
|
|
278
|
+
pending,
|
|
279
|
+
blocked,
|
|
280
|
+
start
|
|
281
|
+
]),
|
|
282
|
+
reader: created === null || blocked ? null : (0, react_jsx_runtime.jsx)(CreatedOptionRead, {
|
|
283
|
+
to: target,
|
|
284
|
+
filter: createdOptionFilter({
|
|
285
|
+
fixed: input.fixedFilters,
|
|
286
|
+
idField: input.idField,
|
|
287
|
+
id: created.id,
|
|
288
|
+
searchDecl: input.searchDecl,
|
|
289
|
+
searchContext: input.searchContext
|
|
290
|
+
}),
|
|
291
|
+
ignoreScope: input.fixedFilters !== void 0 && input.fixedFilters.length > 0,
|
|
292
|
+
by: input.by,
|
|
293
|
+
idField: input.idField,
|
|
294
|
+
onSettled: settle
|
|
295
|
+
}, created.id)
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
function plainStringField(def) {
|
|
299
|
+
if (def === null || typeof def !== "object") return false;
|
|
300
|
+
const field = def;
|
|
301
|
+
return field.kind === "string" && field.system !== true && field.opts?.system !== true && field.opts?.enum === void 0 && field.opts?.localized !== true;
|
|
302
|
+
}
|
|
303
|
+
function RelationCreateButton(props) {
|
|
304
|
+
const gate = (0, _burojs_react.useEntryGate)();
|
|
305
|
+
const { to } = props;
|
|
306
|
+
if (props.create.blocked || gate(to, "create").state !== "open") return null;
|
|
307
|
+
return (0, react_jsx_runtime.jsx)(CreateButton, { ...props });
|
|
308
|
+
}
|
|
309
|
+
function CreateButton({ to, fieldName, create, seeds, search, beforeOpen, className, testId }) {
|
|
310
|
+
const app = (0, _burojs_react.useApp)();
|
|
311
|
+
const t = (0, _burojs_react.useOptionalT)();
|
|
312
|
+
const tid = (0, _burojs_react.useTestIds)();
|
|
313
|
+
const quick = (0, _burojs_react.useQuick)();
|
|
314
|
+
const label = t("relationPicker.create", { defaultValue: "+ Create" });
|
|
315
|
+
return (0, react_jsx_runtime.jsx)("button", {
|
|
316
|
+
type: "button",
|
|
317
|
+
"data-testid": testId ?? tid.relationCreate(to, fieldName),
|
|
318
|
+
disabled: create.pending,
|
|
319
|
+
className,
|
|
320
|
+
onClick: () => {
|
|
321
|
+
const text = search?.trim() ?? "";
|
|
322
|
+
const displayField = app.registry.get(to)?.displayField;
|
|
323
|
+
const fields = app.registry.get(to)?.fields;
|
|
324
|
+
const prefill = text.length > 0 && typeof displayField === "string" && fields !== void 0 && Object.hasOwn(fields, displayField) && plainStringField(fields[displayField]) ? { [displayField]: text } : void 0;
|
|
325
|
+
create.start(() => {
|
|
326
|
+
beforeOpen();
|
|
327
|
+
return quick.create(to, {
|
|
328
|
+
...seeds === void 0 || Object.keys(seeds).length === 0 ? {} : { defaults: seeds },
|
|
329
|
+
...prefill === void 0 ? {} : { input: prefill }
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
},
|
|
333
|
+
children: label
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
//#endregion
|
|
337
|
+
Object.defineProperty(exports, "RelationCreateButton", {
|
|
338
|
+
enumerable: true,
|
|
339
|
+
get: function() {
|
|
340
|
+
return RelationCreateButton;
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
Object.defineProperty(exports, "RelationViewButton", {
|
|
344
|
+
enumerable: true,
|
|
345
|
+
get: function() {
|
|
346
|
+
return RelationViewButton;
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
Object.defineProperty(exports, "selectKey", {
|
|
350
|
+
enumerable: true,
|
|
351
|
+
get: function() {
|
|
352
|
+
return selectKey;
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
Object.defineProperty(exports, "useSelectCreate", {
|
|
356
|
+
enumerable: true,
|
|
357
|
+
get: function() {
|
|
358
|
+
return useSelectCreate;
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
//# sourceMappingURL=relation-create-BOaUe12G.cjs.map
|