@object-ui/plugin-view 2.0.0 → 3.0.1
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/.turbo/turbo-build.log +5 -182
- package/CHANGELOG.md +34 -0
- package/dist/index.js +1 -1
- package/dist/index.umd.cjs +1 -1
- package/package.json +8 -8
- package/src/ObjectView.tsx +2 -2
- package/src/__tests__/toolbar-consistency.test.tsx +755 -0
- package/vite.config.ts +1 -0
- package/dist/plugin-view/src/__tests__/FilterUI.test.d.ts +0 -8
- package/dist/plugin-view/src/__tests__/ObjectView.test.d.ts +0 -8
- package/dist/plugin-view/src/__tests__/SortUI.test.d.ts +0 -8
- package/dist/plugin-view/src/__tests__/registration.test.d.ts +0 -8
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @object-ui/plugin-view@
|
|
2
|
+
> @object-ui/plugin-view@3.0.1 build /home/runner/work/objectui/objectui/packages/plugin-view
|
|
3
3
|
> vite build
|
|
4
4
|
|
|
5
5
|
[36mvite v7.3.1 [32mbuilding client environment for production...[36m[39m
|
|
@@ -8,186 +8,9 @@ transforming...
|
|
|
8
8
|
rendering chunks...
|
|
9
9
|
[32m
|
|
10
10
|
[36m[vite:dts][32m Start generate declaration files...[39m
|
|
11
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m183[0m:[93m42[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
12
|
-
|
|
13
|
-
[7m183[0m expect(screen.getByText('Status')).toBeInTheDocument();
|
|
14
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
15
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m184[0m:[93m40[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
16
|
-
|
|
17
|
-
[7m184[0m expect(screen.getByText('Name')).toBeInTheDocument();
|
|
18
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
19
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m187[0m:[93m51[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement | null>'.
|
|
20
|
-
|
|
21
|
-
[7m187[0m expect(screen.queryByTestId('popover')).not.toBeInTheDocument();
|
|
22
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
23
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m188[0m:[93m50[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement | null>'.
|
|
24
|
-
|
|
25
|
-
[7m188[0m expect(screen.queryByTestId('drawer')).not.toBeInTheDocument();
|
|
26
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
27
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m194[0m:[93m42[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
28
|
-
|
|
29
|
-
[7m194[0m expect(screen.getByText('Status')).toBeInTheDocument();
|
|
30
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
31
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m195[0m:[93m40[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
32
|
-
|
|
33
|
-
[7m195[0m expect(screen.getByText('Name')).toBeInTheDocument();
|
|
34
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
35
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m206[0m:[93m42[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
36
|
-
|
|
37
|
-
[7m206[0m expect(screen.getByText('Status')).toBeInTheDocument();
|
|
38
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
39
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m207[0m:[93m40[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
40
|
-
|
|
41
|
-
[7m207[0m expect(screen.getByText('Name')).toBeInTheDocument();
|
|
42
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
43
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m219[0m:[93m41[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
44
|
-
|
|
45
|
-
[7m219[0m expect(screen.getByText('email')).toBeInTheDocument();
|
|
46
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
47
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m225[0m:[93m42[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
48
|
-
|
|
49
|
-
[7m225[0m expect(screen.getByText('Active')).toBeInTheDocument();
|
|
50
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
51
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m226[0m:[93m44[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
52
|
-
|
|
53
|
-
[7m226[0m expect(screen.getByText('Inactive')).toBeInTheDocument();
|
|
54
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
55
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m239[0m:[93m21[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
56
|
-
|
|
57
|
-
[7m239[0m expect(input).toBeInTheDocument();
|
|
58
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
59
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m320[0m:[93m26[0m - [91merror[0m[90m TS2339: [0mProperty 'toHaveAttribute' does not exist on type 'Assertion<HTMLElement>'.
|
|
60
|
-
|
|
61
|
-
[7m320[0m expect(selectRoot).toHaveAttribute('data-value', 'inactive');
|
|
62
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~[0m
|
|
63
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m331[0m:[93m45[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
64
|
-
|
|
65
|
-
[7m331[0m expect(screen.getByTestId('popover')).toBeInTheDocument();
|
|
66
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
67
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m332[0m:[93m43[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
68
|
-
|
|
69
|
-
[7m332[0m expect(screen.getByText('Filters')).toBeInTheDocument();
|
|
70
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
71
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m339[0m:[93m30[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
72
|
-
|
|
73
|
-
[7m339[0m expect(popoverContent).toBeInTheDocument();
|
|
74
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
75
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m342[0m:[93m42[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
76
|
-
|
|
77
|
-
[7m342[0m expect(screen.getByText('Status')).toBeInTheDocument();
|
|
78
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
79
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m343[0m:[93m40[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
80
|
-
|
|
81
|
-
[7m343[0m expect(screen.getByText('Name')).toBeInTheDocument();
|
|
82
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
83
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m357[0m:[93m37[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
84
|
-
|
|
85
|
-
[7m357[0m expect(screen.getByText('1')).toBeInTheDocument();
|
|
86
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
87
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m369[0m:[93m48[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement | null>'.
|
|
88
|
-
|
|
89
|
-
[7m369[0m expect(screen.queryByText('Status')).not.toBeInTheDocument();
|
|
90
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
91
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m370[0m:[93m46[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement | null>'.
|
|
92
|
-
|
|
93
|
-
[7m370[0m expect(screen.queryByText('Name')).not.toBeInTheDocument();
|
|
94
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
95
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m376[0m:[93m42[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
96
|
-
|
|
97
|
-
[7m376[0m expect(screen.getByText('Status')).toBeInTheDocument();
|
|
98
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
99
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m377[0m:[93m40[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
100
|
-
|
|
101
|
-
[7m377[0m expect(screen.getByText('Name')).toBeInTheDocument();
|
|
102
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
103
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m383[0m:[93m42[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
104
|
-
|
|
105
|
-
[7m383[0m expect(screen.getByText('Status')).toBeInTheDocument();
|
|
106
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
107
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m402[0m:[93m43[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement | null>'.
|
|
108
|
-
|
|
109
|
-
[7m402[0m expect(screen.queryByText('1')).not.toBeInTheDocument();
|
|
110
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
111
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m415[0m:[93m43[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement | null>'.
|
|
112
|
-
|
|
113
|
-
[7m415[0m expect(screen.queryByText('1')).not.toBeInTheDocument();
|
|
114
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
115
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m428[0m:[93m43[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement | null>'.
|
|
116
|
-
|
|
117
|
-
[7m428[0m expect(screen.queryByText('1')).not.toBeInTheDocument();
|
|
118
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
119
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m441[0m:[93m43[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement | null>'.
|
|
120
|
-
|
|
121
|
-
[7m441[0m expect(screen.queryByText('1')).not.toBeInTheDocument();
|
|
122
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
123
|
-
[96msrc/__tests__/FilterUI.test.tsx[0m:[93m454[0m:[93m37[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
124
|
-
|
|
125
|
-
[7m454[0m expect(screen.getByText('2')).toBeInTheDocument();
|
|
126
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
127
|
-
[96msrc/__tests__/SortUI.test.tsx[0m:[93m98[0m:[93m40[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
128
|
-
|
|
129
|
-
[7m98[0m expect(screen.getByText('Name')).toBeInTheDocument();
|
|
130
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
131
|
-
[96msrc/__tests__/SortUI.test.tsx[0m:[93m99[0m:[93m40[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
132
|
-
|
|
133
|
-
[7m99[0m expect(screen.getByText('Date')).toBeInTheDocument();
|
|
134
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
135
|
-
[96msrc/__tests__/SortUI.test.tsx[0m:[93m108[0m:[93m21[0m - [91merror[0m[90m TS2339: [0mProperty 'toHaveAttribute' does not exist on type 'Assertion<HTMLElement>'.
|
|
136
|
-
|
|
137
|
-
[7m108[0m expect(btn).toHaveAttribute('data-variant', 'outline');
|
|
138
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~[0m
|
|
139
|
-
[96msrc/__tests__/SortUI.test.tsx[0m:[93m123[0m:[93m23[0m - [91merror[0m[90m TS2339: [0mProperty 'toHaveAttribute' does not exist on type 'Assertion<HTMLButtonElement>'.
|
|
140
|
-
|
|
141
|
-
[7m123[0m expect(nameBtn).toHaveAttribute('data-variant', 'secondary');
|
|
142
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~[0m
|
|
143
|
-
[96msrc/__tests__/SortUI.test.tsx[0m:[93m126[0m:[93m23[0m - [91merror[0m[90m TS2339: [0mProperty 'toHaveAttribute' does not exist on type 'Assertion<HTMLButtonElement>'.
|
|
144
|
-
|
|
145
|
-
[7m126[0m expect(dateBtn).toHaveAttribute('data-variant', 'outline');
|
|
146
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~[0m
|
|
147
|
-
[96msrc/__tests__/SortUI.test.tsx[0m:[93m157[0m:[93m40[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
148
|
-
|
|
149
|
-
[7m157[0m expect(screen.getByText('Name')).toBeInTheDocument();
|
|
150
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
151
|
-
[96msrc/__tests__/SortUI.test.tsx[0m:[93m158[0m:[93m40[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
152
|
-
|
|
153
|
-
[7m158[0m expect(screen.getByText('Date')).toBeInTheDocument();
|
|
154
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
155
|
-
[96msrc/__tests__/SortUI.test.tsx[0m:[93m164[0m:[93m45[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
156
|
-
|
|
157
|
-
[7m164[0m expect(screen.getByText('Ascending')).toBeInTheDocument();
|
|
158
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
159
|
-
[96msrc/__tests__/SortUI.test.tsx[0m:[93m165[0m:[93m46[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
160
|
-
|
|
161
|
-
[7m165[0m expect(screen.getByText('Descending')).toBeInTheDocument();
|
|
162
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
163
|
-
[96msrc/__tests__/SortUI.test.tsx[0m:[93m188[0m:[93m50[0m - [91merror[0m[90m TS2339: [0mProperty 'toBeInTheDocument' does not exist on type 'Assertion<HTMLElement>'.
|
|
164
|
-
|
|
165
|
-
[7m188[0m expect(screen.getByTestId('sort-builder')).toBeInTheDocument();
|
|
166
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~~~[0m
|
|
167
|
-
[96msrc/__tests__/SortUI.test.tsx[0m:[93m243[0m:[93m23[0m - [91merror[0m[90m TS2339: [0mProperty 'toHaveAttribute' does not exist on type 'Assertion<HTMLButtonElement>'.
|
|
168
|
-
|
|
169
|
-
[7m243[0m expect(dateBtn).toHaveAttribute('data-variant', 'secondary');
|
|
170
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~[0m
|
|
171
|
-
[96msrc/__tests__/SortUI.test.tsx[0m:[93m260[0m:[93m21[0m - [91merror[0m[90m TS2339: [0mProperty 'toHaveAttribute' does not exist on type 'Assertion<HTMLElement>'.
|
|
172
|
-
|
|
173
|
-
[7m260[0m expect(btn).toHaveAttribute('data-variant', 'outline');
|
|
174
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~[0m
|
|
175
|
-
[96msrc/__tests__/SortUI.test.tsx[0m:[93m341[0m:[93m23[0m - [91merror[0m[90m TS2339: [0mProperty 'toHaveAttribute' does not exist on type 'Assertion<HTMLButtonElement>'.
|
|
176
|
-
|
|
177
|
-
[7m341[0m expect(nameBtn).toHaveAttribute('data-variant', 'secondary');
|
|
178
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~[0m
|
|
179
|
-
[96msrc/__tests__/SortUI.test.tsx[0m:[93m342[0m:[93m23[0m - [91merror[0m[90m TS2339: [0mProperty 'toHaveAttribute' does not exist on type 'Assertion<HTMLButtonElement>'.
|
|
180
|
-
|
|
181
|
-
[7m342[0m expect(dateBtn).toHaveAttribute('data-variant', 'secondary');
|
|
182
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~[0m
|
|
183
|
-
[96msrc/__tests__/SortUI.test.tsx[0m:[93m376[0m:[93m21[0m - [91merror[0m[90m TS2339: [0mProperty 'toHaveAttribute' does not exist on type 'Assertion<HTMLElement>'.
|
|
184
|
-
|
|
185
|
-
[7m376[0m expect(btn).toHaveAttribute('data-variant', 'outline');
|
|
186
|
-
[7m [0m [91m ~~~~~~~~~~~~~~~[0m
|
|
187
|
-
|
|
188
11
|
computing gzip size...
|
|
189
|
-
[2mdist/[22m[36mindex.js [39m[1m[2m47.74 kB[22m[1m[22m[2m │ gzip: 12.
|
|
190
|
-
[32m[36m[vite:dts][32m Declaration files built in
|
|
12
|
+
[2mdist/[22m[36mindex.js [39m[1m[2m47.74 kB[22m[1m[22m[2m │ gzip: 12.27 kB[22m
|
|
13
|
+
[32m[36m[vite:dts][32m Declaration files built in 4243ms.
|
|
191
14
|
[39m
|
|
192
15
|
[33mNo name was provided for external module "@object-ui/core" in "output.globals" – guessing "core".[39m
|
|
193
16
|
[33mNo name was provided for external module "@object-ui/plugin-grid" in "output.globals" – guessing "pluginGrid".[39m
|
|
@@ -195,5 +18,5 @@ computing gzip size...
|
|
|
195
18
|
[33mNo name was provided for external module "@object-ui/components" in "output.globals" – guessing "components".[39m
|
|
196
19
|
[33mNo name was provided for external module "lucide-react" in "output.globals" – guessing "lucideReact".[39m
|
|
197
20
|
[33mNo name was provided for external module "@object-ui/react" in "output.globals" – guessing "react".[39m
|
|
198
|
-
[2mdist/[22m[36mindex.umd.cjs [39m[1m[2m33.
|
|
199
|
-
[32m✓ built in
|
|
21
|
+
[2mdist/[22m[36mindex.umd.cjs [39m[1m[2m33.55 kB[22m[1m[22m[2m │ gzip: 10.79 kB[22m
|
|
22
|
+
[32m✓ built in 4.70s[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# @object-ui/plugin-view
|
|
2
2
|
|
|
3
|
+
## 3.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [adf2cc0]
|
|
8
|
+
- @object-ui/react@3.0.1
|
|
9
|
+
- @object-ui/components@3.0.1
|
|
10
|
+
- @object-ui/plugin-form@3.0.1
|
|
11
|
+
- @object-ui/plugin-grid@3.0.1
|
|
12
|
+
- @object-ui/types@3.0.1
|
|
13
|
+
- @object-ui/core@3.0.1
|
|
14
|
+
|
|
15
|
+
## 3.0.0
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- 87979c3: Upgrade to @objectstack v3.0.0 and console bundle optimization
|
|
20
|
+
- Upgraded all @objectstack/\* packages from ^2.0.7 to ^3.0.0
|
|
21
|
+
- Breaking change migrations: Hub → Cloud namespace, definePlugin removed, PaginatedResult.value → .records, PaginatedResult.count → .total, client.meta.getObject() → client.meta.getItem()
|
|
22
|
+
- Console bundle optimization: split monolithic 3.7 MB chunk into 17 granular cacheable chunks (95% main entry reduction)
|
|
23
|
+
- Added gzip + brotli pre-compression via vite-plugin-compression2
|
|
24
|
+
- Lazy MSW loading for build:server (~150 KB gzip saved)
|
|
25
|
+
- Added bundle analysis with rollup-plugin-visualizer
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- Updated dependencies [87979c3]
|
|
30
|
+
- @object-ui/types@3.0.0
|
|
31
|
+
- @object-ui/core@3.0.0
|
|
32
|
+
- @object-ui/react@3.0.0
|
|
33
|
+
- @object-ui/components@3.0.0
|
|
34
|
+
- @object-ui/plugin-form@3.0.0
|
|
35
|
+
- @object-ui/plugin-grid@3.0.0
|
|
36
|
+
|
|
3
37
|
## 2.0.0
|
|
4
38
|
|
|
5
39
|
### Major Changes
|
package/dist/index.js
CHANGED
|
@@ -522,7 +522,7 @@ const Qt = ({
|
|
|
522
522
|
$top: 100
|
|
523
523
|
});
|
|
524
524
|
let Y = [];
|
|
525
|
-
Array.isArray(k) ? Y = k : k && typeof k == "object" && (Array.isArray(k.data) ? Y = k.data : Array.isArray(k.
|
|
525
|
+
Array.isArray(k) ? Y = k : k && typeof k == "object" && (Array.isArray(k.data) ? Y = k.data : Array.isArray(k.records) && (Y = k.records)), n && X(Y);
|
|
526
526
|
} catch (a) {
|
|
527
527
|
console.error("ObjectView data fetch error:", a);
|
|
528
528
|
} finally {
|
package/dist/index.umd.cjs
CHANGED
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
<%s {...props} />
|
|
4
4
|
React keys must be passed directly to JSX without using spread:
|
|
5
5
|
let props = %s;
|
|
6
|
-
<%s key={someKey} {...props} />`,j,_,W,_),h[_+j]=!0)}if(_=null,v!==void 0&&(c(v),_=""+v),F(p)&&(c(p.key),_=""+p.key),"key"in p){v={};for(var ae in p)ae!=="key"&&(v[ae]=p[ae])}else v=p;return _&&y(v,typeof r=="function"?r.displayName||r.name||"Unknown":r),N(r,_,v,w(),ee,te)}function s(r){S(r)?r._store&&(r._store.validated=1):typeof r=="object"&&r!==null&&r.$$typeof===de&&(r._payload.status==="fulfilled"?S(r._payload.value)&&r._payload.value._store&&(r._payload.value._store.validated=1):r._store&&(r._store.validated=1))}function S(r){return typeof r=="object"&&r!==null&&r.$$typeof===V}var m=b,V=Symbol.for("react.transitional.element"),o=Symbol.for("react.portal"),k=Symbol.for("react.fragment"),A=Symbol.for("react.strict_mode"),d=Symbol.for("react.profiler"),x=Symbol.for("react.consumer"),L=Symbol.for("react.context"),Z=Symbol.for("react.forward_ref"),ye=Symbol.for("react.suspense"),ue=Symbol.for("react.suspense_list"),M=Symbol.for("react.memo"),de=Symbol.for("react.lazy"),q=Symbol.for("react.activity"),De=Symbol.for("react.client.reference"),z=m.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,Q=Object.prototype.hasOwnProperty,G=Array.isArray,ne=console.createTask?console.createTask:function(){return null};m={react_stack_bottom_frame:function(r){return r()}};var T,R={},ie=m.react_stack_bottom_frame.bind(m,g)(),ce=ne(u(g)),h={};le.Fragment=k,le.jsx=function(r,p,v){var j=1e4>z.recentlyCreatedOwnerStacks++;return C(r,p,v,!1,j?Error("react-stack-top-frame"):ie,j?ne(u(r)):ce)},le.jsxs=function(r,p,v){var j=1e4>z.recentlyCreatedOwnerStacks++;return C(r,p,v,!0,j?Error("react-stack-top-frame"):ie,j?ne(u(r)):ce)}})()),le}var Ce;function qe(){return Ce||(Ce=1,process.env.NODE_ENV==="production"?se.exports=Be():se.exports=Ue()),se.exports}var t=qe();function Se(e){var n,c,u="";if(typeof e=="string"||typeof e=="number")u+=e;else if(typeof e=="object")if(Array.isArray(e)){var w=e.length;for(n=0;n<w;n++)e[n]&&(c=Se(e[n]))&&(u&&(u+=" "),u+=c)}else for(c in e)e[c]&&(u&&(u+=" "),u+=c);return u}function Ye(){for(var e,n,c=0,u="",w=arguments.length;c<w;c++)(e=arguments[c])&&(n=Se(e))&&(u&&(u+=" "),u+=n);return u}const Ne=e=>typeof e=="boolean"?`${e}`:e===0?"0":e,Ve=Ye,X=(e,n)=>c=>{var u;if(n?.variants==null)return Ve(e,c?.class,c?.className);const{variants:w,defaultVariants:g}=n,F=Object.keys(w).map(N=>{const C=c?.[N],s=g?.[N];if(C===null)return null;const S=Ne(C)||Ne(s);return w[N][S]}),y=c&&Object.entries(c).reduce((N,C)=>{let[s,S]=C;return S===void 0||(N[s]=S),N},{}),E=n==null||(u=n.compoundVariants)===null||u===void 0?void 0:u.reduce((N,C)=>{let{class:s,className:S,...m}=C;return Object.entries(m).every(V=>{let[o,k]=V;return Array.isArray(k)?k.includes({...g,...y}[o]):{...g,...y}[o]===k})?[...N,s,S]:N},[]);return Ve(e,F,E,c?.class,c?.className)},We={list:"List",detail:"Detail",grid:"Grid",kanban:"Kanban",calendar:"Calendar",timeline:"Timeline",map:"Map"},Ge={list:$.List,detail:$.FileText,grid:$.Grid,kanban:$.LayoutGrid,calendar:$.Calendar,timeline:$.Activity,map:$.Map},He=X("flex gap-4",{variants:{position:{top:"flex-col",bottom:"flex-col-reverse",left:"flex-row",right:"flex-row-reverse"}},defaultVariants:{position:"top"}}),Ke=X("w-full",{variants:{orientation:{horizontal:"w-full",vertical:"w-48"}},defaultVariants:{orientation:"horizontal"}}),Je=X("flex gap-2",{variants:{orientation:{horizontal:"flex-row flex-wrap",vertical:"flex-col"}},defaultVariants:{orientation:"horizontal"}}),Xe=X("",{variants:{orientation:{horizontal:"",vertical:"flex h-auto flex-col items-stretch"}},defaultVariants:{orientation:"horizontal"}});function Ze(e){return e.split("-").map(n=>n.charAt(0).toUpperCase()+n.slice(1)).join("")}const Qe={Home:"House"};function et(e){if(!e)return null;const n=Ze(e),c=Qe[n]||n;return $.icons[c]||null}function fe(e){return e.label?e.label:We[e.type]||e.type}function Fe(e){return e.icon?et(e.icon):Ge[e.type]||null}function tt(e){return e.activeView?e.activeView:e.defaultView?e.defaultView:e.views?.[0]?.type}const pe=({schema:e,className:n,onViewChange:c,...u})=>{const w=O.useMemo(()=>e.storageKey?e.storageKey:`view-switcher${e.id?`-${e.id}`:""}`,[e.id,e.storageKey]),[g,F]=O.useState(()=>tt(e));O.useEffect(()=>{if(e.activeView){F(e.activeView);return}if(e.persistPreference)try{const d=localStorage.getItem(w);if(d){const x=e.views.find(L=>L.type===d)?.type;x&&F(x)}}catch{}},[e.activeView,e.persistPreference,e.views,w]),O.useEffect(()=>{if(!(!e.persistPreference||!g||e.activeView))try{localStorage.setItem(w,g)}catch{}},[g,e.activeView,e.persistPreference,w]);const y=O.useCallback(d=>{c?.(d),e.onViewChange&&typeof window<"u"&&window.dispatchEvent(new CustomEvent(e.onViewChange,{detail:{view:d}}))},[c,e.onViewChange]),E=O.useCallback(d=>{F(d),y(d)},[y]),N=g||e.views?.[0]?.type,C=N||"",s=e.views.find(d=>d.type===N)||e.views?.[0],S=e.variant||"tabs",m=e.position||"top",V=m==="left"||m==="right",o=V?"vertical":"horizontal",k=t.jsxs("div",{className:l.cn(Ke({orientation:o})),children:[S==="dropdown"&&t.jsxs(l.Select,{value:C,onValueChange:d=>E(d),children:[t.jsx(l.SelectTrigger,{className:l.cn("w-full",V?"h-10":"h-9"),children:t.jsx(l.SelectValue,{placeholder:"Select view"})}),t.jsx(l.SelectContent,{children:e.views.map((d,x)=>t.jsx(l.SelectItem,{value:d.type,children:fe(d)},`${d.type}-${x}`))})]}),S==="buttons"&&t.jsx("div",{className:l.cn(Je({orientation:o})),children:e.views.map((d,x)=>{const L=d.type===N,Z=Fe(d);return t.jsxs(l.Button,{type:"button",size:"sm",variant:L?"secondary":"ghost",className:l.cn("justify-start gap-2",V?"w-full":""),onClick:()=>E(d.type),children:[Z?t.jsx(Z,{className:"h-4 w-4"}):null,t.jsx("span",{children:fe(d)})]},`${d.type}-${x}`)})}),S==="tabs"&&t.jsx(l.Tabs,{value:C,onValueChange:d=>E(d),children:t.jsx(l.TabsList,{className:l.cn(Xe({orientation:o})),children:e.views.map((d,x)=>{const L=Fe(d);return t.jsxs(l.TabsTrigger,{value:d.type,className:l.cn("gap-2",V?"justify-start":""),children:[L?t.jsx(L,{className:"h-4 w-4"}):null,t.jsx("span",{children:fe(d)})]},`${d.type}-${x}`)})})})]}),A=s?.schema?Array.isArray(s.schema)?t.jsx("div",{className:"space-y-4",children:s.schema.map((d,x)=>t.jsx(je.SchemaRenderer,{schema:d,...u},`${s.type}-${x}`))}):t.jsx(je.SchemaRenderer,{schema:s.schema,...u}):null;return t.jsxs("div",{className:l.cn(He({position:m}),n),children:[t.jsx("div",{className:l.cn("shrink-0",V?"flex flex-col":"flex"),children:k}),t.jsx("div",{className:"flex-1 min-w-0",children:A})]})};let oe=null;try{oe=require("@object-ui/react").SchemaRenderer||null}catch{}const Te=({schema:e,dataSource:n,className:c,views:u,activeViewId:w,onViewChange:g,onRowClick:F,onEdit:y,renderListView:E,toolbarAddon:N})=>{const[C,s]=b.useState(null),[S,m]=b.useState(!1),[V,o]=b.useState("create"),[k,A]=b.useState(null),[d,x]=b.useState(0),[L,Z]=b.useState([]),[ye,ue]=b.useState(!1),[M,de]=b.useState({}),[q,De]=b.useState([]),z=e.listViews,Q=z!=null&&Object.keys(z).length>0,[G,ne]=b.useState(()=>e.defaultListView&&z?.[e.defaultListView]?e.defaultListView:z&&Object.keys(z)[0]||""),T=b.useMemo(()=>!Q||!G?null:z[G]||null,[Q,G,z]),R=b.useMemo(()=>u&&u.length>0?u:null,[u]),ie=R!=null&&R.length>0,ce=w||R?.[0]?.id,h=R?.find(i=>i.id===ce)||R?.[0],r=b.useMemo(()=>T?.type?T.type:h?.type?h.type:e.defaultViewType||"grid",[T,h,e.defaultViewType]),p=e.navigation;b.useEffect(()=>{let i=!0;const f=async()=>{try{const a=await n.getObjectSchema(e.objectName);i&&s(a)}catch(a){console.error("Failed to fetch object schema:",a)}};return e.objectName&&n&&f(),()=>{i=!1}},[e.objectName,n]),b.useEffect(()=>{let i=!0;return(async()=>{if(!(r==="grid"&&!E)&&!(!n||!e.objectName)){ue(!0);try{const a=T?.filter||h?.filter||e.table?.defaultFilters||[],U=Object.entries(M).filter(([,B])=>B!==void 0&&B!==""&&B!==null).map(([B,K])=>[B,"=",K]);let I=[];a.length>0&&U.length>0?I=["and",...a,...U]:U.length===1?I=U[0]:U.length>1?I=["and",...U]:I=a;const H=q.length>0?q.map(B=>({field:B.field,order:B.direction})):T?.sort||h?.sort||e.table?.defaultSort||void 0,D=await n.find(e.objectName,{$filter:I.length>0?I:void 0,$orderby:H,$top:100});let Y=[];Array.isArray(D)?Y=D:D&&typeof D=="object"&&(Array.isArray(D.data)?Y=D.data:Array.isArray(D.value)&&(Y=D.value)),i&&Z(Y)}catch(a){console.error("ObjectView data fetch error:",a)}finally{i&&ue(!1)}}})(),()=>{i=!1}},[e.objectName,n,r,M,q,d,T,h,E]);const v=e.layout||"drawer",j=e.operations||e.table?.operations||{create:!0,read:!0,update:!0,delete:!0},ee=b.useCallback(()=>{v==="page"&&e.onNavigate?e.onNavigate("new","edit"):(o("create"),A(null),m(!0))},[v,e]),te=b.useCallback(i=>{if(y){y(i);return}if(v==="page"&&e.onNavigate){const f=i._id||i.id;e.onNavigate(f,"edit")}else o("edit"),A(i),m(!0)},[v,e,y]),_=b.useCallback(i=>{if(v==="page"&&e.onNavigate){const f=i._id||i.id;e.onNavigate(f,"view")}else o("view"),A(i),m(!0)},[v,e]),W=b.useCallback(i=>{if(F){F(i);return}if(p){if(p.mode==="none"||p.preventNavigation)return;if(p.mode==="new_window"||p.openNewTab){const f=i._id||i.id,a=`/${e.objectName}/${f}`;window.open(a,"_blank");return}if(p.mode==="drawer"){o("view"),A(i),m(!0);return}if(p.mode==="modal"){o("view"),A(i),m(!0);return}if(p.mode==="page"){const f=i._id||i.id;e.onNavigate&&e.onNavigate(f,"view");return}}j.read!==!1&&_(i)},[F,p,j.read,_,e]),ae=b.useCallback(i=>{x(f=>f+1)},[]),ve=b.useCallback(i=>{x(f=>f+1)},[]),at=b.useCallback(()=>{m(!1),A(null),x(i=>i+1)},[]),st=b.useCallback(()=>{m(!1),A(null)},[]);b.useCallback(()=>{x(i=>i+1)},[]);const Pe=b.useMemo(()=>!ie||!R||R.length<=1?null:{type:"view-switcher",variant:"tabs",position:"top",persistPreference:!0,storageKey:`view-pref-${e.objectName}`,defaultView:h?.type||"grid",activeView:h?.type||"grid",views:R.map(i=>{const f={kanban:"kanban",calendar:"calendar",map:"map",gallery:"layout-grid",timeline:"activity",gantt:"gantt-chart",grid:"table",list:"list",detail:"file-text"};return{type:i.type,label:i.label,icon:f[i.type]||"table"}})},[ie,R,h,e.objectName]),ot=b.useCallback(i=>{if(!R)return;const f=R.find(a=>a.type===i);f&&g&&g(f.id)},[R,g]),ut=b.useCallback(i=>{ne(i)},[]);b.useMemo(()=>{if(e.showFilters===!1)return null;const i=e.filterableFields,f=C?.fields||{},U=(i?i.map(I=>[I,f[I]||{label:I}]):Object.entries(f).filter(([,I])=>!I.hidden).slice(0,8)).map(([I,H])=>{const D=H.type||"text";let Y="text",B;return D==="number"||D==="currency"||D==="percent"?Y="number":D==="boolean"||D==="toggle"?Y="boolean":D==="date"||D==="datetime"?Y="date":(D==="select"||H.options)&&(Y="select",B=(H.options||[]).map(K=>typeof K=="string"?{label:K,value:K}:{label:K.label,value:K.value})),{field:I,label:H.label||I,type:Y,placeholder:`Filter ${H.label||I}...`,...B?{options:B}:{}}});return U.length===0?null:{type:"filter-ui",layout:"popover",showClear:!0,showApply:!0,filters:U,values:M}},[e.showFilters,e.filterableFields,C,M]),b.useMemo(()=>{const i=C?.fields||{},f=Object.entries(i).filter(([,a])=>!a.hidden).slice(0,10).map(([a,U])=>({field:a,label:U.label||a}));return f.length===0?null:{type:"sort-ui",variant:"dropdown",multiple:!1,fields:f,sort:q}},[C,q]);const dt=b.useCallback(i=>{const f={objectName:e.objectName,fields:T?.columns||h?.columns||e.table?.fields,className:"h-full w-full",showSearch:!1},a=T?.options||h||{};switch(i){case"kanban":return{type:"object-kanban",...f,groupBy:a.kanban?.groupField||a.groupBy||a.groupField||"status",groupField:a.kanban?.groupField||a.groupField||"status",titleField:a.kanban?.titleField||a.titleField||"name",cardFields:f.fields||[],...a.kanban||{}};case"calendar":return{type:"object-calendar",...f,startDateField:a.calendar?.startDateField||a.startDateField||"start_date",endDateField:a.calendar?.endDateField||a.endDateField||"end_date",titleField:a.calendar?.titleField||a.titleField||"name",...a.calendar||{}};case"gallery":return{type:"object-gallery",...f,imageField:a.gallery?.imageField||a.imageField,titleField:a.gallery?.titleField||a.titleField||"name",subtitleField:a.gallery?.subtitleField||a.subtitleField,...a.gallery||{}};case"timeline":return{type:"object-timeline",...f,dateField:a.timeline?.dateField||a.dateField||"created_at",titleField:a.timeline?.titleField||a.titleField||"name",...a.timeline||{}};case"gantt":return{type:"object-gantt",...f,startDateField:a.gantt?.startDateField||a.startDateField||"start_date",endDateField:a.gantt?.endDateField||a.endDateField||"end_date",progressField:a.gantt?.progressField||a.progressField||"progress",dependenciesField:a.gantt?.dependenciesField||a.dependenciesField||"dependencies",...a.gantt||{}};case"map":return{type:"object-map",...f,locationField:a.map?.locationField||a.locationField||"location",...a.map||{}};default:return null}},[e.objectName,e.table?.fields,T,h]),ct=b.useMemo(()=>({type:"object-grid",objectName:e.objectName,title:e.table?.title,description:e.table?.description,fields:T?.columns||h?.columns||e.table?.fields,columns:T?.columns||h?.columns||e.table?.columns,operations:{...j,create:!1},defaultFilters:T?.filter||h?.filter||e.table?.defaultFilters,defaultSort:T?.sort||h?.sort||e.table?.defaultSort,pageSize:e.table?.pageSize,selectable:e.table?.selectable,className:e.table?.className}),[e,j,T,h]),Ie=()=>{const i=k?k._id||k.id:void 0;return{type:"object-form",objectName:e.objectName,mode:V,recordId:i,title:e.form?.title,description:e.form?.description,fields:e.form?.fields,customFields:e.form?.customFields,groups:e.form?.groups,layout:e.form?.layout,columns:e.form?.columns,showSubmit:e.form?.showSubmit,submitText:e.form?.submitText,showCancel:e.form?.showCancel,cancelText:e.form?.cancelText,showReset:e.form?.showReset,initialValues:e.form?.initialValues,readOnly:e.form?.readOnly||V==="view",className:e.form?.className,onSuccess:at,onCancel:st}},Re=()=>{if(e.form?.title)return e.form.title;const i=C?.label||e.objectName;switch(V){case"create":return`Create ${i}`;case"edit":return`Edit ${i}`;case"view":return`View ${i}`;default:return i}},$e=b.useMemo(()=>{const i=p?.width;return i?typeof i=="number"?`max-w-[${i}px]`:`max-w-[${i}]`:""},[p]),ft=()=>t.jsx(l.Drawer,{open:S,onOpenChange:m,direction:"right",children:t.jsxs(l.DrawerContent,{className:l.cn("w-full sm:max-w-2xl",$e),children:[t.jsxs(l.DrawerHeader,{children:[t.jsx(l.DrawerTitle,{children:Re()}),e.form?.description&&t.jsx(l.DrawerDescription,{children:e.form.description})]}),t.jsx("div",{className:"flex-1 overflow-y-auto px-4 pb-4",children:t.jsx(me.ObjectForm,{schema:Ie(),dataSource:n})})]})}),pt=()=>t.jsx(l.Dialog,{open:S,onOpenChange:m,children:t.jsxs(l.DialogContent,{className:l.cn("max-w-2xl max-h-[90vh] overflow-y-auto",$e),children:[t.jsxs(l.DialogHeader,{children:[t.jsx(l.DialogTitle,{children:Re()}),e.form?.description&&t.jsx(l.DialogDescription,{children:e.form.description})]}),t.jsx(me.ObjectForm,{schema:Ie(),dataSource:n})]})}),bt=b.useMemo(()=>Object.keys(M).some(f=>M[f]!==void 0&&M[f]!==""&&M[f]!==null)?Object.entries(M).filter(([,f])=>f!==void 0&&f!==""&&f!==null).map(([f,a])=>({field:f,operator:"equals",value:a})):T?.filter||h?.filter||e.table?.defaultFilters,[M,T,h,e.table?.defaultFilters]),wt=b.useMemo(()=>q.length>0?q:T?.sort||h?.sort||e.table?.defaultSort,[q,T,h,e.table?.defaultSort]),gt=()=>{const i=`${e.objectName}-${G||h?.id||"default"}-${r}-${d}`;if(E)return E({schema:{type:"list-view",objectName:e.objectName,viewType:r,fields:T?.columns||h?.columns||e.table?.fields,filters:bt,sort:wt,options:T?.options||h},dataSource:n,onEdit:te,onRowClick:W,className:"h-full"});if(r!=="grid"){const f=dt(r);if(f&&oe)return t.jsx(oe,{schema:f,dataSource:n,data:L,loading:ye},i);if(!oe)return t.jsx("div",{className:"flex items-center justify-center h-40 text-muted-foreground",children:t.jsxs("p",{children:["SchemaRenderer not available. Install @object-ui/react to render ",r," views."]})})}return t.jsx(Me.ObjectGrid,{schema:ct,dataSource:n,onRowClick:W,onEdit:j.update!==!1?te:void 0,onDelete:j.delete!==!1?ae:void 0,onBulkDelete:j.delete!==!1?ve:void 0},i)},yt=()=>{if(!Q)return null;const i=Object.entries(z);return i.length<=1?null:t.jsx(l.Tabs,{value:G,onValueChange:ut,className:"w-full",children:t.jsx(l.TabsList,{className:"w-auto",children:i.map(([f,a])=>t.jsx(l.TabsTrigger,{value:f,className:"text-sm",children:a.label||f},f))})})},vt=()=>{const i=e.showCreate!==!1&&j.create!==!1,f=e.showViewSwitcher===!0,a=yt();return!a&&!f&&!i&&!N?null:t.jsxs("div",{className:"flex flex-col gap-3",children:[a,(f||i||N)&&t.jsxs("div",{className:"flex items-center justify-between gap-4",children:[t.jsx("div",{className:"flex items-center gap-2",children:f&&Pe&&t.jsx(pe,{schema:Pe,onViewChange:ot,className:"overflow-x-auto"})}),t.jsxs("div",{className:"flex items-center gap-2",children:[N,i&&t.jsxs(l.Button,{size:"sm",onClick:ee,children:[t.jsx($.Plus,{className:"h-4 w-4"}),"Create"]})]})]})]})},Le=p?.mode==="modal"?"modal":p?.mode==="drawer"?"drawer":v;return t.jsxs("div",{className:l.cn("flex flex-col h-full",c),children:[(e.title||e.description)&&t.jsxs("div",{className:"mb-4 shrink-0",children:[e.title&&t.jsx("h2",{className:"text-2xl font-bold tracking-tight",children:e.title}),e.description&&t.jsx("p",{className:"text-muted-foreground mt-1",children:e.description})]}),t.jsx("div",{className:"mb-4 shrink-0",children:vt()}),t.jsx("div",{className:"flex-1 min-h-0",children:gt()}),Le==="drawer"&&ft(),Le==="modal"&&pt()]})},be=X("flex",{variants:{layout:{inline:"flex-col space-y-4",popover:"items-center",drawer:"items-center"}},defaultVariants:{layout:"inline"}}),rt=e=>e==null||e===""?!0:Array.isArray(e)?e.length===0:typeof e=="object"?Object.values(e).every(n=>n==null||n===""):!1,lt=e=>Array.isArray(e)?{start:e[0]||"",end:e[1]||""}:e&&typeof e=="object"?{start:e.start||"",end:e.end||""}:{start:"",end:""},Ee=({schema:e,className:n,onChange:c})=>{const[u,w]=O.useState(e.values||{}),[g,F]=O.useState(!1);O.useEffect(()=>{e.values&&w(e.values)},[e.values]);const y=O.useCallback(o=>{c?.(o),e.onChange&&typeof window<"u"&&window.dispatchEvent(new CustomEvent(e.onChange,{detail:{values:o}}))},[c,e.onChange]),E=O.useCallback((o,k)=>{const A={...u,[o]:k};w(A),e.showApply||y(A)},[y,e.showApply,u]),N=O.useCallback(()=>{const o={};if(w(o),e.showApply){y(o);return}y(o)},[y,e.showApply]),C=O.useCallback(()=>{y(u),F(!1)},[y,u]),s=O.useMemo(()=>Object.values(u).filter(o=>!rt(o)).length,[u]),S=o=>{const k=o.label||o.field,A=o.placeholder||`Filter by ${k}`;switch(o.type){case"number":return t.jsx(l.Input,{type:"number",value:u[o.field]??"",placeholder:A,onChange:d=>{const x=d.target.value,L=x===""?"":Number(x);E(o.field,L)}});case"select":return t.jsxs(l.Select,{value:u[o.field]!==void 0?String(u[o.field]):"",onValueChange:d=>{const x=o.options?.find(L=>String(L.value)===d);E(o.field,x?x.value:d)},children:[t.jsx(l.SelectTrigger,{children:t.jsx(l.SelectValue,{placeholder:A})}),t.jsx(l.SelectContent,{children:o.options?.map(d=>t.jsx(l.SelectItem,{value:String(d.value),children:d.label},String(d.value)))})]});case"date":return t.jsx(l.Input,{type:"date",value:u[o.field]??"",onChange:d=>E(o.field,d.target.value)});case"date-range":{const d=lt(u[o.field]);return t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(l.Input,{type:"date",value:d.start??"",onChange:x=>{E(o.field,{...d,start:x.target.value})}}),t.jsx(l.Input,{type:"date",value:d.end??"",onChange:x=>{E(o.field,{...d,end:x.target.value})}})]})}case"boolean":return t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(l.Checkbox,{checked:!!u[o.field],onCheckedChange:d=>E(o.field,!!d)}),t.jsx("span",{className:"text-sm text-muted-foreground",children:"Enabled"})]});default:return t.jsx(l.Input,{value:u[o.field]??"",placeholder:A,onChange:d=>E(o.field,d.target.value)})}},m=t.jsxs("div",{className:"space-y-4",children:[t.jsx("div",{className:"grid gap-4 sm:grid-cols-2",children:e.filters.map(o=>t.jsxs("div",{className:"space-y-2",children:[t.jsx(l.Label,{className:"text-xs text-muted-foreground",children:o.label||o.field}),S(o)]},o.field))}),(e.showApply||e.showClear)&&t.jsxs("div",{className:"flex items-center justify-end gap-2 border-t pt-3",children:[e.showClear&&t.jsx(l.Button,{type:"button",variant:"ghost",size:"sm",onClick:N,children:"Clear"}),e.showApply&&t.jsx(l.Button,{type:"button",size:"sm",onClick:C,children:"Apply"})]})]}),V=e.layout||"inline";return V==="popover"?t.jsx("div",{className:l.cn(be({layout:V}),n),children:t.jsxs(l.Popover,{open:g,onOpenChange:F,children:[t.jsx(l.PopoverTrigger,{asChild:!0,children:t.jsxs(l.Button,{type:"button",variant:s>0?"secondary":"outline",size:"sm",className:"gap-2",children:[t.jsx($.SlidersHorizontal,{className:"h-4 w-4"}),"Filters",s>0&&t.jsx("span",{className:"inline-flex h-5 min-w-[20px] items-center justify-center rounded-full bg-primary/10 px-1 text-xs font-medium text-primary",children:s})]})}),t.jsx(l.PopoverContent,{align:"start",className:"w-[520px] p-4",children:m})]})}):V==="drawer"?t.jsxs("div",{className:l.cn(be({layout:V}),n),children:[t.jsxs(l.Button,{type:"button",variant:s>0?"secondary":"outline",size:"sm",className:"gap-2",onClick:()=>F(!0),children:[t.jsx($.SlidersHorizontal,{className:"h-4 w-4"}),"Filters",s>0&&t.jsx("span",{className:"inline-flex h-5 min-w-[20px] items-center justify-center rounded-full bg-primary/10 px-1 text-xs font-medium text-primary",children:s})]}),t.jsx(l.Drawer,{open:g,onOpenChange:F,children:t.jsxs(l.DrawerContent,{children:[t.jsxs(l.DrawerHeader,{children:[t.jsx(l.DrawerTitle,{children:"Filters"}),t.jsx(l.DrawerDescription,{children:"Refine the data with advanced filters."})]}),t.jsx("div",{className:"px-4 pb-6",children:m})]})})]}):t.jsxs("div",{className:l.cn(be({layout:V}),n),children:[m,!e.showApply&&e.showClear&&t.jsxs(l.Button,{type:"button",variant:"ghost",size:"sm",className:"gap-2",onClick:N,children:[t.jsx($.X,{className:"h-3.5 w-3.5"}),"Clear filters"]})]})},we=X("",{variants:{variant:{buttons:"flex flex-wrap gap-2",dropdown:"flex flex-wrap items-center gap-3",builder:"space-y-3"}},defaultVariants:{variant:"dropdown"}}),ge=e=>e?e.map(n=>({field:n.field,direction:n.direction})):[],_e=e=>e.map(n=>({id:`${n.field}-${n.direction}`,field:n.field,order:n.direction})),nt=e=>e.filter(n=>n.field).map(n=>({field:n.field,direction:n.order})),ke=({schema:e,className:n,onChange:c})=>{const[u,w]=O.useState(()=>ge(e.sort)),[g,F]=O.useState(()=>_e(ge(e.sort)));O.useEffect(()=>{const s=ge(e.sort);w(s),F(_e(s))},[e.sort]);const y=O.useCallback(s=>{w(s),c?.(s),e.onChange&&typeof window<"u"&&window.dispatchEvent(new CustomEvent(e.onChange,{detail:{sort:s}}))},[c,e.onChange]),E=O.useCallback(s=>{const S=u.find(o=>o.field===s),m=!!e.multiple;if(!S){const o=m?[...u,{field:s,direction:"asc"}]:[{field:s,direction:"asc"}];y(o);return}if(S.direction==="asc"){const o=u.map(k=>k.field===s?{...k,direction:"desc"}:k);y(o);return}const V=u.filter(o=>o.field!==s);y(V)},[y,e.multiple,u]);if((e.variant||"dropdown")==="buttons")return t.jsx("div",{className:l.cn(we({variant:"buttons"}),n),children:e.fields.map(s=>{const S=u.find(V=>V.field===s.field),m=S?.direction==="asc"?$.ArrowUp:$.ArrowDown;return t.jsxs(l.Button,{type:"button",variant:S?"secondary":"outline",size:"sm",onClick:()=>E(s.field),className:"gap-2",children:[t.jsx("span",{children:s.label||s.field}),S&&t.jsx(m,{className:"h-3.5 w-3.5"})]},s.field)})});if(e.multiple)return t.jsx("div",{className:l.cn(we({variant:"builder"}),n),children:t.jsx(l.SortBuilder,{fields:e.fields.map(s=>({value:s.field,label:s.label||s.field})),value:g,onChange:s=>{F(s),y(nt(s))}})});const C=u[0];return t.jsxs("div",{className:l.cn(we({variant:"dropdown"}),n),children:[t.jsxs(l.Select,{value:C?.field||"",onValueChange:s=>{if(!s){y([]);return}y([{field:s,direction:C?.direction||"asc"}])},children:[t.jsx(l.SelectTrigger,{className:"w-56",children:t.jsx(l.SelectValue,{placeholder:"Select field"})}),t.jsx(l.SelectContent,{children:e.fields.map(s=>t.jsx(l.SelectItem,{value:s.field,children:s.label||s.field},s.field))})]}),t.jsxs(l.Select,{value:C?.direction||"asc",onValueChange:s=>{C?.field&&y([{field:C.field,direction:s}])},children:[t.jsx(l.SelectTrigger,{className:"w-36",children:t.jsx(l.SelectValue,{})}),t.jsxs(l.SelectContent,{children:[t.jsx(l.SelectItem,{value:"asc",children:"Ascending"}),t.jsx(l.SelectItem,{value:"desc",children:"Descending"})]})]})]})};let Oe=b.createContext(null);try{const e=require("@object-ui/react");e.SchemaRendererContext&&(Oe=e.SchemaRendererContext)}catch{}const Ae=({schema:e})=>{const c=b.useContext(Oe)?.dataSource??null;return t.jsx(Te,{schema:e,dataSource:c})};J.ComponentRegistry.register("object-view",Ae,{namespace:"plugin-view",label:"Object View",category:"view",icon:"LayoutDashboard",inputs:[{name:"objectName",type:"string",label:"Object Name",required:!0},{name:"title",type:"string",label:"Title"},{name:"description",type:"string",label:"Description"},{name:"layout",type:"enum",label:"Form Layout",enum:["drawer","modal","page"]},{name:"defaultViewType",type:"enum",label:"Default View Type",enum:["grid","kanban","gallery","calendar","timeline","gantt","map"]},{name:"defaultListView",type:"string",label:"Default Named View"},{name:"showSearch",type:"boolean",label:"Show Search"},{name:"showFilters",type:"boolean",label:"Show Filters"},{name:"showCreate",type:"boolean",label:"Show Create Button"},{name:"showRefresh",type:"boolean",label:"Show Refresh Button"},{name:"showViewSwitcher",type:"boolean",label:"Show View Switcher"},{name:"listViews",type:"object",label:"Named List Views"},{name:"navigation",type:"object",label:"Navigation Config"},{name:"searchableFields",type:"array",label:"Searchable Fields"},{name:"filterableFields",type:"array",label:"Filterable Fields"}],defaultProps:{layout:"drawer",defaultViewType:"grid",showSearch:!0,showFilters:!0,showCreate:!0,showRefresh:!0,showViewSwitcher:!0}}),J.ComponentRegistry.register("view",Ae,{namespace:"plugin-view",label:"View",category:"view"}),J.ComponentRegistry.register("view-switcher",pe,{namespace:"view",label:"View Switcher",category:"view",icon:"LayoutGrid",inputs:[{name:"views",type:"array",label:"Views",required:!0},{name:"defaultView",type:"string",label:"Default View"},{name:"activeView",type:"string",label:"Active View"},{name:"variant",type:"enum",label:"Variant",enum:["tabs","buttons","dropdown"]},{name:"position",type:"enum",label:"Position",enum:["top","bottom","left","right"]},{name:"persistPreference",type:"boolean",label:"Persist Preference"},{name:"storageKey",type:"string",label:"Storage Key"},{name:"onViewChange",type:"string",label:"On View Change Event"}],defaultProps:{variant:"tabs",position:"top",defaultView:"grid",views:[{type:"grid",label:"Grid",schema:{type:"text",content:"Grid view"}},{type:"list",label:"List",schema:{type:"text",content:"List view"}}]}}),J.ComponentRegistry.register("filter-ui",Ee,{namespace:"view",label:"Filter UI",category:"view",icon:"SlidersHorizontal",inputs:[{name:"filters",type:"array",label:"Filters",required:!0},{name:"values",type:"object",label:"Values"},{name:"onChange",type:"string",label:"On Change Event"},{name:"showClear",type:"boolean",label:"Show Clear Button"},{name:"showApply",type:"boolean",label:"Show Apply Button"},{name:"layout",type:"enum",label:"Layout",enum:["inline","popover","drawer"]}],defaultProps:{layout:"inline",showApply:!1,showClear:!0,filters:[{field:"name",label:"Name",type:"text",placeholder:"Search name"},{field:"status",label:"Status",type:"select",options:[{label:"Open",value:"open"},{label:"Closed",value:"closed"}]},{field:"created_at",label:"Created",type:"date"}]}}),J.ComponentRegistry.register("sort-ui",ke,{namespace:"view",label:"Sort UI",category:"view",icon:"ArrowUpDown",inputs:[{name:"fields",type:"array",label:"Fields",required:!0},{name:"sort",type:"array",label:"Sort"},{name:"onChange",type:"string",label:"On Change Event"},{name:"multiple",type:"boolean",label:"Allow Multiple"},{name:"variant",type:"enum",label:"Variant",enum:["dropdown","buttons"]}],defaultProps:{variant:"dropdown",multiple:!0,fields:[{field:"name",label:"Name"},{field:"created_at",label:"Created At"}],sort:[{field:"name",direction:"asc"}]}});const it=({schema:e,className:n,children:c,dataSource:u,...w})=>{const g=e.props?.columns?{display:"grid",gridTemplateColumns:`repeat(${e.props.columns}, 1fr)`,gap:"1rem"}:void 0;return t.jsx("div",{className:n,style:g,...w,children:c})};J.ComponentRegistry.register("view:simple",it,{namespace:"plugin-view",label:"Simple View",category:"view"}),P.FilterUI=Ee,P.ObjectView=Te,P.SortUI=ke,P.ViewSwitcher=pe,Object.defineProperty(P,Symbol.toStringTag,{value:"Module"})}));
|
|
6
|
+
<%s key={someKey} {...props} />`,j,_,W,_),h[_+j]=!0)}if(_=null,v!==void 0&&(c(v),_=""+v),F(p)&&(c(p.key),_=""+p.key),"key"in p){v={};for(var ae in p)ae!=="key"&&(v[ae]=p[ae])}else v=p;return _&&y(v,typeof r=="function"?r.displayName||r.name||"Unknown":r),N(r,_,v,w(),ee,te)}function s(r){S(r)?r._store&&(r._store.validated=1):typeof r=="object"&&r!==null&&r.$$typeof===de&&(r._payload.status==="fulfilled"?S(r._payload.value)&&r._payload.value._store&&(r._payload.value._store.validated=1):r._store&&(r._store.validated=1))}function S(r){return typeof r=="object"&&r!==null&&r.$$typeof===V}var m=b,V=Symbol.for("react.transitional.element"),o=Symbol.for("react.portal"),k=Symbol.for("react.fragment"),A=Symbol.for("react.strict_mode"),d=Symbol.for("react.profiler"),x=Symbol.for("react.consumer"),L=Symbol.for("react.context"),Z=Symbol.for("react.forward_ref"),ye=Symbol.for("react.suspense"),ue=Symbol.for("react.suspense_list"),M=Symbol.for("react.memo"),de=Symbol.for("react.lazy"),q=Symbol.for("react.activity"),De=Symbol.for("react.client.reference"),z=m.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,Q=Object.prototype.hasOwnProperty,G=Array.isArray,ne=console.createTask?console.createTask:function(){return null};m={react_stack_bottom_frame:function(r){return r()}};var T,R={},ie=m.react_stack_bottom_frame.bind(m,g)(),ce=ne(u(g)),h={};le.Fragment=k,le.jsx=function(r,p,v){var j=1e4>z.recentlyCreatedOwnerStacks++;return C(r,p,v,!1,j?Error("react-stack-top-frame"):ie,j?ne(u(r)):ce)},le.jsxs=function(r,p,v){var j=1e4>z.recentlyCreatedOwnerStacks++;return C(r,p,v,!0,j?Error("react-stack-top-frame"):ie,j?ne(u(r)):ce)}})()),le}var Ce;function qe(){return Ce||(Ce=1,process.env.NODE_ENV==="production"?se.exports=Be():se.exports=Ue()),se.exports}var t=qe();function Se(e){var n,c,u="";if(typeof e=="string"||typeof e=="number")u+=e;else if(typeof e=="object")if(Array.isArray(e)){var w=e.length;for(n=0;n<w;n++)e[n]&&(c=Se(e[n]))&&(u&&(u+=" "),u+=c)}else for(c in e)e[c]&&(u&&(u+=" "),u+=c);return u}function Ye(){for(var e,n,c=0,u="",w=arguments.length;c<w;c++)(e=arguments[c])&&(n=Se(e))&&(u&&(u+=" "),u+=n);return u}const Ne=e=>typeof e=="boolean"?`${e}`:e===0?"0":e,Ve=Ye,X=(e,n)=>c=>{var u;if(n?.variants==null)return Ve(e,c?.class,c?.className);const{variants:w,defaultVariants:g}=n,F=Object.keys(w).map(N=>{const C=c?.[N],s=g?.[N];if(C===null)return null;const S=Ne(C)||Ne(s);return w[N][S]}),y=c&&Object.entries(c).reduce((N,C)=>{let[s,S]=C;return S===void 0||(N[s]=S),N},{}),E=n==null||(u=n.compoundVariants)===null||u===void 0?void 0:u.reduce((N,C)=>{let{class:s,className:S,...m}=C;return Object.entries(m).every(V=>{let[o,k]=V;return Array.isArray(k)?k.includes({...g,...y}[o]):{...g,...y}[o]===k})?[...N,s,S]:N},[]);return Ve(e,F,E,c?.class,c?.className)},We={list:"List",detail:"Detail",grid:"Grid",kanban:"Kanban",calendar:"Calendar",timeline:"Timeline",map:"Map"},Ge={list:$.List,detail:$.FileText,grid:$.Grid,kanban:$.LayoutGrid,calendar:$.Calendar,timeline:$.Activity,map:$.Map},He=X("flex gap-4",{variants:{position:{top:"flex-col",bottom:"flex-col-reverse",left:"flex-row",right:"flex-row-reverse"}},defaultVariants:{position:"top"}}),Ke=X("w-full",{variants:{orientation:{horizontal:"w-full",vertical:"w-48"}},defaultVariants:{orientation:"horizontal"}}),Je=X("flex gap-2",{variants:{orientation:{horizontal:"flex-row flex-wrap",vertical:"flex-col"}},defaultVariants:{orientation:"horizontal"}}),Xe=X("",{variants:{orientation:{horizontal:"",vertical:"flex h-auto flex-col items-stretch"}},defaultVariants:{orientation:"horizontal"}});function Ze(e){return e.split("-").map(n=>n.charAt(0).toUpperCase()+n.slice(1)).join("")}const Qe={Home:"House"};function et(e){if(!e)return null;const n=Ze(e),c=Qe[n]||n;return $.icons[c]||null}function fe(e){return e.label?e.label:We[e.type]||e.type}function Fe(e){return e.icon?et(e.icon):Ge[e.type]||null}function tt(e){return e.activeView?e.activeView:e.defaultView?e.defaultView:e.views?.[0]?.type}const pe=({schema:e,className:n,onViewChange:c,...u})=>{const w=O.useMemo(()=>e.storageKey?e.storageKey:`view-switcher${e.id?`-${e.id}`:""}`,[e.id,e.storageKey]),[g,F]=O.useState(()=>tt(e));O.useEffect(()=>{if(e.activeView){F(e.activeView);return}if(e.persistPreference)try{const d=localStorage.getItem(w);if(d){const x=e.views.find(L=>L.type===d)?.type;x&&F(x)}}catch{}},[e.activeView,e.persistPreference,e.views,w]),O.useEffect(()=>{if(!(!e.persistPreference||!g||e.activeView))try{localStorage.setItem(w,g)}catch{}},[g,e.activeView,e.persistPreference,w]);const y=O.useCallback(d=>{c?.(d),e.onViewChange&&typeof window<"u"&&window.dispatchEvent(new CustomEvent(e.onViewChange,{detail:{view:d}}))},[c,e.onViewChange]),E=O.useCallback(d=>{F(d),y(d)},[y]),N=g||e.views?.[0]?.type,C=N||"",s=e.views.find(d=>d.type===N)||e.views?.[0],S=e.variant||"tabs",m=e.position||"top",V=m==="left"||m==="right",o=V?"vertical":"horizontal",k=t.jsxs("div",{className:l.cn(Ke({orientation:o})),children:[S==="dropdown"&&t.jsxs(l.Select,{value:C,onValueChange:d=>E(d),children:[t.jsx(l.SelectTrigger,{className:l.cn("w-full",V?"h-10":"h-9"),children:t.jsx(l.SelectValue,{placeholder:"Select view"})}),t.jsx(l.SelectContent,{children:e.views.map((d,x)=>t.jsx(l.SelectItem,{value:d.type,children:fe(d)},`${d.type}-${x}`))})]}),S==="buttons"&&t.jsx("div",{className:l.cn(Je({orientation:o})),children:e.views.map((d,x)=>{const L=d.type===N,Z=Fe(d);return t.jsxs(l.Button,{type:"button",size:"sm",variant:L?"secondary":"ghost",className:l.cn("justify-start gap-2",V?"w-full":""),onClick:()=>E(d.type),children:[Z?t.jsx(Z,{className:"h-4 w-4"}):null,t.jsx("span",{children:fe(d)})]},`${d.type}-${x}`)})}),S==="tabs"&&t.jsx(l.Tabs,{value:C,onValueChange:d=>E(d),children:t.jsx(l.TabsList,{className:l.cn(Xe({orientation:o})),children:e.views.map((d,x)=>{const L=Fe(d);return t.jsxs(l.TabsTrigger,{value:d.type,className:l.cn("gap-2",V?"justify-start":""),children:[L?t.jsx(L,{className:"h-4 w-4"}):null,t.jsx("span",{children:fe(d)})]},`${d.type}-${x}`)})})})]}),A=s?.schema?Array.isArray(s.schema)?t.jsx("div",{className:"space-y-4",children:s.schema.map((d,x)=>t.jsx(je.SchemaRenderer,{schema:d,...u},`${s.type}-${x}`))}):t.jsx(je.SchemaRenderer,{schema:s.schema,...u}):null;return t.jsxs("div",{className:l.cn(He({position:m}),n),children:[t.jsx("div",{className:l.cn("shrink-0",V?"flex flex-col":"flex"),children:k}),t.jsx("div",{className:"flex-1 min-w-0",children:A})]})};let oe=null;try{oe=require("@object-ui/react").SchemaRenderer||null}catch{}const Te=({schema:e,dataSource:n,className:c,views:u,activeViewId:w,onViewChange:g,onRowClick:F,onEdit:y,renderListView:E,toolbarAddon:N})=>{const[C,s]=b.useState(null),[S,m]=b.useState(!1),[V,o]=b.useState("create"),[k,A]=b.useState(null),[d,x]=b.useState(0),[L,Z]=b.useState([]),[ye,ue]=b.useState(!1),[M,de]=b.useState({}),[q,De]=b.useState([]),z=e.listViews,Q=z!=null&&Object.keys(z).length>0,[G,ne]=b.useState(()=>e.defaultListView&&z?.[e.defaultListView]?e.defaultListView:z&&Object.keys(z)[0]||""),T=b.useMemo(()=>!Q||!G?null:z[G]||null,[Q,G,z]),R=b.useMemo(()=>u&&u.length>0?u:null,[u]),ie=R!=null&&R.length>0,ce=w||R?.[0]?.id,h=R?.find(i=>i.id===ce)||R?.[0],r=b.useMemo(()=>T?.type?T.type:h?.type?h.type:e.defaultViewType||"grid",[T,h,e.defaultViewType]),p=e.navigation;b.useEffect(()=>{let i=!0;const f=async()=>{try{const a=await n.getObjectSchema(e.objectName);i&&s(a)}catch(a){console.error("Failed to fetch object schema:",a)}};return e.objectName&&n&&f(),()=>{i=!1}},[e.objectName,n]),b.useEffect(()=>{let i=!0;return(async()=>{if(!(r==="grid"&&!E)&&!(!n||!e.objectName)){ue(!0);try{const a=T?.filter||h?.filter||e.table?.defaultFilters||[],U=Object.entries(M).filter(([,B])=>B!==void 0&&B!==""&&B!==null).map(([B,K])=>[B,"=",K]);let I=[];a.length>0&&U.length>0?I=["and",...a,...U]:U.length===1?I=U[0]:U.length>1?I=["and",...U]:I=a;const H=q.length>0?q.map(B=>({field:B.field,order:B.direction})):T?.sort||h?.sort||e.table?.defaultSort||void 0,D=await n.find(e.objectName,{$filter:I.length>0?I:void 0,$orderby:H,$top:100});let Y=[];Array.isArray(D)?Y=D:D&&typeof D=="object"&&(Array.isArray(D.data)?Y=D.data:Array.isArray(D.records)&&(Y=D.records)),i&&Z(Y)}catch(a){console.error("ObjectView data fetch error:",a)}finally{i&&ue(!1)}}})(),()=>{i=!1}},[e.objectName,n,r,M,q,d,T,h,E]);const v=e.layout||"drawer",j=e.operations||e.table?.operations||{create:!0,read:!0,update:!0,delete:!0},ee=b.useCallback(()=>{v==="page"&&e.onNavigate?e.onNavigate("new","edit"):(o("create"),A(null),m(!0))},[v,e]),te=b.useCallback(i=>{if(y){y(i);return}if(v==="page"&&e.onNavigate){const f=i._id||i.id;e.onNavigate(f,"edit")}else o("edit"),A(i),m(!0)},[v,e,y]),_=b.useCallback(i=>{if(v==="page"&&e.onNavigate){const f=i._id||i.id;e.onNavigate(f,"view")}else o("view"),A(i),m(!0)},[v,e]),W=b.useCallback(i=>{if(F){F(i);return}if(p){if(p.mode==="none"||p.preventNavigation)return;if(p.mode==="new_window"||p.openNewTab){const f=i._id||i.id,a=`/${e.objectName}/${f}`;window.open(a,"_blank");return}if(p.mode==="drawer"){o("view"),A(i),m(!0);return}if(p.mode==="modal"){o("view"),A(i),m(!0);return}if(p.mode==="page"){const f=i._id||i.id;e.onNavigate&&e.onNavigate(f,"view");return}}j.read!==!1&&_(i)},[F,p,j.read,_,e]),ae=b.useCallback(i=>{x(f=>f+1)},[]),ve=b.useCallback(i=>{x(f=>f+1)},[]),at=b.useCallback(()=>{m(!1),A(null),x(i=>i+1)},[]),st=b.useCallback(()=>{m(!1),A(null)},[]);b.useCallback(()=>{x(i=>i+1)},[]);const Pe=b.useMemo(()=>!ie||!R||R.length<=1?null:{type:"view-switcher",variant:"tabs",position:"top",persistPreference:!0,storageKey:`view-pref-${e.objectName}`,defaultView:h?.type||"grid",activeView:h?.type||"grid",views:R.map(i=>{const f={kanban:"kanban",calendar:"calendar",map:"map",gallery:"layout-grid",timeline:"activity",gantt:"gantt-chart",grid:"table",list:"list",detail:"file-text"};return{type:i.type,label:i.label,icon:f[i.type]||"table"}})},[ie,R,h,e.objectName]),ot=b.useCallback(i=>{if(!R)return;const f=R.find(a=>a.type===i);f&&g&&g(f.id)},[R,g]),ut=b.useCallback(i=>{ne(i)},[]);b.useMemo(()=>{if(e.showFilters===!1)return null;const i=e.filterableFields,f=C?.fields||{},U=(i?i.map(I=>[I,f[I]||{label:I}]):Object.entries(f).filter(([,I])=>!I.hidden).slice(0,8)).map(([I,H])=>{const D=H.type||"text";let Y="text",B;return D==="number"||D==="currency"||D==="percent"?Y="number":D==="boolean"||D==="toggle"?Y="boolean":D==="date"||D==="datetime"?Y="date":(D==="select"||H.options)&&(Y="select",B=(H.options||[]).map(K=>typeof K=="string"?{label:K,value:K}:{label:K.label,value:K.value})),{field:I,label:H.label||I,type:Y,placeholder:`Filter ${H.label||I}...`,...B?{options:B}:{}}});return U.length===0?null:{type:"filter-ui",layout:"popover",showClear:!0,showApply:!0,filters:U,values:M}},[e.showFilters,e.filterableFields,C,M]),b.useMemo(()=>{const i=C?.fields||{},f=Object.entries(i).filter(([,a])=>!a.hidden).slice(0,10).map(([a,U])=>({field:a,label:U.label||a}));return f.length===0?null:{type:"sort-ui",variant:"dropdown",multiple:!1,fields:f,sort:q}},[C,q]);const dt=b.useCallback(i=>{const f={objectName:e.objectName,fields:T?.columns||h?.columns||e.table?.fields,className:"h-full w-full",showSearch:!1},a=T?.options||h||{};switch(i){case"kanban":return{type:"object-kanban",...f,groupBy:a.kanban?.groupField||a.groupBy||a.groupField||"status",groupField:a.kanban?.groupField||a.groupField||"status",titleField:a.kanban?.titleField||a.titleField||"name",cardFields:f.fields||[],...a.kanban||{}};case"calendar":return{type:"object-calendar",...f,startDateField:a.calendar?.startDateField||a.startDateField||"start_date",endDateField:a.calendar?.endDateField||a.endDateField||"end_date",titleField:a.calendar?.titleField||a.titleField||"name",...a.calendar||{}};case"gallery":return{type:"object-gallery",...f,imageField:a.gallery?.imageField||a.imageField,titleField:a.gallery?.titleField||a.titleField||"name",subtitleField:a.gallery?.subtitleField||a.subtitleField,...a.gallery||{}};case"timeline":return{type:"object-timeline",...f,dateField:a.timeline?.dateField||a.dateField||"created_at",titleField:a.timeline?.titleField||a.titleField||"name",...a.timeline||{}};case"gantt":return{type:"object-gantt",...f,startDateField:a.gantt?.startDateField||a.startDateField||"start_date",endDateField:a.gantt?.endDateField||a.endDateField||"end_date",progressField:a.gantt?.progressField||a.progressField||"progress",dependenciesField:a.gantt?.dependenciesField||a.dependenciesField||"dependencies",...a.gantt||{}};case"map":return{type:"object-map",...f,locationField:a.map?.locationField||a.locationField||"location",...a.map||{}};default:return null}},[e.objectName,e.table?.fields,T,h]),ct=b.useMemo(()=>({type:"object-grid",objectName:e.objectName,title:e.table?.title,description:e.table?.description,fields:T?.columns||h?.columns||e.table?.fields,columns:T?.columns||h?.columns||e.table?.columns,operations:{...j,create:!1},defaultFilters:T?.filter||h?.filter||e.table?.defaultFilters,defaultSort:T?.sort||h?.sort||e.table?.defaultSort,pageSize:e.table?.pageSize,selectable:e.table?.selectable,className:e.table?.className}),[e,j,T,h]),Ie=()=>{const i=k?k._id||k.id:void 0;return{type:"object-form",objectName:e.objectName,mode:V,recordId:i,title:e.form?.title,description:e.form?.description,fields:e.form?.fields,customFields:e.form?.customFields,groups:e.form?.groups,layout:e.form?.layout,columns:e.form?.columns,showSubmit:e.form?.showSubmit,submitText:e.form?.submitText,showCancel:e.form?.showCancel,cancelText:e.form?.cancelText,showReset:e.form?.showReset,initialValues:e.form?.initialValues,readOnly:e.form?.readOnly||V==="view",className:e.form?.className,onSuccess:at,onCancel:st}},Re=()=>{if(e.form?.title)return e.form.title;const i=C?.label||e.objectName;switch(V){case"create":return`Create ${i}`;case"edit":return`Edit ${i}`;case"view":return`View ${i}`;default:return i}},$e=b.useMemo(()=>{const i=p?.width;return i?typeof i=="number"?`max-w-[${i}px]`:`max-w-[${i}]`:""},[p]),ft=()=>t.jsx(l.Drawer,{open:S,onOpenChange:m,direction:"right",children:t.jsxs(l.DrawerContent,{className:l.cn("w-full sm:max-w-2xl",$e),children:[t.jsxs(l.DrawerHeader,{children:[t.jsx(l.DrawerTitle,{children:Re()}),e.form?.description&&t.jsx(l.DrawerDescription,{children:e.form.description})]}),t.jsx("div",{className:"flex-1 overflow-y-auto px-4 pb-4",children:t.jsx(me.ObjectForm,{schema:Ie(),dataSource:n})})]})}),pt=()=>t.jsx(l.Dialog,{open:S,onOpenChange:m,children:t.jsxs(l.DialogContent,{className:l.cn("max-w-2xl max-h-[90vh] overflow-y-auto",$e),children:[t.jsxs(l.DialogHeader,{children:[t.jsx(l.DialogTitle,{children:Re()}),e.form?.description&&t.jsx(l.DialogDescription,{children:e.form.description})]}),t.jsx(me.ObjectForm,{schema:Ie(),dataSource:n})]})}),bt=b.useMemo(()=>Object.keys(M).some(f=>M[f]!==void 0&&M[f]!==""&&M[f]!==null)?Object.entries(M).filter(([,f])=>f!==void 0&&f!==""&&f!==null).map(([f,a])=>({field:f,operator:"equals",value:a})):T?.filter||h?.filter||e.table?.defaultFilters,[M,T,h,e.table?.defaultFilters]),wt=b.useMemo(()=>q.length>0?q:T?.sort||h?.sort||e.table?.defaultSort,[q,T,h,e.table?.defaultSort]),gt=()=>{const i=`${e.objectName}-${G||h?.id||"default"}-${r}-${d}`;if(E)return E({schema:{type:"list-view",objectName:e.objectName,viewType:r,fields:T?.columns||h?.columns||e.table?.fields,filters:bt,sort:wt,options:T?.options||h},dataSource:n,onEdit:te,onRowClick:W,className:"h-full"});if(r!=="grid"){const f=dt(r);if(f&&oe)return t.jsx(oe,{schema:f,dataSource:n,data:L,loading:ye},i);if(!oe)return t.jsx("div",{className:"flex items-center justify-center h-40 text-muted-foreground",children:t.jsxs("p",{children:["SchemaRenderer not available. Install @object-ui/react to render ",r," views."]})})}return t.jsx(Me.ObjectGrid,{schema:ct,dataSource:n,onRowClick:W,onEdit:j.update!==!1?te:void 0,onDelete:j.delete!==!1?ae:void 0,onBulkDelete:j.delete!==!1?ve:void 0},i)},yt=()=>{if(!Q)return null;const i=Object.entries(z);return i.length<=1?null:t.jsx(l.Tabs,{value:G,onValueChange:ut,className:"w-full",children:t.jsx(l.TabsList,{className:"w-auto",children:i.map(([f,a])=>t.jsx(l.TabsTrigger,{value:f,className:"text-sm",children:a.label||f},f))})})},vt=()=>{const i=e.showCreate!==!1&&j.create!==!1,f=e.showViewSwitcher===!0,a=yt();return!a&&!f&&!i&&!N?null:t.jsxs("div",{className:"flex flex-col gap-3",children:[a,(f||i||N)&&t.jsxs("div",{className:"flex items-center justify-between gap-4",children:[t.jsx("div",{className:"flex items-center gap-2",children:f&&Pe&&t.jsx(pe,{schema:Pe,onViewChange:ot,className:"overflow-x-auto"})}),t.jsxs("div",{className:"flex items-center gap-2",children:[N,i&&t.jsxs(l.Button,{size:"sm",onClick:ee,children:[t.jsx($.Plus,{className:"h-4 w-4"}),"Create"]})]})]})]})},Le=p?.mode==="modal"?"modal":p?.mode==="drawer"?"drawer":v;return t.jsxs("div",{className:l.cn("flex flex-col h-full",c),children:[(e.title||e.description)&&t.jsxs("div",{className:"mb-4 shrink-0",children:[e.title&&t.jsx("h2",{className:"text-2xl font-bold tracking-tight",children:e.title}),e.description&&t.jsx("p",{className:"text-muted-foreground mt-1",children:e.description})]}),t.jsx("div",{className:"mb-4 shrink-0",children:vt()}),t.jsx("div",{className:"flex-1 min-h-0",children:gt()}),Le==="drawer"&&ft(),Le==="modal"&&pt()]})},be=X("flex",{variants:{layout:{inline:"flex-col space-y-4",popover:"items-center",drawer:"items-center"}},defaultVariants:{layout:"inline"}}),rt=e=>e==null||e===""?!0:Array.isArray(e)?e.length===0:typeof e=="object"?Object.values(e).every(n=>n==null||n===""):!1,lt=e=>Array.isArray(e)?{start:e[0]||"",end:e[1]||""}:e&&typeof e=="object"?{start:e.start||"",end:e.end||""}:{start:"",end:""},Ee=({schema:e,className:n,onChange:c})=>{const[u,w]=O.useState(e.values||{}),[g,F]=O.useState(!1);O.useEffect(()=>{e.values&&w(e.values)},[e.values]);const y=O.useCallback(o=>{c?.(o),e.onChange&&typeof window<"u"&&window.dispatchEvent(new CustomEvent(e.onChange,{detail:{values:o}}))},[c,e.onChange]),E=O.useCallback((o,k)=>{const A={...u,[o]:k};w(A),e.showApply||y(A)},[y,e.showApply,u]),N=O.useCallback(()=>{const o={};if(w(o),e.showApply){y(o);return}y(o)},[y,e.showApply]),C=O.useCallback(()=>{y(u),F(!1)},[y,u]),s=O.useMemo(()=>Object.values(u).filter(o=>!rt(o)).length,[u]),S=o=>{const k=o.label||o.field,A=o.placeholder||`Filter by ${k}`;switch(o.type){case"number":return t.jsx(l.Input,{type:"number",value:u[o.field]??"",placeholder:A,onChange:d=>{const x=d.target.value,L=x===""?"":Number(x);E(o.field,L)}});case"select":return t.jsxs(l.Select,{value:u[o.field]!==void 0?String(u[o.field]):"",onValueChange:d=>{const x=o.options?.find(L=>String(L.value)===d);E(o.field,x?x.value:d)},children:[t.jsx(l.SelectTrigger,{children:t.jsx(l.SelectValue,{placeholder:A})}),t.jsx(l.SelectContent,{children:o.options?.map(d=>t.jsx(l.SelectItem,{value:String(d.value),children:d.label},String(d.value)))})]});case"date":return t.jsx(l.Input,{type:"date",value:u[o.field]??"",onChange:d=>E(o.field,d.target.value)});case"date-range":{const d=lt(u[o.field]);return t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(l.Input,{type:"date",value:d.start??"",onChange:x=>{E(o.field,{...d,start:x.target.value})}}),t.jsx(l.Input,{type:"date",value:d.end??"",onChange:x=>{E(o.field,{...d,end:x.target.value})}})]})}case"boolean":return t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(l.Checkbox,{checked:!!u[o.field],onCheckedChange:d=>E(o.field,!!d)}),t.jsx("span",{className:"text-sm text-muted-foreground",children:"Enabled"})]});default:return t.jsx(l.Input,{value:u[o.field]??"",placeholder:A,onChange:d=>E(o.field,d.target.value)})}},m=t.jsxs("div",{className:"space-y-4",children:[t.jsx("div",{className:"grid gap-4 sm:grid-cols-2",children:e.filters.map(o=>t.jsxs("div",{className:"space-y-2",children:[t.jsx(l.Label,{className:"text-xs text-muted-foreground",children:o.label||o.field}),S(o)]},o.field))}),(e.showApply||e.showClear)&&t.jsxs("div",{className:"flex items-center justify-end gap-2 border-t pt-3",children:[e.showClear&&t.jsx(l.Button,{type:"button",variant:"ghost",size:"sm",onClick:N,children:"Clear"}),e.showApply&&t.jsx(l.Button,{type:"button",size:"sm",onClick:C,children:"Apply"})]})]}),V=e.layout||"inline";return V==="popover"?t.jsx("div",{className:l.cn(be({layout:V}),n),children:t.jsxs(l.Popover,{open:g,onOpenChange:F,children:[t.jsx(l.PopoverTrigger,{asChild:!0,children:t.jsxs(l.Button,{type:"button",variant:s>0?"secondary":"outline",size:"sm",className:"gap-2",children:[t.jsx($.SlidersHorizontal,{className:"h-4 w-4"}),"Filters",s>0&&t.jsx("span",{className:"inline-flex h-5 min-w-[20px] items-center justify-center rounded-full bg-primary/10 px-1 text-xs font-medium text-primary",children:s})]})}),t.jsx(l.PopoverContent,{align:"start",className:"w-[520px] p-4",children:m})]})}):V==="drawer"?t.jsxs("div",{className:l.cn(be({layout:V}),n),children:[t.jsxs(l.Button,{type:"button",variant:s>0?"secondary":"outline",size:"sm",className:"gap-2",onClick:()=>F(!0),children:[t.jsx($.SlidersHorizontal,{className:"h-4 w-4"}),"Filters",s>0&&t.jsx("span",{className:"inline-flex h-5 min-w-[20px] items-center justify-center rounded-full bg-primary/10 px-1 text-xs font-medium text-primary",children:s})]}),t.jsx(l.Drawer,{open:g,onOpenChange:F,children:t.jsxs(l.DrawerContent,{children:[t.jsxs(l.DrawerHeader,{children:[t.jsx(l.DrawerTitle,{children:"Filters"}),t.jsx(l.DrawerDescription,{children:"Refine the data with advanced filters."})]}),t.jsx("div",{className:"px-4 pb-6",children:m})]})})]}):t.jsxs("div",{className:l.cn(be({layout:V}),n),children:[m,!e.showApply&&e.showClear&&t.jsxs(l.Button,{type:"button",variant:"ghost",size:"sm",className:"gap-2",onClick:N,children:[t.jsx($.X,{className:"h-3.5 w-3.5"}),"Clear filters"]})]})},we=X("",{variants:{variant:{buttons:"flex flex-wrap gap-2",dropdown:"flex flex-wrap items-center gap-3",builder:"space-y-3"}},defaultVariants:{variant:"dropdown"}}),ge=e=>e?e.map(n=>({field:n.field,direction:n.direction})):[],_e=e=>e.map(n=>({id:`${n.field}-${n.direction}`,field:n.field,order:n.direction})),nt=e=>e.filter(n=>n.field).map(n=>({field:n.field,direction:n.order})),ke=({schema:e,className:n,onChange:c})=>{const[u,w]=O.useState(()=>ge(e.sort)),[g,F]=O.useState(()=>_e(ge(e.sort)));O.useEffect(()=>{const s=ge(e.sort);w(s),F(_e(s))},[e.sort]);const y=O.useCallback(s=>{w(s),c?.(s),e.onChange&&typeof window<"u"&&window.dispatchEvent(new CustomEvent(e.onChange,{detail:{sort:s}}))},[c,e.onChange]),E=O.useCallback(s=>{const S=u.find(o=>o.field===s),m=!!e.multiple;if(!S){const o=m?[...u,{field:s,direction:"asc"}]:[{field:s,direction:"asc"}];y(o);return}if(S.direction==="asc"){const o=u.map(k=>k.field===s?{...k,direction:"desc"}:k);y(o);return}const V=u.filter(o=>o.field!==s);y(V)},[y,e.multiple,u]);if((e.variant||"dropdown")==="buttons")return t.jsx("div",{className:l.cn(we({variant:"buttons"}),n),children:e.fields.map(s=>{const S=u.find(V=>V.field===s.field),m=S?.direction==="asc"?$.ArrowUp:$.ArrowDown;return t.jsxs(l.Button,{type:"button",variant:S?"secondary":"outline",size:"sm",onClick:()=>E(s.field),className:"gap-2",children:[t.jsx("span",{children:s.label||s.field}),S&&t.jsx(m,{className:"h-3.5 w-3.5"})]},s.field)})});if(e.multiple)return t.jsx("div",{className:l.cn(we({variant:"builder"}),n),children:t.jsx(l.SortBuilder,{fields:e.fields.map(s=>({value:s.field,label:s.label||s.field})),value:g,onChange:s=>{F(s),y(nt(s))}})});const C=u[0];return t.jsxs("div",{className:l.cn(we({variant:"dropdown"}),n),children:[t.jsxs(l.Select,{value:C?.field||"",onValueChange:s=>{if(!s){y([]);return}y([{field:s,direction:C?.direction||"asc"}])},children:[t.jsx(l.SelectTrigger,{className:"w-56",children:t.jsx(l.SelectValue,{placeholder:"Select field"})}),t.jsx(l.SelectContent,{children:e.fields.map(s=>t.jsx(l.SelectItem,{value:s.field,children:s.label||s.field},s.field))})]}),t.jsxs(l.Select,{value:C?.direction||"asc",onValueChange:s=>{C?.field&&y([{field:C.field,direction:s}])},children:[t.jsx(l.SelectTrigger,{className:"w-36",children:t.jsx(l.SelectValue,{})}),t.jsxs(l.SelectContent,{children:[t.jsx(l.SelectItem,{value:"asc",children:"Ascending"}),t.jsx(l.SelectItem,{value:"desc",children:"Descending"})]})]})]})};let Oe=b.createContext(null);try{const e=require("@object-ui/react");e.SchemaRendererContext&&(Oe=e.SchemaRendererContext)}catch{}const Ae=({schema:e})=>{const c=b.useContext(Oe)?.dataSource??null;return t.jsx(Te,{schema:e,dataSource:c})};J.ComponentRegistry.register("object-view",Ae,{namespace:"plugin-view",label:"Object View",category:"view",icon:"LayoutDashboard",inputs:[{name:"objectName",type:"string",label:"Object Name",required:!0},{name:"title",type:"string",label:"Title"},{name:"description",type:"string",label:"Description"},{name:"layout",type:"enum",label:"Form Layout",enum:["drawer","modal","page"]},{name:"defaultViewType",type:"enum",label:"Default View Type",enum:["grid","kanban","gallery","calendar","timeline","gantt","map"]},{name:"defaultListView",type:"string",label:"Default Named View"},{name:"showSearch",type:"boolean",label:"Show Search"},{name:"showFilters",type:"boolean",label:"Show Filters"},{name:"showCreate",type:"boolean",label:"Show Create Button"},{name:"showRefresh",type:"boolean",label:"Show Refresh Button"},{name:"showViewSwitcher",type:"boolean",label:"Show View Switcher"},{name:"listViews",type:"object",label:"Named List Views"},{name:"navigation",type:"object",label:"Navigation Config"},{name:"searchableFields",type:"array",label:"Searchable Fields"},{name:"filterableFields",type:"array",label:"Filterable Fields"}],defaultProps:{layout:"drawer",defaultViewType:"grid",showSearch:!0,showFilters:!0,showCreate:!0,showRefresh:!0,showViewSwitcher:!0}}),J.ComponentRegistry.register("view",Ae,{namespace:"plugin-view",label:"View",category:"view"}),J.ComponentRegistry.register("view-switcher",pe,{namespace:"view",label:"View Switcher",category:"view",icon:"LayoutGrid",inputs:[{name:"views",type:"array",label:"Views",required:!0},{name:"defaultView",type:"string",label:"Default View"},{name:"activeView",type:"string",label:"Active View"},{name:"variant",type:"enum",label:"Variant",enum:["tabs","buttons","dropdown"]},{name:"position",type:"enum",label:"Position",enum:["top","bottom","left","right"]},{name:"persistPreference",type:"boolean",label:"Persist Preference"},{name:"storageKey",type:"string",label:"Storage Key"},{name:"onViewChange",type:"string",label:"On View Change Event"}],defaultProps:{variant:"tabs",position:"top",defaultView:"grid",views:[{type:"grid",label:"Grid",schema:{type:"text",content:"Grid view"}},{type:"list",label:"List",schema:{type:"text",content:"List view"}}]}}),J.ComponentRegistry.register("filter-ui",Ee,{namespace:"view",label:"Filter UI",category:"view",icon:"SlidersHorizontal",inputs:[{name:"filters",type:"array",label:"Filters",required:!0},{name:"values",type:"object",label:"Values"},{name:"onChange",type:"string",label:"On Change Event"},{name:"showClear",type:"boolean",label:"Show Clear Button"},{name:"showApply",type:"boolean",label:"Show Apply Button"},{name:"layout",type:"enum",label:"Layout",enum:["inline","popover","drawer"]}],defaultProps:{layout:"inline",showApply:!1,showClear:!0,filters:[{field:"name",label:"Name",type:"text",placeholder:"Search name"},{field:"status",label:"Status",type:"select",options:[{label:"Open",value:"open"},{label:"Closed",value:"closed"}]},{field:"created_at",label:"Created",type:"date"}]}}),J.ComponentRegistry.register("sort-ui",ke,{namespace:"view",label:"Sort UI",category:"view",icon:"ArrowUpDown",inputs:[{name:"fields",type:"array",label:"Fields",required:!0},{name:"sort",type:"array",label:"Sort"},{name:"onChange",type:"string",label:"On Change Event"},{name:"multiple",type:"boolean",label:"Allow Multiple"},{name:"variant",type:"enum",label:"Variant",enum:["dropdown","buttons"]}],defaultProps:{variant:"dropdown",multiple:!0,fields:[{field:"name",label:"Name"},{field:"created_at",label:"Created At"}],sort:[{field:"name",direction:"asc"}]}});const it=({schema:e,className:n,children:c,dataSource:u,...w})=>{const g=e.props?.columns?{display:"grid",gridTemplateColumns:`repeat(${e.props.columns}, 1fr)`,gap:"1rem"}:void 0;return t.jsx("div",{className:n,style:g,...w,children:c})};J.ComponentRegistry.register("view:simple",it,{namespace:"plugin-view",label:"Simple View",category:"view"}),P.FilterUI=Ee,P.ObjectView=Te,P.SortUI=ke,P.ViewSwitcher=pe,Object.defineProperty(P,Symbol.toStringTag,{value:"Module"})}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@object-ui/plugin-view",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Object View plugin for Object UI",
|
|
@@ -17,19 +17,19 @@
|
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"class-variance-authority": "^0.7.1",
|
|
19
19
|
"lucide-react": "^0.563.0",
|
|
20
|
-
"@object-ui/components": "
|
|
21
|
-
"@object-ui/core": "
|
|
22
|
-
"@object-ui/plugin-form": "
|
|
23
|
-
"@object-ui/plugin-grid": "
|
|
24
|
-
"@object-ui/react": "
|
|
25
|
-
"@object-ui/types": "
|
|
20
|
+
"@object-ui/components": "3.0.1",
|
|
21
|
+
"@object-ui/core": "3.0.1",
|
|
22
|
+
"@object-ui/plugin-form": "3.0.1",
|
|
23
|
+
"@object-ui/plugin-grid": "3.0.1",
|
|
24
|
+
"@object-ui/react": "3.0.1",
|
|
25
|
+
"@object-ui/types": "3.0.1"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"react": "^18.0.0 || ^19.0.0",
|
|
29
29
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@vitejs/plugin-react": "^5.1.
|
|
32
|
+
"@vitejs/plugin-react": "^5.1.4",
|
|
33
33
|
"typescript": "^5.9.3",
|
|
34
34
|
"vite": "^7.3.1",
|
|
35
35
|
"vite-plugin-dts": "^4.5.4"
|
package/src/ObjectView.tsx
CHANGED
|
@@ -320,8 +320,8 @@ export const ObjectView: React.FC<ObjectViewProps> = ({
|
|
|
320
320
|
} else if (results && typeof results === 'object') {
|
|
321
321
|
if (Array.isArray((results as any).data)) {
|
|
322
322
|
items = (results as any).data;
|
|
323
|
-
} else if (Array.isArray((results as any).
|
|
324
|
-
items = (results as any).
|
|
323
|
+
} else if (Array.isArray((results as any).records)) {
|
|
324
|
+
items = (results as any).records;
|
|
325
325
|
}
|
|
326
326
|
}
|
|
327
327
|
|
|
@@ -0,0 +1,755 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Toolbar Consistency Tests
|
|
11
|
+
*
|
|
12
|
+
* Verifies that toolbar, filter, sort, and view-switcher controls render
|
|
13
|
+
* with consistent structure and accessible attributes across all view types.
|
|
14
|
+
*
|
|
15
|
+
* Strategy: Each section renders the relevant component in isolation using
|
|
16
|
+
* the same lightweight Shadcn mocks from sibling test files, then asserts
|
|
17
|
+
* ARIA roles, labels, and keyboard-accessibility invariants.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
21
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
22
|
+
import { ObjectView } from '../ObjectView';
|
|
23
|
+
import { FilterUI } from '../FilterUI';
|
|
24
|
+
import { SortUI } from '../SortUI';
|
|
25
|
+
import { ViewSwitcher } from '../ViewSwitcher';
|
|
26
|
+
import type {
|
|
27
|
+
ObjectViewSchema,
|
|
28
|
+
DataSource,
|
|
29
|
+
FilterUISchema,
|
|
30
|
+
SortUISchema,
|
|
31
|
+
ViewSwitcherSchema,
|
|
32
|
+
} from '@object-ui/types';
|
|
33
|
+
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Mocks – mirrors ObjectView.test.tsx
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
vi.mock('@object-ui/react', () => ({
|
|
38
|
+
SchemaRenderer: ({ schema }: any) => (
|
|
39
|
+
<div data-testid="schema-renderer" data-schema-type={schema?.type}>
|
|
40
|
+
{schema?.type}
|
|
41
|
+
</div>
|
|
42
|
+
),
|
|
43
|
+
SchemaRendererContext: null,
|
|
44
|
+
}));
|
|
45
|
+
|
|
46
|
+
vi.mock('@object-ui/plugin-grid', () => ({
|
|
47
|
+
ObjectGrid: ({ schema }: any) => (
|
|
48
|
+
<div data-testid="object-grid" data-object={schema?.objectName}>
|
|
49
|
+
Grid
|
|
50
|
+
</div>
|
|
51
|
+
),
|
|
52
|
+
}));
|
|
53
|
+
|
|
54
|
+
vi.mock('@object-ui/plugin-form', () => ({
|
|
55
|
+
ObjectForm: ({ schema }: any) => (
|
|
56
|
+
<div data-testid="object-form" data-mode={schema?.mode}>
|
|
57
|
+
Form ({schema?.mode})
|
|
58
|
+
</div>
|
|
59
|
+
),
|
|
60
|
+
}));
|
|
61
|
+
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
// Mock @object-ui/components – lightweight Shadcn stand-ins
|
|
64
|
+
// (mirrors FilterUI.test.tsx / SortUI.test.tsx)
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
vi.mock('@object-ui/components', async () => {
|
|
67
|
+
const React = await import('react');
|
|
68
|
+
const cn = (...args: any[]) => args.filter(Boolean).join(' ');
|
|
69
|
+
|
|
70
|
+
const Button = ({ children, onClick, variant, size, type, ...rest }: any) => (
|
|
71
|
+
<button onClick={onClick} data-variant={variant} data-size={size} type={type} {...rest}>
|
|
72
|
+
{children}
|
|
73
|
+
</button>
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const Input = ({ value, onChange, placeholder, type, ...rest }: any) => (
|
|
77
|
+
<input
|
|
78
|
+
value={value}
|
|
79
|
+
onChange={onChange}
|
|
80
|
+
placeholder={placeholder}
|
|
81
|
+
type={type}
|
|
82
|
+
data-testid={`input-${type || 'text'}`}
|
|
83
|
+
{...rest}
|
|
84
|
+
/>
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const Label = ({ children, className, htmlFor }: any) => (
|
|
88
|
+
<label className={className} htmlFor={htmlFor}>
|
|
89
|
+
{children}
|
|
90
|
+
</label>
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
const Checkbox = ({ checked, onCheckedChange }: any) => (
|
|
94
|
+
<input
|
|
95
|
+
type="checkbox"
|
|
96
|
+
data-testid="checkbox"
|
|
97
|
+
checked={checked}
|
|
98
|
+
onChange={(e: any) => onCheckedChange?.(e.target.checked)}
|
|
99
|
+
/>
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
// Select family with context for onValueChange propagation
|
|
103
|
+
const SelectCtx = React.createContext<((v: string) => void) | undefined>(undefined);
|
|
104
|
+
|
|
105
|
+
const Select = ({ children, value, onValueChange }: any) => (
|
|
106
|
+
<SelectCtx.Provider value={onValueChange}>
|
|
107
|
+
<div data-testid="select-root" data-value={value}>
|
|
108
|
+
{children}
|
|
109
|
+
</div>
|
|
110
|
+
</SelectCtx.Provider>
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
const SelectTrigger = ({ children, className }: any) => (
|
|
114
|
+
<button data-testid="select-trigger" className={className}>
|
|
115
|
+
{children}
|
|
116
|
+
</button>
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
const SelectValue = ({ placeholder }: any) => (
|
|
120
|
+
<span data-testid="select-value">{placeholder}</span>
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
const SelectContent = ({ children }: any) => (
|
|
124
|
+
<div data-testid="select-content">{children}</div>
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
const SelectItem = ({ children, value }: any) => {
|
|
128
|
+
const onValueChange = React.useContext(SelectCtx);
|
|
129
|
+
return (
|
|
130
|
+
<div
|
|
131
|
+
data-testid="select-item"
|
|
132
|
+
data-value={value}
|
|
133
|
+
role="option"
|
|
134
|
+
onClick={() => onValueChange?.(String(value))}
|
|
135
|
+
>
|
|
136
|
+
{children}
|
|
137
|
+
</div>
|
|
138
|
+
);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const Popover = ({ children, open }: any) => (
|
|
142
|
+
<div data-testid="popover" data-open={open}>{children}</div>
|
|
143
|
+
);
|
|
144
|
+
const PopoverTrigger = ({ children }: any) => (
|
|
145
|
+
<div data-testid="popover-trigger">{children}</div>
|
|
146
|
+
);
|
|
147
|
+
const PopoverContent = ({ children }: any) => (
|
|
148
|
+
<div data-testid="popover-content">{children}</div>
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
const Drawer = ({ children, open }: any) => (
|
|
152
|
+
<div data-testid="drawer" data-open={open}>{children}</div>
|
|
153
|
+
);
|
|
154
|
+
const DrawerContent = ({ children }: any) => (
|
|
155
|
+
<div data-testid="drawer-content">{children}</div>
|
|
156
|
+
);
|
|
157
|
+
const DrawerHeader = ({ children }: any) => (
|
|
158
|
+
<div data-testid="drawer-header">{children}</div>
|
|
159
|
+
);
|
|
160
|
+
const DrawerTitle = ({ children }: any) => (
|
|
161
|
+
<h2 data-testid="drawer-title">{children}</h2>
|
|
162
|
+
);
|
|
163
|
+
const DrawerDescription = ({ children }: any) => (
|
|
164
|
+
<p data-testid="drawer-description">{children}</p>
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
const Dialog = ({ children, open }: any) => (
|
|
168
|
+
<div data-testid="dialog" data-open={open}>{children}</div>
|
|
169
|
+
);
|
|
170
|
+
const DialogContent = ({ children }: any) => (
|
|
171
|
+
<div data-testid="dialog-content">{children}</div>
|
|
172
|
+
);
|
|
173
|
+
const DialogHeader = ({ children }: any) => (
|
|
174
|
+
<div data-testid="dialog-header">{children}</div>
|
|
175
|
+
);
|
|
176
|
+
const DialogTitle = ({ children }: any) => (
|
|
177
|
+
<h2 data-testid="dialog-title">{children}</h2>
|
|
178
|
+
);
|
|
179
|
+
const DialogDescription = ({ children }: any) => (
|
|
180
|
+
<p data-testid="dialog-description">{children}</p>
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
// Tabs family – render role="tablist" for TabsList
|
|
184
|
+
const TabsCtx = React.createContext<{ value: string; onValueChange?: (v: string) => void }>({
|
|
185
|
+
value: '',
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const Tabs = ({ children, value, onValueChange }: any) => (
|
|
189
|
+
<TabsCtx.Provider value={{ value, onValueChange }}>
|
|
190
|
+
<div data-testid="tabs">{children}</div>
|
|
191
|
+
</TabsCtx.Provider>
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
const TabsList = ({ children, className }: any) => (
|
|
195
|
+
<div role="tablist" className={className}>{children}</div>
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
const TabsTrigger = ({ children, value, className }: any) => {
|
|
199
|
+
const ctx = React.useContext(TabsCtx);
|
|
200
|
+
const isActive = ctx.value === value;
|
|
201
|
+
return (
|
|
202
|
+
<button
|
|
203
|
+
role="tab"
|
|
204
|
+
aria-selected={isActive}
|
|
205
|
+
data-state={isActive ? 'active' : 'inactive'}
|
|
206
|
+
className={className}
|
|
207
|
+
onClick={() => ctx.onValueChange?.(value)}
|
|
208
|
+
>
|
|
209
|
+
{children}
|
|
210
|
+
</button>
|
|
211
|
+
);
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const SortBuilder = ({ fields, value, onChange }: any) => (
|
|
215
|
+
<div data-testid="sort-builder" data-fields={JSON.stringify(fields)} data-value={JSON.stringify(value)}>
|
|
216
|
+
<button
|
|
217
|
+
data-testid="sort-builder-change"
|
|
218
|
+
onClick={() => onChange?.([{ id: 'date-desc', field: 'date', order: 'desc' }])}
|
|
219
|
+
>
|
|
220
|
+
Change Sort
|
|
221
|
+
</button>
|
|
222
|
+
</div>
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
cn,
|
|
227
|
+
Button,
|
|
228
|
+
Input,
|
|
229
|
+
Label,
|
|
230
|
+
Checkbox,
|
|
231
|
+
Select,
|
|
232
|
+
SelectTrigger,
|
|
233
|
+
SelectValue,
|
|
234
|
+
SelectContent,
|
|
235
|
+
SelectItem,
|
|
236
|
+
Popover,
|
|
237
|
+
PopoverTrigger,
|
|
238
|
+
PopoverContent,
|
|
239
|
+
Drawer,
|
|
240
|
+
DrawerContent,
|
|
241
|
+
DrawerHeader,
|
|
242
|
+
DrawerTitle,
|
|
243
|
+
DrawerDescription,
|
|
244
|
+
Dialog,
|
|
245
|
+
DialogContent,
|
|
246
|
+
DialogHeader,
|
|
247
|
+
DialogTitle,
|
|
248
|
+
DialogDescription,
|
|
249
|
+
Tabs,
|
|
250
|
+
TabsList,
|
|
251
|
+
TabsTrigger,
|
|
252
|
+
SortBuilder,
|
|
253
|
+
};
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// ---------------------------------------------------------------------------
|
|
257
|
+
// Shared helpers
|
|
258
|
+
// ---------------------------------------------------------------------------
|
|
259
|
+
const createMockDataSource = (overrides: Partial<DataSource> = {}): DataSource =>
|
|
260
|
+
({
|
|
261
|
+
find: vi.fn().mockResolvedValue([]),
|
|
262
|
+
findOne: vi.fn().mockResolvedValue(null),
|
|
263
|
+
create: vi.fn().mockResolvedValue({}),
|
|
264
|
+
update: vi.fn().mockResolvedValue({}),
|
|
265
|
+
delete: vi.fn().mockResolvedValue({}),
|
|
266
|
+
getObjectSchema: vi.fn().mockResolvedValue({
|
|
267
|
+
label: 'Contacts',
|
|
268
|
+
fields: {
|
|
269
|
+
name: { label: 'Name', type: 'text' },
|
|
270
|
+
email: { label: 'Email', type: 'text' },
|
|
271
|
+
status: {
|
|
272
|
+
label: 'Status',
|
|
273
|
+
type: 'select',
|
|
274
|
+
options: [
|
|
275
|
+
{ label: 'Active', value: 'active' },
|
|
276
|
+
{ label: 'Inactive', value: 'inactive' },
|
|
277
|
+
],
|
|
278
|
+
},
|
|
279
|
+
created_at: { label: 'Created', type: 'date' },
|
|
280
|
+
},
|
|
281
|
+
}),
|
|
282
|
+
...overrides,
|
|
283
|
+
} as DataSource);
|
|
284
|
+
|
|
285
|
+
// ===========================================================================
|
|
286
|
+
// 1. ObjectView renders a toolbar region
|
|
287
|
+
// ===========================================================================
|
|
288
|
+
describe('Toolbar consistency across view types', () => {
|
|
289
|
+
let mockDataSource: DataSource;
|
|
290
|
+
|
|
291
|
+
beforeEach(() => {
|
|
292
|
+
vi.clearAllMocks();
|
|
293
|
+
mockDataSource = createMockDataSource();
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
describe('ObjectView toolbar region', () => {
|
|
297
|
+
it('renders a toolbar container that wraps action buttons', () => {
|
|
298
|
+
const schema: ObjectViewSchema = {
|
|
299
|
+
type: 'object-view',
|
|
300
|
+
objectName: 'contacts',
|
|
301
|
+
title: 'Contacts',
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
const { container } = render(
|
|
305
|
+
<ObjectView schema={schema} dataSource={mockDataSource} />,
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
// The Create button lives inside the toolbar area
|
|
309
|
+
const createBtn = screen.getByText('Create');
|
|
310
|
+
expect(createBtn).toBeDefined();
|
|
311
|
+
// Toolbar wrapper is a parent div
|
|
312
|
+
expect(createBtn.closest('div')).toBeDefined();
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it('renders Create button as a focusable element', () => {
|
|
316
|
+
const schema: ObjectViewSchema = {
|
|
317
|
+
type: 'object-view',
|
|
318
|
+
objectName: 'contacts',
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
render(<ObjectView schema={schema} dataSource={mockDataSource} />);
|
|
322
|
+
|
|
323
|
+
const btn = screen.getByText('Create');
|
|
324
|
+
expect(btn.tagName).toBe('BUTTON');
|
|
325
|
+
// Buttons are keyboard-focusable by default (no tabIndex=-1)
|
|
326
|
+
expect(btn.getAttribute('tabindex')).not.toBe('-1');
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it('hides toolbar when no actions or tabs are needed', () => {
|
|
330
|
+
const schema: ObjectViewSchema = {
|
|
331
|
+
type: 'object-view',
|
|
332
|
+
objectName: 'contacts',
|
|
333
|
+
showCreate: false,
|
|
334
|
+
showViewSwitcher: false,
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
const { container } = render(
|
|
338
|
+
<ObjectView schema={schema} dataSource={mockDataSource} />,
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
// No Create button
|
|
342
|
+
expect(screen.queryByText('Create')).toBeNull();
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
// =========================================================================
|
|
347
|
+
// 2. Filter controls are accessible
|
|
348
|
+
// =========================================================================
|
|
349
|
+
describe('FilterUI accessibility', () => {
|
|
350
|
+
const makeFilterSchema = (overrides: Partial<FilterUISchema> = {}): FilterUISchema => ({
|
|
351
|
+
type: 'filter-ui',
|
|
352
|
+
filters: [
|
|
353
|
+
{
|
|
354
|
+
field: 'status',
|
|
355
|
+
label: 'Status',
|
|
356
|
+
type: 'select',
|
|
357
|
+
options: [
|
|
358
|
+
{ label: 'Active', value: 'active' },
|
|
359
|
+
{ label: 'Inactive', value: 'inactive' },
|
|
360
|
+
],
|
|
361
|
+
},
|
|
362
|
+
{ field: 'name', label: 'Name', type: 'text' },
|
|
363
|
+
],
|
|
364
|
+
...overrides,
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it('renders a visible label for each filter field', () => {
|
|
368
|
+
render(<FilterUI schema={makeFilterSchema()} />);
|
|
369
|
+
|
|
370
|
+
expect(screen.getByText('Status')).toBeInTheDocument();
|
|
371
|
+
expect(screen.getByText('Name')).toBeInTheDocument();
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it('renders text filter inputs with descriptive placeholders', () => {
|
|
375
|
+
render(
|
|
376
|
+
<FilterUI
|
|
377
|
+
schema={makeFilterSchema({
|
|
378
|
+
filters: [{ field: 'search', label: 'Search', type: 'text' }],
|
|
379
|
+
})}
|
|
380
|
+
/>,
|
|
381
|
+
);
|
|
382
|
+
|
|
383
|
+
const input = screen.getByPlaceholderText('Filter by Search');
|
|
384
|
+
expect(input).toBeInTheDocument();
|
|
385
|
+
expect(input.tagName).toBe('INPUT');
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
it('renders select filters with option role="option" items', () => {
|
|
389
|
+
render(<FilterUI schema={makeFilterSchema()} />);
|
|
390
|
+
|
|
391
|
+
const options = screen.getAllByRole('option');
|
|
392
|
+
expect(options.length).toBeGreaterThanOrEqual(2);
|
|
393
|
+
expect(options[0]).toHaveAttribute('data-value', 'active');
|
|
394
|
+
expect(options[1]).toHaveAttribute('data-value', 'inactive');
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it('renders filters consistently in popover layout', () => {
|
|
398
|
+
render(<FilterUI schema={makeFilterSchema({ layout: 'popover' })} />);
|
|
399
|
+
|
|
400
|
+
// Popover trigger should contain a "Filters" label
|
|
401
|
+
expect(screen.getByText('Filters')).toBeInTheDocument();
|
|
402
|
+
// Filter labels are still present inside popover content
|
|
403
|
+
expect(screen.getByText('Status')).toBeInTheDocument();
|
|
404
|
+
expect(screen.getByText('Name')).toBeInTheDocument();
|
|
405
|
+
});
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
// =========================================================================
|
|
409
|
+
// 3. Sort controls render consistently with proper attributes
|
|
410
|
+
// =========================================================================
|
|
411
|
+
describe('SortUI accessibility', () => {
|
|
412
|
+
const makeSortSchema = (overrides: Partial<SortUISchema> = {}): SortUISchema => ({
|
|
413
|
+
type: 'sort-ui',
|
|
414
|
+
fields: [
|
|
415
|
+
{ field: 'name', label: 'Name' },
|
|
416
|
+
{ field: 'date', label: 'Date' },
|
|
417
|
+
],
|
|
418
|
+
...overrides,
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
it('renders sort buttons as focusable button elements', () => {
|
|
422
|
+
render(<SortUI schema={makeSortSchema({ variant: 'buttons' })} />);
|
|
423
|
+
|
|
424
|
+
const buttons = screen.getAllByRole('button');
|
|
425
|
+
expect(buttons).toHaveLength(2);
|
|
426
|
+
buttons.forEach((btn) => {
|
|
427
|
+
expect(btn.tagName).toBe('BUTTON');
|
|
428
|
+
expect(btn.getAttribute('tabindex')).not.toBe('-1');
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
it('renders active sort with secondary variant for visual distinction', () => {
|
|
433
|
+
render(
|
|
434
|
+
<SortUI
|
|
435
|
+
schema={makeSortSchema({
|
|
436
|
+
variant: 'buttons',
|
|
437
|
+
sort: [{ field: 'name', direction: 'asc' }],
|
|
438
|
+
})}
|
|
439
|
+
/>,
|
|
440
|
+
);
|
|
441
|
+
|
|
442
|
+
const nameBtn = screen.getByText('Name').closest('button')!;
|
|
443
|
+
expect(nameBtn).toHaveAttribute('data-variant', 'secondary');
|
|
444
|
+
|
|
445
|
+
const dateBtn = screen.getByText('Date').closest('button')!;
|
|
446
|
+
expect(dateBtn).toHaveAttribute('data-variant', 'outline');
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
it('renders dropdown variant with select controls', () => {
|
|
450
|
+
render(<SortUI schema={makeSortSchema({ variant: 'dropdown' })} />);
|
|
451
|
+
|
|
452
|
+
const selectRoots = screen.getAllByTestId('select-root');
|
|
453
|
+
// Field selector + direction selector
|
|
454
|
+
expect(selectRoots).toHaveLength(2);
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
it('renders sort direction options (Ascending / Descending)', () => {
|
|
458
|
+
render(<SortUI schema={makeSortSchema({ variant: 'dropdown' })} />);
|
|
459
|
+
|
|
460
|
+
expect(screen.getByText('Ascending')).toBeInTheDocument();
|
|
461
|
+
expect(screen.getByText('Descending')).toBeInTheDocument();
|
|
462
|
+
});
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
// =========================================================================
|
|
466
|
+
// 4. Toolbar actions are keyboard-accessible
|
|
467
|
+
// =========================================================================
|
|
468
|
+
describe('Toolbar keyboard accessibility', () => {
|
|
469
|
+
it('Create button responds to keyboard activation', () => {
|
|
470
|
+
const schema: ObjectViewSchema = {
|
|
471
|
+
type: 'object-view',
|
|
472
|
+
objectName: 'contacts',
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
render(<ObjectView schema={schema} dataSource={mockDataSource} />);
|
|
476
|
+
|
|
477
|
+
const createBtn = screen.getByText('Create');
|
|
478
|
+
// Simulate keyboard activation (Enter key on a focused button triggers click)
|
|
479
|
+
fireEvent.keyDown(createBtn, { key: 'Enter', code: 'Enter' });
|
|
480
|
+
fireEvent.keyUp(createBtn, { key: 'Enter', code: 'Enter' });
|
|
481
|
+
// Button is a native <button>, so keyboard activation is inherent
|
|
482
|
+
expect(createBtn.tagName).toBe('BUTTON');
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
it('sort buttons respond to click events (keyboard proxied)', () => {
|
|
486
|
+
const onChange = vi.fn();
|
|
487
|
+
render(
|
|
488
|
+
<SortUI
|
|
489
|
+
schema={{
|
|
490
|
+
type: 'sort-ui',
|
|
491
|
+
fields: [{ field: 'name', label: 'Name' }],
|
|
492
|
+
variant: 'buttons',
|
|
493
|
+
}}
|
|
494
|
+
onChange={onChange}
|
|
495
|
+
/>,
|
|
496
|
+
);
|
|
497
|
+
|
|
498
|
+
const btn = screen.getByText('Name').closest('button')!;
|
|
499
|
+
fireEvent.click(btn);
|
|
500
|
+
expect(onChange).toHaveBeenCalledWith([{ field: 'name', direction: 'asc' }]);
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
it('filter text inputs accept keyboard input', () => {
|
|
504
|
+
const onChange = vi.fn();
|
|
505
|
+
render(
|
|
506
|
+
<FilterUI
|
|
507
|
+
schema={{
|
|
508
|
+
type: 'filter-ui',
|
|
509
|
+
filters: [{ field: 'query', label: 'Search', type: 'text' }],
|
|
510
|
+
}}
|
|
511
|
+
onChange={onChange}
|
|
512
|
+
/>,
|
|
513
|
+
);
|
|
514
|
+
|
|
515
|
+
const input = screen.getByPlaceholderText('Filter by Search');
|
|
516
|
+
fireEvent.change(input, { target: { value: 'test' } });
|
|
517
|
+
expect(onChange).toHaveBeenCalledWith({ query: 'test' });
|
|
518
|
+
});
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
// =========================================================================
|
|
522
|
+
// 5. Search input in toolbar has proper label and role
|
|
523
|
+
// =========================================================================
|
|
524
|
+
describe('Search input accessibility', () => {
|
|
525
|
+
it('filter text input has an associated label element', () => {
|
|
526
|
+
render(
|
|
527
|
+
<FilterUI
|
|
528
|
+
schema={{
|
|
529
|
+
type: 'filter-ui',
|
|
530
|
+
filters: [{ field: 'search', label: 'Search', type: 'text' }],
|
|
531
|
+
}}
|
|
532
|
+
/>,
|
|
533
|
+
);
|
|
534
|
+
|
|
535
|
+
// Label with text "Search" should exist
|
|
536
|
+
expect(screen.getByText('Search')).toBeInTheDocument();
|
|
537
|
+
// Input should have descriptive placeholder
|
|
538
|
+
const input = screen.getByPlaceholderText('Filter by Search');
|
|
539
|
+
expect(input).toBeInTheDocument();
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
it('filter text input is an <input> element that is focusable', () => {
|
|
543
|
+
render(
|
|
544
|
+
<FilterUI
|
|
545
|
+
schema={{
|
|
546
|
+
type: 'filter-ui',
|
|
547
|
+
filters: [{ field: 'q', label: 'Quick Search', type: 'text' }],
|
|
548
|
+
}}
|
|
549
|
+
/>,
|
|
550
|
+
);
|
|
551
|
+
|
|
552
|
+
const input = screen.getByPlaceholderText('Filter by Quick Search');
|
|
553
|
+
expect(input.tagName).toBe('INPUT');
|
|
554
|
+
expect(input.getAttribute('tabindex')).not.toBe('-1');
|
|
555
|
+
});
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
// =========================================================================
|
|
559
|
+
// 6. View type selector renders with role="tablist"
|
|
560
|
+
// =========================================================================
|
|
561
|
+
describe('ViewSwitcher tablist rendering', () => {
|
|
562
|
+
const makeViewSwitcherSchema = (
|
|
563
|
+
overrides: Partial<ViewSwitcherSchema> = {},
|
|
564
|
+
): ViewSwitcherSchema => ({
|
|
565
|
+
type: 'view-switcher',
|
|
566
|
+
views: [
|
|
567
|
+
{ type: 'grid', label: 'Grid' },
|
|
568
|
+
{ type: 'kanban', label: 'Kanban' },
|
|
569
|
+
{ type: 'calendar', label: 'Calendar' },
|
|
570
|
+
],
|
|
571
|
+
variant: 'tabs',
|
|
572
|
+
...overrides,
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
it('renders tabs variant with role="tablist"', () => {
|
|
576
|
+
render(<ViewSwitcher schema={makeViewSwitcherSchema()} />);
|
|
577
|
+
|
|
578
|
+
const tablist = screen.getByRole('tablist');
|
|
579
|
+
expect(tablist).toBeInTheDocument();
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
it('renders individual tabs with role="tab"', () => {
|
|
583
|
+
render(<ViewSwitcher schema={makeViewSwitcherSchema()} />);
|
|
584
|
+
|
|
585
|
+
const tabs = screen.getAllByRole('tab');
|
|
586
|
+
expect(tabs).toHaveLength(3);
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
it('marks the active tab with aria-selected="true"', () => {
|
|
590
|
+
render(
|
|
591
|
+
<ViewSwitcher
|
|
592
|
+
schema={makeViewSwitcherSchema({ activeView: 'kanban' })}
|
|
593
|
+
/>,
|
|
594
|
+
);
|
|
595
|
+
|
|
596
|
+
const tabs = screen.getAllByRole('tab');
|
|
597
|
+
const kanbanTab = tabs.find((t) => t.textContent?.includes('Kanban'));
|
|
598
|
+
expect(kanbanTab).toBeDefined();
|
|
599
|
+
expect(kanbanTab!.getAttribute('aria-selected')).toBe('true');
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
it('marks inactive tabs with aria-selected="false"', () => {
|
|
603
|
+
render(
|
|
604
|
+
<ViewSwitcher
|
|
605
|
+
schema={makeViewSwitcherSchema({ activeView: 'grid' })}
|
|
606
|
+
/>,
|
|
607
|
+
);
|
|
608
|
+
|
|
609
|
+
const tabs = screen.getAllByRole('tab');
|
|
610
|
+
const kanbanTab = tabs.find((t) => t.textContent?.includes('Kanban'));
|
|
611
|
+
expect(kanbanTab!.getAttribute('aria-selected')).toBe('false');
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
it('tabs are keyboard-activatable via click', () => {
|
|
615
|
+
const onViewChange = vi.fn();
|
|
616
|
+
render(
|
|
617
|
+
<ViewSwitcher
|
|
618
|
+
schema={makeViewSwitcherSchema()}
|
|
619
|
+
onViewChange={onViewChange}
|
|
620
|
+
/>,
|
|
621
|
+
);
|
|
622
|
+
|
|
623
|
+
const tabs = screen.getAllByRole('tab');
|
|
624
|
+
const calendarTab = tabs.find((t) => t.textContent?.includes('Calendar'));
|
|
625
|
+
fireEvent.click(calendarTab!);
|
|
626
|
+
|
|
627
|
+
expect(onViewChange).toHaveBeenCalledWith('calendar');
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
it('renders buttons variant without tablist role', () => {
|
|
631
|
+
render(
|
|
632
|
+
<ViewSwitcher
|
|
633
|
+
schema={makeViewSwitcherSchema({ variant: 'buttons' })}
|
|
634
|
+
/>,
|
|
635
|
+
);
|
|
636
|
+
|
|
637
|
+
expect(screen.queryByRole('tablist')).not.toBeInTheDocument();
|
|
638
|
+
// Should render plain buttons instead
|
|
639
|
+
const buttons = screen.getAllByRole('button');
|
|
640
|
+
expect(buttons.length).toBe(3);
|
|
641
|
+
});
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
// =========================================================================
|
|
645
|
+
// 7. Density / view variant selector renders with accessible options
|
|
646
|
+
// =========================================================================
|
|
647
|
+
describe('ViewSwitcher dropdown variant accessibility', () => {
|
|
648
|
+
const makeDropdownSchema = (
|
|
649
|
+
overrides: Partial<ViewSwitcherSchema> = {},
|
|
650
|
+
): ViewSwitcherSchema => ({
|
|
651
|
+
type: 'view-switcher',
|
|
652
|
+
views: [
|
|
653
|
+
{ type: 'grid', label: 'Grid' },
|
|
654
|
+
{ type: 'kanban', label: 'Kanban' },
|
|
655
|
+
],
|
|
656
|
+
variant: 'dropdown',
|
|
657
|
+
...overrides,
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
it('renders dropdown with select-root controls', () => {
|
|
661
|
+
render(<ViewSwitcher schema={makeDropdownSchema()} />);
|
|
662
|
+
|
|
663
|
+
const selectRoot = screen.getByTestId('select-root');
|
|
664
|
+
expect(selectRoot).toBeInTheDocument();
|
|
665
|
+
});
|
|
666
|
+
|
|
667
|
+
it('renders all view options inside the select', () => {
|
|
668
|
+
render(<ViewSwitcher schema={makeDropdownSchema()} />);
|
|
669
|
+
|
|
670
|
+
const items = screen.getAllByTestId('select-item');
|
|
671
|
+
expect(items).toHaveLength(2);
|
|
672
|
+
expect(items[0]).toHaveTextContent('Grid');
|
|
673
|
+
expect(items[1]).toHaveTextContent('Kanban');
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
it('renders option items with role="option"', () => {
|
|
677
|
+
render(<ViewSwitcher schema={makeDropdownSchema()} />);
|
|
678
|
+
|
|
679
|
+
const options = screen.getAllByRole('option');
|
|
680
|
+
expect(options.length).toBe(2);
|
|
681
|
+
});
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
// =========================================================================
|
|
685
|
+
// Cross-view consistency: named list views use tablist
|
|
686
|
+
// =========================================================================
|
|
687
|
+
describe('Named list views tablist consistency', () => {
|
|
688
|
+
it('renders named view tabs with role="tablist" for multiple views', () => {
|
|
689
|
+
const schema: ObjectViewSchema = {
|
|
690
|
+
type: 'object-view',
|
|
691
|
+
objectName: 'contacts',
|
|
692
|
+
listViews: {
|
|
693
|
+
all: { label: 'All Contacts', type: 'grid' },
|
|
694
|
+
active: { label: 'Active', type: 'grid', filter: [['status', '=', 'active']] },
|
|
695
|
+
},
|
|
696
|
+
defaultListView: 'all',
|
|
697
|
+
};
|
|
698
|
+
|
|
699
|
+
render(<ObjectView schema={schema} dataSource={mockDataSource} />);
|
|
700
|
+
|
|
701
|
+
const tablist = screen.getByRole('tablist');
|
|
702
|
+
expect(tablist).toBeInTheDocument();
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
it('renders individual named view tabs with role="tab"', () => {
|
|
706
|
+
const schema: ObjectViewSchema = {
|
|
707
|
+
type: 'object-view',
|
|
708
|
+
objectName: 'contacts',
|
|
709
|
+
listViews: {
|
|
710
|
+
all: { label: 'All Contacts', type: 'grid' },
|
|
711
|
+
active: { label: 'Active', type: 'grid' },
|
|
712
|
+
archived: { label: 'Archived', type: 'grid' },
|
|
713
|
+
},
|
|
714
|
+
defaultListView: 'all',
|
|
715
|
+
};
|
|
716
|
+
|
|
717
|
+
render(<ObjectView schema={schema} dataSource={mockDataSource} />);
|
|
718
|
+
|
|
719
|
+
const tabs = screen.getAllByRole('tab');
|
|
720
|
+
expect(tabs).toHaveLength(3);
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
it('marks default named view tab as active', () => {
|
|
724
|
+
const schema: ObjectViewSchema = {
|
|
725
|
+
type: 'object-view',
|
|
726
|
+
objectName: 'contacts',
|
|
727
|
+
listViews: {
|
|
728
|
+
all: { label: 'All Contacts', type: 'grid' },
|
|
729
|
+
active: { label: 'Active', type: 'grid' },
|
|
730
|
+
},
|
|
731
|
+
defaultListView: 'all',
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
render(<ObjectView schema={schema} dataSource={mockDataSource} />);
|
|
735
|
+
|
|
736
|
+
const tabs = screen.getAllByRole('tab');
|
|
737
|
+
const allTab = tabs.find((t) => t.textContent?.includes('All Contacts'));
|
|
738
|
+
expect(allTab!.getAttribute('aria-selected')).toBe('true');
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
it('does not render tablist when only one named view exists', () => {
|
|
742
|
+
const schema: ObjectViewSchema = {
|
|
743
|
+
type: 'object-view',
|
|
744
|
+
objectName: 'contacts',
|
|
745
|
+
listViews: {
|
|
746
|
+
all: { label: 'All Contacts', type: 'grid' },
|
|
747
|
+
},
|
|
748
|
+
};
|
|
749
|
+
|
|
750
|
+
render(<ObjectView schema={schema} dataSource={mockDataSource} />);
|
|
751
|
+
|
|
752
|
+
expect(screen.queryByRole('tablist')).toBeNull();
|
|
753
|
+
});
|
|
754
|
+
});
|
|
755
|
+
});
|
package/vite.config.ts
CHANGED