@object-ui/plugin-view 0.5.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +7 -6
- package/CHANGELOG.md +38 -0
- package/README.md +58 -0
- package/dist/index.js +1168 -349
- package/dist/index.umd.cjs +2 -2
- package/dist/plugin-view/src/FilterUI.d.ts +16 -0
- package/dist/plugin-view/src/ObjectView.d.ts +85 -5
- package/dist/plugin-view/src/SortUI.d.ts +16 -0
- package/dist/plugin-view/src/ViewSwitcher.d.ts +16 -0
- package/dist/plugin-view/src/index.d.ts +7 -1
- package/package.json +9 -8
- package/src/FilterUI.tsx +317 -0
- package/src/ObjectView.tsx +668 -148
- package/src/SortUI.tsx +210 -0
- package/src/ViewSwitcher.tsx +311 -0
- package/src/__tests__/FilterUI.test.tsx +544 -0
- package/src/__tests__/ObjectView.test.tsx +375 -0
- package/src/__tests__/SortUI.test.tsx +380 -0
- package/src/__tests__/registration.test.tsx +32 -0
- package/src/__tests__/toolbar-consistency.test.tsx +755 -0
- package/src/index.tsx +147 -5
- package/vite.config.ts +1 -0
- package/vitest.config.ts +12 -0
- package/vitest.setup.ts +1 -0
package/src/index.tsx
CHANGED
|
@@ -6,24 +6,166 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import React from 'react';
|
|
9
|
+
import React, { useContext } from 'react';
|
|
10
10
|
import { ComponentRegistry } from '@object-ui/core';
|
|
11
11
|
import { ObjectView } from './ObjectView';
|
|
12
|
+
import { ViewSwitcher } from './ViewSwitcher';
|
|
13
|
+
import { FilterUI } from './FilterUI';
|
|
14
|
+
import { SortUI } from './SortUI';
|
|
12
15
|
|
|
13
|
-
export { ObjectView };
|
|
16
|
+
export { ObjectView, ViewSwitcher, FilterUI, SortUI };
|
|
14
17
|
export type { ObjectViewProps } from './ObjectView';
|
|
18
|
+
export type { ViewSwitcherProps } from './ViewSwitcher';
|
|
19
|
+
export type { FilterUIProps } from './FilterUI';
|
|
20
|
+
export type { SortUIProps } from './SortUI';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* SchemaRendererContext is created by @object-ui/react.
|
|
24
|
+
* We import it dynamically to avoid a circular dependency.
|
|
25
|
+
* The context value provides { dataSource }.
|
|
26
|
+
* A fallback context is created so hooks are never called conditionally.
|
|
27
|
+
*/
|
|
28
|
+
const FallbackContext = React.createContext<any>(null);
|
|
29
|
+
let SchemaRendererContext: React.Context<any> = FallbackContext;
|
|
30
|
+
try {
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
32
|
+
const mod = require('@object-ui/react');
|
|
33
|
+
// The context is re-exported from @object-ui/react
|
|
34
|
+
if (mod.SchemaRendererContext) {
|
|
35
|
+
SchemaRendererContext = mod.SchemaRendererContext;
|
|
36
|
+
}
|
|
37
|
+
} catch {
|
|
38
|
+
// @object-ui/react not available — registry-based dataSource only
|
|
39
|
+
}
|
|
15
40
|
|
|
16
41
|
// Register object-view component
|
|
17
42
|
const ObjectViewRenderer: React.FC<{ schema: any }> = ({ schema }) => {
|
|
18
|
-
|
|
43
|
+
// Resolve dataSource from SchemaRendererProvider context
|
|
44
|
+
const ctx = useContext(SchemaRendererContext);
|
|
45
|
+
const dataSource = ctx?.dataSource ?? null;
|
|
46
|
+
|
|
47
|
+
return <ObjectView schema={schema} dataSource={dataSource} />;
|
|
19
48
|
};
|
|
20
49
|
|
|
21
50
|
ComponentRegistry.register('object-view', ObjectViewRenderer, {
|
|
22
|
-
namespace: 'plugin-view'
|
|
51
|
+
namespace: 'plugin-view',
|
|
52
|
+
label: 'Object View',
|
|
53
|
+
category: 'view',
|
|
54
|
+
icon: 'LayoutDashboard',
|
|
55
|
+
inputs: [
|
|
56
|
+
{ name: 'objectName', type: 'string', label: 'Object Name', required: true },
|
|
57
|
+
{ name: 'title', type: 'string', label: 'Title' },
|
|
58
|
+
{ name: 'description', type: 'string', label: 'Description' },
|
|
59
|
+
{ name: 'layout', type: 'enum', label: 'Form Layout', enum: ['drawer', 'modal', 'page'] },
|
|
60
|
+
{ name: 'defaultViewType', type: 'enum', label: 'Default View Type', enum: ['grid', 'kanban', 'gallery', 'calendar', 'timeline', 'gantt', 'map'] },
|
|
61
|
+
{ name: 'defaultListView', type: 'string', label: 'Default Named View' },
|
|
62
|
+
{ name: 'showSearch', type: 'boolean', label: 'Show Search' },
|
|
63
|
+
{ name: 'showFilters', type: 'boolean', label: 'Show Filters' },
|
|
64
|
+
{ name: 'showCreate', type: 'boolean', label: 'Show Create Button' },
|
|
65
|
+
{ name: 'showRefresh', type: 'boolean', label: 'Show Refresh Button' },
|
|
66
|
+
{ name: 'showViewSwitcher', type: 'boolean', label: 'Show View Switcher' },
|
|
67
|
+
{ name: 'listViews', type: 'object', label: 'Named List Views' },
|
|
68
|
+
{ name: 'navigation', type: 'object', label: 'Navigation Config' },
|
|
69
|
+
{ name: 'searchableFields', type: 'array', label: 'Searchable Fields' },
|
|
70
|
+
{ name: 'filterableFields', type: 'array', label: 'Filterable Fields' },
|
|
71
|
+
],
|
|
72
|
+
defaultProps: {
|
|
73
|
+
layout: 'drawer',
|
|
74
|
+
defaultViewType: 'grid',
|
|
75
|
+
showSearch: true,
|
|
76
|
+
showFilters: true,
|
|
77
|
+
showCreate: true,
|
|
78
|
+
showRefresh: true,
|
|
79
|
+
showViewSwitcher: true,
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Register alias 'view' → same renderer
|
|
84
|
+
ComponentRegistry.register('view', ObjectViewRenderer, {
|
|
85
|
+
namespace: 'plugin-view',
|
|
86
|
+
label: 'View',
|
|
87
|
+
category: 'view',
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
ComponentRegistry.register('view-switcher', ViewSwitcher, {
|
|
91
|
+
namespace: 'view',
|
|
92
|
+
label: 'View Switcher',
|
|
93
|
+
category: 'view',
|
|
94
|
+
icon: 'LayoutGrid',
|
|
95
|
+
inputs: [
|
|
96
|
+
{ name: 'views', type: 'array', label: 'Views', required: true },
|
|
97
|
+
{ name: 'defaultView', type: 'string', label: 'Default View' },
|
|
98
|
+
{ name: 'activeView', type: 'string', label: 'Active View' },
|
|
99
|
+
{ name: 'variant', type: 'enum', label: 'Variant', enum: ['tabs', 'buttons', 'dropdown'] },
|
|
100
|
+
{ name: 'position', type: 'enum', label: 'Position', enum: ['top', 'bottom', 'left', 'right'] },
|
|
101
|
+
{ name: 'persistPreference', type: 'boolean', label: 'Persist Preference' },
|
|
102
|
+
{ name: 'storageKey', type: 'string', label: 'Storage Key' },
|
|
103
|
+
{ name: 'onViewChange', type: 'string', label: 'On View Change Event' },
|
|
104
|
+
],
|
|
105
|
+
defaultProps: {
|
|
106
|
+
variant: 'tabs',
|
|
107
|
+
position: 'top',
|
|
108
|
+
defaultView: 'grid',
|
|
109
|
+
views: [
|
|
110
|
+
{ type: 'grid', label: 'Grid', schema: { type: 'text', content: 'Grid view' } },
|
|
111
|
+
{ type: 'list', label: 'List', schema: { type: 'text', content: 'List view' } },
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
ComponentRegistry.register('filter-ui', FilterUI, {
|
|
117
|
+
namespace: 'view',
|
|
118
|
+
label: 'Filter UI',
|
|
119
|
+
category: 'view',
|
|
120
|
+
icon: 'SlidersHorizontal',
|
|
121
|
+
inputs: [
|
|
122
|
+
{ name: 'filters', type: 'array', label: 'Filters', required: true },
|
|
123
|
+
{ name: 'values', type: 'object', label: 'Values' },
|
|
124
|
+
{ name: 'onChange', type: 'string', label: 'On Change Event' },
|
|
125
|
+
{ name: 'showClear', type: 'boolean', label: 'Show Clear Button' },
|
|
126
|
+
{ name: 'showApply', type: 'boolean', label: 'Show Apply Button' },
|
|
127
|
+
{ name: 'layout', type: 'enum', label: 'Layout', enum: ['inline', 'popover', 'drawer'] },
|
|
128
|
+
],
|
|
129
|
+
defaultProps: {
|
|
130
|
+
layout: 'inline',
|
|
131
|
+
showApply: false,
|
|
132
|
+
showClear: true,
|
|
133
|
+
filters: [
|
|
134
|
+
{ field: 'name', label: 'Name', type: 'text', placeholder: 'Search name' },
|
|
135
|
+
{ field: 'status', label: 'Status', type: 'select', options: [
|
|
136
|
+
{ label: 'Open', value: 'open' },
|
|
137
|
+
{ label: 'Closed', value: 'closed' },
|
|
138
|
+
] },
|
|
139
|
+
{ field: 'created_at', label: 'Created', type: 'date' },
|
|
140
|
+
],
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
ComponentRegistry.register('sort-ui', SortUI, {
|
|
145
|
+
namespace: 'view',
|
|
146
|
+
label: 'Sort UI',
|
|
147
|
+
category: 'view',
|
|
148
|
+
icon: 'ArrowUpDown',
|
|
149
|
+
inputs: [
|
|
150
|
+
{ name: 'fields', type: 'array', label: 'Fields', required: true },
|
|
151
|
+
{ name: 'sort', type: 'array', label: 'Sort' },
|
|
152
|
+
{ name: 'onChange', type: 'string', label: 'On Change Event' },
|
|
153
|
+
{ name: 'multiple', type: 'boolean', label: 'Allow Multiple' },
|
|
154
|
+
{ name: 'variant', type: 'enum', label: 'Variant', enum: ['dropdown', 'buttons'] },
|
|
155
|
+
],
|
|
156
|
+
defaultProps: {
|
|
157
|
+
variant: 'dropdown',
|
|
158
|
+
multiple: true,
|
|
159
|
+
fields: [
|
|
160
|
+
{ field: 'name', label: 'Name' },
|
|
161
|
+
{ field: 'created_at', label: 'Created At' },
|
|
162
|
+
],
|
|
163
|
+
sort: [{ field: 'name', direction: 'asc' }],
|
|
164
|
+
},
|
|
23
165
|
});
|
|
24
166
|
|
|
25
167
|
// Simple View Renderer (Container)
|
|
26
|
-
const SimpleViewRenderer: React.FC<any> = ({ schema, className, children, ...props }) => {
|
|
168
|
+
const SimpleViewRenderer: React.FC<any> = ({ schema, className, children, dataSource, ...props }) => {
|
|
27
169
|
// If columns prop is present, use grid layout
|
|
28
170
|
const style = schema.props?.columns
|
|
29
171
|
? { display: 'grid', gridTemplateColumns: `repeat(${schema.props.columns}, 1fr)`, gap: '1rem' }
|
package/vite.config.ts
CHANGED
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/// <reference types="vitest" />
|
|
2
|
+
import { defineConfig } from 'vite';
|
|
3
|
+
import react from '@vitejs/plugin-react';
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [react()],
|
|
7
|
+
test: {
|
|
8
|
+
environment: 'happy-dom',
|
|
9
|
+
globals: true,
|
|
10
|
+
setupFiles: ['./vitest.setup.ts'],
|
|
11
|
+
},
|
|
12
|
+
});
|
package/vitest.setup.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|