@object-ui/plugin-aggrid 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +21 -0
- package/CHANGELOG.md +11 -0
- package/OBJECT_AGGRID_CN.md +483 -0
- package/QUICKSTART.md +186 -0
- package/README.md +221 -1
- package/dist/{AgGridImpl-DKkq6v1B.js → AgGridImpl-BQ6tBvrq.js} +61 -57
- package/dist/ObjectAgGridImpl-CGFeGvOH.js +372 -0
- package/dist/{index-B6NPAFZx.js → index-CLKYMco3.js} +273 -139
- package/dist/index.css +1 -1
- package/dist/index.js +4 -3
- package/dist/index.umd.cjs +5 -2
- package/dist/src/ObjectAgGridImpl.d.ts +6 -0
- package/dist/src/VirtualScrolling.d.ts +72 -0
- package/dist/src/index.d.ts +42 -0
- package/dist/src/object-aggrid.types.d.ts +74 -0
- package/package.json +10 -9
- package/src/AgGridImpl.tsx +5 -1
- package/src/ObjectAgGridImpl.tsx +603 -0
- package/src/VirtualScrolling.ts +74 -0
- package/src/index.test.ts +1 -1
- package/src/index.tsx +182 -0
- package/src/object-aggrid.test.ts +99 -0
- package/src/object-aggrid.types.ts +123 -0
- package/vite.config.ts +13 -0
package/README.md
CHANGED
|
@@ -31,6 +31,21 @@ pnpm add @object-ui/plugin-aggrid ag-grid-community ag-grid-react
|
|
|
31
31
|
|
|
32
32
|
Note: `ag-grid-community` and `ag-grid-react` are peer dependencies and must be installed separately.
|
|
33
33
|
|
|
34
|
+
### Next.js App Router Setup
|
|
35
|
+
|
|
36
|
+
If you're using Next.js with the App Router and dynamic imports, you may need to import AG Grid CSS in your root layout to ensure styles load correctly:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
// app/layout.tsx
|
|
40
|
+
import 'ag-grid-community/styles/ag-grid.css';
|
|
41
|
+
import 'ag-grid-community/styles/ag-theme-quartz.css';
|
|
42
|
+
import 'ag-grid-community/styles/ag-theme-alpine.css';
|
|
43
|
+
import 'ag-grid-community/styles/ag-theme-balham.css';
|
|
44
|
+
import 'ag-grid-community/styles/ag-theme-material.css';
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
This is necessary when the plugin is loaded dynamically (e.g., via `React.lazy()` or dynamic imports in client components), as Next.js may not properly process CSS imports from dynamically loaded modules.
|
|
48
|
+
|
|
34
49
|
## Usage
|
|
35
50
|
|
|
36
51
|
### Automatic Registration (Side-Effect Import)
|
|
@@ -497,7 +512,212 @@ pnpm type-check
|
|
|
497
512
|
|
|
498
513
|
MIT
|
|
499
514
|
|
|
500
|
-
##
|
|
515
|
+
## Object AgGrid - Metadata-Driven AG Grid
|
|
516
|
+
|
|
517
|
+
The `object-aggrid` component extends the standard `aggrid` with metadata-driven capabilities using `@objectstack/client`. It automatically fetches object schemas and data, and generates appropriate column definitions based on field types.
|
|
518
|
+
|
|
519
|
+
### Features
|
|
520
|
+
|
|
521
|
+
- **Automatic Metadata Fetching**: Retrieves object schema from ObjectStack backend
|
|
522
|
+
- **Automatic Data Loading**: Fetches data with pagination, filtering, and sorting
|
|
523
|
+
- **Field Type Support**: Supports all ObjectUI field types with appropriate formatters and renderers
|
|
524
|
+
- **Inline Editing**: Automatically saves changes to the backend
|
|
525
|
+
- **Zero Column Configuration**: Columns are generated from metadata
|
|
526
|
+
- **Selective Field Display**: Optionally show only specific fields
|
|
527
|
+
|
|
528
|
+
### Installation
|
|
529
|
+
|
|
530
|
+
```bash
|
|
531
|
+
pnpm add @object-ui/plugin-aggrid @object-ui/data-objectstack ag-grid-community ag-grid-react
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### Usage
|
|
535
|
+
|
|
536
|
+
```typescript
|
|
537
|
+
import '@object-ui/plugin-aggrid';
|
|
538
|
+
import { ObjectStackAdapter } from '@object-ui/data-objectstack';
|
|
539
|
+
|
|
540
|
+
// Create data source
|
|
541
|
+
const dataSource = new ObjectStackAdapter({
|
|
542
|
+
baseUrl: 'https://api.example.com',
|
|
543
|
+
token: 'your-api-token'
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
// Use in schema
|
|
547
|
+
const schema = {
|
|
548
|
+
type: 'object-aggrid',
|
|
549
|
+
objectName: 'contacts', // Object to fetch
|
|
550
|
+
dataSource: dataSource, // ObjectStack data source
|
|
551
|
+
pagination: true,
|
|
552
|
+
pageSize: 20,
|
|
553
|
+
theme: 'quartz',
|
|
554
|
+
height: 600
|
|
555
|
+
};
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
### Supported Field Types
|
|
559
|
+
|
|
560
|
+
The component automatically applies appropriate formatters and cell renderers for all field types:
|
|
561
|
+
|
|
562
|
+
- **Text Types**: text, textarea, markdown, html
|
|
563
|
+
- **Numeric Types**: number, currency (with locale formatting), percent
|
|
564
|
+
- **Boolean**: Displays ✓ Yes / ✗ No
|
|
565
|
+
- **Date/Time**: date, datetime, time (with locale formatting)
|
|
566
|
+
- **Contact**: email (clickable mailto), phone (clickable tel), url (clickable link)
|
|
567
|
+
- **Select/Lookup**: select, lookup, master_detail (shows labels)
|
|
568
|
+
- **Visual**: color (with color swatch), image, avatar, rating (stars)
|
|
569
|
+
- **Advanced**: formula, summary, auto_number, user, file
|
|
570
|
+
|
|
571
|
+
### Schema API for Object AgGrid
|
|
572
|
+
|
|
573
|
+
```typescript
|
|
574
|
+
{
|
|
575
|
+
type: 'object-aggrid',
|
|
576
|
+
|
|
577
|
+
// Required
|
|
578
|
+
objectName: string, // Name of the object to fetch
|
|
579
|
+
dataSource: DataSource, // ObjectStack data source instance
|
|
580
|
+
|
|
581
|
+
// Optional Field Configuration
|
|
582
|
+
fieldNames?: string[], // Show only these fields (default: all)
|
|
583
|
+
fields?: FieldMetadata[], // Override field metadata
|
|
584
|
+
|
|
585
|
+
// Query Parameters
|
|
586
|
+
filters?: Record<string, any>, // Query filters
|
|
587
|
+
sort?: Record<string, 'asc' | 'desc'>, // Sorting
|
|
588
|
+
pageSize?: number, // Rows per page (default: 10)
|
|
589
|
+
|
|
590
|
+
// Display Options (same as aggrid)
|
|
591
|
+
pagination?: boolean, // Enable pagination (default: true)
|
|
592
|
+
theme?: string, // Grid theme (default: 'quartz')
|
|
593
|
+
height?: number | string, // Grid height (default: 500)
|
|
594
|
+
|
|
595
|
+
// Editing
|
|
596
|
+
editable?: boolean, // Enable inline editing (auto-saves to backend)
|
|
597
|
+
|
|
598
|
+
// Export, Status Bar, Callbacks, etc. (same as aggrid)
|
|
599
|
+
exportConfig?: ExportConfig,
|
|
600
|
+
statusBar?: StatusBarConfig,
|
|
601
|
+
columnConfig?: ColumnConfig,
|
|
602
|
+
callbacks?: {
|
|
603
|
+
onDataLoaded?: (data: any[]) => void,
|
|
604
|
+
onDataError?: (error: Error) => void,
|
|
605
|
+
// ... other aggrid callbacks
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
### Examples
|
|
611
|
+
|
|
612
|
+
#### Basic Usage
|
|
613
|
+
|
|
614
|
+
```typescript
|
|
615
|
+
const schema = {
|
|
616
|
+
type: 'object-aggrid',
|
|
617
|
+
objectName: 'users',
|
|
618
|
+
dataSource: myDataSource,
|
|
619
|
+
pagination: true,
|
|
620
|
+
pageSize: 25
|
|
621
|
+
};
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
#### With Field Selection
|
|
625
|
+
|
|
626
|
+
```typescript
|
|
627
|
+
const schema = {
|
|
628
|
+
type: 'object-aggrid',
|
|
629
|
+
objectName: 'contacts',
|
|
630
|
+
dataSource: myDataSource,
|
|
631
|
+
fieldNames: ['name', 'email', 'phone', 'company'],
|
|
632
|
+
pagination: true
|
|
633
|
+
};
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
#### With Filters and Sorting
|
|
637
|
+
|
|
638
|
+
```typescript
|
|
639
|
+
const schema = {
|
|
640
|
+
type: 'object-aggrid',
|
|
641
|
+
objectName: 'products',
|
|
642
|
+
dataSource: myDataSource,
|
|
643
|
+
filters: {
|
|
644
|
+
category: 'Electronics',
|
|
645
|
+
price: { $lt: 1000 }
|
|
646
|
+
},
|
|
647
|
+
sort: {
|
|
648
|
+
price: 'asc'
|
|
649
|
+
},
|
|
650
|
+
pagination: true
|
|
651
|
+
};
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
#### Editable Grid with Auto-Save
|
|
655
|
+
|
|
656
|
+
```typescript
|
|
657
|
+
const schema = {
|
|
658
|
+
type: 'object-aggrid',
|
|
659
|
+
objectName: 'tasks',
|
|
660
|
+
dataSource: myDataSource,
|
|
661
|
+
editable: true, // Enable editing
|
|
662
|
+
singleClickEdit: true, // Single-click to edit
|
|
663
|
+
callbacks: {
|
|
664
|
+
onCellValueChanged: (event) => {
|
|
665
|
+
// Changes are automatically saved to backend
|
|
666
|
+
console.log('Saved:', event.data);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
#### With Export
|
|
673
|
+
|
|
674
|
+
```typescript
|
|
675
|
+
const schema = {
|
|
676
|
+
type: 'object-aggrid',
|
|
677
|
+
objectName: 'sales',
|
|
678
|
+
dataSource: myDataSource,
|
|
679
|
+
exportConfig: {
|
|
680
|
+
enabled: true,
|
|
681
|
+
fileName: 'sales-report.csv'
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
### Field Type Formatting Examples
|
|
687
|
+
|
|
688
|
+
**Currency Field:**
|
|
689
|
+
```typescript
|
|
690
|
+
// Schema defines: { type: 'currency', currency: 'USD', precision: 2 }
|
|
691
|
+
// Renders as: $1,234.56
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
**Percent Field:**
|
|
695
|
+
```typescript
|
|
696
|
+
// Schema defines: { type: 'percent', precision: 1 }
|
|
697
|
+
// Renders as: 45.5%
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
**Email Field:**
|
|
701
|
+
```typescript
|
|
702
|
+
// Schema defines: { type: 'email' }
|
|
703
|
+
// Renders as: <a href="mailto:user@example.com">user@example.com</a>
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
**Rating Field:**
|
|
707
|
+
```typescript
|
|
708
|
+
// Schema defines: { type: 'rating', max: 5 }
|
|
709
|
+
// Renders as: ⭐⭐⭐⭐⭐
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
**Color Field:**
|
|
713
|
+
```typescript
|
|
714
|
+
// Schema defines: { type: 'color' }
|
|
715
|
+
// Renders as: [color swatch] #FF5733
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
## License
|
|
719
|
+
|
|
720
|
+
|
|
501
721
|
|
|
502
722
|
- [AG Grid Community Documentation](https://www.ag-grid.com/documentation/)
|
|
503
723
|
- [AG Grid Column Definitions](https://www.ag-grid.com/documentation/javascript/column-definitions/)
|
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
import { j as
|
|
2
|
-
import { useRef as
|
|
3
|
-
import { AgGridReact as
|
|
4
|
-
function
|
|
5
|
-
rowData:
|
|
6
|
-
columnDefs:
|
|
7
|
-
gridOptions:
|
|
1
|
+
import { j as d } from "./index-CLKYMco3.js";
|
|
2
|
+
import { useRef as O, useMemo as f, useCallback as i } from "react";
|
|
3
|
+
import { AgGridReact as Q } from "ag-grid-react";
|
|
4
|
+
function Z({
|
|
5
|
+
rowData: u = [],
|
|
6
|
+
columnDefs: g = [],
|
|
7
|
+
gridOptions: m = {},
|
|
8
8
|
pagination: x = !1,
|
|
9
|
-
paginationPageSize:
|
|
10
|
-
domLayout:
|
|
11
|
-
animateRows:
|
|
9
|
+
paginationPageSize: b = 10,
|
|
10
|
+
domLayout: P = "normal",
|
|
11
|
+
animateRows: A = !0,
|
|
12
12
|
rowSelection: S,
|
|
13
13
|
theme: H = "quartz",
|
|
14
|
-
height:
|
|
15
|
-
className:
|
|
16
|
-
editable:
|
|
14
|
+
height: c = 500,
|
|
15
|
+
className: B = "",
|
|
16
|
+
editable: p = !1,
|
|
17
17
|
editType: j,
|
|
18
18
|
singleClickEdit: y = !1,
|
|
19
19
|
stopEditingWhenCellsLoseFocus: R = !0,
|
|
20
20
|
exportConfig: o,
|
|
21
|
-
statusBar:
|
|
21
|
+
statusBar: h,
|
|
22
22
|
callbacks: t,
|
|
23
23
|
columnConfig: a,
|
|
24
|
-
enableRangeSelection:
|
|
25
|
-
enableCharts:
|
|
24
|
+
enableRangeSelection: V = !1,
|
|
25
|
+
enableCharts: z = !1,
|
|
26
26
|
contextMenu: l
|
|
27
27
|
}) {
|
|
28
|
-
const n =
|
|
29
|
-
if (!
|
|
30
|
-
const e =
|
|
28
|
+
const n = O(null), C = f(() => {
|
|
29
|
+
if (!h?.enabled) return;
|
|
30
|
+
const e = h.aggregations || ["count", "sum", "avg"], s = [];
|
|
31
31
|
return e.includes("count") && s.push({ statusPanel: "agAggregationComponent", statusPanelParams: { aggFuncs: ["count"] } }), e.includes("sum") && s.push({ statusPanel: "agAggregationComponent", statusPanelParams: { aggFuncs: ["sum"] } }), e.includes("avg") && s.push({ statusPanel: "agAggregationComponent", statusPanelParams: { aggFuncs: ["avg"] } }), e.includes("min") && s.push({ statusPanel: "agAggregationComponent", statusPanelParams: { aggFuncs: ["min"] } }), e.includes("max") && s.push({ statusPanel: "agAggregationComponent", statusPanelParams: { aggFuncs: ["max"] } }), s;
|
|
32
|
-
}, [
|
|
32
|
+
}, [h]), v = i(() => {
|
|
33
33
|
if (!n.current?.api) return;
|
|
34
34
|
const e = {
|
|
35
35
|
fileName: o?.fileName || "export.csv",
|
|
@@ -38,17 +38,17 @@ function Y({
|
|
|
38
38
|
onlySelected: o?.onlySelected || !1
|
|
39
39
|
};
|
|
40
40
|
if (n.current.api.exportDataAsCsv(e), t?.onExport) {
|
|
41
|
-
const s = o?.onlySelected ? n.current.api.getSelectedRows() :
|
|
41
|
+
const s = o?.onlySelected ? n.current.api.getSelectedRows() : u;
|
|
42
42
|
t.onExport(s || [], "csv");
|
|
43
43
|
}
|
|
44
|
-
}, [o, t,
|
|
44
|
+
}, [o, t, u]), E = i((e) => {
|
|
45
45
|
if (!l?.enabled) return [];
|
|
46
46
|
const s = [];
|
|
47
47
|
return (l.items || ["copy", "copyWithHeaders", "separator", "export"]).forEach((r) => {
|
|
48
48
|
r === "export" ? s.push({
|
|
49
49
|
name: "Export CSV",
|
|
50
50
|
icon: "<span>📥</span>",
|
|
51
|
-
action: () =>
|
|
51
|
+
action: () => v()
|
|
52
52
|
}) : r === "autoSizeAll" ? s.push({
|
|
53
53
|
name: "Auto-size All Columns",
|
|
54
54
|
action: () => {
|
|
@@ -69,7 +69,7 @@ function Y({
|
|
|
69
69
|
}
|
|
70
70
|
});
|
|
71
71
|
})), s;
|
|
72
|
-
}, [l,
|
|
72
|
+
}, [l, v, t]), N = i((e) => {
|
|
73
73
|
t?.onCellClicked?.(e);
|
|
74
74
|
}, [t]), F = i((e) => {
|
|
75
75
|
t?.onRowClicked?.(e);
|
|
@@ -79,85 +79,89 @@ function Y({
|
|
|
79
79
|
t?.onCellValueChanged?.(e);
|
|
80
80
|
}, [t]), G = i((e) => {
|
|
81
81
|
n.current = e;
|
|
82
|
-
}, []), $ =
|
|
82
|
+
}, []), $ = f(() => g ? g.map((e) => {
|
|
83
83
|
const s = { ...e };
|
|
84
|
-
return
|
|
85
|
-
}) : [], [
|
|
86
|
-
...
|
|
84
|
+
return p && e.editable !== !1 && (s.editable = !0), a && (a.resizable !== void 0 && e.resizable === void 0 && (s.resizable = a.resizable), a.sortable !== void 0 && e.sortable === void 0 && (s.sortable = a.sortable), a.filterable !== void 0 && e.filter === void 0 && (s.filter = a.filterable)), s;
|
|
85
|
+
}) : [], [g, p, a]), q = f(() => ({
|
|
86
|
+
...m,
|
|
87
87
|
pagination: x,
|
|
88
|
-
paginationPageSize:
|
|
89
|
-
domLayout:
|
|
90
|
-
animateRows:
|
|
88
|
+
paginationPageSize: b,
|
|
89
|
+
domLayout: P,
|
|
90
|
+
animateRows: A,
|
|
91
91
|
rowSelection: S,
|
|
92
92
|
editType: j,
|
|
93
93
|
singleClickEdit: y,
|
|
94
94
|
stopEditingWhenCellsLoseFocus: R,
|
|
95
|
-
statusBar:
|
|
96
|
-
enableRangeSelection:
|
|
97
|
-
enableCharts:
|
|
98
|
-
getContextMenuItems: l?.enabled ?
|
|
95
|
+
statusBar: C ? { statusPanels: C } : void 0,
|
|
96
|
+
enableRangeSelection: V,
|
|
97
|
+
enableCharts: z,
|
|
98
|
+
getContextMenuItems: l?.enabled ? E : void 0,
|
|
99
99
|
// Default options for better UX
|
|
100
|
-
suppressCellFocus: !
|
|
100
|
+
suppressCellFocus: !p,
|
|
101
101
|
enableCellTextSelection: !0,
|
|
102
102
|
ensureDomOrder: !0,
|
|
103
|
+
// Virtual scrolling optimizations for large datasets
|
|
104
|
+
rowBuffer: m.rowBuffer ?? 10,
|
|
105
|
+
debounceVerticalScrollbar: m.debounceVerticalScrollbar ?? u.length > 1e3,
|
|
103
106
|
// Event handlers
|
|
104
|
-
onCellClicked:
|
|
107
|
+
onCellClicked: N,
|
|
105
108
|
onRowClicked: F,
|
|
106
109
|
onSelectionChanged: I,
|
|
107
110
|
onCellValueChanged: w,
|
|
108
111
|
onGridReady: G
|
|
109
112
|
}), [
|
|
110
|
-
|
|
113
|
+
m,
|
|
111
114
|
x,
|
|
115
|
+
b,
|
|
112
116
|
P,
|
|
113
117
|
A,
|
|
114
|
-
b,
|
|
115
118
|
S,
|
|
116
119
|
j,
|
|
117
120
|
y,
|
|
118
121
|
R,
|
|
119
|
-
|
|
122
|
+
C,
|
|
123
|
+
V,
|
|
120
124
|
z,
|
|
121
|
-
E,
|
|
122
125
|
l,
|
|
126
|
+
E,
|
|
127
|
+
p,
|
|
128
|
+
u.length,
|
|
123
129
|
N,
|
|
124
|
-
m,
|
|
125
|
-
V,
|
|
126
130
|
F,
|
|
127
131
|
I,
|
|
128
132
|
w,
|
|
129
133
|
G
|
|
130
|
-
]),
|
|
131
|
-
height: typeof
|
|
134
|
+
]), J = f(() => ({
|
|
135
|
+
height: typeof c == "number" ? `${c}px` : c,
|
|
132
136
|
width: "100%"
|
|
133
|
-
}), [
|
|
137
|
+
}), [c]), K = [
|
|
134
138
|
`ag-theme-${H}`,
|
|
135
139
|
"rounded-xl",
|
|
136
140
|
"border",
|
|
137
141
|
"border-border",
|
|
138
142
|
"overflow-hidden",
|
|
139
143
|
"shadow-lg",
|
|
140
|
-
|
|
144
|
+
B
|
|
141
145
|
].filter(Boolean).join(" ");
|
|
142
|
-
return /* @__PURE__ */
|
|
143
|
-
o?.enabled && /* @__PURE__ */
|
|
146
|
+
return /* @__PURE__ */ d.jsxs("div", { className: "ag-grid-container", children: [
|
|
147
|
+
o?.enabled && /* @__PURE__ */ d.jsx("div", { className: "mb-2 flex gap-2", children: /* @__PURE__ */ d.jsx(
|
|
144
148
|
"button",
|
|
145
149
|
{
|
|
146
|
-
onClick:
|
|
150
|
+
onClick: v,
|
|
147
151
|
className: "px-3 py-1.5 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 rounded-md transition-colors",
|
|
148
152
|
children: "Export CSV"
|
|
149
153
|
}
|
|
150
154
|
) }),
|
|
151
|
-
/* @__PURE__ */
|
|
155
|
+
/* @__PURE__ */ d.jsx(
|
|
152
156
|
"div",
|
|
153
157
|
{
|
|
154
|
-
className:
|
|
155
|
-
style:
|
|
156
|
-
children: /* @__PURE__ */
|
|
157
|
-
|
|
158
|
+
className: K,
|
|
159
|
+
style: J,
|
|
160
|
+
children: /* @__PURE__ */ d.jsx(
|
|
161
|
+
Q,
|
|
158
162
|
{
|
|
159
163
|
ref: n,
|
|
160
|
-
rowData:
|
|
164
|
+
rowData: u,
|
|
161
165
|
columnDefs: $,
|
|
162
166
|
gridOptions: q
|
|
163
167
|
}
|
|
@@ -167,5 +171,5 @@ function Y({
|
|
|
167
171
|
] });
|
|
168
172
|
}
|
|
169
173
|
export {
|
|
170
|
-
|
|
174
|
+
Z as default
|
|
171
175
|
};
|