@object-ui/plugin-tree 7.0.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/CHANGELOG.md +53 -0
- package/LICENSE +21 -0
- package/README.md +46 -0
- package/dist/ObjectTree.d.ts +14 -0
- package/dist/ObjectTree.d.ts.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +263 -0
- package/dist/index.umd.cjs +1 -0
- package/package.json +76 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# @object-ui/plugin-tree
|
|
2
|
+
|
|
3
|
+
## 7.0.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 4eb9cb6: feat(plugin-tree): add a `tree` / tree-grid object view type
|
|
8
|
+
|
|
9
|
+
Renders a self-referencing object as an indented, expand/collapse tree-grid —
|
|
10
|
+
the right view for arbitrary-depth hierarchies (business unit / org chart,
|
|
11
|
+
category trees, BOMs, nested comments) that fixed-depth grouping can't express.
|
|
12
|
+
New `@object-ui/plugin-tree` package (`object-tree`/`tree`), `tree` added to the
|
|
13
|
+
`ViewType` union, and dispatch wired through plugin-list `ListView` +
|
|
14
|
+
app-shell `ObjectView` (the console path).
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Updated dependencies [5976ba3]
|
|
19
|
+
- Updated dependencies [a00e16d]
|
|
20
|
+
- Updated dependencies [eaccefd]
|
|
21
|
+
- Updated dependencies [f7f325d]
|
|
22
|
+
- Updated dependencies [c12986e]
|
|
23
|
+
- Updated dependencies [71d7ce0]
|
|
24
|
+
- Updated dependencies [053c948]
|
|
25
|
+
- Updated dependencies [ddbe4a2]
|
|
26
|
+
- Updated dependencies [2d47e94]
|
|
27
|
+
- Updated dependencies [9049bbe]
|
|
28
|
+
- Updated dependencies [6c0c92c]
|
|
29
|
+
- Updated dependencies [cb2fdb1]
|
|
30
|
+
- Updated dependencies [c3749eb]
|
|
31
|
+
- Updated dependencies [6cfa330]
|
|
32
|
+
- Updated dependencies [ad8ade6]
|
|
33
|
+
- Updated dependencies [d54346c]
|
|
34
|
+
- Updated dependencies [3870c20]
|
|
35
|
+
- Updated dependencies [2eb3096]
|
|
36
|
+
- Updated dependencies [b88c560]
|
|
37
|
+
- Updated dependencies [d16566f]
|
|
38
|
+
- Updated dependencies [90acb7f]
|
|
39
|
+
- Updated dependencies [7913390]
|
|
40
|
+
- Updated dependencies [1394e34]
|
|
41
|
+
- Updated dependencies [e95cc25]
|
|
42
|
+
- Updated dependencies [abe8ebc]
|
|
43
|
+
- Updated dependencies [300d755]
|
|
44
|
+
- Updated dependencies [bd8b054]
|
|
45
|
+
- Updated dependencies [4eb9cb6]
|
|
46
|
+
- Updated dependencies [7c239fd]
|
|
47
|
+
- Updated dependencies [858ad94]
|
|
48
|
+
- Updated dependencies [2270239]
|
|
49
|
+
- Updated dependencies [8d1195d]
|
|
50
|
+
- @object-ui/core@7.0.0
|
|
51
|
+
- @object-ui/components@7.0.0
|
|
52
|
+
- @object-ui/react@7.0.0
|
|
53
|
+
- @object-ui/types@7.0.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 ObjectQL
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# @object-ui/plugin-tree
|
|
2
|
+
|
|
3
|
+
Tree / tree-grid view plugin for Object UI.
|
|
4
|
+
|
|
5
|
+
Renders a **self-referencing object** as an indented, expand/collapse tree-grid —
|
|
6
|
+
the right view for hierarchies of unbounded depth such as **business unit /
|
|
7
|
+
org chart**, category trees, menu trees, BOMs, or nested comments. (Grouping
|
|
8
|
+
handles *fixed-depth* hierarchies; a tree handles arbitrary depth.)
|
|
9
|
+
|
|
10
|
+
It registers two component types via the `ComponentRegistry`:
|
|
11
|
+
|
|
12
|
+
- `object-tree` — the object-bound renderer
|
|
13
|
+
- `tree` — the view-type alias used by `ObjectView` / `ViewSwitcher`
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
// As a view inside an ObjectView
|
|
19
|
+
{
|
|
20
|
+
type: 'object-view',
|
|
21
|
+
objectName: 'business_unit',
|
|
22
|
+
views: [
|
|
23
|
+
{
|
|
24
|
+
type: 'tree',
|
|
25
|
+
tree: {
|
|
26
|
+
parentField: 'parent', // single-parent pointer (auto-detected if omitted)
|
|
27
|
+
labelField: 'name', // indented first column
|
|
28
|
+
fields: ['name', 'manager'], // additional flat columns
|
|
29
|
+
defaultExpandedDepth: 1, // 0 = roots only; omit = expand all
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Config
|
|
37
|
+
|
|
38
|
+
| Key | Default | Description |
|
|
39
|
+
| --- | --- | --- |
|
|
40
|
+
| `parentField` | auto-detected | Field holding the parent reference. When omitted, the renderer picks the object's `tree` field (or a lookup/master_detail that references the same object). |
|
|
41
|
+
| `labelField` | `name` | Field rendered indented in the first column. |
|
|
42
|
+
| `fields` | `[]` | Additional fields rendered as flat columns. |
|
|
43
|
+
| `defaultExpandedDepth` | _unset_ | Initial expansion depth. `0` = roots only; unset = expand everything. |
|
|
44
|
+
|
|
45
|
+
Records whose parent is missing (or points outside the result set) are kept as
|
|
46
|
+
roots, so nothing is silently dropped.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { DataSource } from '@object-ui/types';
|
|
3
|
+
export interface ObjectTreeProps {
|
|
4
|
+
schema: any;
|
|
5
|
+
dataSource?: DataSource;
|
|
6
|
+
className?: string;
|
|
7
|
+
onRowClick?: (record: any) => void;
|
|
8
|
+
/** Inline data (passed by ListView/ObjectView for non-grid views). */
|
|
9
|
+
data?: any[];
|
|
10
|
+
loading?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare const ObjectTree: React.FC<ObjectTreeProps>;
|
|
13
|
+
export default ObjectTree;
|
|
14
|
+
//# sourceMappingURL=ObjectTree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ObjectTree.d.ts","sourceRoot":"","sources":["../src/ObjectTree.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;GAWG;AAEH,OAAO,KAAuC,MAAM,OAAO,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAY,MAAM,kBAAkB,CAAC;AAM7D,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,GAAG,CAAC;IACZ,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACnC,sEAAsE;IACtE,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AA8JD,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CA8PhD,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EAAE,UAAU,EAAE,CAAC;AACtB,YAAY,EAAE,eAAe,EAAE,CAAC;AAIhC,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,GAAG,CAG5C,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { useEffect as e, useMemo as t, useState as n } from "react";
|
|
2
|
+
import { ComponentRegistry as r, buildExpandFields as i, extractRecords as a } from "@object-ui/core";
|
|
3
|
+
import { useNavigationOverlay as o, useSchemaContext as s } from "@object-ui/react";
|
|
4
|
+
import { NavigationOverlay as c, cn as l } from "@object-ui/components";
|
|
5
|
+
import { ChevronDown as u, ChevronRight as d } from "lucide-react";
|
|
6
|
+
import { jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
7
|
+
//#region src/ObjectTree.tsx
|
|
8
|
+
function m(e) {
|
|
9
|
+
return e.data ? e.data : e.staticData ? {
|
|
10
|
+
provider: "value",
|
|
11
|
+
items: e.staticData
|
|
12
|
+
} : e.objectName ? {
|
|
13
|
+
provider: "object",
|
|
14
|
+
object: e.objectName
|
|
15
|
+
} : null;
|
|
16
|
+
}
|
|
17
|
+
function h(e) {
|
|
18
|
+
let t = e.tree || e.filter?.tree || {};
|
|
19
|
+
return {
|
|
20
|
+
parentField: e.parentField ?? t.parentField,
|
|
21
|
+
labelField: e.labelField ?? t.labelField ?? e.titleField ?? "name",
|
|
22
|
+
fields: Array.isArray(e.fields) ? e.fields : Array.isArray(t.fields) ? t.fields : [],
|
|
23
|
+
defaultExpandedDepth: e.defaultExpandedDepth ?? t.defaultExpandedDepth
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function g(e, t) {
|
|
27
|
+
let n = e?.fields;
|
|
28
|
+
if (!n || typeof n != "object") return;
|
|
29
|
+
let r;
|
|
30
|
+
for (let [e, i] of Object.entries(n)) {
|
|
31
|
+
if (i?.type === "tree") return e;
|
|
32
|
+
let n = i?.reference || i?.reference_to || i?.referenceTo;
|
|
33
|
+
!r && (i?.type === "lookup" || i?.type === "master_detail") && n && t && n === t && (r = e);
|
|
34
|
+
}
|
|
35
|
+
return r;
|
|
36
|
+
}
|
|
37
|
+
function _(e) {
|
|
38
|
+
let t = e?.id ?? e?._id;
|
|
39
|
+
return t == null ? void 0 : String(t);
|
|
40
|
+
}
|
|
41
|
+
function v(e, t) {
|
|
42
|
+
if (!t) return;
|
|
43
|
+
let n = e?.[t];
|
|
44
|
+
if (n != null) {
|
|
45
|
+
if (typeof n == "object") {
|
|
46
|
+
let e = n.id ?? n._id;
|
|
47
|
+
return e == null ? void 0 : String(e);
|
|
48
|
+
}
|
|
49
|
+
return String(n);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function y(e, t) {
|
|
53
|
+
let n = /* @__PURE__ */ new Map(), r = [];
|
|
54
|
+
for (let t of e) {
|
|
55
|
+
let e = _(t);
|
|
56
|
+
e != null && (n.set(e, {
|
|
57
|
+
id: e,
|
|
58
|
+
record: t,
|
|
59
|
+
depth: 0,
|
|
60
|
+
children: []
|
|
61
|
+
}), r.push(e));
|
|
62
|
+
}
|
|
63
|
+
let i = [];
|
|
64
|
+
for (let e of r) {
|
|
65
|
+
let r = n.get(e), a = v(r.record, t), o = a == null ? void 0 : n.get(a);
|
|
66
|
+
o && o !== r ? o.children.push(r) : i.push(r);
|
|
67
|
+
}
|
|
68
|
+
let a = (e, t) => {
|
|
69
|
+
for (let n of e) n.depth = t, a(n.children, t + 1);
|
|
70
|
+
};
|
|
71
|
+
return a(i, 0), i;
|
|
72
|
+
}
|
|
73
|
+
function b(e, t) {
|
|
74
|
+
let n = [], r = (e) => {
|
|
75
|
+
for (let i of e) n.push(i), i.children.length > 0 && t.has(i.id) && r(i.children);
|
|
76
|
+
};
|
|
77
|
+
return r(e), n;
|
|
78
|
+
}
|
|
79
|
+
function x(e, t) {
|
|
80
|
+
let n = /* @__PURE__ */ new Set(), r = (e) => {
|
|
81
|
+
for (let i of e) i.children.length !== 0 && (t == null || i.depth < t) && (n.add(i.id), r(i.children));
|
|
82
|
+
};
|
|
83
|
+
return r(e), n;
|
|
84
|
+
}
|
|
85
|
+
function S(e) {
|
|
86
|
+
return e == null ? "" : String(typeof e == "object" ? e.name ?? e.label ?? e.id ?? e._id ?? "" : e);
|
|
87
|
+
}
|
|
88
|
+
var C = ({ schema: r, dataSource: s, className: _, onRowClick: v, ...C }) => {
|
|
89
|
+
let [w, T] = n([]), [E, D] = n(!0), [O, k] = n(null), [A, j] = n(null), M = t(() => m(r), [r]), N = Array.isArray(C.data) || Array.isArray(r.data) || M?.provider === "value";
|
|
90
|
+
e(() => {
|
|
91
|
+
let e = !1;
|
|
92
|
+
return N || (async () => {
|
|
93
|
+
try {
|
|
94
|
+
if (!s || typeof s.getObjectSchema != "function") return;
|
|
95
|
+
let t = M?.provider === "object" ? M.object : r.objectName;
|
|
96
|
+
if (!t) return;
|
|
97
|
+
let n = await s.getObjectSchema(t);
|
|
98
|
+
e || j(n);
|
|
99
|
+
} catch (e) {
|
|
100
|
+
console.error("[ObjectTree] Failed to fetch object schema:", e);
|
|
101
|
+
}
|
|
102
|
+
})(), () => {
|
|
103
|
+
e = !0;
|
|
104
|
+
};
|
|
105
|
+
}, [
|
|
106
|
+
r.objectName,
|
|
107
|
+
s,
|
|
108
|
+
M,
|
|
109
|
+
N
|
|
110
|
+
]), e(() => {
|
|
111
|
+
let e = !1;
|
|
112
|
+
return (async () => {
|
|
113
|
+
try {
|
|
114
|
+
if (D(!0), k(null), M?.provider === "object" && s && typeof s.find == "function") {
|
|
115
|
+
let t = i(A?.fields), n = await s.find(M.object, {
|
|
116
|
+
$filter: r.filter,
|
|
117
|
+
...t.length > 0 ? { $expand: t } : {}
|
|
118
|
+
});
|
|
119
|
+
e || (T(a(n)), D(!1));
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
let t = C.data ?? r.data;
|
|
123
|
+
if (Array.isArray(t)) {
|
|
124
|
+
e || (T(t), D(!1));
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (M?.provider === "value") {
|
|
128
|
+
e || (T(M.items ?? []), D(!1));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
e || (T([]), D(!1));
|
|
132
|
+
} catch (t) {
|
|
133
|
+
e || (k(t), D(!1));
|
|
134
|
+
}
|
|
135
|
+
})(), () => {
|
|
136
|
+
e = !0;
|
|
137
|
+
};
|
|
138
|
+
}, [
|
|
139
|
+
M,
|
|
140
|
+
s,
|
|
141
|
+
r.filter,
|
|
142
|
+
A,
|
|
143
|
+
C.data
|
|
144
|
+
]);
|
|
145
|
+
let P = t(() => h(r), [r]), F = t(() => P.parentField ?? g(A, r.objectName), [
|
|
146
|
+
P.parentField,
|
|
147
|
+
A,
|
|
148
|
+
r.objectName
|
|
149
|
+
]), I = t(() => y(w, F), [w, F]), [L, R] = n(/* @__PURE__ */ new Set());
|
|
150
|
+
e(() => {
|
|
151
|
+
R(x(I, P.defaultExpandedDepth));
|
|
152
|
+
}, [I, P.defaultExpandedDepth]);
|
|
153
|
+
let z = (e) => R((t) => {
|
|
154
|
+
let n = new Set(t);
|
|
155
|
+
return n.has(e) ? n.delete(e) : n.add(e), n;
|
|
156
|
+
}), B = t(() => b(I, L), [I, L]), V = (e) => A?.fields?.[e]?.label || e.replace(/_/g, " ").replace(/\b\w/g, (e) => e.toUpperCase()), H = o({
|
|
157
|
+
navigation: r.navigation,
|
|
158
|
+
objectName: r.objectName,
|
|
159
|
+
onRowClick: v
|
|
160
|
+
});
|
|
161
|
+
return O ? /* @__PURE__ */ f("div", {
|
|
162
|
+
className: l("flex items-center justify-center h-40 text-destructive", _),
|
|
163
|
+
children: /* @__PURE__ */ p("p", { children: ["Failed to load tree: ", O.message] })
|
|
164
|
+
}) : E ? /* @__PURE__ */ f("div", {
|
|
165
|
+
className: l("flex items-center justify-center h-40 text-muted-foreground", _),
|
|
166
|
+
children: /* @__PURE__ */ f("p", { children: "Loading…" })
|
|
167
|
+
}) : w.length === 0 ? /* @__PURE__ */ f("div", {
|
|
168
|
+
className: l("flex items-center justify-center h-40 text-muted-foreground", _),
|
|
169
|
+
children: /* @__PURE__ */ f("p", { children: "No records" })
|
|
170
|
+
}) : /* @__PURE__ */ p("div", {
|
|
171
|
+
className: l("w-full overflow-auto", _),
|
|
172
|
+
"data-testid": "object-tree",
|
|
173
|
+
children: [/* @__PURE__ */ p("table", {
|
|
174
|
+
className: "w-full border-collapse text-sm",
|
|
175
|
+
children: [/* @__PURE__ */ f("thead", { children: /* @__PURE__ */ p("tr", {
|
|
176
|
+
className: "border-b text-left text-muted-foreground",
|
|
177
|
+
children: [/* @__PURE__ */ f("th", {
|
|
178
|
+
className: "px-3 py-2 font-medium",
|
|
179
|
+
children: V(P.labelField)
|
|
180
|
+
}), P.fields.filter((e) => e !== P.labelField).map((e) => /* @__PURE__ */ f("th", {
|
|
181
|
+
className: "px-3 py-2 font-medium",
|
|
182
|
+
children: V(e)
|
|
183
|
+
}, e))]
|
|
184
|
+
}) }), /* @__PURE__ */ f("tbody", { children: B.map((e) => {
|
|
185
|
+
let t = e.children.length > 0, n = L.has(e.id);
|
|
186
|
+
return /* @__PURE__ */ p("tr", {
|
|
187
|
+
className: "border-b hover:bg-accent/50 cursor-pointer",
|
|
188
|
+
"data-testid": "object-tree-row",
|
|
189
|
+
"data-depth": e.depth,
|
|
190
|
+
onClick: (t) => H.handleClick(e.record, t),
|
|
191
|
+
children: [/* @__PURE__ */ f("td", {
|
|
192
|
+
className: "px-3 py-2",
|
|
193
|
+
children: /* @__PURE__ */ p("div", {
|
|
194
|
+
className: "flex items-center gap-1",
|
|
195
|
+
style: { paddingLeft: `${e.depth * 20}px` },
|
|
196
|
+
children: [t ? /* @__PURE__ */ f("button", {
|
|
197
|
+
type: "button",
|
|
198
|
+
"aria-label": n ? "Collapse" : "Expand",
|
|
199
|
+
className: "flex h-5 w-5 items-center justify-center rounded-sm text-muted-foreground hover:bg-muted",
|
|
200
|
+
onClick: (t) => {
|
|
201
|
+
t.stopPropagation(), z(e.id);
|
|
202
|
+
},
|
|
203
|
+
children: f(n ? u : d, { className: "h-4 w-4" })
|
|
204
|
+
}) : /* @__PURE__ */ f("span", { className: "inline-block h-5 w-5" }), /* @__PURE__ */ f("span", {
|
|
205
|
+
className: "truncate",
|
|
206
|
+
children: S(e.record[P.labelField]) || "—"
|
|
207
|
+
})]
|
|
208
|
+
})
|
|
209
|
+
}), P.fields.filter((e) => e !== P.labelField).map((t) => /* @__PURE__ */ f("td", {
|
|
210
|
+
className: "px-3 py-2 text-muted-foreground",
|
|
211
|
+
children: S(e.record[t])
|
|
212
|
+
}, t))]
|
|
213
|
+
}, e.id);
|
|
214
|
+
}) })]
|
|
215
|
+
}), H.isOverlay && /* @__PURE__ */ f(c, {
|
|
216
|
+
...H,
|
|
217
|
+
title: "Record Details",
|
|
218
|
+
children: (e) => /* @__PURE__ */ f("div", {
|
|
219
|
+
className: "space-y-3",
|
|
220
|
+
children: Object.entries(e).map(([e, t]) => /* @__PURE__ */ p("div", {
|
|
221
|
+
className: "flex flex-col",
|
|
222
|
+
children: [/* @__PURE__ */ f("span", {
|
|
223
|
+
className: "text-xs font-medium text-muted-foreground uppercase tracking-wide",
|
|
224
|
+
children: e.replace(/_/g, " ")
|
|
225
|
+
}), /* @__PURE__ */ f("span", {
|
|
226
|
+
className: "text-sm",
|
|
227
|
+
children: S(t) || "—"
|
|
228
|
+
})]
|
|
229
|
+
}, e))
|
|
230
|
+
})
|
|
231
|
+
})]
|
|
232
|
+
});
|
|
233
|
+
}, w = ({ schema: e, ...t }) => {
|
|
234
|
+
let { dataSource: n } = s() || {};
|
|
235
|
+
return /* @__PURE__ */ f(C, {
|
|
236
|
+
schema: e,
|
|
237
|
+
dataSource: n,
|
|
238
|
+
...t
|
|
239
|
+
});
|
|
240
|
+
}, T = [{
|
|
241
|
+
name: "objectName",
|
|
242
|
+
type: "string",
|
|
243
|
+
label: "Object Name",
|
|
244
|
+
required: !0
|
|
245
|
+
}, {
|
|
246
|
+
name: "tree",
|
|
247
|
+
type: "object",
|
|
248
|
+
label: "Tree Config",
|
|
249
|
+
description: "parentField, labelField, fields, defaultExpandedDepth"
|
|
250
|
+
}];
|
|
251
|
+
r.register("object-tree", w, {
|
|
252
|
+
namespace: "plugin-tree",
|
|
253
|
+
label: "Object Tree",
|
|
254
|
+
category: "view",
|
|
255
|
+
inputs: T
|
|
256
|
+
}), r.register("tree", w, {
|
|
257
|
+
namespace: "view",
|
|
258
|
+
label: "Tree View",
|
|
259
|
+
category: "view",
|
|
260
|
+
inputs: T
|
|
261
|
+
});
|
|
262
|
+
//#endregion
|
|
263
|
+
export { C as ObjectTree, w as ObjectTreeRenderer };
|
|
@@ -0,0 +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("lucide-react"),require("react/jsx-runtime")):typeof define==`function`&&define.amd?define([`exports`,`react`,`@object-ui/core`,`@object-ui/react`,`@object-ui/components`,`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.LucideReact,e.react_jsx_runtime))})(this,function(e,t,n,r,i,a,o){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var s=Object.create,c=Object.defineProperty,l=Object.getOwnPropertyDescriptor,u=Object.getOwnPropertyNames,d=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty,p=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=u(t),a=0,o=i.length,s;a<o;a++)s=i[a],!f.call(e,s)&&s!==n&&c(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=l(t,s))||r.enumerable});return e};t=((e,t,n)=>(n=e==null?{}:s(d(e)),p(t||!e||!e.__esModule?c(n,`default`,{value:e,enumerable:!0}):n,e)))(t,1);function m(e){return e.data?e.data:e.staticData?{provider:`value`,items:e.staticData}:e.objectName?{provider:`object`,object:e.objectName}:null}function h(e){let t=e.tree||e.filter?.tree||{};return{parentField:e.parentField??t.parentField,labelField:e.labelField??t.labelField??e.titleField??`name`,fields:Array.isArray(e.fields)?e.fields:Array.isArray(t.fields)?t.fields:[],defaultExpandedDepth:e.defaultExpandedDepth??t.defaultExpandedDepth}}function g(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 _(e){let t=e?.id??e?._id;return t==null?void 0:String(t)}function v(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 y(e,t){let n=new Map,r=[];for(let t of e){let e=_(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=v(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 b(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 x(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 S(e){return e==null?``:String(typeof e==`object`?e.name??e.label??e.id??e._id??``:e)}var C=({schema:e,dataSource:s,className:c,onRowClick:l,...u})=>{let[d,f]=(0,t.useState)([]),[p,_]=(0,t.useState)(!0),[v,C]=(0,t.useState)(null),[w,T]=(0,t.useState)(null),E=(0,t.useMemo)(()=>m(e),[e]),D=Array.isArray(u.data)||Array.isArray(e.data)||E?.provider===`value`;(0,t.useEffect)(()=>{let t=!1;return D||(async()=>{try{if(!s||typeof s.getObjectSchema!=`function`)return;let n=E?.provider===`object`?E.object:e.objectName;if(!n)return;let r=await s.getObjectSchema(n);t||T(r)}catch(e){console.error(`[ObjectTree] Failed to fetch object schema:`,e)}})(),()=>{t=!0}},[e.objectName,s,E,D]),(0,t.useEffect)(()=>{let t=!1;return(async()=>{try{if(_(!0),C(null),E?.provider===`object`&&s&&typeof s.find==`function`){let r=(0,n.buildExpandFields)(w?.fields),i=await s.find(E.object,{$filter:e.filter,...r.length>0?{$expand:r}:{}});t||(f((0,n.extractRecords)(i)),_(!1));return}let r=u.data??e.data;if(Array.isArray(r)){t||(f(r),_(!1));return}if(E?.provider===`value`){t||(f(E.items??[]),_(!1));return}t||(f([]),_(!1))}catch(e){t||(C(e),_(!1))}})(),()=>{t=!0}},[E,s,e.filter,w,u.data]);let O=(0,t.useMemo)(()=>h(e),[e]),k=(0,t.useMemo)(()=>O.parentField??g(w,e.objectName),[O.parentField,w,e.objectName]),A=(0,t.useMemo)(()=>y(d,k),[d,k]),[j,M]=(0,t.useState)(new Set);(0,t.useEffect)(()=>{M(x(A,O.defaultExpandedDepth))},[A,O.defaultExpandedDepth]);let N=e=>M(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n}),P=(0,t.useMemo)(()=>b(A,j),[A,j]),F=e=>w?.fields?.[e]?.label||e.replace(/_/g,` `).replace(/\b\w/g,e=>e.toUpperCase()),I=(0,r.useNavigationOverlay)({navigation:e.navigation,objectName:e.objectName,onRowClick:l});return v?(0,o.jsx)(`div`,{className:(0,i.cn)(`flex items-center justify-center h-40 text-destructive`,c),children:(0,o.jsxs)(`p`,{children:[`Failed to load tree: `,v.message]})}):p?(0,o.jsx)(`div`,{className:(0,i.cn)(`flex items-center justify-center h-40 text-muted-foreground`,c),children:(0,o.jsx)(`p`,{children:`Loading…`})}):d.length===0?(0,o.jsx)(`div`,{className:(0,i.cn)(`flex items-center justify-center h-40 text-muted-foreground`,c),children:(0,o.jsx)(`p`,{children:`No records`})}):(0,o.jsxs)(`div`,{className:(0,i.cn)(`w-full overflow-auto`,c),"data-testid":`object-tree`,children:[(0,o.jsxs)(`table`,{className:`w-full border-collapse text-sm`,children:[(0,o.jsx)(`thead`,{children:(0,o.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,o.jsx)(`th`,{className:`px-3 py-2 font-medium`,children:F(O.labelField)}),O.fields.filter(e=>e!==O.labelField).map(e=>(0,o.jsx)(`th`,{className:`px-3 py-2 font-medium`,children:F(e)},e))]})}),(0,o.jsx)(`tbody`,{children:P.map(e=>{let t=e.children.length>0,n=j.has(e.id);return(0,o.jsxs)(`tr`,{className:`border-b hover:bg-accent/50 cursor-pointer`,"data-testid":`object-tree-row`,"data-depth":e.depth,onClick:t=>I.handleClick(e.record,t),children:[(0,o.jsx)(`td`,{className:`px-3 py-2`,children:(0,o.jsxs)(`div`,{className:`flex items-center gap-1`,style:{paddingLeft:`${e.depth*20}px`},children:[t?(0,o.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(),N(e.id)},children:n?(0,o.jsx)(a.ChevronDown,{className:`h-4 w-4`}):(0,o.jsx)(a.ChevronRight,{className:`h-4 w-4`})}):(0,o.jsx)(`span`,{className:`inline-block h-5 w-5`}),(0,o.jsx)(`span`,{className:`truncate`,children:S(e.record[O.labelField])||`—`})]})}),O.fields.filter(e=>e!==O.labelField).map(t=>(0,o.jsx)(`td`,{className:`px-3 py-2 text-muted-foreground`,children:S(e.record[t])},t))]},e.id)})})]}),I.isOverlay&&(0,o.jsx)(i.NavigationOverlay,{...I,title:`Record Details`,children:e=>(0,o.jsx)(`div`,{className:`space-y-3`,children:Object.entries(e).map(([e,t])=>(0,o.jsxs)(`div`,{className:`flex flex-col`,children:[(0,o.jsx)(`span`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wide`,children:e.replace(/_/g,` `)}),(0,o.jsx)(`span`,{className:`text-sm`,children:S(t)||`—`})]},e))})})]})},w=({schema:e,...t})=>{let{dataSource:n}=(0,r.useSchemaContext)()||{};return(0,o.jsx)(C,{schema:e,dataSource:n,...t})},T=[{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`,w,{namespace:`plugin-tree`,label:`Object Tree`,category:`view`,inputs:T}),n.ComponentRegistry.register(`tree`,w,{namespace:`view`,label:`Tree View`,category:`view`,inputs:T}),e.ObjectTree=C,e.ObjectTreeRenderer=w});
|
package/package.json
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@object-ui/plugin-tree",
|
|
3
|
+
"version": "7.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"description": "Tree / tree-grid visualization plugin for Object UI",
|
|
7
|
+
"homepage": "https://www.objectui.org/docs/plugins/plugin-tree",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/objectstack-ai/objectui.git",
|
|
11
|
+
"directory": "packages/plugin-tree"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/objectstack-ai/objectui/issues"
|
|
15
|
+
},
|
|
16
|
+
"main": "dist/index.umd.cjs",
|
|
17
|
+
"module": "dist/index.js",
|
|
18
|
+
"types": "dist/index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"import": "./dist/index.js",
|
|
23
|
+
"require": "./dist/index.umd.cjs"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@objectstack/spec": "^10.0.0",
|
|
28
|
+
"lucide-react": "^1.21.0",
|
|
29
|
+
"@object-ui/components": "7.0.0",
|
|
30
|
+
"@object-ui/core": "7.0.0",
|
|
31
|
+
"@object-ui/react": "7.0.0",
|
|
32
|
+
"@object-ui/types": "7.0.0"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
36
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/react": "19.2.17",
|
|
40
|
+
"@types/react-dom": "19.2.3",
|
|
41
|
+
"@vitejs/plugin-react": "^6.0.2",
|
|
42
|
+
"typescript": "^6.0.3",
|
|
43
|
+
"vite": "^8.0.16",
|
|
44
|
+
"vite-plugin-dts": "^5.0.2"
|
|
45
|
+
},
|
|
46
|
+
"keywords": [
|
|
47
|
+
"objectui",
|
|
48
|
+
"sdui",
|
|
49
|
+
"schema-driven-ui",
|
|
50
|
+
"react",
|
|
51
|
+
"tailwind",
|
|
52
|
+
"shadcn",
|
|
53
|
+
"objectstack",
|
|
54
|
+
"plugin",
|
|
55
|
+
"tree",
|
|
56
|
+
"tree-grid",
|
|
57
|
+
"hierarchy"
|
|
58
|
+
],
|
|
59
|
+
"author": "ObjectStack Team <team@objectstack.ai>",
|
|
60
|
+
"publishConfig": {
|
|
61
|
+
"access": "public"
|
|
62
|
+
},
|
|
63
|
+
"files": [
|
|
64
|
+
"dist",
|
|
65
|
+
"README.md",
|
|
66
|
+
"CHANGELOG.md",
|
|
67
|
+
"LICENSE"
|
|
68
|
+
],
|
|
69
|
+
"scripts": {
|
|
70
|
+
"build": "vite build",
|
|
71
|
+
"test": "vitest run",
|
|
72
|
+
"test:watch": "vitest",
|
|
73
|
+
"type-check": "tsc --noEmit",
|
|
74
|
+
"lint": "eslint ."
|
|
75
|
+
}
|
|
76
|
+
}
|