argent-grid 0.1.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/.github/workflows/pages.yml +68 -0
- package/AGENTS.md +179 -0
- package/README.md +222 -0
- package/demo-app/README.md +70 -0
- package/demo-app/angular.json +78 -0
- package/demo-app/e2e/benchmark.spec.ts +53 -0
- package/demo-app/e2e/demo-page.spec.ts +77 -0
- package/demo-app/e2e/grid-features.spec.ts +269 -0
- package/demo-app/package-lock.json +14023 -0
- package/demo-app/package.json +36 -0
- package/demo-app/playwright-test-menu.js +19 -0
- package/demo-app/playwright.config.ts +23 -0
- package/demo-app/src/app/app.component.ts +10 -0
- package/demo-app/src/app/app.config.ts +13 -0
- package/demo-app/src/app/app.routes.ts +7 -0
- package/demo-app/src/app/demo-page/demo-page.component.css +313 -0
- package/demo-app/src/app/demo-page/demo-page.component.html +124 -0
- package/demo-app/src/app/demo-page/demo-page.component.ts +366 -0
- package/demo-app/src/index.html +19 -0
- package/demo-app/src/main.ts +6 -0
- package/demo-app/tsconfig.json +31 -0
- package/ng-package.json +8 -0
- package/package.json +60 -0
- package/plan.md +131 -0
- package/setup-vitest.ts +18 -0
- package/src/lib/argent-grid.module.ts +21 -0
- package/src/lib/components/argent-grid.component.css +483 -0
- package/src/lib/components/argent-grid.component.html +320 -0
- package/src/lib/components/argent-grid.component.spec.ts +189 -0
- package/src/lib/components/argent-grid.component.ts +1188 -0
- package/src/lib/directives/ag-grid-compatibility.directive.ts +92 -0
- package/src/lib/rendering/canvas-renderer.ts +962 -0
- package/src/lib/rendering/render/blit.spec.ts +453 -0
- package/src/lib/rendering/render/blit.ts +393 -0
- package/src/lib/rendering/render/cells.ts +369 -0
- package/src/lib/rendering/render/index.ts +105 -0
- package/src/lib/rendering/render/lines.ts +363 -0
- package/src/lib/rendering/render/theme.spec.ts +282 -0
- package/src/lib/rendering/render/theme.ts +201 -0
- package/src/lib/rendering/render/types.ts +279 -0
- package/src/lib/rendering/render/walk.spec.ts +360 -0
- package/src/lib/rendering/render/walk.ts +360 -0
- package/src/lib/rendering/utils/damage-tracker.spec.ts +444 -0
- package/src/lib/rendering/utils/damage-tracker.ts +423 -0
- package/src/lib/rendering/utils/index.ts +7 -0
- package/src/lib/services/grid.service.spec.ts +1039 -0
- package/src/lib/services/grid.service.ts +1284 -0
- package/src/lib/types/ag-grid-types.ts +970 -0
- package/src/public-api.ts +22 -0
- package/tsconfig.json +32 -0
- package/tsconfig.lib.json +11 -0
- package/tsconfig.spec.json +8 -0
- package/vitest.config.ts +55 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
name: Deploy to GitHub Pages
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
paths:
|
|
9
|
+
- 'src/**'
|
|
10
|
+
- 'demo-app/**'
|
|
11
|
+
- '.github/workflows/pages.yml'
|
|
12
|
+
- 'package.json'
|
|
13
|
+
- 'package-lock.json'
|
|
14
|
+
- 'ng-package.json'
|
|
15
|
+
- 'tsconfig.json'
|
|
16
|
+
workflow_dispatch:
|
|
17
|
+
|
|
18
|
+
permissions:
|
|
19
|
+
contents: read
|
|
20
|
+
pages: write
|
|
21
|
+
id-token: write
|
|
22
|
+
|
|
23
|
+
concurrency:
|
|
24
|
+
group: "pages"
|
|
25
|
+
cancel-in-progress: true
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
build-and-deploy:
|
|
29
|
+
environment:
|
|
30
|
+
name: github-pages
|
|
31
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
steps:
|
|
34
|
+
- name: Checkout
|
|
35
|
+
uses: actions/checkout@v4
|
|
36
|
+
|
|
37
|
+
- name: Setup Node.js
|
|
38
|
+
uses: actions/setup-node@v4
|
|
39
|
+
with:
|
|
40
|
+
node-version: '20'
|
|
41
|
+
cache: 'npm'
|
|
42
|
+
cache-dependency-path: './package-lock.json'
|
|
43
|
+
|
|
44
|
+
- name: Install root dependencies
|
|
45
|
+
run: npm ci
|
|
46
|
+
|
|
47
|
+
- name: Build ArgentGrid library
|
|
48
|
+
run: npm run build
|
|
49
|
+
|
|
50
|
+
- name: Install demo app dependencies
|
|
51
|
+
working-directory: ./demo-app
|
|
52
|
+
run: npm install
|
|
53
|
+
|
|
54
|
+
- name: Build demo app
|
|
55
|
+
working-directory: ./demo-app
|
|
56
|
+
run: npm run build:gh-pages
|
|
57
|
+
|
|
58
|
+
- name: Setup Pages
|
|
59
|
+
uses: actions/configure-pages@v5
|
|
60
|
+
|
|
61
|
+
- name: Upload artifact
|
|
62
|
+
uses: actions/upload-pages-artifact@v3
|
|
63
|
+
with:
|
|
64
|
+
path: './demo-app/dist/argent-grid-demo/browser'
|
|
65
|
+
|
|
66
|
+
- name: Deploy to GitHub Pages
|
|
67
|
+
id: deployment
|
|
68
|
+
uses: actions/deploy-pages@v4
|
package/AGENTS.md
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# ArgentGrid - Agent Context File
|
|
2
|
+
|
|
3
|
+
> **Purpose:** This file preserves critical project context for AI agents across sessions. Read this first when starting work.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
**ArgentGrid** is a free, high-performance alternative to AG Grid Enterprise built with Angular 18+. It uses canvas rendering for the data viewport to achieve 60fps performance with 100,000+ rows.
|
|
8
|
+
|
|
9
|
+
**Repository:** https://github.com/HainanZhao/ArgentGrid
|
|
10
|
+
|
|
11
|
+
**License:** MIT
|
|
12
|
+
|
|
13
|
+
## Core Architecture
|
|
14
|
+
|
|
15
|
+
### Hybrid Rendering Approach
|
|
16
|
+
```
|
|
17
|
+
┌─────────────────────────────────────┐
|
|
18
|
+
│ Header Layer (DOM-based) │ ← Accessibility, CSS styling
|
|
19
|
+
├─────────────────────────────────────┤
|
|
20
|
+
│ Canvas Layer (Data Viewport) │ ← High-performance rendering
|
|
21
|
+
│ - Virtual scrolling │
|
|
22
|
+
│ - Only renders visible rows │
|
|
23
|
+
│ - 100k+ rows at 60fps │
|
|
24
|
+
└─────────────────────────────────────┘
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Key Design Decisions
|
|
28
|
+
|
|
29
|
+
1. **Canvas for data viewport** - DOM-based grids struggle with 10k+ rows; canvas handles 100k+
|
|
30
|
+
2. **DOM headers** - Keep headers as DOM elements for accessibility and CSS styling
|
|
31
|
+
3. **AG Grid API compatibility** - 1:1 TypeScript definitions so users can switch by changing imports
|
|
32
|
+
4. **Headless logic layer** - GridService handles all data operations independently of rendering
|
|
33
|
+
5. **TDD approach** - Tests written before implementation (209 passing tests)
|
|
34
|
+
|
|
35
|
+
## Project Structure
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
ArgentGrid/
|
|
39
|
+
├── src/
|
|
40
|
+
│ ├── lib/
|
|
41
|
+
│ │ ├── types/
|
|
42
|
+
│ │ │ └── ag-grid-types.ts # AG Grid compatible TypeScript definitions
|
|
43
|
+
│ │ ├── components/
|
|
44
|
+
│ │ │ ├── argent-grid.component.ts
|
|
45
|
+
│ │ │ └── argent-grid.component.spec.ts
|
|
46
|
+
│ │ ├── services/
|
|
47
|
+
│ │ │ ├── grid.service.ts # Headless logic layer
|
|
48
|
+
│ │ │ └── grid.service.spec.ts
|
|
49
|
+
│ │ ├── rendering/
|
|
50
|
+
│ │ │ └── canvas-renderer.ts # Canvas painting engine
|
|
51
|
+
│ │ ├── directives/
|
|
52
|
+
│ │ │ └── ag-grid-compatibility.directive.ts
|
|
53
|
+
│ │ └── argent-grid.module.ts
|
|
54
|
+
│ └── public-api.ts # Public API exports
|
|
55
|
+
├── package.json # Angular 18, TypeScript 5.4
|
|
56
|
+
├── ng-package.json # ng-packagr config
|
|
57
|
+
├── tsconfig.json # TypeScript config
|
|
58
|
+
├── vitest.config.ts # Vitest test config
|
|
59
|
+
├── setup-vitest.ts # Vitest zoneless setup
|
|
60
|
+
└── README.md
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Implementation Status
|
|
64
|
+
|
|
65
|
+
### ✅ Phase I, II, III & IV - COMPLETE! 🚀
|
|
66
|
+
|
|
67
|
+
| Feature | Status | Notes |
|
|
68
|
+
|---------|--------|-------|
|
|
69
|
+
| AG Grid TypeScript definitions | ✅ | Full GridOptions, ColDef, GridApi |
|
|
70
|
+
| Angular 18 library setup | ✅ | ng-packagr build |
|
|
71
|
+
| Canvas renderer | ✅ | Virtual scrolling, row buffering, pinning support |
|
|
72
|
+
| GridService (headless logic) | ✅ | $O(1)$ row lookups, reactive state |
|
|
73
|
+
| Sorting | ✅ | Client-side, multi-column, menu-driven |
|
|
74
|
+
| Filtering | ✅ | Text, number, date, boolean |
|
|
75
|
+
| Floating Filters | ✅ | Quick headers filters with clear button |
|
|
76
|
+
| Row Grouping | ✅ | Hierarchical, Auto Group column support |
|
|
77
|
+
| Cell Editing | ✅ | Enter/Escape/Tab navigation, group prevention |
|
|
78
|
+
| Column Pinning | ✅ | Left/right sticky columns (Canvas + Header sync) |
|
|
79
|
+
| Column Re-ordering | ✅ | Drag & Drop via Angular CDK |
|
|
80
|
+
| Selection | ✅ | Checkbox, multi-select, header checkbox |
|
|
81
|
+
| Menus | ✅ | Header menus (ellipsis) and Context menus (right-click) |
|
|
82
|
+
| Guard Rail Tests | ✅ | 7+ passing Playwright E2E scenarios |
|
|
83
|
+
|
|
84
|
+
### ⏳ Phase V (Future)
|
|
85
|
+
|
|
86
|
+
| Feature | Priority | Notes |
|
|
87
|
+
|---------|----------|-------|
|
|
88
|
+
| Excel-like Range Selection | High | Drag-to-select rectangular ranges |
|
|
89
|
+
| Column Virtualization | Medium | Horizontal scrolling for 50+ columns |
|
|
90
|
+
| Pivot Tables | Low | Complex but powerful |
|
|
91
|
+
| Tree Data | Low | Parent/child relationships |
|
|
92
|
+
| Master/Detail | Low | Nested grids |
|
|
93
|
+
| Integrated Sparklines | Low | Mini-charts in cells |
|
|
94
|
+
|
|
95
|
+
## Technical Details
|
|
96
|
+
|
|
97
|
+
### Key Interfaces
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
// Main component
|
|
101
|
+
<argent-grid
|
|
102
|
+
[columnDefs]="columnDefs"
|
|
103
|
+
[rowData]="rowData"
|
|
104
|
+
[gridOptions]="gridOptions"
|
|
105
|
+
(gridReady)="onGridReady($event)"
|
|
106
|
+
(rowClicked)="onRowClicked($event)">
|
|
107
|
+
</argent-grid>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### GridService API & Reactivity
|
|
111
|
+
|
|
112
|
+
The grid uses a reactive state model. programmtic changes to filters, sorts, or options via the API are emitted through `gridStateChanged$`, ensuring the Canvas and DOM layers stay synchronized.
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
// Programmatic filter
|
|
116
|
+
api.setFilterModel({
|
|
117
|
+
department: { filterType: 'text', type: 'contains', filter: 'Eng' }
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Programmatic option toggle
|
|
121
|
+
api.setGridOption('floatingFilter', true);
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Agent Tooling & Verification
|
|
125
|
+
|
|
126
|
+
Agents working on this repository should utilize the following tools for high-quality contributions:
|
|
127
|
+
|
|
128
|
+
1. **Playwright Skill**: Used for running the `demo-app` E2E suite (`npm run test:e2e`).
|
|
129
|
+
2. **Computer Use (Browser Automation)**: Highly recommended for visual verification of Canvas rendering. Always verify menu positioning, scrolling alignment, and interactive states (like editing) in a live browser before concluding a task.
|
|
130
|
+
3. **TS Strict Mode**: The library is verified against the `demo-app`'s strict TypeScript configuration. Ensure all property accesses (especially dynamic ones in tests) are type-safe.
|
|
131
|
+
|
|
132
|
+
## Known Issues / TODOs
|
|
133
|
+
|
|
134
|
+
1. **Row grouping tests** - Skipped in Vitest due to service instance sharing. Playwright E2E tests now cover this logic in a real browser.
|
|
135
|
+
|
|
136
|
+
2. **Column virtualization** - Currently renders all columns; should virtualize horizontal scrolling for wide grids.
|
|
137
|
+
|
|
138
|
+
3. **Context Menu Customization** - Currently only supports fixed default items (Copy, Export, Reset).
|
|
139
|
+
|
|
140
|
+
4. **Range Selection** - Visual selection box on canvas is not yet implemented.
|
|
141
|
+
|
|
142
|
+
## Next Steps (Phase V - Advanced Analysis)
|
|
143
|
+
|
|
144
|
+
1. **Excel-like Range Selection**
|
|
145
|
+
- Drag-to-select multiple cells
|
|
146
|
+
- Visual selection overlay on Canvas
|
|
147
|
+
- Copy-paste range support
|
|
148
|
+
|
|
149
|
+
2. **Full-featured Excel Export**
|
|
150
|
+
- Use `exceljs` for native `.xlsx` files with styles/colors.
|
|
151
|
+
|
|
152
|
+
3. **Column Virtualization**
|
|
153
|
+
- Only render visible columns in CanvasRenderer.renderColGroup.
|
|
154
|
+
|
|
155
|
+
## Recent Changes (Phase IV Highlights)
|
|
156
|
+
|
|
157
|
+
- **be1273d** fix: resolve editor update issues and Escape key handling
|
|
158
|
+
- **b44ebbd** fix: synchronize floating filter inputs with GridApi
|
|
159
|
+
- **90cca11** feat: implement Auto Group column and AG Grid-compatible grouping
|
|
160
|
+
- **9c7b162** feat: implement column re-ordering via Drag & Drop
|
|
161
|
+
- **72cddb8** feat: implement Header Menus (Sort, Hide, Pin)
|
|
162
|
+
- **ce0139e** feat: implement Context Menus on Canvas
|
|
163
|
+
- **6b540aa** test: add comprehensive Playwright guard rail suite
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
## Important Notes
|
|
167
|
+
|
|
168
|
+
- **DO NOT use Web Workers** - Deprioritized. Current virtual scrolling handles 100k rows efficiently without the complexity.
|
|
169
|
+
|
|
170
|
+
- **Keep AG Grid API compatibility** - This is the main differentiator. Users should be able to switch by changing imports.
|
|
171
|
+
|
|
172
|
+
- **Test-first approach** - Continue writing tests before implementation for new features.
|
|
173
|
+
|
|
174
|
+
- **Angular 18+** - Do not downgrade. The library targets Angular 18+.
|
|
175
|
+
|
|
176
|
+
## Contact / Repository
|
|
177
|
+
|
|
178
|
+
- **GitHub:** https://github.com/HainanZhao/ArgentGrid
|
|
179
|
+
- **Issues:** https://github.com/HainanZhao/ArgentGrid/issues
|
package/README.md
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# ArgentGrid
|
|
2
|
+
|
|
3
|
+
A **free, high-performance** alternative to AG Grid Enterprise built with Angular and Canvas rendering.
|
|
4
|
+
|
|
5
|
+
## 🌐 Live Demo
|
|
6
|
+
|
|
7
|
+
Check out the interactive demo: **[https://hainanzhao.github.io/ArgentGrid/](https://hainanzhao.github.io/ArgentGrid/)**
|
|
8
|
+
|
|
9
|
+
The demo showcases:
|
|
10
|
+
- Canvas-based rendering with 100,000+ rows
|
|
11
|
+
- Virtual scrolling
|
|
12
|
+
- Sorting, filtering, and selection
|
|
13
|
+
- Cell editing
|
|
14
|
+
- Column and row pinning
|
|
15
|
+
- Excel/CSV export
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
- 🚀 **High Performance**: Canvas-based rendering for 100,000+ rows at 60fps
|
|
20
|
+
- 🎯 **AG Grid Compatible**: Drop-in replacement with 1:1 API compatibility
|
|
21
|
+
- 📦 **Angular Native**: Built with Angular 18+ using modern best practices
|
|
22
|
+
- 🧪 **TDD Developed**: Comprehensive test coverage with Vitest
|
|
23
|
+
- 🎨 **Hybrid Architecture**: Canvas viewport + DOM headers for accessibility
|
|
24
|
+
|
|
25
|
+
## ⚖️ Feature Parity
|
|
26
|
+
|
|
27
|
+
For a detailed comparison with AG Grid and our development roadmap, see:
|
|
28
|
+
**[plan](./plan.md)**
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install argent-grid
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Requirements
|
|
37
|
+
|
|
38
|
+
- Angular 18+
|
|
39
|
+
- TypeScript 5.4+
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
### Basic Usage
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { Component } from '@angular/core';
|
|
47
|
+
import { ColDef } from 'argent-grid';
|
|
48
|
+
|
|
49
|
+
interface RowData {
|
|
50
|
+
id: number;
|
|
51
|
+
name: string;
|
|
52
|
+
age: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@Component({
|
|
56
|
+
selector: 'app-root',
|
|
57
|
+
template: `
|
|
58
|
+
<argent-grid
|
|
59
|
+
[columnDefs]="columnDefs"
|
|
60
|
+
[rowData]="rowData"
|
|
61
|
+
[rowHeight]="32"
|
|
62
|
+
height="600px">
|
|
63
|
+
</argent-grid>
|
|
64
|
+
`
|
|
65
|
+
})
|
|
66
|
+
export class AppComponent {
|
|
67
|
+
columnDefs: ColDef<RowData>[] = [
|
|
68
|
+
{ colId: 'id', field: 'id', headerName: 'ID', width: 100 },
|
|
69
|
+
{ colId: 'name', field: 'name', headerName: 'Name', width: 150 },
|
|
70
|
+
{ colId: 'age', field: 'age', headerName: 'Age', width: 80, sortable: true }
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
rowData: RowData[] = [
|
|
74
|
+
{ id: 1, name: 'John Doe', age: 30 },
|
|
75
|
+
{ id: 2, name: 'Jane Smith', age: 25 }
|
|
76
|
+
];
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Module Import
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import { NgModule } from '@angular/core';
|
|
84
|
+
import { ArgentGridModule } from 'argent-grid';
|
|
85
|
+
|
|
86
|
+
@NgModule({
|
|
87
|
+
imports: [
|
|
88
|
+
ArgentGridModule
|
|
89
|
+
]
|
|
90
|
+
})
|
|
91
|
+
export class AppModule {}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Architecture
|
|
95
|
+
|
|
96
|
+
### Hybrid Rendering Approach
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
┌─────────────────────────────────────┐
|
|
100
|
+
│ Header Layer (DOM-based) │ ← Accessibility, Styling
|
|
101
|
+
├─────────────────────────────────────┤
|
|
102
|
+
│ Canvas Layer (Data Viewport) │ ← High-performance rendering
|
|
103
|
+
│ - 100,000+ rows │
|
|
104
|
+
│ - 60fps scrolling │
|
|
105
|
+
│ - Virtual scrolling │
|
|
106
|
+
└─────────────────────────────────────┘
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Core Components
|
|
110
|
+
|
|
111
|
+
- **ArgentGridComponent**: Main grid component
|
|
112
|
+
- **CanvasRenderer**: High-performance canvas painting engine
|
|
113
|
+
- **GridService**: Headless logic layer for data management
|
|
114
|
+
- **AgGridCompatibilityDirective**: AG Grid API compatibility layer
|
|
115
|
+
|
|
116
|
+
## Development
|
|
117
|
+
|
|
118
|
+
### Setup
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
npm install
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Build
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
npm run build
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Test
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
npm test # Run tests
|
|
134
|
+
npm run test:watch # Watch mode
|
|
135
|
+
npm run test:coverage # With coverage
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Lint
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
npm run lint
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## 🎨 Demo App Development
|
|
145
|
+
|
|
146
|
+
The repository includes a standalone Angular application for visual testing and performance benchmarking. It is configured to import `argent-grid` directly from the `src/` folder using TypeScript path mapping.
|
|
147
|
+
|
|
148
|
+
**Why this is better:**
|
|
149
|
+
- **No Build Step:** You don't need to run `npm run build` in the root every time you change the library.
|
|
150
|
+
- **HMR / Live Reload:** Changes in `src/` are detected by the Angular dev-server, triggering an immediate browser refresh.
|
|
151
|
+
- **Easier Debugging:** Sourcemaps point directly to your original library source code.
|
|
152
|
+
|
|
153
|
+
### Run Demo App
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
cd demo-app
|
|
157
|
+
npm install
|
|
158
|
+
npm start
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Open [http://localhost:4200](http://localhost:4200) to view the demo.
|
|
162
|
+
|
|
163
|
+
### E2E Testing (Playwright)
|
|
164
|
+
|
|
165
|
+
argent-grid uses Playwright for end-to-end testing of visual and interactive features (like Canvas rendering, dragging, and menu interactions).
|
|
166
|
+
|
|
167
|
+
**Prerequisites:**
|
|
168
|
+
The demo app must be running (`npm start` inside `demo-app/`).
|
|
169
|
+
|
|
170
|
+
**Run Tests:**
|
|
171
|
+
```bash
|
|
172
|
+
cd demo-app
|
|
173
|
+
npx playwright test
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
This will execute the **Feature Guard Rails** suite which verifies:
|
|
177
|
+
- Row Grouping & Expansion
|
|
178
|
+
- Floating Filters
|
|
179
|
+
- Cell Editing (Enter/Escape/Tab)
|
|
180
|
+
- Column Pinning & Scroll Sync
|
|
181
|
+
- Column Re-ordering (Drag & Drop)
|
|
182
|
+
|
|
183
|
+
### Performance Benchmarking
|
|
184
|
+
|
|
185
|
+
ArgentGrid includes a built-in benchmarking suite to measure rendering efficiency, scroll performance, and memory overhead.
|
|
186
|
+
|
|
187
|
+
**Option 1: Interactive (UI)**
|
|
188
|
+
1. Start the demo app: `cd demo-app && npm start`
|
|
189
|
+
2. Open [http://localhost:4200](http://localhost:4200)
|
|
190
|
+
3. Click the **🚀 Benchmark** button in the header.
|
|
191
|
+
4. View real-time **ms frame** metrics and a detailed report covering initial render, scrolling, and selection updates.
|
|
192
|
+
|
|
193
|
+
**Option 2: Automated (CLI)**
|
|
194
|
+
To run the automated performance test and see results in your terminal:
|
|
195
|
+
```bash
|
|
196
|
+
cd demo-app
|
|
197
|
+
npx playwright test e2e/benchmark.spec.ts --reporter=list
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Performance Targets
|
|
201
|
+
|
|
202
|
+
| Metric | Baseline | Target | Status |
|
|
203
|
+
| :--- | :--- | :--- | :--- |
|
|
204
|
+
| **Initial Render (100k rows)** | ~45ms | < 30ms | 🚀 (Optimizing) |
|
|
205
|
+
| **Scroll Frame Time (avg)** | ~3.8ms | < 4ms | ✅ |
|
|
206
|
+
| **Selection Update (All)** | ~12ms | < 20ms | ✅ (Damage Tracking) |
|
|
207
|
+
| **Memory per 100k rows** | ~45MB | < 30MB | 🚀 (Optimizing) |
|
|
208
|
+
| **Max Rows (60fps)** | 1,000,000+ | 1,000,000+ | ✅ |
|
|
209
|
+
|
|
210
|
+
## License
|
|
211
|
+
|
|
212
|
+
MIT License - See [LICENSE](LICENSE) for details.
|
|
213
|
+
|
|
214
|
+
## Contributing
|
|
215
|
+
|
|
216
|
+
Contributions are welcome! Please read our contributing guidelines before submitting PRs.
|
|
217
|
+
|
|
218
|
+
## Acknowledgments
|
|
219
|
+
|
|
220
|
+
- [AG Grid](https://www.ag-grid.com/) for the API inspiration
|
|
221
|
+
- [Glide Data Grid](https://github.com/hyperledger-labs/glide-data-grid) for canvas rendering approach
|
|
222
|
+
- [TanStack Table](https://tanstack.com/table) for headless architecture concept
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# ArgentGrid Demo App
|
|
2
|
+
|
|
3
|
+
Live demo showcasing the canvas-based high-performance Angular grid.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Install dependencies
|
|
9
|
+
npm install
|
|
10
|
+
|
|
11
|
+
# Start dev server
|
|
12
|
+
npm start
|
|
13
|
+
|
|
14
|
+
# Build for production
|
|
15
|
+
npm run build
|
|
16
|
+
|
|
17
|
+
# Build for GitHub Pages
|
|
18
|
+
npm run build:gh-pages
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## E2E Testing (Playwright)
|
|
22
|
+
|
|
23
|
+
End-to-end tests are located in the `e2e/` folder. They verify critical visual and interactive features that cannot be easily tested with unit tests (like Canvas rendering and Drag & Drop).
|
|
24
|
+
|
|
25
|
+
**Prerequisites:**
|
|
26
|
+
Ensure the dev server is running (`npm start`).
|
|
27
|
+
|
|
28
|
+
**Run All Tests:**
|
|
29
|
+
```bash
|
|
30
|
+
npx playwright test
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Run with UI:**
|
|
34
|
+
```bash
|
|
35
|
+
npx playwright test --ui
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Key Scenarios Covered:**
|
|
39
|
+
- Row Grouping & Hierarchical Expansion
|
|
40
|
+
- Floating Filters & Quick Clear
|
|
41
|
+
- Inline Cell Editing (Enter/Escape/Tab)
|
|
42
|
+
- Column Pinning (Sticky Columns)
|
|
43
|
+
- Column Re-ordering via Drag & Drop
|
|
44
|
+
|
|
45
|
+
## Demo Features
|
|
46
|
+
|
|
47
|
+
- **100K rows** - Standard load test
|
|
48
|
+
- **500K rows** - Heavy load test
|
|
49
|
+
- **1M rows** - Extreme stress test
|
|
50
|
+
- **Real-time FPS** - Monitor rendering performance
|
|
51
|
+
- **Canvas rendering** - Zero DOM overhead
|
|
52
|
+
|
|
53
|
+
## Live Demo
|
|
54
|
+
|
|
55
|
+
https://hainanzhao.github.io/ArgentGrid/
|
|
56
|
+
|
|
57
|
+
## Tech Stack
|
|
58
|
+
|
|
59
|
+
- Angular 18
|
|
60
|
+
- Canvas 2D API
|
|
61
|
+
- RequestAnimationFrame for 60fps
|
|
62
|
+
- Zero dependencies beyond Angular
|
|
63
|
+
|
|
64
|
+
## Performance Targets
|
|
65
|
+
|
|
66
|
+
| Rows | Load Time | FPS | Memory |
|
|
67
|
+
|------|-----------|-----|--------|
|
|
68
|
+
| 100K | < 500ms | 60 | ~50MB |
|
|
69
|
+
| 500K | < 2s | 60 | ~150MB |
|
|
70
|
+
| 1M | < 5s | 55-60 | ~300MB |
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"newProjectRoot": "projects",
|
|
5
|
+
"projects": {
|
|
6
|
+
"argent-grid-demo": {
|
|
7
|
+
"projectType": "application",
|
|
8
|
+
"schematics": {},
|
|
9
|
+
"root": "",
|
|
10
|
+
"sourceRoot": "src",
|
|
11
|
+
"prefix": "app",
|
|
12
|
+
"architect": {
|
|
13
|
+
"build": {
|
|
14
|
+
"builder": "@angular-devkit/build-angular:application",
|
|
15
|
+
"options": {
|
|
16
|
+
"outputPath": "dist/argent-grid-demo",
|
|
17
|
+
"index": "src/index.html",
|
|
18
|
+
"browser": "src/main.ts",
|
|
19
|
+
"polyfills": [],
|
|
20
|
+
"tsConfig": "tsconfig.json",
|
|
21
|
+
"preserveSymlinks": true,
|
|
22
|
+
"sourceMap": true,
|
|
23
|
+
"assets": [
|
|
24
|
+
{
|
|
25
|
+
"glob": "**/*",
|
|
26
|
+
"input": "public"
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"styles": [],
|
|
30
|
+
"scripts": []
|
|
31
|
+
},
|
|
32
|
+
"configurations": {
|
|
33
|
+
"production": {
|
|
34
|
+
"budgets": [
|
|
35
|
+
{
|
|
36
|
+
"type": "initial",
|
|
37
|
+
"maximumWarning": "500kB",
|
|
38
|
+
"maximumError": "2MB"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"type": "anyComponentStyle",
|
|
42
|
+
"maximumWarning": "10kB",
|
|
43
|
+
"maximumError": "20kB"
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"outputHashing": "all",
|
|
47
|
+
"sourceMap": true
|
|
48
|
+
},
|
|
49
|
+
"development": {
|
|
50
|
+
"optimization": false,
|
|
51
|
+
"extractLicenses": false,
|
|
52
|
+
"sourceMap": true
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"defaultConfiguration": "production"
|
|
56
|
+
},
|
|
57
|
+
"serve": {
|
|
58
|
+
"builder": "@angular-devkit/build-angular:dev-server",
|
|
59
|
+
"configurations": {
|
|
60
|
+
"production": {
|
|
61
|
+
"buildTarget": "argent-grid-demo:build:production"
|
|
62
|
+
},
|
|
63
|
+
"development": {
|
|
64
|
+
"buildTarget": "argent-grid-demo:build:development"
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"defaultConfiguration": "development"
|
|
68
|
+
},
|
|
69
|
+
"extract-i18n": {
|
|
70
|
+
"builder": "@angular-devkit/build-angular:extract-i18n"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"cli": {
|
|
76
|
+
"analytics": false
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
test.describe('ArgentGrid Performance Benchmark', () => {
|
|
4
|
+
test('should run the benchmark and report results', async ({ page }) => {
|
|
5
|
+
// Navigate to the demo page
|
|
6
|
+
await page.goto('/', { waitUntil: 'networkidle' });
|
|
7
|
+
|
|
8
|
+
// Wait for the grid to be ready
|
|
9
|
+
await page.waitForSelector('argent-grid', { timeout: 10000 });
|
|
10
|
+
|
|
11
|
+
// Click the Benchmark button
|
|
12
|
+
console.log('Starting benchmark...');
|
|
13
|
+
await page.click('.btn-benchmark');
|
|
14
|
+
|
|
15
|
+
// Wait for benchmark to complete (isBenchmarking becomes false)
|
|
16
|
+
// The benchmark-results section appears when finished
|
|
17
|
+
await page.waitForSelector('.benchmark-results', { timeout: 30000 });
|
|
18
|
+
|
|
19
|
+
// Extract results
|
|
20
|
+
const results = await page.evaluate(() => {
|
|
21
|
+
const items = document.querySelectorAll('.result-item');
|
|
22
|
+
const data: Record<string, string> = {};
|
|
23
|
+
items.forEach(item => {
|
|
24
|
+
const label = item.querySelector('label')?.textContent?.replace(':', '') || 'unknown';
|
|
25
|
+
const value = item.querySelector('span')?.textContent || '0';
|
|
26
|
+
data[label] = value;
|
|
27
|
+
});
|
|
28
|
+
return data;
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
console.log('-------------------------------------------');
|
|
32
|
+
console.log('🚀 ArgentGrid Performance Benchmark Results');
|
|
33
|
+
console.log('-------------------------------------------');
|
|
34
|
+
Object.entries(results).forEach(([label, value]) => {
|
|
35
|
+
console.log(`${label.padEnd(20)}: ${value}`);
|
|
36
|
+
});
|
|
37
|
+
console.log('-------------------------------------------');
|
|
38
|
+
|
|
39
|
+
// Optional assertions based on targets
|
|
40
|
+
const initialRender = parseFloat(results['Initial Render']);
|
|
41
|
+
const scrollFrame = parseFloat(results['Avg Scroll Frame']);
|
|
42
|
+
|
|
43
|
+
console.log(`Checking against targets...`);
|
|
44
|
+
console.log(`Initial Render: ${initialRender}ms (Target: < 30ms)`);
|
|
45
|
+
console.log(`Avg Scroll Frame: ${scrollFrame}ms (Target: < 4ms)`);
|
|
46
|
+
|
|
47
|
+
// We don't fail the test if targets aren't met yet, but we report it
|
|
48
|
+
if (initialRender > 30) console.warn('⚠️ Initial render is slower than target (30ms)');
|
|
49
|
+
if (scrollFrame > 4) console.warn('⚠️ Scroll frame time is slower than target (4ms)');
|
|
50
|
+
|
|
51
|
+
expect(results['Total Test Time']).toBeDefined();
|
|
52
|
+
});
|
|
53
|
+
});
|