@object-ui/plugin-tree 17.6.0 → 17.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,49 +1,45 @@
1
1
  import { useEffect as e, useMemo as t, useState as n } from "react";
2
- import { ComponentRegistry as r, buildExpandFields as i, columnIdentity as a, extractRecords as o } from "@object-ui/core";
3
- import { useNavigationOverlay as s, useSafeFieldLabel as c, useSchemaContext as l } from "@object-ui/react";
4
- import { NavigationOverlay as u, cn as d } from "@object-ui/components";
5
- import { createSafeTranslation as f } from "@object-ui/i18n";
6
- import { ChevronDown as p, ChevronRight as m } from "lucide-react";
7
- import { jsx as h, jsxs as g } from "react/jsx-runtime";
2
+ import { ComponentRegistry as r, ValueDataSource as i, applyNonGridRowCeiling as a, buildExpandFields as o, columnIdentity as s, getRecordDisplayName as c, humanizeLabel as l, isExpandableFieldType as u, nonGridRowCeilingQuery as d, resolveRecordSourceConfig as ee, resolveRecordSourceObjectName as f } from "@object-ui/core";
3
+ import { NonGridRowCeilingNote as p, useDataInvalidation as te, useFilterScope as ne, useNavigationOverlay as re, useResolvedFilter as ie, useSafeFieldLabel as ae, useSchemaContext as m, useSettledSchema as oe } from "@object-ui/react";
4
+ import { NavigationOverlay as se, RefreshIndicator as ce, cn as h, legacyRecordDrawerWidthKey as g, recordOverlayWidthStorageKey as _, useOverlayAnchor as v } from "@object-ui/components";
5
+ import { RECORD_OVERLAY_DEFAULT_WIDTH as le, RecordDetailPanel as ue } from "@object-ui/plugin-detail";
6
+ import { createSafeTranslation as y } from "@object-ui/i18n";
7
+ import { usePermissions as de } from "@object-ui/permissions";
8
+ import { ChevronDown as fe, ChevronRight as pe } from "lucide-react";
9
+ import { Fragment as b, jsx as x, jsxs as S } from "react/jsx-runtime";
8
10
  //#region src/ObjectTree.tsx
9
- var _ = f({ "detail.recordDetail": "Record Detail" }, "detail.recordDetail");
10
- function v(e) {
11
- return e.data ? e.data : e.staticData ? {
12
- provider: "value",
13
- items: e.staticData
14
- } : e.objectName ? {
15
- provider: "object",
16
- object: e.objectName
17
- } : null;
11
+ var me = y({
12
+ "detail.recordDetail": "Record Detail",
13
+ "grid.refreshing": "Refreshing…"
14
+ }, "detail.recordDetail"), he = [];
15
+ function C(e) {
16
+ return s(e) || (e && typeof e == "object" ? e.key : void 0) || void 0;
18
17
  }
19
- function y(e) {
20
- return a(e) || (e && typeof e == "object" ? e.key : void 0) || void 0;
21
- }
22
- function b(e) {
23
- let t = e.tree || e.filter?.tree || {}, n = Array.isArray(e.fields) ? e.fields : Array.isArray(t.fields) ? t.fields : [];
18
+ function ge(e) {
19
+ let t = e.tree || {}, n = Array.isArray(e.fields) ? e.fields : Array.isArray(t.fields) ? t.fields : [];
24
20
  return {
25
- parentField: y(e.parentField ?? t.parentField),
26
- labelField: y(e.labelField ?? t.labelField ?? e.titleField) ?? "name",
27
- fields: n.map(y).filter((e) => !!e),
21
+ parentField: C(e.parentField ?? t.parentField),
22
+ labelField: C(e.labelField ?? t.labelField) ?? "name",
23
+ fields: n.map(C).filter((e) => !!e),
28
24
  defaultExpandedDepth: e.defaultExpandedDepth ?? t.defaultExpandedDepth
29
25
  };
30
26
  }
31
- function x(e, t) {
27
+ function _e(e, t) {
32
28
  let n = e?.fields;
33
29
  if (!n || typeof n != "object") return;
34
30
  let r;
35
31
  for (let [e, i] of Object.entries(n)) {
36
- if (i?.type === "tree") return e;
37
- let n = i?.reference || i?.reference_to || i?.referenceTo;
32
+ let n = i?.reference;
33
+ if (i?.type === "tree" && (n === void 0 || t && n === t)) return e;
38
34
  !r && (i?.type === "lookup" || i?.type === "master_detail") && n && t && n === t && (r = e);
39
35
  }
40
36
  return r;
41
37
  }
42
- function S(e) {
38
+ function w(e) {
43
39
  let t = e?.id ?? e?._id;
44
40
  return t == null ? void 0 : String(t);
45
41
  }
46
- function C(e, t) {
42
+ function T(e, t) {
47
43
  if (!t) return;
48
44
  let n = e?.[t];
49
45
  if (n != null) {
@@ -54,10 +50,10 @@ function C(e, t) {
54
50
  return String(n);
55
51
  }
56
52
  }
57
- function w(e, t) {
53
+ function ve(e, t) {
58
54
  let n = /* @__PURE__ */ new Map(), r = [];
59
55
  for (let t of e) {
60
- let e = S(t);
56
+ let e = w(t);
61
57
  e != null && (n.set(e, {
62
58
  id: e,
63
59
  record: t,
@@ -67,7 +63,7 @@ function w(e, t) {
67
63
  }
68
64
  let i = [];
69
65
  for (let e of r) {
70
- let r = n.get(e), a = C(r.record, t), o = a == null ? void 0 : n.get(a);
66
+ let r = n.get(e), a = T(r.record, t), o = a == null ? void 0 : n.get(a);
71
67
  o && o !== r ? o.children.push(r) : i.push(r);
72
68
  }
73
69
  let a = (e, t) => {
@@ -75,7 +71,7 @@ function w(e, t) {
75
71
  };
76
72
  return a(i, 0), i;
77
73
  }
78
- function T(e, t) {
74
+ function ye(e, t) {
79
75
  let n = [], r = (e) => {
80
76
  for (let i of e) n.push(i), i.children.length > 0 && t.has(i.id) && r(i.children);
81
77
  };
@@ -87,185 +83,275 @@ function E(e, t) {
87
83
  };
88
84
  return r(e), n;
89
85
  }
90
- function D(e) {
91
- return e == null ? "" : String(typeof e == "object" ? e.name ?? e.label ?? e.id ?? e._id ?? "" : e);
86
+ function be(e, t, n) {
87
+ let r = E(e, t);
88
+ if (n.size === 0) return r;
89
+ let i = (e) => {
90
+ for (let t of e) {
91
+ let e = n.get(t.id);
92
+ e === !0 ? r.add(t.id) : e === !1 && r.delete(t.id), i(t.children);
93
+ }
94
+ };
95
+ return i(e), r;
92
96
  }
93
- var O = ({ schema: r, dataSource: a, className: l, onRowClick: f, ...y }) => {
94
- let [S, C] = n([]), [O, k] = n(!0), [A, j] = n(null), [M, N] = n(null), P = t(() => v(r), [r]), F = Array.isArray(y.data) || Array.isArray(r.data) || P?.provider === "value";
95
- e(() => {
96
- let e = !1;
97
- return F || (async () => {
98
- try {
99
- if (!a || typeof a.getObjectSchema != "function") return;
100
- let t = P?.provider === "object" ? P.object : r.objectName;
101
- if (!t) return;
102
- let n = await a.getObjectSchema(t);
103
- e || N(n);
104
- } catch (e) {
105
- console.error("[ObjectTree] Failed to fetch object schema:", e);
106
- }
107
- })(), () => {
108
- e = !0;
97
+ function D(e, t) {
98
+ if (e == null) return "";
99
+ let n = Array.isArray(t?.fieldDef?.options) ? t.fieldDef.options : null;
100
+ if (n && n.length > 0) {
101
+ let r = t.objectName ? t.translateOptions(t.objectName, t.fieldName, n) : n, i = (e) => {
102
+ let t = r.find((t) => t?.value === e);
103
+ if (t) return String(t.label ?? e);
104
+ let n = String(e).toLowerCase(), i = r.find((e) => String(e?.value).toLowerCase() === n);
105
+ return i ? String(i.label ?? e) : l(String(e));
109
106
  };
110
- }, [
111
- r.objectName,
112
- a,
113
- P,
114
- F
115
- ]), e(() => {
107
+ return Array.isArray(e) ? e.filter((e) => e != null).map(i).join(", ") : i(e);
108
+ }
109
+ return typeof e == "object" && u(t?.fieldDef) ? c(void 0, e) : String(typeof e == "object" ? e.name ?? e.label ?? e.id ?? e._id ?? "" : e);
110
+ }
111
+ var O = ({ schema: r, dataSource: s, className: c, onRowClick: l, ...u }) => {
112
+ let [m, y] = n(null), [C, w] = n(null), [T, E] = n(!0), [O, k] = n(null), A = t(() => ee(r, "view-data"), [r]), j = f(r, A) ?? "", { ready: M, def: N } = oe(j, s), P = A?.provider, F = A?.provider === "object" ? A.object : void 0, I = A?.provider === "value" ? A.items : void 0, L = de(), xe = ne(), R = ie(r.filter, xe), Se = te(s ? F : void 0);
113
+ e(() => {
116
114
  let e = !1;
117
115
  return (async () => {
118
116
  try {
119
- if (k(!0), j(null), P?.provider === "object" && a && typeof a.find == "function") {
120
- let t = i(M?.fields), n = await a.find(P.object, {
121
- $filter: r.filter,
122
- ...t.length > 0 ? { $expand: t } : {}
123
- });
124
- e || (C(o(n)), k(!1));
117
+ if (E(!0), k(null), P === "object" && s && typeof s.find == "function") {
118
+ if (!M) return;
119
+ let t = o(N?.fields), n = L?.isLoaded ? t.filter((e) => L.checkField(F, e, "read")) : t, r = await s.find(F, {
120
+ $filter: R,
121
+ ...d(),
122
+ ...n.length > 0 ? { $expand: n } : {}
123
+ }), i = a(r);
124
+ e || (y({
125
+ provider: P,
126
+ object: F,
127
+ rows: i.rows
128
+ }), w(i), E(!1));
125
129
  return;
126
130
  }
127
- let t = y.data ?? r.data;
131
+ let t = u.data;
128
132
  if (Array.isArray(t)) {
129
- e || (C(t), k(!1));
133
+ e || (y({
134
+ provider: P,
135
+ object: F,
136
+ rows: t
137
+ }), w(null), E(!1));
130
138
  return;
131
139
  }
132
- if (P?.provider === "value") {
133
- e || (C(P.items ?? []), k(!1));
140
+ if (P === "value") {
141
+ let t = await new i({ items: I ?? [] }).find("", {
142
+ $filter: R,
143
+ ...d()
144
+ }), n = a(t);
145
+ e || (y({
146
+ provider: P,
147
+ object: F,
148
+ rows: n.rows
149
+ }), w(n), E(!1));
134
150
  return;
135
151
  }
136
- e || (C([]), k(!1));
152
+ e || (y({
153
+ provider: P,
154
+ object: F,
155
+ rows: []
156
+ }), E(!1));
137
157
  } catch (t) {
138
- e || (j(t), k(!1));
158
+ e || (k(t), E(!1));
139
159
  }
140
160
  })(), () => {
141
161
  e = !0;
142
162
  };
143
163
  }, [
144
164
  P,
145
- a,
146
- r.filter,
165
+ F,
166
+ I,
167
+ s,
168
+ R,
169
+ N,
147
170
  M,
148
- y.data
171
+ u.data,
172
+ L,
173
+ Se
149
174
  ]);
150
- let I = t(() => b(r), [r]), L = t(() => I.parentField ?? x(M, r.objectName), [
151
- I.parentField,
152
- M,
175
+ let z = t(() => ge(r), [r]), B = t(() => z.parentField ?? _e(N, r.objectName), [
176
+ z.parentField,
177
+ N,
153
178
  r.objectName
154
- ]), R = t(() => w(S, L), [S, L]), [z, B] = n(/* @__PURE__ */ new Set());
155
- e(() => {
156
- B(E(R, I.defaultExpandedDepth));
157
- }, [R, I.defaultExpandedDepth]);
158
- let V = (e) => B((t) => {
159
- let n = new Set(t);
160
- return n.has(e) ? n.delete(e) : n.add(e), n;
161
- }), H = t(() => T(R, z), [R, z]), U = c(), W = (P?.provider === "object" ? P.object : void 0) ?? r.objectName, G = (e) => {
162
- let t = M?.fields?.[e]?.label || e.replace(/_/g, " ").replace(/\b\w/g, (e) => e.toUpperCase());
163
- return W ? U.fieldLabel(W, e, t) : t;
164
- }, K = s({
179
+ ]), V = m && m.provider === P && m.object === F ? m.rows : null, H = t(() => ve(V ?? he, B), [V, B]), [U, Ce] = n(() => /* @__PURE__ */ new Map()), W = t(() => be(H, z.defaultExpandedDepth, U), [
180
+ H,
181
+ z.defaultExpandedDepth,
182
+ U
183
+ ]), we = (e, t) => Ce((n) => {
184
+ let r = new Map(n);
185
+ return r.set(e, !t), r;
186
+ }), Te = t(() => ye(H, W), [H, W]), G = ae(), K = f(r, A) ?? r.objectName, q = (e) => {
187
+ let t = N?.fields?.[e]?.label || e.replace(/_/g, " ").replace(/\b\w/g, (e) => e.toUpperCase());
188
+ return K ? G.fieldLabel(K, e, t) : t;
189
+ }, J = (e) => ({
190
+ fieldDef: N?.fields?.[e],
191
+ fieldName: e,
192
+ objectName: K,
193
+ translateOptions: G.translateOptions
194
+ }), Y = re({
165
195
  navigation: r.navigation,
166
- objectName: r.objectName,
167
- onRowClick: f
168
- }), { t: q } = _();
169
- return A ? /* @__PURE__ */ h("div", {
170
- className: d("flex items-center justify-center h-40 text-destructive", l),
171
- children: /* @__PURE__ */ g("p", { children: ["Failed to load tree: ", A.message] })
172
- }) : O ? /* @__PURE__ */ h("div", {
173
- className: d("flex items-center justify-center h-40 text-muted-foreground", l),
174
- children: /* @__PURE__ */ h("p", { children: "Loading…" })
175
- }) : S.length === 0 ? /* @__PURE__ */ h("div", {
176
- className: d("flex items-center justify-center h-40 text-muted-foreground", l),
177
- children: /* @__PURE__ */ h("p", { children: "No records" })
178
- }) : /* @__PURE__ */ g("div", {
179
- className: d("w-full overflow-auto", l),
196
+ objectName: f(r, A) ?? r.objectName,
197
+ onRowClick: l
198
+ }), { anchorRef: Ee, captureAnchor: X } = v(), { t: Z } = me();
199
+ if (O) return /* @__PURE__ */ x("div", {
200
+ className: h("flex items-center justify-center h-40 text-destructive", c),
201
+ children: /* @__PURE__ */ S("p", { children: ["Failed to load tree: ", O.message] })
202
+ });
203
+ if (V === null || T && V.length === 0) return /* @__PURE__ */ x("div", {
204
+ className: h("flex items-center justify-center h-40 text-muted-foreground", c),
205
+ children: /* @__PURE__ */ x("p", { children: "Loading…" })
206
+ });
207
+ if (V.length === 0) return /* @__PURE__ */ x("div", {
208
+ className: h("flex items-center justify-center h-40 text-muted-foreground", c),
209
+ children: /* @__PURE__ */ x("p", { children: "No records" })
210
+ });
211
+ let Q = (e) => {
212
+ if (!Y.isOverlay) return null;
213
+ let t = f(r, A) ?? r.objectName;
214
+ return /* @__PURE__ */ x(se, {
215
+ ...Y,
216
+ title: Z("detail.recordDetail"),
217
+ mainContent: e,
218
+ popoverAnchorRef: Ee,
219
+ storageKey: t ? _(t) : void 0,
220
+ legacyStorageKey: t ? g(t) : void 0,
221
+ width: Y.width ?? le,
222
+ children: (e) => {
223
+ let n = e, r = n.id ?? n._id, i = !!N?.fields && Object.keys(N.fields).length > 0;
224
+ return !t || r == null || !i ? /* @__PURE__ */ x("div", {
225
+ className: "space-y-3 p-4",
226
+ children: Object.entries(n).map(([e, t]) => /* @__PURE__ */ S("div", {
227
+ className: "flex flex-col",
228
+ children: [/* @__PURE__ */ x("span", {
229
+ className: "text-xs font-medium text-muted-foreground uppercase tracking-wide",
230
+ children: e.replace(/_/g, " ")
231
+ }), /* @__PURE__ */ x("span", {
232
+ className: "text-sm",
233
+ children: D(t, J(e)) || "—"
234
+ })]
235
+ }, e))
236
+ }) : /* @__PURE__ */ x("div", {
237
+ className: "px-6 pt-6 pb-6",
238
+ children: /* @__PURE__ */ x(ue, {
239
+ record: n,
240
+ objectName: t,
241
+ recordId: r,
242
+ dataSource: s,
243
+ objectSchema: N,
244
+ onClose: Y.close
245
+ })
246
+ });
247
+ }
248
+ });
249
+ }, $ = /* @__PURE__ */ S("div", {
250
+ className: h("w-full overflow-auto", c),
180
251
  "data-testid": "object-tree",
181
- children: [/* @__PURE__ */ g("table", {
182
- className: "w-full border-collapse text-sm",
183
- children: [/* @__PURE__ */ h("thead", { children: /* @__PURE__ */ g("tr", {
184
- className: "border-b text-left text-muted-foreground",
185
- children: [/* @__PURE__ */ h("th", {
186
- className: "px-3 py-2 font-medium",
187
- children: G(I.labelField)
188
- }), I.fields.filter((e) => e !== I.labelField).map((e) => /* @__PURE__ */ h("th", {
189
- className: "px-3 py-2 font-medium",
190
- children: G(e)
191
- }, e))]
192
- }) }), /* @__PURE__ */ h("tbody", { children: H.map((e) => {
193
- let t = e.children.length > 0, n = z.has(e.id);
194
- return /* @__PURE__ */ g("tr", {
195
- className: "border-b hover:bg-accent/50 cursor-pointer",
196
- "data-testid": "object-tree-row",
197
- "data-depth": e.depth,
198
- onClick: (t) => K.handleClick(e.record, t),
199
- children: [/* @__PURE__ */ h("td", {
200
- className: "px-3 py-2",
201
- children: /* @__PURE__ */ g("div", {
202
- className: "flex items-center gap-1",
203
- style: { paddingLeft: `${e.depth * 20}px` },
204
- children: [t ? /* @__PURE__ */ h("button", {
205
- type: "button",
206
- "aria-label": n ? "Collapse" : "Expand",
207
- className: "flex h-5 w-5 items-center justify-center rounded-sm text-muted-foreground hover:bg-muted",
208
- onClick: (t) => {
209
- t.stopPropagation(), V(e.id);
210
- },
211
- children: h(n ? p : m, { className: "h-4 w-4" })
212
- }) : /* @__PURE__ */ h("span", { className: "inline-block h-5 w-5" }), /* @__PURE__ */ h("span", {
213
- className: "truncate",
214
- children: D(e.record[I.labelField]) || "—"
215
- })]
216
- })
217
- }), I.fields.filter((e) => e !== I.labelField).map((t) => /* @__PURE__ */ h("td", {
218
- className: "px-3 py-2 text-muted-foreground",
219
- children: D(e.record[t])
220
- }, t))]
221
- }, e.id);
222
- }) })]
223
- }), K.isOverlay && /* @__PURE__ */ h(u, {
224
- ...K,
225
- title: q("detail.recordDetail"),
226
- children: (e) => /* @__PURE__ */ h("div", {
227
- className: "space-y-3",
228
- children: Object.entries(e).map(([e, t]) => /* @__PURE__ */ g("div", {
229
- className: "flex flex-col",
230
- children: [/* @__PURE__ */ h("span", {
231
- className: "text-xs font-medium text-muted-foreground uppercase tracking-wide",
232
- children: e.replace(/_/g, " ")
233
- }), /* @__PURE__ */ h("span", {
234
- className: "text-sm",
235
- children: D(t) || "—"
236
- })]
237
- }, e))
238
- })
239
- })]
252
+ children: [
253
+ /* @__PURE__ */ x(ce, {
254
+ active: T && V.length > 0,
255
+ ariaLabel: Z("grid.refreshing"),
256
+ className: "sticky -mb-0.5"
257
+ }),
258
+ /* @__PURE__ */ S("table", {
259
+ className: "w-full border-collapse text-sm",
260
+ children: [/* @__PURE__ */ x("thead", { children: /* @__PURE__ */ S("tr", {
261
+ className: "border-b text-left text-muted-foreground",
262
+ children: [/* @__PURE__ */ x("th", {
263
+ className: "px-3 py-2 font-medium",
264
+ children: q(z.labelField)
265
+ }), z.fields.filter((e) => e !== z.labelField).map((e) => /* @__PURE__ */ x("th", {
266
+ className: "px-3 py-2 font-medium",
267
+ children: q(e)
268
+ }, e))]
269
+ }) }), /* @__PURE__ */ x("tbody", { children: Te.map((e) => {
270
+ let t = e.children.length > 0, n = W.has(e.id);
271
+ return /* @__PURE__ */ S("tr", {
272
+ className: "border-b hover:bg-accent/50 cursor-pointer",
273
+ "data-testid": "object-tree-row",
274
+ "data-depth": e.depth,
275
+ onClick: (t) => {
276
+ X(t), Y.handleClick(e.record, t);
277
+ },
278
+ children: [/* @__PURE__ */ x("td", {
279
+ className: "px-3 py-2",
280
+ children: /* @__PURE__ */ S("div", {
281
+ className: "flex items-center gap-1",
282
+ style: { paddingLeft: `${e.depth * 20}px` },
283
+ children: [t ? /* @__PURE__ */ x("button", {
284
+ type: "button",
285
+ "aria-label": n ? "Collapse" : "Expand",
286
+ className: "flex h-5 w-5 items-center justify-center rounded-sm text-muted-foreground hover:bg-muted",
287
+ onClick: (t) => {
288
+ t.stopPropagation(), we(e.id, n);
289
+ },
290
+ children: x(n ? fe : pe, { className: "h-4 w-4" })
291
+ }) : /* @__PURE__ */ x("span", { className: "inline-block h-5 w-5" }), /* @__PURE__ */ x("span", {
292
+ className: "truncate",
293
+ children: D(e.record[z.labelField], J(z.labelField)) || "—"
294
+ })]
295
+ })
296
+ }), z.fields.filter((e) => e !== z.labelField).map((t) => /* @__PURE__ */ x("td", {
297
+ className: "px-3 py-2 text-muted-foreground",
298
+ children: D(e.record[t], J(t))
299
+ }, t))]
300
+ }, e.id);
301
+ }) })]
302
+ }),
303
+ C && /* @__PURE__ */ x(p, { result: C })
304
+ ]
240
305
  });
306
+ if (Y.isOverlay && Y.mode === "split" && Y.isOpen && Y.selectedRecord) {
307
+ let e = Q($);
308
+ if (e) return /* @__PURE__ */ x(b, { children: e });
309
+ }
310
+ return /* @__PURE__ */ S(b, { children: [$, Q()] });
241
311
  }, k = ({ schema: e, ...t }) => {
242
- let { dataSource: n } = l() || {};
243
- return /* @__PURE__ */ h(O, {
312
+ let { dataSource: n } = m() || {};
313
+ return /* @__PURE__ */ x(O, {
244
314
  schema: e,
245
315
  dataSource: n,
246
316
  ...t
247
317
  });
248
- }, A = [{
249
- name: "objectName",
250
- type: "string",
251
- label: "Object Name",
252
- required: !0
253
- }, {
254
- name: "tree",
255
- type: "object",
256
- label: "Tree Config",
257
- description: "parentField, labelField, fields, defaultExpandedDepth"
258
- }];
318
+ };
259
319
  r.register("object-tree", k, {
260
320
  namespace: "plugin-tree",
261
321
  label: "Object Tree",
262
322
  category: "view",
263
- inputs: A
264
- }), r.register("tree", k, {
265
- namespace: "view",
266
- label: "Tree View",
267
- category: "view",
268
- inputs: A
323
+ inputs: [
324
+ {
325
+ name: "objectName",
326
+ type: "string",
327
+ description: "ObjectQL object name. The record source is one of `data`, `staticData` and `objectName`, read in that order: a tree on `data` or `staticData` never queries this object. On a tree whose rows are inline it still names the record page a new-tab click opens."
328
+ },
329
+ {
330
+ name: "tree",
331
+ type: "object",
332
+ description: "The field configuration: `parentField` names the field holding each record’s parent id (auto-detected from the object’s self-referencing field when omitted), `labelField` the field drawn indented in the first column (default `name`), `fields` the further fields drawn as flat columns after it, and `defaultExpandedDepth` how many levels open on first draw (`0` shows roots only; omitted, every level is open)."
333
+ },
334
+ {
335
+ name: "data",
336
+ type: "object",
337
+ description: "A `{ provider, … }` data-source configuration, read FIRST on the record-source ladder: a tree carrying one never reaches `staticData` and never queries `objectName`. `{ provider: 'value', items }` draws those records and `{ provider: 'object', object }` queries that object, both narrowed by `filter`. The `api` and `schema` providers draw no rows on the tree. A bare array is not this key’s shape and is not a record source: the tree falls through to `staticData`, then `objectName`, so inline rows belong under `staticData`."
338
+ },
339
+ {
340
+ name: "staticData",
341
+ type: "array",
342
+ description: "Inline records, read SECOND on the record-source ladder: a `data` configuration wins and this key is then never reached, while `objectName` is read AFTER it, so a tree carrying both draws these rows and never queries that object. Each record is placed under the record its `parentField` value names, and one naming no record is drawn as a root. `filter` narrows these rows exactly as it does fetched ones."
343
+ },
344
+ {
345
+ name: "filter",
346
+ type: "array",
347
+ description: "Base query filter in the rule-array form `[{ field, operator, value }, ...]`, narrowing the records the tree draws — fetched rows and inline (`staticData`, `{ provider: 'value' }`) rows alike. Context tokens such as `{current_user_id}` are resolved first, then the filter is lowered to `$filter` on the query. A record whose parent the filter removed is drawn as a root. The MongoDB-style record form is not this key’s shape."
348
+ },
349
+ {
350
+ name: "navigation",
351
+ type: "object",
352
+ description: "What a row click opens — the `{ mode, size, openNewTab, preventNavigation }` block a list view declares. With the key ABSENT a click opens nothing: this renderer supplies no drawer default. `mode` is an overlay (`drawer`, `modal`, `split`, `popover`), `new_window`, `page` or `none`, and a block written without `mode` takes the spec’s `page` default. `drawer`, `modal` and `popover` open the row’s record in that overlay, and `split` opens it beside the tree; `new_window` opens the record page in a new tab; `none` opens nothing. `page` opens the record page of `data.object` when `data` is the object provider, else of the tree’s `objectName`, through the record navigator the host publishes (the console publishes one on its custom pages, record pages and list views); under a host that publishes none, such as an embedded renderer, or on a tree that names neither (inline rows with no `objectName`), there is no record page to open and the click opens nothing. `preventNavigation: true` opens nothing whatever the mode, `openNewTab: true` opens the record page in a new tab and outranks every mode except `none`, and `size` sets the overlay width. A click handler from a parent view outranks the whole key."
353
+ }
354
+ ]
269
355
  });
270
356
  //#endregion
271
357
  export { O as ObjectTree, k as ObjectTreeRenderer };
@@ -1 +1 @@
1
- (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react"),require("@object-ui/core"),require("@object-ui/react"),require("@object-ui/components"),require("@object-ui/i18n"),require("lucide-react"),require("react/jsx-runtime")):typeof define==`function`&&define.amd?define([`exports`,`react`,`@object-ui/core`,`@object-ui/react`,`@object-ui/components`,`@object-ui/i18n`,`lucide-react`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ObjectUIPluginTree={},e.React,e.ObjectUICore,e.ObjectUIReact,e.ObjectUIComponents,e.ObjectUII18n,e.LucideReact,e.react_jsx_runtime))})(this,function(e,t,n,r,i,a,o,s){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var c=Object.create,l=Object.defineProperty,u=Object.getOwnPropertyDescriptor,d=Object.getOwnPropertyNames,f=Object.getPrototypeOf,p=Object.prototype.hasOwnProperty,m=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=d(t),a=0,o=i.length,s;a<o;a++)s=i[a],!p.call(e,s)&&s!==n&&l(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=u(t,s))||r.enumerable});return e};t=((e,t,n)=>(n=e==null?{}:c(f(e)),m(t||!e||!e.__esModule||!p.call(e,`default`)?l(n,`default`,{value:e,enumerable:!0}):n,e)))(t,1);var h=(0,a.createSafeTranslation)({"detail.recordDetail":`Record Detail`},`detail.recordDetail`);function g(e){return e.data?e.data:e.staticData?{provider:`value`,items:e.staticData}:e.objectName?{provider:`object`,object:e.objectName}:null}function _(e){return(0,n.columnIdentity)(e)||(e&&typeof e==`object`?e.key:void 0)||void 0}function v(e){let t=e.tree||e.filter?.tree||{},n=Array.isArray(e.fields)?e.fields:Array.isArray(t.fields)?t.fields:[];return{parentField:_(e.parentField??t.parentField),labelField:_(e.labelField??t.labelField??e.titleField)??`name`,fields:n.map(_).filter(e=>!!e),defaultExpandedDepth:e.defaultExpandedDepth??t.defaultExpandedDepth}}function y(e,t){let n=e?.fields;if(!n||typeof n!=`object`)return;let r;for(let[e,i]of Object.entries(n)){if(i?.type===`tree`)return e;let n=i?.reference||i?.reference_to||i?.referenceTo;!r&&(i?.type===`lookup`||i?.type===`master_detail`)&&n&&t&&n===t&&(r=e)}return r}function b(e){let t=e?.id??e?._id;return t==null?void 0:String(t)}function x(e,t){if(!t)return;let n=e?.[t];if(n!=null){if(typeof n==`object`){let e=n.id??n._id;return e==null?void 0:String(e)}return String(n)}}function S(e,t){let n=new Map,r=[];for(let t of e){let e=b(t);e!=null&&(n.set(e,{id:e,record:t,depth:0,children:[]}),r.push(e))}let i=[];for(let e of r){let r=n.get(e),a=x(r.record,t),o=a==null?void 0:n.get(a);o&&o!==r?o.children.push(r):i.push(r)}let a=(e,t)=>{for(let n of e)n.depth=t,a(n.children,t+1)};return a(i,0),i}function C(e,t){let n=[],r=e=>{for(let i of e)n.push(i),i.children.length>0&&t.has(i.id)&&r(i.children)};return r(e),n}function w(e,t){let n=new Set,r=e=>{for(let i of e)i.children.length!==0&&(t==null||i.depth<t)&&(n.add(i.id),r(i.children))};return r(e),n}function T(e){return e==null?``:String(typeof e==`object`?e.name??e.label??e.id??e._id??``:e)}var E=({schema:e,dataSource:a,className:c,onRowClick:l,...u})=>{let[d,f]=(0,t.useState)([]),[p,m]=(0,t.useState)(!0),[_,b]=(0,t.useState)(null),[x,E]=(0,t.useState)(null),D=(0,t.useMemo)(()=>g(e),[e]),O=Array.isArray(u.data)||Array.isArray(e.data)||D?.provider===`value`;(0,t.useEffect)(()=>{let t=!1;return O||(async()=>{try{if(!a||typeof a.getObjectSchema!=`function`)return;let n=D?.provider===`object`?D.object:e.objectName;if(!n)return;let r=await a.getObjectSchema(n);t||E(r)}catch(e){console.error(`[ObjectTree] Failed to fetch object schema:`,e)}})(),()=>{t=!0}},[e.objectName,a,D,O]),(0,t.useEffect)(()=>{let t=!1;return(async()=>{try{if(m(!0),b(null),D?.provider===`object`&&a&&typeof a.find==`function`){let r=(0,n.buildExpandFields)(x?.fields),i=await a.find(D.object,{$filter:e.filter,...r.length>0?{$expand:r}:{}});t||(f((0,n.extractRecords)(i)),m(!1));return}let r=u.data??e.data;if(Array.isArray(r)){t||(f(r),m(!1));return}if(D?.provider===`value`){t||(f(D.items??[]),m(!1));return}t||(f([]),m(!1))}catch(e){t||(b(e),m(!1))}})(),()=>{t=!0}},[D,a,e.filter,x,u.data]);let k=(0,t.useMemo)(()=>v(e),[e]),A=(0,t.useMemo)(()=>k.parentField??y(x,e.objectName),[k.parentField,x,e.objectName]),j=(0,t.useMemo)(()=>S(d,A),[d,A]),[M,N]=(0,t.useState)(new Set);(0,t.useEffect)(()=>{N(w(j,k.defaultExpandedDepth))},[j,k.defaultExpandedDepth]);let P=e=>N(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n}),F=(0,t.useMemo)(()=>C(j,M),[j,M]),I=(0,r.useSafeFieldLabel)(),L=(D?.provider===`object`?D.object:void 0)??e.objectName,R=e=>{let t=x?.fields?.[e]?.label||e.replace(/_/g,` `).replace(/\b\w/g,e=>e.toUpperCase());return L?I.fieldLabel(L,e,t):t},z=(0,r.useNavigationOverlay)({navigation:e.navigation,objectName:e.objectName,onRowClick:l}),{t:B}=h();return _?(0,s.jsx)(`div`,{className:(0,i.cn)(`flex items-center justify-center h-40 text-destructive`,c),children:(0,s.jsxs)(`p`,{children:[`Failed to load tree: `,_.message]})}):p?(0,s.jsx)(`div`,{className:(0,i.cn)(`flex items-center justify-center h-40 text-muted-foreground`,c),children:(0,s.jsx)(`p`,{children:`Loading…`})}):d.length===0?(0,s.jsx)(`div`,{className:(0,i.cn)(`flex items-center justify-center h-40 text-muted-foreground`,c),children:(0,s.jsx)(`p`,{children:`No records`})}):(0,s.jsxs)(`div`,{className:(0,i.cn)(`w-full overflow-auto`,c),"data-testid":`object-tree`,children:[(0,s.jsxs)(`table`,{className:`w-full border-collapse text-sm`,children:[(0,s.jsx)(`thead`,{children:(0,s.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,s.jsx)(`th`,{className:`px-3 py-2 font-medium`,children:R(k.labelField)}),k.fields.filter(e=>e!==k.labelField).map(e=>(0,s.jsx)(`th`,{className:`px-3 py-2 font-medium`,children:R(e)},e))]})}),(0,s.jsx)(`tbody`,{children:F.map(e=>{let t=e.children.length>0,n=M.has(e.id);return(0,s.jsxs)(`tr`,{className:`border-b hover:bg-accent/50 cursor-pointer`,"data-testid":`object-tree-row`,"data-depth":e.depth,onClick:t=>z.handleClick(e.record,t),children:[(0,s.jsx)(`td`,{className:`px-3 py-2`,children:(0,s.jsxs)(`div`,{className:`flex items-center gap-1`,style:{paddingLeft:`${e.depth*20}px`},children:[t?(0,s.jsx)(`button`,{type:`button`,"aria-label":n?`Collapse`:`Expand`,className:`flex h-5 w-5 items-center justify-center rounded-sm text-muted-foreground hover:bg-muted`,onClick:t=>{t.stopPropagation(),P(e.id)},children:n?(0,s.jsx)(o.ChevronDown,{className:`h-4 w-4`}):(0,s.jsx)(o.ChevronRight,{className:`h-4 w-4`})}):(0,s.jsx)(`span`,{className:`inline-block h-5 w-5`}),(0,s.jsx)(`span`,{className:`truncate`,children:T(e.record[k.labelField])||`—`})]})}),k.fields.filter(e=>e!==k.labelField).map(t=>(0,s.jsx)(`td`,{className:`px-3 py-2 text-muted-foreground`,children:T(e.record[t])},t))]},e.id)})})]}),z.isOverlay&&(0,s.jsx)(i.NavigationOverlay,{...z,title:B(`detail.recordDetail`),children:e=>(0,s.jsx)(`div`,{className:`space-y-3`,children:Object.entries(e).map(([e,t])=>(0,s.jsxs)(`div`,{className:`flex flex-col`,children:[(0,s.jsx)(`span`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wide`,children:e.replace(/_/g,` `)}),(0,s.jsx)(`span`,{className:`text-sm`,children:T(t)||`—`})]},e))})})]})},D=({schema:e,...t})=>{let{dataSource:n}=(0,r.useSchemaContext)()||{};return(0,s.jsx)(E,{schema:e,dataSource:n,...t})},O=[{name:`objectName`,type:`string`,label:`Object Name`,required:!0},{name:`tree`,type:`object`,label:`Tree Config`,description:`parentField, labelField, fields, defaultExpandedDepth`}];n.ComponentRegistry.register(`object-tree`,D,{namespace:`plugin-tree`,label:`Object Tree`,category:`view`,inputs:O}),n.ComponentRegistry.register(`tree`,D,{namespace:`view`,label:`Tree View`,category:`view`,inputs:O}),e.ObjectTree=E,e.ObjectTreeRenderer=D});
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react"),require("@object-ui/core"),require("@object-ui/react"),require("@object-ui/components"),require("@object-ui/plugin-detail"),require("@object-ui/i18n"),require("@object-ui/permissions"),require("lucide-react"),require("react/jsx-runtime")):typeof define==`function`&&define.amd?define([`exports`,`react`,`@object-ui/core`,`@object-ui/react`,`@object-ui/components`,`@object-ui/plugin-detail`,`@object-ui/i18n`,`@object-ui/permissions`,`lucide-react`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ObjectUIPluginTree={},e.React,e.ObjectUICore,e.ObjectUIReact,e.ObjectUIComponents,e._object_ui_plugin_detail,e.ObjectUII18n,e._object_ui_permissions,e.LucideReact,e.react_jsx_runtime))})(this,function(e,t,n,r,i,a,o,s,c,l){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var u=Object.create,d=Object.defineProperty,f=Object.getOwnPropertyDescriptor,p=Object.getOwnPropertyNames,m=Object.getPrototypeOf,h=Object.prototype.hasOwnProperty,g=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=p(t),a=0,o=i.length,s;a<o;a++)s=i[a],!h.call(e,s)&&s!==n&&d(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=f(t,s))||r.enumerable});return e};t=((e,t,n)=>(n=e==null?{}:u(m(e)),g(t||!e||!e.__esModule||!h.call(e,`default`)?d(n,`default`,{value:e,enumerable:!0}):n,e)))(t,1);var _=(0,o.createSafeTranslation)({"detail.recordDetail":`Record Detail`,"grid.refreshing":`Refreshing…`},`detail.recordDetail`),ee=[];function v(e){return(0,n.columnIdentity)(e)||(e&&typeof e==`object`?e.key:void 0)||void 0}function y(e){let t=e.tree||{},n=Array.isArray(e.fields)?e.fields:Array.isArray(t.fields)?t.fields:[];return{parentField:v(e.parentField??t.parentField),labelField:v(e.labelField??t.labelField)??`name`,fields:n.map(v).filter(e=>!!e),defaultExpandedDepth:e.defaultExpandedDepth??t.defaultExpandedDepth}}function b(e,t){let n=e?.fields;if(!n||typeof n!=`object`)return;let r;for(let[e,i]of Object.entries(n)){let n=i?.reference;if(i?.type===`tree`&&(n===void 0||t&&n===t))return e;!r&&(i?.type===`lookup`||i?.type===`master_detail`)&&n&&t&&n===t&&(r=e)}return r}function x(e){let t=e?.id??e?._id;return t==null?void 0:String(t)}function S(e,t){if(!t)return;let n=e?.[t];if(n!=null){if(typeof n==`object`){let e=n.id??n._id;return e==null?void 0:String(e)}return String(n)}}function C(e,t){let n=new Map,r=[];for(let t of e){let e=x(t);e!=null&&(n.set(e,{id:e,record:t,depth:0,children:[]}),r.push(e))}let i=[];for(let e of r){let r=n.get(e),a=S(r.record,t),o=a==null?void 0:n.get(a);o&&o!==r?o.children.push(r):i.push(r)}let a=(e,t)=>{for(let n of e)n.depth=t,a(n.children,t+1)};return a(i,0),i}function w(e,t){let n=[],r=e=>{for(let i of e)n.push(i),i.children.length>0&&t.has(i.id)&&r(i.children)};return r(e),n}function T(e,t){let n=new Set,r=e=>{for(let i of e)i.children.length!==0&&(t==null||i.depth<t)&&(n.add(i.id),r(i.children))};return r(e),n}function E(e,t,n){let r=T(e,t);if(n.size===0)return r;let i=e=>{for(let t of e){let e=n.get(t.id);e===!0?r.add(t.id):e===!1&&r.delete(t.id),i(t.children)}};return i(e),r}function D(e,t){if(e==null)return``;let r=Array.isArray(t?.fieldDef?.options)?t.fieldDef.options:null;if(r&&r.length>0){let i=t.objectName?t.translateOptions(t.objectName,t.fieldName,r):r,a=e=>{let t=i.find(t=>t?.value===e);if(t)return String(t.label??e);let r=String(e).toLowerCase(),a=i.find(e=>String(e?.value).toLowerCase()===r);return a?String(a.label??e):(0,n.humanizeLabel)(String(e))};return Array.isArray(e)?e.filter(e=>e!=null).map(a).join(`, `):a(e)}return typeof e==`object`&&(0,n.isExpandableFieldType)(t?.fieldDef)?(0,n.getRecordDisplayName)(void 0,e):String(typeof e==`object`?e.name??e.label??e.id??e._id??``:e)}var O=({schema:e,dataSource:o,className:u,onRowClick:d,...f})=>{let[p,m]=(0,t.useState)(null),[h,g]=(0,t.useState)(null),[v,x]=(0,t.useState)(!0),[S,T]=(0,t.useState)(null),O=(0,t.useMemo)(()=>(0,n.resolveRecordSourceConfig)(e,`view-data`),[e]),k=(0,n.resolveRecordSourceObjectName)(e,O)??``,{ready:A,def:j}=(0,r.useSettledSchema)(k,o),M=O?.provider,N=O?.provider===`object`?O.object:void 0,P=O?.provider===`value`?O.items:void 0,F=(0,s.usePermissions)(),te=(0,r.useFilterScope)(),I=(0,r.useResolvedFilter)(e.filter,te),L=(0,r.useDataInvalidation)(o?N:void 0);(0,t.useEffect)(()=>{let e=!1;return(async()=>{try{if(x(!0),T(null),M===`object`&&o&&typeof o.find==`function`){if(!A)return;let t=(0,n.buildExpandFields)(j?.fields),r=F?.isLoaded?t.filter(e=>F.checkField(N,e,`read`)):t,i=await o.find(N,{$filter:I,...(0,n.nonGridRowCeilingQuery)(),...r.length>0?{$expand:r}:{}}),a=(0,n.applyNonGridRowCeiling)(i);e||(m({provider:M,object:N,rows:a.rows}),g(a),x(!1));return}let t=f.data;if(Array.isArray(t)){e||(m({provider:M,object:N,rows:t}),g(null),x(!1));return}if(M===`value`){let t=await new n.ValueDataSource({items:P??[]}).find(``,{$filter:I,...(0,n.nonGridRowCeilingQuery)()}),r=(0,n.applyNonGridRowCeiling)(t);e||(m({provider:M,object:N,rows:r.rows}),g(r),x(!1));return}e||(m({provider:M,object:N,rows:[]}),x(!1))}catch(t){e||(T(t),x(!1))}})(),()=>{e=!0}},[M,N,P,o,I,j,A,f.data,F,L]);let R=(0,t.useMemo)(()=>y(e),[e]),z=(0,t.useMemo)(()=>R.parentField??b(j,e.objectName),[R.parentField,j,e.objectName]),B=p&&p.provider===M&&p.object===N?p.rows:null,V=(0,t.useMemo)(()=>C(B??ee,z),[B,z]),[H,ne]=(0,t.useState)(()=>new Map),U=(0,t.useMemo)(()=>E(V,R.defaultExpandedDepth,H),[V,R.defaultExpandedDepth,H]),W=(e,t)=>ne(n=>{let r=new Map(n);return r.set(e,!t),r}),G=(0,t.useMemo)(()=>w(V,U),[V,U]),K=(0,r.useSafeFieldLabel)(),q=(0,n.resolveRecordSourceObjectName)(e,O)??e.objectName,J=e=>{let t=j?.fields?.[e]?.label||e.replace(/_/g,` `).replace(/\b\w/g,e=>e.toUpperCase());return q?K.fieldLabel(q,e,t):t},Y=e=>({fieldDef:j?.fields?.[e],fieldName:e,objectName:q,translateOptions:K.translateOptions}),X=(0,r.useNavigationOverlay)({navigation:e.navigation,objectName:(0,n.resolveRecordSourceObjectName)(e,O)??e.objectName,onRowClick:d}),{anchorRef:re,captureAnchor:ie}=(0,i.useOverlayAnchor)(),{t:Z}=_();if(S)return(0,l.jsx)(`div`,{className:(0,i.cn)(`flex items-center justify-center h-40 text-destructive`,u),children:(0,l.jsxs)(`p`,{children:[`Failed to load tree: `,S.message]})});if(B===null||v&&B.length===0)return(0,l.jsx)(`div`,{className:(0,i.cn)(`flex items-center justify-center h-40 text-muted-foreground`,u),children:(0,l.jsx)(`p`,{children:`Loading…`})});if(B.length===0)return(0,l.jsx)(`div`,{className:(0,i.cn)(`flex items-center justify-center h-40 text-muted-foreground`,u),children:(0,l.jsx)(`p`,{children:`No records`})});let Q=t=>{if(!X.isOverlay)return null;let r=(0,n.resolveRecordSourceObjectName)(e,O)??e.objectName;return(0,l.jsx)(i.NavigationOverlay,{...X,title:Z(`detail.recordDetail`),mainContent:t,popoverAnchorRef:re,storageKey:r?(0,i.recordOverlayWidthStorageKey)(r):void 0,legacyStorageKey:r?(0,i.legacyRecordDrawerWidthKey)(r):void 0,width:X.width??a.RECORD_OVERLAY_DEFAULT_WIDTH,children:e=>{let t=e,n=t.id??t._id,i=!!j?.fields&&Object.keys(j.fields).length>0;return!r||n==null||!i?(0,l.jsx)(`div`,{className:`space-y-3 p-4`,children:Object.entries(t).map(([e,t])=>(0,l.jsxs)(`div`,{className:`flex flex-col`,children:[(0,l.jsx)(`span`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wide`,children:e.replace(/_/g,` `)}),(0,l.jsx)(`span`,{className:`text-sm`,children:D(t,Y(e))||`—`})]},e))}):(0,l.jsx)(`div`,{className:`px-6 pt-6 pb-6`,children:(0,l.jsx)(a.RecordDetailPanel,{record:t,objectName:r,recordId:n,dataSource:o,objectSchema:j,onClose:X.close})})}})},$=(0,l.jsxs)(`div`,{className:(0,i.cn)(`w-full overflow-auto`,u),"data-testid":`object-tree`,children:[(0,l.jsx)(i.RefreshIndicator,{active:v&&B.length>0,ariaLabel:Z(`grid.refreshing`),className:`sticky -mb-0.5`}),(0,l.jsxs)(`table`,{className:`w-full border-collapse text-sm`,children:[(0,l.jsx)(`thead`,{children:(0,l.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,l.jsx)(`th`,{className:`px-3 py-2 font-medium`,children:J(R.labelField)}),R.fields.filter(e=>e!==R.labelField).map(e=>(0,l.jsx)(`th`,{className:`px-3 py-2 font-medium`,children:J(e)},e))]})}),(0,l.jsx)(`tbody`,{children:G.map(e=>{let t=e.children.length>0,n=U.has(e.id);return(0,l.jsxs)(`tr`,{className:`border-b hover:bg-accent/50 cursor-pointer`,"data-testid":`object-tree-row`,"data-depth":e.depth,onClick:t=>{ie(t),X.handleClick(e.record,t)},children:[(0,l.jsx)(`td`,{className:`px-3 py-2`,children:(0,l.jsxs)(`div`,{className:`flex items-center gap-1`,style:{paddingLeft:`${e.depth*20}px`},children:[t?(0,l.jsx)(`button`,{type:`button`,"aria-label":n?`Collapse`:`Expand`,className:`flex h-5 w-5 items-center justify-center rounded-sm text-muted-foreground hover:bg-muted`,onClick:t=>{t.stopPropagation(),W(e.id,n)},children:n?(0,l.jsx)(c.ChevronDown,{className:`h-4 w-4`}):(0,l.jsx)(c.ChevronRight,{className:`h-4 w-4`})}):(0,l.jsx)(`span`,{className:`inline-block h-5 w-5`}),(0,l.jsx)(`span`,{className:`truncate`,children:D(e.record[R.labelField],Y(R.labelField))||`—`})]})}),R.fields.filter(e=>e!==R.labelField).map(t=>(0,l.jsx)(`td`,{className:`px-3 py-2 text-muted-foreground`,children:D(e.record[t],Y(t))},t))]},e.id)})})]}),h&&(0,l.jsx)(r.NonGridRowCeilingNote,{result:h})]});if(X.isOverlay&&X.mode===`split`&&X.isOpen&&X.selectedRecord){let e=Q($);if(e)return(0,l.jsx)(l.Fragment,{children:e})}return(0,l.jsxs)(l.Fragment,{children:[$,Q()]})},k=({schema:e,...t})=>{let{dataSource:n}=(0,r.useSchemaContext)()||{};return(0,l.jsx)(O,{schema:e,dataSource:n,...t})};n.ComponentRegistry.register(`object-tree`,k,{namespace:`plugin-tree`,label:`Object Tree`,category:`view`,inputs:[{name:`objectName`,type:`string`,description:"ObjectQL object name. The record source is one of `data`, `staticData` and `objectName`, read in that order: a tree on `data` or `staticData` never queries this object. On a tree whose rows are inline it still names the record page a new-tab click opens."},{name:`tree`,type:`object`,description:"The field configuration: `parentField` names the field holding each record’s parent id (auto-detected from the object’s self-referencing field when omitted), `labelField` the field drawn indented in the first column (default `name`), `fields` the further fields drawn as flat columns after it, and `defaultExpandedDepth` how many levels open on first draw (`0` shows roots only; omitted, every level is open)."},{name:`data`,type:`object`,description:"A `{ provider, … }` data-source configuration, read FIRST on the record-source ladder: a tree carrying one never reaches `staticData` and never queries `objectName`. `{ provider: 'value', items }` draws those records and `{ provider: 'object', object }` queries that object, both narrowed by `filter`. The `api` and `schema` providers draw no rows on the tree. A bare array is not this key’s shape and is not a record source: the tree falls through to `staticData`, then `objectName`, so inline rows belong under `staticData`."},{name:`staticData`,type:`array`,description:"Inline records, read SECOND on the record-source ladder: a `data` configuration wins and this key is then never reached, while `objectName` is read AFTER it, so a tree carrying both draws these rows and never queries that object. Each record is placed under the record its `parentField` value names, and one naming no record is drawn as a root. `filter` narrows these rows exactly as it does fetched ones."},{name:`filter`,type:`array`,description:"Base query filter in the rule-array form `[{ field, operator, value }, ...]`, narrowing the records the tree draws — fetched rows and inline (`staticData`, `{ provider: 'value' }`) rows alike. Context tokens such as `{current_user_id}` are resolved first, then the filter is lowered to `$filter` on the query. A record whose parent the filter removed is drawn as a root. The MongoDB-style record form is not this key’s shape."},{name:`navigation`,type:`object`,description:"What a row click opens — the `{ mode, size, openNewTab, preventNavigation }` block a list view declares. With the key ABSENT a click opens nothing: this renderer supplies no drawer default. `mode` is an overlay (`drawer`, `modal`, `split`, `popover`), `new_window`, `page` or `none`, and a block written without `mode` takes the spec’s `page` default. `drawer`, `modal` and `popover` open the row’s record in that overlay, and `split` opens it beside the tree; `new_window` opens the record page in a new tab; `none` opens nothing. `page` opens the record page of `data.object` when `data` is the object provider, else of the tree’s `objectName`, through the record navigator the host publishes (the console publishes one on its custom pages, record pages and list views); under a host that publishes none, such as an embedded renderer, or on a tree that names neither (inline rows with no `objectName`), there is no record page to open and the click opens nothing. `preventNavigation: true` opens nothing whatever the mode, `openNewTab: true` opens the record page in a new tab and outranks every mode except `none`, and `size` sets the overlay width. A click handler from a parent view outranks the whole key."}]}),e.ObjectTree=O,e.ObjectTreeRenderer=k});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@object-ui/plugin-tree",
3
- "version": "17.6.0",
3
+ "version": "17.7.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Tree / tree-grid visualization plugin for Object UI",
@@ -25,12 +25,14 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "@objectstack/spec": "^17.0.0",
28
- "lucide-react": "^1.31.0",
29
- "@object-ui/components": "17.6.0",
30
- "@object-ui/i18n": "17.6.0",
31
- "@object-ui/core": "17.6.0",
32
- "@object-ui/react": "17.6.0",
33
- "@object-ui/types": "17.6.0"
28
+ "lucide-react": "^1.43.0",
29
+ "@object-ui/components": "17.7.0",
30
+ "@object-ui/core": "17.7.0",
31
+ "@object-ui/permissions": "17.7.0",
32
+ "@object-ui/i18n": "17.7.0",
33
+ "@object-ui/plugin-detail": "17.7.0",
34
+ "@object-ui/react": "17.7.0",
35
+ "@object-ui/types": "17.7.0"
34
36
  },
35
37
  "peerDependencies": {
36
38
  "react": "^18.0.0 || ^19.0.0",
@@ -42,7 +44,9 @@
42
44
  "@vitejs/plugin-react": "^6.0.5",
43
45
  "typescript": "^6.0.3",
44
46
  "vite": "^8.2.1",
45
- "vite-plugin-dts": "^5.0.3"
47
+ "vite-plugin-dts": "^5.0.3",
48
+ "@object-ui/sdui-parser": "17.7.0",
49
+ "@object-ui/test-support": "17.4.0"
46
50
  },
47
51
  "keywords": [
48
52
  "objectui",
@@ -69,8 +73,8 @@
69
73
  ],
70
74
  "scripts": {
71
75
  "build": "vite build",
72
- "test": "vitest run",
73
- "test:watch": "vitest",
76
+ "test": "vitest run --root ../.. packages/plugin-tree/",
77
+ "test:watch": "vitest --root ../.. packages/plugin-tree/",
74
78
  "type-check": "tsc --noEmit && tsc -p tsconfig.test.json",
75
79
  "lint": "eslint ."
76
80
  }