From 999f78386388a2963e0b3fe2916dec020a56c9ad Mon Sep 17 00:00:00 2001 From: seanlandsman Date: Wed, 10 Jun 2026 08:08:46 +0100 Subject: [PATCH 01/13] SEO Work (#14009) --- .../src/utils/htaccess/htaccessRules.test.ts | 209 ++++++++++++++++++ .../src/utils/htaccess/htaccessRules.ts | 18 +- 2 files changed, 217 insertions(+), 10 deletions(-) create mode 100644 documentation/ag-grid-docs/src/utils/htaccess/htaccessRules.test.ts diff --git a/documentation/ag-grid-docs/src/utils/htaccess/htaccessRules.test.ts b/documentation/ag-grid-docs/src/utils/htaccess/htaccessRules.test.ts new file mode 100644 index 00000000000..45dc4aff2dd --- /dev/null +++ b/documentation/ag-grid-docs/src/utils/htaccess/htaccessRules.test.ts @@ -0,0 +1,209 @@ +import { getHtaccessContent } from './htaccessRules'; +import { SITE_301_REDIRECTS } from './redirects'; + +describe('htaccessRules', () => { + let productionContent: string; + let stagingContent: string; + + beforeAll(() => { + productionContent = getHtaccessContent({ env: 'production' }); + stagingContent = getHtaccessContent({ env: 'staging' }); + }); + + describe('AG-17159 / AG-17158: non-www to www redirect', () => { + it('should redirect ag-grid.com to www.ag-grid.com', () => { + expect(productionContent).toContain('RewriteCond %{HTTP_HOST} ^ag-grid\\.com$ [NC]'); + expect(productionContent).toContain('RewriteRule ^(.*)$ https://www.ag-grid.com/$1 [R=301,L]'); + }); + + it('should preserve the full path in the redirect', () => { + const match = productionContent.match( + /RewriteCond %\{HTTP_HOST\} \^ag-grid\\\.com\$ \[NC\]\s*\n\s*RewriteRule \^\(\.\*\)\$ https:\/\/www\.ag-grid\.com\/\$1/ + ); + expect(match).not.toBeNull(); + }); + + it('should not redirect www.ag-grid.com (only bare domain)', () => { + const nonWwwCond = productionContent.match(/RewriteCond %\{HTTP_HOST\} \^ag-grid\\\.com\$/); + expect(nonWwwCond).not.toBeNull(); + }); + }); + + describe('AG-17136 / SE-26: Phase 1 subdomain 301 redirects', () => { + const phase1Subdomains = [ + 'angulargrid.ag-grid.com', + 'angular-grid.ag-grid.com', + 'javascript-grid.ag-grid.com', + 'react-grid.ag-grid.com', + ]; + + for (const subdomain of phase1Subdomains) { + it(`should redirect ${subdomain} to www.ag-grid.com`, () => { + const escapedInHtaccess = subdomain.replace(/\./g, '\\.'); + expect(productionContent).toContain(escapedInHtaccess); + expect(productionContent).toContain('https://www.ag-grid.com/$1 [R=301,L]'); + }); + + it(`should redirect all paths for ${subdomain} (not just root)`, () => { + const lines = productionContent.split('\n'); + const escapedInHtaccess = subdomain.replace(/\./g, '\\.'); + const condIndex = lines.findIndex((l) => l.includes(escapedInHtaccess)); + expect(condIndex).toBeGreaterThan(-1); + const ruleLineIndex = condIndex + 1; + expect(lines[ruleLineIndex]).toContain('^(.*)$'); + }); + } + }); + + describe('AG-17133: Security headers', () => { + it('should include Referrer-Policy header', () => { + expect(productionContent).toContain('Referrer-Policy'); + expect(productionContent).toContain('strict-origin-when-cross-origin'); + }); + + it('should include Permissions-Policy header', () => { + expect(productionContent).toContain('Permissions-Policy'); + expect(productionContent).toContain('geolocation=(), microphone=(), camera=()'); + }); + + it('should NOT include X-Frame-Options header directive (replaced by CSP frame-ancestors)', () => { + expect(productionContent).not.toMatch(/Header\s+.*set\s+X-Frame-Options/); + }); + }); + + describe('AG-17152: /charts/ framework overview redirects', () => { + const chartsFrameworkRedirects = [ + { from: '^/javascript-charts', to: 'charts/javascript/quick-start/' }, + { from: '^/angular-charts', to: 'charts/angular/quick-start/' }, + { from: '^/react-charts', to: 'charts/react/quick-start/' }, + { from: '^/vue-charts', to: 'charts/vue/quick-start/' }, + ]; + + for (const { from, to } of chartsFrameworkRedirects) { + it(`should have a server-side 301 for ${from} -> ${to}`, () => { + const matchingRedirect = SITE_301_REDIRECTS.find( + (r) => 'fromPattern' in r && (r as any).fromPattern.includes(from.replace('^', '')) + ); + expect(matchingRedirect).toBeDefined(); + expect((matchingRedirect as any).to).toContain(to); + }); + } + + const docChartsRedirects = [ + { from: '^/documentation/javascript/charts', to: 'charts/javascript/quick-start/' }, + { from: '^/documentation/angular/charts', to: 'charts/angular/quick-start/' }, + { from: '^/documentation/react/charts', to: 'charts/react/quick-start/' }, + { from: '^/documentation/vue/charts', to: 'charts/vue/quick-start/' }, + ]; + + for (const { from, to } of docChartsRedirects) { + it(`should have a server-side 301 for ${from} -> ${to}`, () => { + const matchingRedirect = SITE_301_REDIRECTS.find( + (r) => 'fromPattern' in r && (r as any).fromPattern.includes(from.replace('^', '')) + ); + expect(matchingRedirect).toBeDefined(); + expect((matchingRedirect as any).to).toContain(to); + }); + } + + it('should render charts redirects as RedirectMatch 301 in the generated htaccess', () => { + expect(productionContent).toContain('RedirectMatch 301'); + expect(productionContent).toContain('javascript-charts'); + }); + }); + + describe('AG-17157: noindex for archive paths', () => { + it('should have redirect rules for /archive paths', () => { + const archiveRedirects = SITE_301_REDIRECTS.filter( + (r) => 'fromPattern' in r && (r as any).fromPattern.includes('archive') + ); + expect(archiveRedirects.length).toBeGreaterThan(0); + }); + }); + + describe('htaccess quality: redundant directives', () => { + it('should have only one RewriteEngine On directive', () => { + const matches = productionContent.match(/RewriteEngine On/g); + expect(matches).not.toBeNull(); + expect(matches!.length).toBe(1); + }); + }); + + describe('htaccess quality: HTTPS redirect scoping', () => { + it('should scope the HTTPS redirect to www/bare domain only', () => { + const lines = productionContent.split('\n'); + const httpsRuleIndex = lines.findIndex((l) => l.includes('RewriteCond %{SERVER_PORT} 80')); + expect(httpsRuleIndex).toBeGreaterThan(-1); + const hostCondIndex = lines.findIndex( + (l, i) => + i >= httpsRuleIndex - 3 && + i <= httpsRuleIndex + 3 && + l.includes('HTTP_HOST') && + (l.includes('ag-grid') || l.includes('www')) + ); + expect(hostCondIndex).toBeGreaterThan(-1); + }); + }); + + describe('htaccess quality: angulargrid.com redirect', () => { + it('should use HTTPS for angulargrid.com redirect', () => { + const lines = productionContent.split('\n'); + const angulargridCondIndex = lines.findIndex( + (l) => l.includes('angulargrid\\.com') && !l.includes('.ag-grid.com') + ); + expect(angulargridCondIndex).toBeGreaterThan(-1); + const nextRuleLine = lines.slice(angulargridCondIndex).find((l) => l.includes('RewriteRule')); + expect(nextRuleLine).toBeDefined(); + expect(nextRuleLine).toContain('https://www.ag-grid.com'); + expect(nextRuleLine).not.toContain('http\\:'); + }); + + it('should redirect all paths for angulargrid.com (not just root)', () => { + const lines = productionContent.split('\n'); + const angulargridCondIndex = lines.findIndex( + (l) => l.includes('angulargrid\\.com') && !l.includes('.ag-grid.com') + ); + expect(angulargridCondIndex).toBeGreaterThan(-1); + const nextRuleLine = lines.slice(angulargridCondIndex).find((l) => l.includes('RewriteRule')); + expect(nextRuleLine).toBeDefined(); + expect(nextRuleLine).toContain('^(.*)$'); + }); + }); + + describe('production vs staging', () => { + it('should include mod_rewrite rules in production only', () => { + expect(productionContent).toContain('mod_rewrite.c'); + expect(stagingContent).not.toContain('mod_rewrite.c'); + }); + + it('should include mod_expires rules in production only', () => { + expect(productionContent).toContain('mod_expires.c'); + expect(stagingContent).not.toContain('mod_expires.c'); + }); + + it('should include CORS headers in production only', () => { + expect(productionContent).toContain('Access-Control-Allow-Origin'); + expect(stagingContent).not.toContain('Access-Control-Allow-Origin'); + }); + + it('should include CSP in both environments', () => { + expect(productionContent).toContain('Content-Security-Policy'); + expect(stagingContent).toContain('Content-Security-Policy'); + }); + }); + + describe('basic structure', () => { + it('should include the autogenerated header', () => { + expect(productionContent).toContain('### AUTOGENERATED DO NOT EDIT'); + }); + + it('should include a 404 error document', () => { + expect(productionContent).toContain('ErrorDocument 404 /404.html'); + }); + + it('should include MIME types for example files', () => { + expect(productionContent).toContain('AddType text/javascript jsx'); + expect(productionContent).toContain('AddType application/typescript ts tsx'); + }); + }); +}); diff --git a/documentation/ag-grid-docs/src/utils/htaccess/htaccessRules.ts b/documentation/ag-grid-docs/src/utils/htaccess/htaccessRules.ts index d14da9ba640..d4ba63e036d 100644 --- a/documentation/ag-grid-docs/src/utils/htaccess/htaccessRules.ts +++ b/documentation/ag-grid-docs/src/utils/htaccess/htaccessRules.ts @@ -67,8 +67,9 @@ const getModRewriteRules = (): string => ` RewriteEngine On - # Always use https for secure connections - # (as it appears on your SSL certificate) + # Always use https for secure connections (scoped to www/bare domain only + # so that charts.ag-grid.com and studio.ag-grid.com are not affected) + RewriteCond %{HTTP_HOST} ^(www\\.)?ag-grid\\.com$ [NC] RewriteCond %{SERVER_PORT} 80 RewriteCond %{REQUEST_URI} !^/\\.well-known/acme-challenge/[0-9a-zA-Z_-]+$ RewriteCond %{REQUEST_URI} !^/\\.well-known/cpanel-dcv/[0-9a-zA-Z_-]+$ @@ -79,24 +80,21 @@ const getModRewriteRules = (): string => ` # Redirect non-www to www RewriteCond %{HTTP_HOST} ^ag-grid\\.com$ [NC] RewriteRule ^(.*)$ https://www.ag-grid.com/$1 [R=301,L] - - RewriteEngine On + + # Redirect legacy Phase 1 subdomains to www RewriteCond %{HTTP_HOST} ^angulargrid\\.ag-grid\\.com$ [NC] RewriteRule ^(.*)$ https://www.ag-grid.com/$1 [R=301,L] - RewriteEngine On RewriteCond %{HTTP_HOST} ^angular-grid\\.ag-grid\\.com$ [NC] RewriteRule ^(.*)$ https://www.ag-grid.com/$1 [R=301,L] - RewriteEngine On RewriteCond %{HTTP_HOST} ^javascript-grid\\.ag-grid\\.com$ [NC] RewriteRule ^(.*)$ https://www.ag-grid.com/$1 [R=301,L] - RewriteEngine On RewriteCond %{HTTP_HOST} ^react-grid\\.ag-grid\\.com$ [NC] RewriteRule ^(.*)$ https://www.ag-grid.com/$1 [R=301,L] - - # Redirect angulargrid.com to ag-grid.com + + # Redirect angulargrid.com to www.ag-grid.com RewriteCond %{HTTP_HOST} ^angulargrid\\.com$ [OR] RewriteCond %{HTTP_HOST} ^www\\.angulargrid\\.com$ - RewriteRule ^/?$ "http\\:\\/\\/www\\.ag\\-grid\\.com" [R=301,L] + RewriteRule ^(.*)$ https://www.ag-grid.com/$1 [R=301,L] # Remove "index.php" from URLs RewriteCond %{REQUEST_URI} !^/\\.well-known/acme-challenge/[0-9a-zA-Z_-]+$ From b86681de305301e9c5c6e23d471e144a7aa33fda Mon Sep 17 00:00:00 2001 From: Stephen Cooper Date: Wed, 10 Jun 2026 10:43:59 +0100 Subject: [PATCH 02/13] Remove editing helper from core bundle (#14014) * Remove editing helper from core bundle * reduce diff --- packages/ag-grid-community/src/edit/editService.ts | 5 +++++ .../src/edit/strategy/fullRowEditStrategy.ts | 11 +++-------- .../ag-grid-community/src/rendering/cell/cellCtrl.ts | 3 +-- .../src/rendering/cell/cellKeyboardListenerFeature.ts | 5 ++--- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/packages/ag-grid-community/src/edit/editService.ts b/packages/ag-grid-community/src/edit/editService.ts index 029f0f5525c..b2c19ab37af 100644 --- a/packages/ag-grid-community/src/edit/editService.ts +++ b/packages/ag-grid-community/src/edit/editService.ts @@ -925,6 +925,11 @@ export class EditService extends BeanStub implements NamedBean { return 'continue'; } + /** Calls through to standalone method for treeshaking via the editService */ + public populateModelValidationErrors() { + _populateModelValidationErrors(this.beans); + } + public revertSingleCellEdit(cellPosition: Required, focus = false): void { const cellCtrl = _getCellCtrl(this.beans, cellPosition); if (!cellCtrl?.comp?.getCellEditor()) { diff --git a/packages/ag-grid-community/src/edit/strategy/fullRowEditStrategy.ts b/packages/ag-grid-community/src/edit/strategy/fullRowEditStrategy.ts index d1c64ff591c..9c5081c035d 100644 --- a/packages/ag-grid-community/src/edit/strategy/fullRowEditStrategy.ts +++ b/packages/ag-grid-community/src/edit/strategy/fullRowEditStrategy.ts @@ -6,12 +6,7 @@ import type { EditPosition, EditRowPosition, StartEditWithPositionParams } from import type { IRowNode } from '../../interfaces/iRowNode'; import type { CellCtrl } from '../../rendering/cell/cellCtrl'; import { _getCellCtrl, _getRowCtrl } from '../utils/controllers'; -import { - _destroyEditor, - _populateModelValidationErrors, - _setupEditor, - _sourceAndPendingDiffer, -} from '../utils/editors'; +import { _destroyEditor, _setupEditor, _sourceAndPendingDiffer } from '../utils/editors'; import type { EditValidationAction, EditValidationResult } from './baseEditStrategy'; import { BaseEditStrategy } from './baseEditStrategy'; @@ -140,7 +135,7 @@ export class FullRowEditStrategy extends BaseEditStrategy { } public override stopCommitted(event: Event | null, commit: boolean): boolean { - const { rowNode, beans, model, editSvc } = this; + const { rowNode, model, editSvc } = this; if (rowNode && !model.hasEdits()) { return false; } @@ -159,7 +154,7 @@ export class FullRowEditStrategy extends BaseEditStrategy { } }); - _populateModelValidationErrors(beans); + editSvc.populateModelValidationErrors(); if (editSvc.checkNavWithValidation({ rowNode }) === 'block-stop') { return false; } diff --git a/packages/ag-grid-community/src/rendering/cell/cellCtrl.ts b/packages/ag-grid-community/src/rendering/cell/cellCtrl.ts index a80f8966089..e7c136754dd 100644 --- a/packages/ag-grid-community/src/rendering/cell/cellCtrl.ts +++ b/packages/ag-grid-community/src/rendering/cell/cellCtrl.ts @@ -16,7 +16,6 @@ import { BeanStub } from '../../context/beanStub'; import type { BeanCollection } from '../../context/context'; import type { RowDragComp } from '../../dragAndDrop/rowDragComp'; import type { EditService } from '../../edit/editService'; -import { _populateModelValidationErrors } from '../../edit/utils/editors'; import type { AgColumn } from '../../entities/agColumn'; import type { CellStyle, CheckboxSelectionCallback, ColDef } from '../../entities/colDef'; import type { RowNode } from '../../entities/rowNode'; @@ -229,7 +228,7 @@ export class CellCtrl extends BeanStub { } this.editorTooltipFeature = this.beans.tooltipSvc?.setupCellEditorTooltip(this, editor); - _populateModelValidationErrors(this.beans); + this.editSvc?.populateModelValidationErrors(); } public disableEditorTooltipFeature(): void { diff --git a/packages/ag-grid-community/src/rendering/cell/cellKeyboardListenerFeature.ts b/packages/ag-grid-community/src/rendering/cell/cellKeyboardListenerFeature.ts index 021411c1605..70b1a6c3172 100644 --- a/packages/ag-grid-community/src/rendering/cell/cellKeyboardListenerFeature.ts +++ b/packages/ag-grid-community/src/rendering/cell/cellKeyboardListenerFeature.ts @@ -3,7 +3,6 @@ import { KeyCode, _isMacOsUserAgent } from 'ag-stack'; import { isRowNumberCol } from '../../columns/columnUtils'; import { BeanStub } from '../../context/beanStub'; import type { BeanCollection } from '../../context/context'; -import { _populateModelValidationErrors } from '../../edit/utils/editors'; import type { AgColumn } from '../../entities/agColumn'; import type { RowNode } from '../../entities/rowNode'; import { _isCellSelectionEnabled, _isRowSelection } from '../../gridOptionsUtils'; @@ -173,7 +172,7 @@ export class CellKeyboardListenerFeature extends BeanStub { } // re-run ALL validations, Enter key is used to commit the edit, so we want to ensure it's valid - _populateModelValidationErrors(beans); + editSvc?.populateModelValidationErrors(); if (editSvc?.checkNavWithValidation(undefined, event) === 'block-stop') { return; @@ -232,7 +231,7 @@ export class CellKeyboardListenerFeature extends BeanStub { if (editing) { // re-run ALL validations, F2 is used to initiate a new edit. If we have one already in progress, // we want to ensure it's valid before initiating a new edit cycle - _populateModelValidationErrors(this.beans); + editSvc?.populateModelValidationErrors(); if (editSvc?.checkNavWithValidation(undefined, event) === 'block-stop') { return; From d92f40de32c89c5cb8ba90e656a5e154e49e57b5 Mon Sep 17 00:00:00 2001 From: AgGitDeployment <80415517+AgGitDeployment@users.noreply.github.com> Date: Wed, 10 Jun 2026 11:53:32 +0100 Subject: [PATCH 03/13] Merge from latest. (#14016) --- documentation/ag-grid-docs/package.json | 12 ++-- packages/ag-grid-community/package.json | 2 +- packages/ag-grid-enterprise/package.json | 8 +-- testing/accessibility/package.json | 4 +- testing/module-size-angular/package.json | 4 +- testing/module-size/package.json | 4 +- yarn.lock | 82 ++++++++++++------------ 7 files changed, 58 insertions(+), 58 deletions(-) diff --git a/documentation/ag-grid-docs/package.json b/documentation/ag-grid-docs/package.json index e95ff06a69b..8ed24130b2d 100644 --- a/documentation/ag-grid-docs/package.json +++ b/documentation/ag-grid-docs/package.json @@ -53,12 +53,12 @@ "@tweenjs/tween.js": "^18.6.4", "@types/react": "^18.2.47", "@types/react-dom": "^18.2.18", - "ag-charts-angular": "13.3.0-beta.20260609", - "ag-charts-community": "13.3.0-beta.20260609", - "ag-charts-enterprise": "13.3.0-beta.20260609", - "ag-charts-types": "13.3.0-beta.20260609", - "ag-charts-react": "13.3.0-beta.20260609", - "ag-charts-vue3": "13.3.0-beta.20260609", + "ag-charts-angular": "13.3.0-beta.20260610", + "ag-charts-community": "13.3.0-beta.20260610", + "ag-charts-enterprise": "13.3.0-beta.20260610", + "ag-charts-types": "13.3.0-beta.20260610", + "ag-charts-react": "13.3.0-beta.20260610", + "ag-charts-vue3": "13.3.0-beta.20260610", "ag-grid-angular": "35.3.0-beta.20260609.1239", "ag-grid-community": "35.3.0-beta.20260609.1239", "ag-grid-enterprise": "35.3.0-beta.20260609.1239", diff --git a/packages/ag-grid-community/package.json b/packages/ag-grid-community/package.json index e6ef3b8b2f8..4ac13f3615b 100644 --- a/packages/ag-grid-community/package.json +++ b/packages/ag-grid-community/package.json @@ -120,7 +120,7 @@ "homepage": "https://www.ag-grid.com/", "dependencies": { "ag-stack": "35.3.0-beta.20260609.1239", - "ag-charts-types": "13.3.0-beta.20260609" + "ag-charts-types": "13.3.0-beta.20260610" }, "devDependencies": { "web-streams-polyfill": "^4.2.0", diff --git a/packages/ag-grid-enterprise/package.json b/packages/ag-grid-enterprise/package.json index 36a5949cddd..9db5db0ae66 100644 --- a/packages/ag-grid-enterprise/package.json +++ b/packages/ag-grid-enterprise/package.json @@ -117,12 +117,12 @@ "ag-grid-community": "35.3.0-beta.20260609.1239" }, "optionalDependencies": { - "ag-charts-community": "13.3.0-beta.20260609", - "ag-charts-enterprise": "13.3.0-beta.20260609" + "ag-charts-community": "13.3.0-beta.20260610", + "ag-charts-enterprise": "13.3.0-beta.20260610" }, "devDependencies": { - "ag-charts-community": "13.3.0-beta.20260609", - "ag-charts-enterprise": "13.3.0-beta.20260609", + "ag-charts-community": "13.3.0-beta.20260610", + "ag-charts-enterprise": "13.3.0-beta.20260610", "canvas": "^3.2.3" } } diff --git a/testing/accessibility/package.json b/testing/accessibility/package.json index c2b58c59143..ce58d197743 100644 --- a/testing/accessibility/package.json +++ b/testing/accessibility/package.json @@ -21,8 +21,8 @@ "ag-grid-angular": "35.3.0-beta.20260609.1239", "ag-grid-community": "35.3.0-beta.20260609.1239", "ag-grid-enterprise": "35.3.0-beta.20260609.1239", - "ag-charts-community": "13.3.0-beta.20260609", - "ag-charts-enterprise": "13.3.0-beta.20260609", + "ag-charts-community": "13.3.0-beta.20260610", + "ag-charts-enterprise": "13.3.0-beta.20260610", "rxjs": "~7.8.2", "tslib": "^2.8.1", "zone.js": "~0.15.0" diff --git a/testing/module-size-angular/package.json b/testing/module-size-angular/package.json index a33ac8e6e69..fe615ba9299 100644 --- a/testing/module-size-angular/package.json +++ b/testing/module-size-angular/package.json @@ -23,8 +23,8 @@ "ag-grid-angular": "35.3.0-beta.20260609.1239", "ag-grid-community": "35.3.0-beta.20260609.1239", "ag-grid-enterprise": "35.3.0-beta.20260609.1239", - "ag-charts-community": "13.3.0-beta.20260609", - "ag-charts-enterprise": "13.3.0-beta.20260609", + "ag-charts-community": "13.3.0-beta.20260610", + "ag-charts-enterprise": "13.3.0-beta.20260610", "rxjs": "~7.8.2", "tslib": "^2.8.1", "zone.js": "~0.15.0" diff --git a/testing/module-size/package.json b/testing/module-size/package.json index f68a3debb5b..953f25f294e 100644 --- a/testing/module-size/package.json +++ b/testing/module-size/package.json @@ -17,8 +17,8 @@ "ag-grid-react": "35.3.0-beta.20260609.1239", "ag-grid-community": "35.3.0-beta.20260609.1239", "ag-grid-enterprise": "35.3.0-beta.20260609.1239", - "ag-charts-community": "13.3.0-beta.20260609", - "ag-charts-enterprise": "13.3.0-beta.20260609", + "ag-charts-community": "13.3.0-beta.20260610", + "ag-charts-enterprise": "13.3.0-beta.20260610", "ag-shared": "0.0.1", "react": "^18.3.1", "react-dom": "^18.3.1" diff --git a/yarn.lock b/yarn.lock index 31b0989dc38..ac332ffd557 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8557,61 +8557,61 @@ adm-zip@^0.5.10: resolved "https://registry.ag-grid.com/adm-zip/-/adm-zip-0.5.16.tgz#0b5e4c779f07dedea5805cdccb1147071d94a909" integrity sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ== -ag-charts-angular@13.3.0-beta.20260609: - version "13.3.0-beta.20260609" - resolved "https://registry.ag-grid.com/ag-charts-angular/-/ag-charts-angular-13.3.0-beta.20260609.tgz#cb577d6ac4ec7c03935cd163e0a817c5b0fad337" - integrity sha512-sa+8R0BxpO1vIHJZFgpkiRXpV0eTHorNgx6V9smVILic5JAk/Ff/JNn7sytbLhKS7/2G3lJYxFdqsc0NRlfPtw== +ag-charts-angular@13.3.0-beta.20260610: + version "13.3.0-beta.20260610" + resolved "https://registry.ag-grid.com/ag-charts-angular/-/ag-charts-angular-13.3.0-beta.20260610.tgz#25e9e7e5f2bc0745442bb7eab660f22cb38146cd" + integrity sha512-pPtCsQzyqUepUn1mNZFolfLeFF3JmpXP1BNjYEjit/N1Qu+A8Jt2aTq8odD809O5lfWJUKwkD46DhUVBDAqU1g== dependencies: - ag-charts-community "13.3.0-beta.20260609" + ag-charts-community "13.3.0-beta.20260610" tslib "^2.8.1" -ag-charts-community@13.3.0-beta.20260609: - version "13.3.0-beta.20260609" - resolved "https://registry.ag-grid.com/ag-charts-community/-/ag-charts-community-13.3.0-beta.20260609.tgz#6604801d95bac335b9651f5766dff0731f0cd9e1" - integrity sha512-uY2XpENXYwr+51qkYtJugqdeXE1JVLB+zYbMGikpmP6mxMWqQTdky6ks1daM4rnJsEsyLCOCItp5Fp3ZTGx2MQ== +ag-charts-community@13.3.0-beta.20260610: + version "13.3.0-beta.20260610" + resolved "https://registry.ag-grid.com/ag-charts-community/-/ag-charts-community-13.3.0-beta.20260610.tgz#56cca7d8990b1a4d8a14d76c6d8d30bb54007f04" + integrity sha512-x2PVBhZvlIMi+56M9WfT/VPse4hdd6xcMnJ0sFXUq6YBvjSnj2EI+wUuBCod/YCe2wAyKNtu38ERUMBGWHHYiw== dependencies: - ag-charts-core "13.3.0-beta.20260609" - ag-charts-locale "13.3.0-beta.20260609" - ag-charts-types "13.3.0-beta.20260609" + ag-charts-core "13.3.0-beta.20260610" + ag-charts-locale "13.3.0-beta.20260610" + ag-charts-types "13.3.0-beta.20260610" -ag-charts-core@13.3.0-beta.20260609: - version "13.3.0-beta.20260609" - resolved "https://registry.ag-grid.com/ag-charts-core/-/ag-charts-core-13.3.0-beta.20260609.tgz#566ad07294069a5c5ff19abe34576d641cbbcba6" - integrity sha512-3mXSbPCo9xamOvPXpOTlsWyQKT7WacRVPQ8qJRQ0wdvcQ1Dxs57FPIGaxZKSsV5QsWxi1vm4lXaoHmMusfwgzg== +ag-charts-core@13.3.0-beta.20260610: + version "13.3.0-beta.20260610" + resolved "https://registry.ag-grid.com/ag-charts-core/-/ag-charts-core-13.3.0-beta.20260610.tgz#9978c5016652617be6f77d1f5db9e8c5ea626ef6" + integrity sha512-CH9kdgoDQRXioObXS3iKyOdnxezPUxDdTgAF1FMtAcYHG1W+uQD4Rn0Jfh3g4hGfSlYJFsjZ28OzTYdDxkOorw== dependencies: - ag-charts-types "13.3.0-beta.20260609" + ag-charts-types "13.3.0-beta.20260610" -ag-charts-enterprise@13.3.0-beta.20260609: - version "13.3.0-beta.20260609" - resolved "https://registry.ag-grid.com/ag-charts-enterprise/-/ag-charts-enterprise-13.3.0-beta.20260609.tgz#2d70e97b251548e53d62bd9b28b914f3dc818cd2" - integrity sha512-wnW35lSk+B27me2O/RaG0P/DCcO8Dlfx7hGu5duOeZzWGp/VlySOvmds5lBampu1rq3fZDmwN76TYIOCQQP/oA== +ag-charts-enterprise@13.3.0-beta.20260610: + version "13.3.0-beta.20260610" + resolved "https://registry.ag-grid.com/ag-charts-enterprise/-/ag-charts-enterprise-13.3.0-beta.20260610.tgz#4dacd5cdfdef9aea7300a80bc0fe415b57613df8" + integrity sha512-9yBPaZpGfmuLA24yuOGhCc0l14awbTYhJ5Qz4f7EeVsbs1R+ZkLThnCgwqbdpifnwF7gvFusf/HJsVmE+0f8yA== dependencies: - ag-charts-community "13.3.0-beta.20260609" - ag-charts-core "13.3.0-beta.20260609" + ag-charts-community "13.3.0-beta.20260610" + ag-charts-core "13.3.0-beta.20260610" -ag-charts-locale@13.3.0-beta.20260609: - version "13.3.0-beta.20260609" - resolved "https://registry.ag-grid.com/ag-charts-locale/-/ag-charts-locale-13.3.0-beta.20260609.tgz#79d9556979cf10a916e8709061931f3606f2ee5f" - integrity sha512-UQ2B2mEkmCB6ceMj4UPRE3Upo1fYvdIz2UkmV59o3dZPIRtyH/b1tFcVpbf5wkhJvbrbp+PuKzKdye8j6Fc3NA== +ag-charts-locale@13.3.0-beta.20260610: + version "13.3.0-beta.20260610" + resolved "https://registry.ag-grid.com/ag-charts-locale/-/ag-charts-locale-13.3.0-beta.20260610.tgz#00674618ce88343f38456954dedaf335bf111f2b" + integrity sha512-DGobzPDUPmSjryK+iMSJQTiGkL6ptSUShsUzLJWzi9/6ddMEfwJ2sYh2ifUtwpSuORvvWmB9fncWIbbCijmGxA== -ag-charts-react@13.3.0-beta.20260609: - version "13.3.0-beta.20260609" - resolved "https://registry.ag-grid.com/ag-charts-react/-/ag-charts-react-13.3.0-beta.20260609.tgz#8e56744ad58f4d9fb0b778c842b5591fc0073e17" - integrity sha512-XB58yp6QrBKaqpPnO0V5q+lRyOiKVAyHxuFRwSiDqW8IjzX2TFN4Q0T37Fs8hd4FH3/G8Kueti4RD5FduhIiyQ== +ag-charts-react@13.3.0-beta.20260610: + version "13.3.0-beta.20260610" + resolved "https://registry.ag-grid.com/ag-charts-react/-/ag-charts-react-13.3.0-beta.20260610.tgz#ad13c9fb89e2d2d27c0e0a37dd980e6e08db5568" + integrity sha512-WrmRGgQVHhITXG5uRi78rRlxgV/fLcxk/0/8ZMbiQqvLInmHEhHsLPbKU5rvNVVjU4W7FTqL+VjAqZ4tRODh+w== dependencies: - ag-charts-community "13.3.0-beta.20260609" + ag-charts-community "13.3.0-beta.20260610" -ag-charts-types@13.3.0-beta.20260609: - version "13.3.0-beta.20260609" - resolved "https://registry.ag-grid.com/ag-charts-types/-/ag-charts-types-13.3.0-beta.20260609.tgz#38df75e9bbd391507afa6bc4a01106da715d9a2e" - integrity sha512-wAdwxoYWrd6r0GCw3Yb+exSQCKYYiOssFsVaCVGV3llCe9kZ+DHOuS/FFJ5b0Un4uKBpXnFATwNIp8K6HjR7eA== +ag-charts-types@13.3.0-beta.20260610: + version "13.3.0-beta.20260610" + resolved "https://registry.ag-grid.com/ag-charts-types/-/ag-charts-types-13.3.0-beta.20260610.tgz#0404c8ad2b4fe1e88cf2a756e1dc51d85ce390e5" + integrity sha512-EVaKGlnTpfl64ATrdl/Ji/V33MPFAmPr1tAEHzwK5UNKICvX7gznnB+80V8NVtq54y5/pqn5PEJuY4WRSecXnQ== -ag-charts-vue3@13.3.0-beta.20260609: - version "13.3.0-beta.20260609" - resolved "https://registry.ag-grid.com/ag-charts-vue3/-/ag-charts-vue3-13.3.0-beta.20260609.tgz#f7351f1d279555a8aa13e07b49ce807a7e79a5ab" - integrity sha512-QzYZ7dzASGJkMISTNXCmX8caUy+sglajTq0mGGlLtWU8gW1Jfng0Ke85jIIL/wnkrW3e7ot4zWlzgkHmAcfHOg== +ag-charts-vue3@13.3.0-beta.20260610: + version "13.3.0-beta.20260610" + resolved "https://registry.ag-grid.com/ag-charts-vue3/-/ag-charts-vue3-13.3.0-beta.20260610.tgz#646ce087fee017b43cd9f2cca6abd9275cab7709" + integrity sha512-tF67BIHZXwf92tMqvW/kxmkeWl/W7rzM3Ixs8Fgc2CyeSBU2NqILas3Z2FBBc10DBNOor7JVvBIW7yqSxqU0OA== dependencies: - ag-charts-community "13.3.0-beta.20260609" + ag-charts-community "13.3.0-beta.20260610" agent-base@6, agent-base@^6.0.2: version "6.0.2" From fe61b7d3a7293946f4d69d7a827f5d8b9b1a0fa3 Mon Sep 17 00:00:00 2001 From: Tak Tran Date: Wed, 10 Jun 2026 12:06:14 +0100 Subject: [PATCH 04/13] AG-17134 Enforce grid production CSP on latest (#14015) Port the production enforce flip to latest, now that the release-branch enforce rollout is deployed and verified clean in production (charts, studio, grid root). Switch the production .htaccess from the bare report-only header to getCspHtaccessBlock in enforce mode (matching staging + the release branch): it unsets the inherited headers (incl. the legacy vhost wildcard) and sets the tightened policy as the enforced Content-Security-Policy. Drop the now-unused getCspHtaccessLine import. --- .../src/utils/htaccess/htaccessRules.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/documentation/ag-grid-docs/src/utils/htaccess/htaccessRules.ts b/documentation/ag-grid-docs/src/utils/htaccess/htaccessRules.ts index d4ba63e036d..e46c3e04e47 100644 --- a/documentation/ag-grid-docs/src/utils/htaccess/htaccessRules.ts +++ b/documentation/ag-grid-docs/src/utils/htaccess/htaccessRules.ts @@ -1,6 +1,6 @@ import { urlWithBaseUrl } from '../urlWithBaseUrl'; import type { CspEnv } from './cspRules'; -import { getCspHtaccessBlock, getCspHtaccessLine } from './cspRules'; +import { getCspHtaccessBlock } from './cspRules'; import { SITE_301_REDIRECTS } from './redirects'; export type HtaccessEnv = Extract; @@ -154,8 +154,7 @@ function getStagingHtaccessContent(): string { return `${baseRules} # Content-Security-Policy — enforced. Unsets the legacy wildcard CSP on the staging -# vhost so this tightened policy is the only one in effect. Production stays -# report-only on latest until the release enforce rollout is verified. +# vhost so this tightened policy is the only one in effect. ${getCspHtaccessBlock({ env: 'staging' }, 'enforce')} Options -Indexes @@ -174,11 +173,12 @@ ${getModRewriteRules()} Header always set Referrer-Policy "strict-origin-when-cross-origin" Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()" -# Content-Security-Policy — report-only while validating the tightened policy on production. -# Ships alongside the existing loose enforcing CSP on the vhost: that one still allows -# everything (nothing breaks), this one reports what the tightened policy would block. -# Flip to enforce + remove the vhost wildcard once the report-only window is clean. -${getCspHtaccessLine({ env: 'production' }, 'report-only')} +# Content-Security-Policy — enforced (the report-only validation window is complete). +# The block unsets the inherited headers (incl. the legacy wildcard CSP on the vhost) +# and sets this tightened policy as the enforced CSP. If the vhost wildcard lingers as a +# separate header, browsers enforce the intersection, so the tightened policy still wins; +# removing the vhost wildcard line is a follow-up infra cleanup. +${getCspHtaccessBlock({ env: 'production' }, 'enforce')} # CORS settings Header add Access-Control-Allow-Origin "*" From 91bccac692d9f7c19254948755b3f4bac0de14f7 Mon Sep 17 00:00:00 2001 From: AgGitDeployment <80415517+AgGitDeployment@users.noreply.github.com> Date: Wed, 10 Jun 2026 12:16:40 +0100 Subject: [PATCH 05/13] Merge from latest. (#14017) --- .env | 4 ++-- community-modules/locale/package.json | 2 +- community-modules/styles/package.json | 2 +- documentation/ag-grid-docs/package.json | 12 ++++++------ documentation/update-algolia-indices/package.json | 2 +- package.json | 2 +- packages/ag-grid-angular/package.json | 6 +++--- .../projects/ag-grid-angular/package.json | 4 ++-- packages/ag-grid-community/package.json | 4 ++-- packages/ag-grid-community/src/version.ts | 2 +- packages/ag-grid-enterprise/package.json | 6 +++--- packages/ag-grid-enterprise/src/version.ts | 2 +- packages/ag-grid-react/package.json | 6 +++--- packages/ag-grid-vue3/package.json | 4 ++-- packages/ag-stack/package.json | 2 +- packages/ag-stack/src/version.ts | 2 +- .../package.json | 2 +- plugins/ag-grid-generate-example-files/package.json | 4 ++-- plugins/ag-grid-task-autogen/package.json | 2 +- testing/accessibility/package.json | 8 ++++---- testing/angular-tests/package.json | 6 +++--- testing/behavioural/package.json | 8 ++++---- testing/behavioural/src/version.ts | 2 +- testing/csp/package.json | 2 +- testing/module-size-angular/package.json | 8 ++++---- testing/module-size/package.json | 8 ++++---- testing/public-recipes/e2e/package.json | 4 ++-- testing/vue3-tests/package.json | 8 ++++---- 28 files changed, 62 insertions(+), 62 deletions(-) diff --git a/.env b/.env index d8dbf36b8aa..ffd70502fd7 100644 --- a/.env +++ b/.env @@ -1,6 +1,6 @@ # Production Build -BUILD_GRID_VERSION=35.3.0-beta.20260609.1239 -BUILD_CHARTS_VERSION=13.3.0-beta.20260609 +BUILD_GRID_VERSION=35.3.0-beta.20260610.1055 +BUILD_CHARTS_VERSION=13.3.0-beta.20260610 ENV=local NX_BATCH_MODE=true NX_ADD_PLUGINS=false diff --git a/community-modules/locale/package.json b/community-modules/locale/package.json index 0ee3110f396..143c24bd109 100644 --- a/community-modules/locale/package.json +++ b/community-modules/locale/package.json @@ -1,6 +1,6 @@ { "name": "@ag-grid-community/locale", - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "description": "Localisation Module for AG Grid, providing translations in 31 languages.", "main": "./dist/package/main.cjs.js", "types": "./dist/types/src/main.d.ts", diff --git a/community-modules/styles/package.json b/community-modules/styles/package.json index 573065f69a8..83d66f80cc0 100644 --- a/community-modules/styles/package.json +++ b/community-modules/styles/package.json @@ -1,6 +1,6 @@ { "name": "@ag-grid-community/styles", - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "description": "AG Grid Styles and Themes", "main": "_index.scss", "files": [ diff --git a/documentation/ag-grid-docs/package.json b/documentation/ag-grid-docs/package.json index 8ed24130b2d..8a92d1aeda1 100644 --- a/documentation/ag-grid-docs/package.json +++ b/documentation/ag-grid-docs/package.json @@ -2,7 +2,7 @@ "name": "ag-grid-docs", "description": "Documentation for AG Grid", "type": "module", - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "repository": { "type": "git", "url": "https://github.com/ag-grid/ag-grid.git" @@ -59,11 +59,11 @@ "ag-charts-types": "13.3.0-beta.20260610", "ag-charts-react": "13.3.0-beta.20260610", "ag-charts-vue3": "13.3.0-beta.20260610", - "ag-grid-angular": "35.3.0-beta.20260609.1239", - "ag-grid-community": "35.3.0-beta.20260609.1239", - "ag-grid-enterprise": "35.3.0-beta.20260609.1239", - "ag-grid-react": "35.3.0-beta.20260609.1239", - "ag-grid-vue3": "35.3.0-beta.20260609.1239", + "ag-grid-angular": "35.3.0-beta.20260610.1055", + "ag-grid-community": "35.3.0-beta.20260610.1055", + "ag-grid-enterprise": "35.3.0-beta.20260610.1055", + "ag-grid-react": "35.3.0-beta.20260610.1055", + "ag-grid-vue3": "35.3.0-beta.20260610.1055", "algoliasearch": "^5.51.0", "astro": "6.1.9", "cheerio": "^1.0.0", diff --git a/documentation/update-algolia-indices/package.json b/documentation/update-algolia-indices/package.json index 343f883f268..f0f01659374 100644 --- a/documentation/update-algolia-indices/package.json +++ b/documentation/update-algolia-indices/package.json @@ -1,6 +1,6 @@ { "name": "update-algolia-indices", - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "description": "Update algolia indices", "main": "src/index.ts", "type": "module", diff --git a/package.json b/package.json index bba6eacbeef..5a5ac8e9c33 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid", - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "license": "MIT", "scripts": { "compressVideo": "tsx external/ag-website-shared/scripts/compress-video", diff --git a/packages/ag-grid-angular/package.json b/packages/ag-grid-angular/package.json index a56666229d3..65b5f3902bd 100644 --- a/packages/ag-grid-angular/package.json +++ b/packages/ag-grid-angular/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-angular", - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "description": "AG Grid Angular Component", "scripts": { "clean": "rimraf dist", @@ -15,7 +15,7 @@ "module": "./dist/ag-grid-angular/fesm2022/ag-grid-angular.mjs", "typings": "./dist/ag-grid-angular/index.d.ts", "dependencies": { - "ag-grid-community": "35.3.0-beta.20260609.1239", + "ag-grid-community": "35.3.0-beta.20260610.1055", "@angular/animations": "^20.0.0", "@angular/common": "^20.0.0", "@angular/compiler": "^20.0.0", @@ -27,7 +27,7 @@ "zone.js": "~0.15.1" }, "devDependencies": { - "ag-grid-community": "35.3.0-beta.20260609.1239", + "ag-grid-community": "35.3.0-beta.20260610.1055", "@angular/build": "^20.0.0", "@angular/cli": "^20.0.0", "@angular/forms": "^20.0.0", diff --git a/packages/ag-grid-angular/projects/ag-grid-angular/package.json b/packages/ag-grid-angular/projects/ag-grid-angular/package.json index 6c6cb41baa8..748f25e5c14 100644 --- a/packages/ag-grid-angular/projects/ag-grid-angular/package.json +++ b/packages/ag-grid-angular/projects/ag-grid-angular/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-angular", - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "description": "AG Grid Angular Component", "license": "MIT", "peerDependencies": { @@ -8,7 +8,7 @@ "@angular/core": ">= 20.0.0" }, "dependencies": { - "ag-grid-community": "35.3.0-beta.20260609.1239", + "ag-grid-community": "35.3.0-beta.20260610.1055", "tslib": "^2.8.1" }, "repository": { diff --git a/packages/ag-grid-community/package.json b/packages/ag-grid-community/package.json index 4ac13f3615b..6ab5e81fcad 100644 --- a/packages/ag-grid-community/package.json +++ b/packages/ag-grid-community/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-community", - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "description": "Advanced Data Grid / Data Table supporting Javascript / Typescript / React / Angular / Vue", "main": "./dist/package/main.cjs.js", "types": "./dist/types/src/main.d.ts", @@ -119,7 +119,7 @@ ], "homepage": "https://www.ag-grid.com/", "dependencies": { - "ag-stack": "35.3.0-beta.20260609.1239", + "ag-stack": "35.3.0-beta.20260610.1055", "ag-charts-types": "13.3.0-beta.20260610" }, "devDependencies": { diff --git a/packages/ag-grid-community/src/version.ts b/packages/ag-grid-community/src/version.ts index fe252f610fe..c1f816adaf7 100644 --- a/packages/ag-grid-community/src/version.ts +++ b/packages/ag-grid-community/src/version.ts @@ -1,2 +1,2 @@ // DO NOT UPDATE MANUALLY: Generated from script during build time -export const VERSION = '35.3.0-beta.20260609.1239'; +export const VERSION = '35.3.0-beta.20260610.1055'; diff --git a/packages/ag-grid-enterprise/package.json b/packages/ag-grid-enterprise/package.json index 9db5db0ae66..cf414d8911d 100644 --- a/packages/ag-grid-enterprise/package.json +++ b/packages/ag-grid-enterprise/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-enterprise", - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "description": "Advanced Data Grid / Data Table supporting Javascript / Typescript / React / Angular / Vue", "main": "./dist/package/main.cjs.js", "types": "./dist/types/src/main.d.ts", @@ -113,8 +113,8 @@ ], "homepage": "https://www.ag-grid.com/", "dependencies": { - "ag-stack": "35.3.0-beta.20260609.1239", - "ag-grid-community": "35.3.0-beta.20260609.1239" + "ag-stack": "35.3.0-beta.20260610.1055", + "ag-grid-community": "35.3.0-beta.20260610.1055" }, "optionalDependencies": { "ag-charts-community": "13.3.0-beta.20260610", diff --git a/packages/ag-grid-enterprise/src/version.ts b/packages/ag-grid-enterprise/src/version.ts index fe252f610fe..c1f816adaf7 100644 --- a/packages/ag-grid-enterprise/src/version.ts +++ b/packages/ag-grid-enterprise/src/version.ts @@ -1,2 +1,2 @@ // DO NOT UPDATE MANUALLY: Generated from script during build time -export const VERSION = '35.3.0-beta.20260609.1239'; +export const VERSION = '35.3.0-beta.20260610.1055'; diff --git a/packages/ag-grid-react/package.json b/packages/ag-grid-react/package.json index 5179776c8b4..cd17099b610 100644 --- a/packages/ag-grid-react/package.json +++ b/packages/ag-grid-react/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-react", - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "description": "AG Grid React Component", "main": "./dist/package/index.cjs.js", "types": "./dist/types/src/index.d.ts", @@ -31,7 +31,7 @@ "devDependencies": { "@babel/runtime": "^7.29.2", "prop-types": "^15.6.2", - "ag-grid-community": "35.3.0-beta.20260609.1239", + "ag-grid-community": "35.3.0-beta.20260610.1055", "@babel/plugin-proposal-throw-expressions": "^7.27.1", "@babel/preset-typescript": "^7.28.5", "@types/react": "~18.3.26", @@ -44,7 +44,7 @@ }, "dependencies": { "prop-types": "^15.8.1", - "ag-grid-community": "35.3.0-beta.20260609.1239" + "ag-grid-community": "35.3.0-beta.20260610.1055" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", diff --git a/packages/ag-grid-vue3/package.json b/packages/ag-grid-vue3/package.json index a482953f094..52f7f88fe6b 100644 --- a/packages/ag-grid-vue3/package.json +++ b/packages/ag-grid-vue3/package.json @@ -1,7 +1,7 @@ { "name": "ag-grid-vue3", "description": "AG Grid Vue 3 Component", - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "author": "Sean Landsman ", "license": "MIT", "files": [ @@ -44,7 +44,7 @@ "build-only:watch": "vite build --watch" }, "dependencies": { - "ag-grid-community": "35.3.0-beta.20260609.1239" + "ag-grid-community": "35.3.0-beta.20260610.1055" }, "devDependencies": { "vue": "^3.5.32", diff --git a/packages/ag-stack/package.json b/packages/ag-stack/package.json index 6f357b76b43..692b7e8f875 100644 --- a/packages/ag-stack/package.json +++ b/packages/ag-stack/package.json @@ -1,6 +1,6 @@ { "name": "ag-stack", - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "description": "Advanced Data Grid / Data Table supporting Javascript / Typescript / React / Angular / Vue", "main": "./dist/package/main.cjs.js", "types": "./dist/types/src/main.d.ts", diff --git a/packages/ag-stack/src/version.ts b/packages/ag-stack/src/version.ts index fe252f610fe..c1f816adaf7 100644 --- a/packages/ag-stack/src/version.ts +++ b/packages/ag-stack/src/version.ts @@ -1,2 +1,2 @@ // DO NOT UPDATE MANUALLY: Generated from script during build time -export const VERSION = '35.3.0-beta.20260609.1239'; +export const VERSION = '35.3.0-beta.20260610.1055'; diff --git a/plugins/ag-grid-generate-code-reference-files/package.json b/plugins/ag-grid-generate-code-reference-files/package.json index 6467165e8c3..680d24841eb 100644 --- a/plugins/ag-grid-generate-code-reference-files/package.json +++ b/plugins/ag-grid-generate-code-reference-files/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-generate-code-reference-files", - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "private": true, "dependencies": { "ag-shared": "0.0.1", diff --git a/plugins/ag-grid-generate-example-files/package.json b/plugins/ag-grid-generate-example-files/package.json index 27c6e14a594..3c186c70adc 100644 --- a/plugins/ag-grid-generate-example-files/package.json +++ b/plugins/ag-grid-generate-example-files/package.json @@ -1,10 +1,10 @@ { "name": "ag-grid-generate-example-files", - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "private": true, "dependencies": { "ag-shared": "0.0.1", - "ag-grid-community": "35.3.0-beta.20260609.1239", + "ag-grid-community": "35.3.0-beta.20260610.1055", "glob": "^11.1.0", "typescript": "~5.8.3", "cheerio": "^1.2.0", diff --git a/plugins/ag-grid-task-autogen/package.json b/plugins/ag-grid-task-autogen/package.json index 7f85a0c7080..e26a2469274 100644 --- a/plugins/ag-grid-task-autogen/package.json +++ b/plugins/ag-grid-task-autogen/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-task-autogen", - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "private": true, "dependencies": { "@nx/devkit": "20.8.4", diff --git a/testing/accessibility/package.json b/testing/accessibility/package.json index ce58d197743..86717846166 100644 --- a/testing/accessibility/package.json +++ b/testing/accessibility/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-accessibility", - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "scripts": { "download-examples": "curl --retry 5 -retry-all-errors https://grid-staging.ag-grid.com/debug/all-examples.json > ./all-examples.json", "download-examples-local": "curl https://localhost:4610/debug/all-examples.json > ./all-examples.json", @@ -18,9 +18,9 @@ "@angular/platform-browser": "^19.0.0", "@angular/platform-browser-dynamic": "^19.0.0", "@angular/router": "^19.0.0", - "ag-grid-angular": "35.3.0-beta.20260609.1239", - "ag-grid-community": "35.3.0-beta.20260609.1239", - "ag-grid-enterprise": "35.3.0-beta.20260609.1239", + "ag-grid-angular": "35.3.0-beta.20260610.1055", + "ag-grid-community": "35.3.0-beta.20260610.1055", + "ag-grid-enterprise": "35.3.0-beta.20260610.1055", "ag-charts-community": "13.3.0-beta.20260610", "ag-charts-enterprise": "13.3.0-beta.20260610", "rxjs": "~7.8.2", diff --git a/testing/angular-tests/package.json b/testing/angular-tests/package.json index bad21fb4b9a..d72eac29470 100644 --- a/testing/angular-tests/package.json +++ b/testing/angular-tests/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-angular-tests", - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "private": true, "scripts": { "test:e2e": "jest --no-cache" @@ -11,8 +11,8 @@ "@angular/core": "^21.0.0", "@angular/platform-browser": "^21.0.0", "@angular/platform-browser-dynamic": "^21.0.0", - "ag-grid-angular": "35.3.0-beta.20260609.1239", - "ag-grid-community": "35.3.0-beta.20260609.1239", + "ag-grid-angular": "35.3.0-beta.20260610.1055", + "ag-grid-community": "35.3.0-beta.20260610.1055", "rxjs": "~7.8.2", "tslib": "^2.8.1", "zone.js": "~0.15.0" diff --git a/testing/behavioural/package.json b/testing/behavioural/package.json index edc9903e41c..e8591b0bef4 100644 --- a/testing/behavioural/package.json +++ b/testing/behavioural/package.json @@ -1,6 +1,6 @@ { "name": "ag-behavioural-testing", - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "private": true, "description": "Behavioural unit testing for ag-Grid", "dependencies": { @@ -8,9 +8,9 @@ }, "type": "module", "devDependencies": { - "ag-grid-community": "35.3.0-beta.20260609.1239", - "ag-grid-enterprise": "35.3.0-beta.20260609.1239", - "ag-grid-react": "35.3.0-beta.20260609.1239", + "ag-grid-community": "35.3.0-beta.20260610.1055", + "ag-grid-enterprise": "35.3.0-beta.20260610.1055", + "ag-grid-react": "35.3.0-beta.20260610.1055", "@types/react": "^18.3.23", "@types/react-dom": "^18.3.7", "@testing-library/dom": "^10.4.1", diff --git a/testing/behavioural/src/version.ts b/testing/behavioural/src/version.ts index fe252f610fe..c1f816adaf7 100644 --- a/testing/behavioural/src/version.ts +++ b/testing/behavioural/src/version.ts @@ -1,2 +1,2 @@ // DO NOT UPDATE MANUALLY: Generated from script during build time -export const VERSION = '35.3.0-beta.20260609.1239'; +export const VERSION = '35.3.0-beta.20260610.1055'; diff --git a/testing/csp/package.json b/testing/csp/package.json index 14a0eab2ac8..d5a5972ee5d 100644 --- a/testing/csp/package.json +++ b/testing/csp/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-csp", - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "description": "CSP testing for AG Grid", "main": "index.js", "scripts": {}, diff --git a/testing/module-size-angular/package.json b/testing/module-size-angular/package.json index fe615ba9299..a0233eb7d5f 100644 --- a/testing/module-size-angular/package.json +++ b/testing/module-size-angular/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-module-size-angular", - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "scripts": { "ng": "ng", "start": "ng serve", @@ -20,9 +20,9 @@ "@angular/platform-browser": "^20.0.0", "@angular/platform-browser-dynamic": "^20.0.0", "@angular/router": "^20.0.0", - "ag-grid-angular": "35.3.0-beta.20260609.1239", - "ag-grid-community": "35.3.0-beta.20260609.1239", - "ag-grid-enterprise": "35.3.0-beta.20260609.1239", + "ag-grid-angular": "35.3.0-beta.20260610.1055", + "ag-grid-community": "35.3.0-beta.20260610.1055", + "ag-grid-enterprise": "35.3.0-beta.20260610.1055", "ag-charts-community": "13.3.0-beta.20260610", "ag-charts-enterprise": "13.3.0-beta.20260610", "rxjs": "~7.8.2", diff --git a/testing/module-size/package.json b/testing/module-size/package.json index 953f25f294e..c460594a52b 100644 --- a/testing/module-size/package.json +++ b/testing/module-size/package.json @@ -1,7 +1,7 @@ { "name": "ag-grid-module-size", "private": true, - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "scripts": { "dev": "vite", "cp-app": "cp ./src/App_Src.tsx ./src/App_AUTO.tsx", @@ -14,9 +14,9 @@ "test:e2e": "run-s \"module-combinations -- {1}\" module-validate --" }, "dependencies": { - "ag-grid-react": "35.3.0-beta.20260609.1239", - "ag-grid-community": "35.3.0-beta.20260609.1239", - "ag-grid-enterprise": "35.3.0-beta.20260609.1239", + "ag-grid-react": "35.3.0-beta.20260610.1055", + "ag-grid-community": "35.3.0-beta.20260610.1055", + "ag-grid-enterprise": "35.3.0-beta.20260610.1055", "ag-charts-community": "13.3.0-beta.20260610", "ag-charts-enterprise": "13.3.0-beta.20260610", "ag-shared": "0.0.1", diff --git a/testing/public-recipes/e2e/package.json b/testing/public-recipes/e2e/package.json index 9f78a8a09d6..8964cc25abe 100644 --- a/testing/public-recipes/e2e/package.json +++ b/testing/public-recipes/e2e/package.json @@ -1,12 +1,12 @@ { "name": "ag-grid-public-e2e-testing-recipes", - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "description": "Public E2E testing recipes for AG Grid", "main": "index.js", "scripts": {}, "license": "MIT", "devDependencies": { - "ag-grid-community": "35.3.0-beta.20260609.1239", + "ag-grid-community": "35.3.0-beta.20260610.1055", "playwright": "^1.59.1", "@playwright/test": "^1.59.1", "@types/node": "^22.15.3" diff --git a/testing/vue3-tests/package.json b/testing/vue3-tests/package.json index 69837e4754b..67e5c0be435 100644 --- a/testing/vue3-tests/package.json +++ b/testing/vue3-tests/package.json @@ -1,7 +1,7 @@ { "name": "ag-grid-vue3-tests", "private": true, - "version": "35.3.0-beta.20260609.1239", + "version": "35.3.0-beta.20260610.1055", "type": "module", "scripts": { "dev": "vite", @@ -15,9 +15,9 @@ "dependencies": { "vue": "^3.5.32", "vue-router": "^5.0.6", - "ag-grid-community": "35.3.0-beta.20260609.1239", - "ag-grid-enterprise": "35.3.0-beta.20260609.1239", - "ag-grid-vue3": "35.3.0-beta.20260609.1239", + "ag-grid-community": "35.3.0-beta.20260610.1055", + "ag-grid-enterprise": "35.3.0-beta.20260610.1055", + "ag-grid-vue3": "35.3.0-beta.20260610.1055", "decimal.js": "^10.6.0" }, "devDependencies": { From 391a4d7fc5920931ace563522af6691a7dd16a87 Mon Sep 17 00:00:00 2001 From: Guilherme Lopes Date: Wed, 10 Jun 2026 08:17:01 -0300 Subject: [PATCH 06/13] [Calculated Column] - Code Cleanup (#14013) --- .../base/parts/_calculated-columns.scss | 13 ---- .../src/edit/strategy/strategyUtils.ts | 3 +- .../ag-grid-community/src/main-internal.ts | 2 +- .../src/styling/calculatedColumnCss.ts | 5 +- .../src/tooltip/tooltipService.ts | 3 +- .../calculatedColumns/calculatedColumnForm.ts | 50 +++++--------- .../calculatedColumnReferenceMapper.ts | 2 +- .../calculatedColumnUtils.ts | 2 +- .../calculatedColumnsService.ts | 65 ++++++++++++------- .../src/formula/formulaService.ts | 4 +- .../src/menu/columnMenuFactory.ts | 3 +- .../src/menu/contextMenu.ts | 24 ++----- .../src/menu/menuItemMapper.ts | 5 +- 13 files changed, 72 insertions(+), 109 deletions(-) diff --git a/community-modules/styles/src/internal/base/parts/_calculated-columns.scss b/community-modules/styles/src/internal/base/parts/_calculated-columns.scss index 0559846160f..388d8aff703 100644 --- a/community-modules/styles/src/internal/base/parts/_calculated-columns.scss +++ b/community-modules/styles/src/internal/base/parts/_calculated-columns.scss @@ -29,13 +29,6 @@ } } - .ag-calculated-column-expression-error { - color: var(--ag-invalid-color); - font-size: 11px; - line-height: normal; - margin-top: calc(var(--ag-grid-size) / 2); - } - .ag-calculated-column-expression-tools { display: flex; gap: calc(var(--ag-grid-size) / 2); @@ -83,12 +76,6 @@ flex: none; } - .ag-calculated-column-properties { - display: flex; - flex-direction: column; - gap: calc(var(--ag-grid-size) / 2); - } - .ag-calculated-column-actions { display: flex; justify-content: flex-end; diff --git a/packages/ag-grid-community/src/edit/strategy/strategyUtils.ts b/packages/ag-grid-community/src/edit/strategy/strategyUtils.ts index 33b15114a37..553de18f949 100644 --- a/packages/ag-grid-community/src/edit/strategy/strategyUtils.ts +++ b/packages/ag-grid-community/src/edit/strategy/strategyUtils.ts @@ -1,6 +1,5 @@ import { KeyCode } from 'ag-stack'; -import { _hasCalculatedExpression } from '../../columns/calculatedColumnUtils'; import type { BeanCollection } from '../../context/context'; import type { AgColumn } from '../../entities/agColumn'; import type { ColDef } from '../../entities/colDef'; @@ -77,7 +76,7 @@ export function isCellEditable(beans: BeanCollection, editPosition: Required = { cellDataType: 'text', @@ -221,23 +221,20 @@ export class CalculatedColumnForm extends Component { } private addActionListeners(): void { - if (this.expressionPickers.has('columns')) { - this.addManagedElementListeners(this.eColumns, { - mousedown: () => this.rememberExpressionSelection(), - click: () => this.openPicker('column', this.eColumns), - }); - } - if (this.expressionPickers.has('functions')) { - this.addManagedElementListeners(this.eFunctions, { - mousedown: () => this.rememberExpressionSelection(), - click: () => this.openPicker('function', this.eFunctions), - }); - } - if (this.expressionPickers.has('operators')) { - this.addManagedElementListeners(this.eOperators, { - mousedown: () => this.rememberExpressionSelection(), - click: () => this.openPicker('operator', this.eOperators), - }); + const expressionPickers = this.expressionPickers; + const pickerButtons: [CalculatedColumnExpressionPicker, ColumnSuggestion['type'], HTMLButtonElement][] = [ + ['columns', 'column', this.eColumns], + ['functions', 'function', this.eFunctions], + ['operators', 'operator', this.eOperators], + ]; + for (const pickerButton of pickerButtons) { + const [pickerKey, suggestionType, button] = pickerButton; + if (expressionPickers.has(pickerKey)) { + this.addManagedElementListeners(button, { + mousedown: () => this.rememberExpressionSelection(), + click: () => this.openPicker(suggestionType, button), + }); + } } if (!this.livePreview) { this.addManagedElementListeners(this.eApply, { @@ -557,7 +554,7 @@ export class CalculatedColumnForm extends Component { } private getFunctionToken(value: string, caret: number): { start: number; end: number; prefix: string } | null { - if (this.isInsideStringLiteral(value, caret)) { + if (isInsideStringLiteral(value, caret)) { return null; } @@ -591,19 +588,4 @@ export class CalculatedColumnForm extends Component { } return null; } - - private isInsideStringLiteral(value: string, offset: number): boolean { - let inString = false; - for (let i = 0; i < offset && i < value.length; i++) { - if (value[i] !== '"') { - continue; - } - if (value[i + 1] === '"') { - i++; - continue; - } - inString = !inString; - } - return inString; - } } diff --git a/packages/ag-grid-enterprise/src/calculatedColumns/calculatedColumnReferenceMapper.ts b/packages/ag-grid-enterprise/src/calculatedColumns/calculatedColumnReferenceMapper.ts index 312ddca0083..6ec6b90378d 100644 --- a/packages/ag-grid-enterprise/src/calculatedColumns/calculatedColumnReferenceMapper.ts +++ b/packages/ag-grid-enterprise/src/calculatedColumns/calculatedColumnReferenceMapper.ts @@ -10,7 +10,7 @@ interface CalculatedColumnReferenceError { reference: string; } -interface CalculatedColumnReferenceMapper { +export interface CalculatedColumnReferenceMapper { suggestions: ColumnSuggestion[]; toInternalExpression(expression: string): { expression: string } | { error: CalculatedColumnReferenceError }; toInternalExpressionBestEffort(expression: string): string; diff --git a/packages/ag-grid-enterprise/src/calculatedColumns/calculatedColumnUtils.ts b/packages/ag-grid-enterprise/src/calculatedColumns/calculatedColumnUtils.ts index ec2a4388e25..19476064ca4 100644 --- a/packages/ag-grid-enterprise/src/calculatedColumns/calculatedColumnUtils.ts +++ b/packages/ag-grid-enterprise/src/calculatedColumns/calculatedColumnUtils.ts @@ -187,7 +187,7 @@ function isInsideBracketReference(expression: string, offset: number): boolean { return bracketStart > bracketEnd; } -function isInsideStringLiteral(expression: string, offset: number): boolean { +export function isInsideStringLiteral(expression: string, offset: number): boolean { let inString = false; for (let i = 0; i < offset && i < expression.length; ++i) { if (expression[i] !== '"') { diff --git a/packages/ag-grid-enterprise/src/calculatedColumns/calculatedColumnsService.ts b/packages/ag-grid-enterprise/src/calculatedColumns/calculatedColumnsService.ts index 1b395c8164a..400ae248c51 100644 --- a/packages/ag-grid-enterprise/src/calculatedColumns/calculatedColumnsService.ts +++ b/packages/ag-grid-enterprise/src/calculatedColumns/calculatedColumnsService.ts @@ -18,7 +18,6 @@ import { BeanStub, _addColumnDefaultAndTypes, _createUserColumn, - _hasCalculatedExpression, _mergedEqual, _normaliseCalculatedExpression, _warn, @@ -39,6 +38,7 @@ import type { CalculatedColumnDraft, ColumnSuggestion, } from './calculatedColumnFormTypes'; +import type { CalculatedColumnReferenceMapper } from './calculatedColumnReferenceMapper'; import { createCalculatedColumnReferenceMapper, translateCalculatedColumnReferenceError, @@ -47,6 +47,9 @@ import { clearStaleDataTypeProperties, replaceBracketReferences } from './calcul type ValidationState = 'valid' | CalculatedColumnValidationReason; +// bounds the parse-error memo; dialog keystrokes feed it one entry per expression variant. +const FORMULA_ERROR_CACHE_LIMIT = 256; + const BASE_DATA_TYPE_LOCALE_KEYS: Record = { text: 'dataTypeText', number: 'dataTypeNumber', @@ -82,7 +85,7 @@ type OpenCalculatedColumnDialog = { type PendingLivePreviewUpdate = { draft: CalculatedColumnDraft; - mapper: ReturnType; + mapper: CalculatedColumnReferenceMapper; }; type KnownCalculatedColumn = { @@ -111,6 +114,8 @@ export class CalculatedColumnsService extends BeanStub implements NamedBean, ICa private readonly openDialogsByColId = new Map(); private readonly scheduledLivePreviewColIds = new Set(); private readonly pendingLivePreviewUpdatesByColId = new Map(); + // Memoised parse results keyed by expression; see getFormulaError. + private readonly formulaErrorsByExpression = new Map(); public postConstruct(): void { this.addManagedEventListeners({ @@ -155,7 +160,7 @@ export class CalculatedColumnsService extends BeanStub implements NamedBean, ICa const source: ColumnEventType = 'calculatedColumn'; const { colModel } = this.beans; const targetColumn = colModel.getCol(column); - if (targetColumn == null || !_hasCalculatedExpression(targetColumn.colDef)) { + if (!targetColumn?.isCalculatedCol) { return; } const oldExpression = targetColumn.colDef.calculatedExpression; @@ -207,9 +212,22 @@ export class CalculatedColumnsService extends BeanStub implements NamedBean, ICa this.refreshCalculatedColumn(targetColId); } + private getFormulaError(expression: string): FormulaError | null { + const cache = this.formulaErrorsByExpression; + const cached = cache.get(expression); + if (cached !== undefined) { + return cached; + } + if (cache.size >= FORMULA_ERROR_CACHE_LIMIT) { + cache.clear(); + } + const error = (this.beans.formula?.validateExpression(`=${expression}`) ?? null) as FormulaError | null; + cache.set(expression, error); + return error; + } + private getFormulaExpressionError(expression: string): string | null { - const error = this.beans.formula?.validateExpression(`=${expression}`); - return error ? (error as FormulaError).getTranslatedMessage(this.getLocaleTextFunc()) : null; + return this.getFormulaError(expression)?.getTranslatedMessage(this.getLocaleTextFunc()) ?? null; } private validateFormulaExpression(expression: string): boolean { @@ -278,10 +296,12 @@ export class CalculatedColumnsService extends BeanStub implements NamedBean, ICa return; } - if (column == null || !_hasCalculatedExpression(column.colDef)) { + if (!column?.isCalculatedCol) { return; } - const draft = this.toDraft(column); + // Built once and shared by toDraft + showDialog — both need the same column snapshot. + const mapper = createCalculatedColumnReferenceMapper(this.beans, this.beans.colModel.colsList, column.colId); + const draft = this.toDraft(column, mapper); this.showDialog( draft, (nextDraft) => { @@ -290,7 +310,8 @@ export class CalculatedColumnsService extends BeanStub implements NamedBean, ICa }, column, focus, - livePreview + livePreview, + mapper ); } @@ -324,7 +345,7 @@ export class CalculatedColumnsService extends BeanStub implements NamedBean, ICa } public removeCalculatedColumn(column: AgColumn | null | undefined): void { - if (column == null || !_hasCalculatedExpression(column.colDef)) { + if (!column?.isCalculatedCol) { return; } const source: ColumnEventType = 'calculatedColumn'; @@ -496,7 +517,8 @@ export class CalculatedColumnsService extends BeanStub implements NamedBean, ICa onApply: (draft: CalculatedColumnDraft) => void, columnToHighlight?: AgColumn | null, focusDialog = true, - livePreview = false + livePreview = false, + existingMapper?: CalculatedColumnReferenceMapper ): void { const openDialogState = this.openDialogsByColId.get(draft.colId); if (openDialogState) { @@ -508,7 +530,8 @@ export class CalculatedColumnsService extends BeanStub implements NamedBean, ICa const state: { close?: () => void; resolved: boolean } = { resolved: false }; const beans = this.beans; - const mapper = createCalculatedColumnReferenceMapper(beans, beans.colModel.colsList, draft.colId); + const mapper = + existingMapper ?? createCalculatedColumnReferenceMapper(beans, beans.colModel.colsList, draft.colId); const getValidatedExpression = ( nextDraft: CalculatedColumnDraft @@ -620,10 +643,7 @@ export class CalculatedColumnsService extends BeanStub implements NamedBean, ICa dialog.addEventListener('destroyed', () => this.destroyBean(form)); } - private scheduleLivePreviewUpdate( - draft: CalculatedColumnDraft, - mapper: ReturnType - ): void { + private scheduleLivePreviewUpdate(draft: CalculatedColumnDraft, mapper: CalculatedColumnReferenceMapper): void { const colId = draft.colId; this.pendingLivePreviewUpdatesByColId.set(colId, { draft, mapper }); if (this.scheduledLivePreviewColIds.has(colId)) { @@ -719,22 +739,17 @@ export class CalculatedColumnsService extends BeanStub implements NamedBean, ICa : (expressionPickers ?? []); } - private toDraft(column: AgColumn): CalculatedColumnDraft { - const beans = this.beans; + private toDraft(column: AgColumn, mapper: CalculatedColumnReferenceMapper): CalculatedColumnDraft { const colDef = column.colDef; const colId = column.colId; const cellDataType = colDef.cellDataType; - const displayName = beans.colNames.getDisplayNameForColumn(column, 'header'); + const displayName = this.beans.colNames.getDisplayNameForColumn(column, 'header'); return { colId, headerName: colDef.headerName ?? displayName ?? colId, cellDataType: typeof cellDataType === 'string' ? cellDataType : DEFAULT_DRAFT.cellDataType, - calculatedExpression: createCalculatedColumnReferenceMapper( - beans, - beans.colModel.colsList, - colId - ).toDisplayExpression(colDef.calculatedExpression ?? ''), + calculatedExpression: mapper.toDisplayExpression(colDef.calculatedExpression ?? ''), }; } @@ -797,7 +812,7 @@ export class CalculatedColumnsService extends BeanStub implements NamedBean, ICa const cols = this.beans.colModel.colsList; for (let i = 0, len = cols.length; i < len; ++i) { const column = cols[i]; - if (!_hasCalculatedExpression(column.colDef)) { + if (!column.isCalculatedCol) { continue; } const expression = column.colDef.calculatedExpression ?? ''; @@ -849,7 +864,7 @@ export class CalculatedColumnsService extends BeanStub implements NamedBean, ICa const cols = this.beans.colModel.colsList; for (let i = 0, len = cols.length; i < len; ++i) { const column = cols[i]; - if (!_hasCalculatedExpression(column.colDef)) { + if (!column.isCalculatedCol) { continue; } const expression = column.colDef.calculatedExpression ?? ''; diff --git a/packages/ag-grid-enterprise/src/formula/formulaService.ts b/packages/ag-grid-enterprise/src/formula/formulaService.ts index cb05810ac06..3bcd30bfeb9 100644 --- a/packages/ag-grid-enterprise/src/formula/formulaService.ts +++ b/packages/ag-grid-enterprise/src/formula/formulaService.ts @@ -11,7 +11,7 @@ import type { RowNodeDataChangedEvent, _ChangedRowNodes, } from 'ag-grid-community'; -import { BeanStub, _convertColumnEventSourceType, _hasCalculatedExpression, _warn } from 'ag-grid-community'; +import { BeanStub, _convertColumnEventSourceType, _warn } from 'ag-grid-community'; import { parseFormula } from './ast/parsers'; import { serializeFormula } from './ast/serializer'; @@ -116,7 +116,7 @@ export class FormulaService extends BeanStub implements IFormulaService, NamedBe if (col.isAllowFormula()) { editableFormulaColumnsPresent = true; } - if (calculatedColumnsEnabled && _hasCalculatedExpression(col.colDef)) { + if (col.isCalculatedCol) { calculatedColumnsPresent = true; } if (editableFormulaColumnsPresent && (calculatedColumnsPresent || !calculatedColumnsEnabled)) { diff --git a/packages/ag-grid-enterprise/src/menu/columnMenuFactory.ts b/packages/ag-grid-enterprise/src/menu/columnMenuFactory.ts index 6966fb2d03c..e0c7bfcfbff 100644 --- a/packages/ag-grid-enterprise/src/menu/columnMenuFactory.ts +++ b/packages/ag-grid-enterprise/src/menu/columnMenuFactory.ts @@ -4,7 +4,6 @@ import { _addGridCommonParams, _getDisplaySortForColumn, _getGrandTotalRow, - _hasCalculatedExpression, _isClientSideRowModel, _isLegacyMenuEnabled, } from 'ag-grid-community'; @@ -174,7 +173,7 @@ export class ColumnMenuFactory extends BeanStub implements NamedBean { if (!colModel.pivotMode) { result.push('calculatedColumn'); } - if (_hasCalculatedExpression(column?.colDef)) { + if (column?.isCalculatedCol) { result.push('editCalculatedColumn'); result.push('removeCalculatedColumn'); } diff --git a/packages/ag-grid-enterprise/src/menu/contextMenu.ts b/packages/ag-grid-enterprise/src/menu/contextMenu.ts index 1b33eb79f97..c57e5c7dd6a 100644 --- a/packages/ag-grid-enterprise/src/menu/contextMenu.ts +++ b/packages/ag-grid-enterprise/src/menu/contextMenu.ts @@ -23,13 +23,7 @@ import type { TouchShowContextMenuParam, WithoutGridCommon, } from 'ag-grid-community'; -import { - BeanStub, - _addGridCommonParams, - _attemptToRestoreCellFocus, - _getGrandTotalRow, - _hasCalculatedExpression, -} from 'ag-grid-community'; +import { BeanStub, _addGridCommonParams, _attemptToRestoreCellFocus, _getGrandTotalRow } from 'ag-grid-community'; import { AgContextMenuService } from '../agStack/agContextMenuService'; import { MENU_ITEM_CALLBACKS } from '../widgets/menuItemComponent'; @@ -92,19 +86,9 @@ export class ContextMenuService extends BeanStub implements NamedBean, IContextM const defaultMenuOptions: DefaultMenuItem[] = []; - const { - clipboardSvc, - chartSvc, - csvCreator, - excelCreator, - colModel, - rangeSvc, - gos, - notesSvc, - calculatedColsSvc, - } = this.beans; - - const isCalculatedColumn = _hasCalculatedExpression(column?.getColDef()) && calculatedColsSvc != null; + const { clipboardSvc, chartSvc, csvCreator, excelCreator, colModel, rangeSvc, gos, notesSvc } = this.beans; + + const isCalculatedColumn = !!(column as AgColumn | null)?.isCalculatedCol; if (_exists(node) && clipboardSvc) { if (column) { diff --git a/packages/ag-grid-enterprise/src/menu/menuItemMapper.ts b/packages/ag-grid-enterprise/src/menu/menuItemMapper.ts index c3558fff456..cf6fd81c5b6 100644 --- a/packages/ag-grid-enterprise/src/menu/menuItemMapper.ts +++ b/packages/ag-grid-enterprise/src/menu/menuItemMapper.ts @@ -20,7 +20,6 @@ import { BeanStub, _createIconNoSpan, _getRowNode, - _hasCalculatedExpression, _normalizeSortType, _resetColumnState, _warn, @@ -489,7 +488,7 @@ export class MenuItemMapper extends BeanStub implements NamedBean { } : null; case 'editCalculatedColumn': - return calculatedColsSvc && _hasCalculatedExpression(column?.colDef) + return calculatedColsSvc && column?.isCalculatedCol ? { name: localeTextFunc('calculatedColumnEdit', 'Edit Calculated Column'), icon: _createIconNoSpan('calculatedColumnEdit', beans, null), @@ -497,7 +496,7 @@ export class MenuItemMapper extends BeanStub implements NamedBean { } : null; case 'removeCalculatedColumn': - return calculatedColsSvc && _hasCalculatedExpression(column?.colDef) + return calculatedColsSvc && column?.isCalculatedCol ? { name: localeTextFunc('calculatedColumnRemove', 'Remove Calculated Column'), icon: _createIconNoSpan('calculatedColumnRemove', beans, null), From b9e0a85c871e2039e5d9ac158aae70b1c0df7ca9 Mon Sep 17 00:00:00 2001 From: Pete Reynolds <40919976+peterjrreynolds@users.noreply.github.com> Date: Wed, 10 Jun 2026 12:45:19 +0100 Subject: [PATCH 07/13] AG-17544 - allow overrides to styled root behaviour (#14018) --- packages/ag-stack/src/core/baseEnvironment.ts | 7 ++++++- packages/ag-stack/src/main-internal.ts | 7 ++++++- packages/ag-stack/src/theming/styledRoot.ts | 7 ++++++- scripts/setupLocalDeps.patch | 15 --------------- scripts/setupLocalDeps.sh | 3 --- 5 files changed, 18 insertions(+), 21 deletions(-) delete mode 100644 scripts/setupLocalDeps.patch diff --git a/packages/ag-stack/src/core/baseEnvironment.ts b/packages/ag-stack/src/core/baseEnvironment.ts index 389b5118ea3..fbbbedc6ee2 100644 --- a/packages/ag-stack/src/core/baseEnvironment.ts +++ b/packages/ag-stack/src/core/baseEnvironment.ts @@ -89,7 +89,7 @@ export abstract class BaseEnvironment< }); this.addDestroyFunc(() => this.mutationObserver.disconnect()); - this.addDestroyFunc(_initStyledRootFromInnerOfThreeElements(this, eRootDiv)); + this.initStyledRoot(); this.getSizeEl(LIST_ITEM_HEIGHT); this.initVariables(); @@ -307,6 +307,11 @@ export abstract class BaseEnvironment< [`${change}Changed`]: true, }); } + + // overridden by studio + protected initStyledRoot(): void { + this.addDestroyFunc(_initStyledRootFromInnerOfThreeElements(this, this.eRootDiv)); + } } /** @internal AG_GRID_INTERNAL - Not for public use. Can change / be removed at any time. */ diff --git a/packages/ag-stack/src/main-internal.ts b/packages/ag-stack/src/main-internal.ts index 1c6d3587f2e..984079ab6a9 100644 --- a/packages/ag-stack/src/main-internal.ts +++ b/packages/ag-stack/src/main-internal.ts @@ -75,7 +75,12 @@ export { AutoScrollService } from './rendering/autoScrollService'; export { CssClassManager } from './rendering/cssClassManager'; export { defaultFontFamily, defaultLightColorSchemeParams, sharedDefaults } from './theming/shared/shared-css'; export type { SharedThemeParams } from './theming/shared/shared-css'; -export { _createStyledRootElements, _initDetachedStyledRoot, _initStyledRoot } from './theming/styledRoot'; +export { + _createStyledRootElements, + _initDetachedStyledRoot, + _initStyledRoot, + _initStyledRootFromInnerOfThreeElements, +} from './theming/styledRoot'; export { _asThemeImpl, createSharedTheme, ThemeImpl } from './theming/themeImpl'; export type { ThemeLogger } from './theming/themeLogger'; export { diff --git a/packages/ag-stack/src/theming/styledRoot.ts b/packages/ag-stack/src/theming/styledRoot.ts index 6faf4df0665..c8e572ef860 100644 --- a/packages/ag-stack/src/theming/styledRoot.ts +++ b/packages/ag-stack/src/theming/styledRoot.ts @@ -30,7 +30,11 @@ export function _createStyledRootElements(): [outer: HTMLElement, inner: HTMLEle } /** @internal AG_GRID_INTERNAL - Not for public use. Can change / be removed at any time. */ -export function _initStyledRootFromInnerOfThreeElements(env: IEnvironment, inner: HTMLElement): () => void { +export function _initStyledRootFromInnerOfThreeElements( + env: IEnvironment, + inner: HTMLElement, + postApplyClasses?: () => void +): () => void { const middle = inner.parentElement!; const outer = middle.parentElement!; const applyClasses = () => { @@ -38,6 +42,7 @@ export function _initStyledRootFromInnerOfThreeElements(env: IEnvironment, inner outer.className = ['ag-styled-root', inheritClass].join(' '); middle.className = ['ag-styled-root', applyClass].join(' '); inner.className = ['ag-styled-root', directionClass].join(' '); + postApplyClasses?.(); }; applyClasses(); return env.onThemeChanged(applyClasses); diff --git a/scripts/setupLocalDeps.patch b/scripts/setupLocalDeps.patch deleted file mode 100644 index 49e902b8b5c..00000000000 --- a/scripts/setupLocalDeps.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/packages/ag-grid-enterprise/tsconfig.lib.json b/packages/ag-grid-enterprise/tsconfig.lib.json -index 1a566f32fc..096f4e6dbc 100644 ---- a/packages/ag-grid-enterprise/tsconfig.lib.json -+++ b/packages/ag-grid-enterprise/tsconfig.lib.json -@@ -3,8 +3,8 @@ - "compilerOptions": { - "types": [], - "baseUrl": "src", -- "module": "node16", -- "moduleResolution": "node16" -+ "module": "es2020", -+ "moduleResolution": "bundler" - }, - "include": ["src/**/*.ts"], - "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts", "src/**/test/**", "src/**/test-utils/**"] diff --git a/scripts/setupLocalDeps.sh b/scripts/setupLocalDeps.sh index 523fe3ea4c0..7857155cb16 100755 --- a/scripts/setupLocalDeps.sh +++ b/scripts/setupLocalDeps.sh @@ -25,6 +25,3 @@ packages=( for name in ${packages[@]} ; do ln -s $(readlink -f $(pwd)/..)/ag-charts/packages/${name}/ ./node_modules/${name} done - -echo "Applying configuration patch..." -git apply ./scripts/setupLocalDeps.patch From c7dba4bb9d4f3734ae5997dc8c7e8c0075b7baee Mon Sep 17 00:00:00 2001 From: Pete Reynolds <40919976+peterjrreynolds@users.noreply.github.com> Date: Wed, 10 Jun 2026 13:02:52 +0100 Subject: [PATCH 08/13] AG-17544 - update unlink script (#14021) --- scripts/removeLocalDeps.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/scripts/removeLocalDeps.sh b/scripts/removeLocalDeps.sh index cdf447bd466..cf3c763160a 100755 --- a/scripts/removeLocalDeps.sh +++ b/scripts/removeLocalDeps.sh @@ -7,6 +7,3 @@ find ./node_modules ./packages/*/node_modules -name ag-charts-\* -type l -depth echo "Reinstalling latest ag-charts-* versions." npm run bootstrap --force - -echo "Reverting configuration patch..." -git apply -R ./scripts/setupLocalDeps.patch From b0acd8040e72d603c027c4cb694c7c7dc81891c0 Mon Sep 17 00:00:00 2001 From: AgGitDeployment <80415517+AgGitDeployment@users.noreply.github.com> Date: Wed, 10 Jun 2026 13:07:40 +0100 Subject: [PATCH 09/13] Merge from latest. (#14020) --- .env | 2 +- community-modules/locale/package.json | 2 +- community-modules/styles/package.json | 2 +- documentation/ag-grid-docs/package.json | 12 ++++++------ documentation/update-algolia-indices/package.json | 2 +- package.json | 2 +- packages/ag-grid-angular/package.json | 6 +++--- .../projects/ag-grid-angular/package.json | 4 ++-- packages/ag-grid-community/package.json | 4 ++-- packages/ag-grid-community/src/version.ts | 2 +- packages/ag-grid-enterprise/package.json | 6 +++--- packages/ag-grid-enterprise/src/version.ts | 2 +- packages/ag-grid-react/package.json | 6 +++--- packages/ag-grid-vue3/package.json | 4 ++-- packages/ag-stack/package.json | 2 +- packages/ag-stack/src/version.ts | 2 +- .../package.json | 2 +- plugins/ag-grid-generate-example-files/package.json | 4 ++-- plugins/ag-grid-task-autogen/package.json | 2 +- testing/accessibility/package.json | 8 ++++---- testing/angular-tests/package.json | 6 +++--- testing/behavioural/package.json | 8 ++++---- testing/behavioural/src/version.ts | 2 +- testing/csp/package.json | 2 +- testing/module-size-angular/package.json | 8 ++++---- testing/module-size/package.json | 8 ++++---- testing/public-recipes/e2e/package.json | 4 ++-- testing/vue3-tests/package.json | 8 ++++---- 28 files changed, 61 insertions(+), 61 deletions(-) diff --git a/.env b/.env index ffd70502fd7..f20131068a4 100644 --- a/.env +++ b/.env @@ -1,5 +1,5 @@ # Production Build -BUILD_GRID_VERSION=35.3.0-beta.20260610.1055 +BUILD_GRID_VERSION=35.3.0-beta.20260610.1146 BUILD_CHARTS_VERSION=13.3.0-beta.20260610 ENV=local NX_BATCH_MODE=true diff --git a/community-modules/locale/package.json b/community-modules/locale/package.json index 143c24bd109..c76c08e297d 100644 --- a/community-modules/locale/package.json +++ b/community-modules/locale/package.json @@ -1,6 +1,6 @@ { "name": "@ag-grid-community/locale", - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "description": "Localisation Module for AG Grid, providing translations in 31 languages.", "main": "./dist/package/main.cjs.js", "types": "./dist/types/src/main.d.ts", diff --git a/community-modules/styles/package.json b/community-modules/styles/package.json index 83d66f80cc0..f1cb677fdb3 100644 --- a/community-modules/styles/package.json +++ b/community-modules/styles/package.json @@ -1,6 +1,6 @@ { "name": "@ag-grid-community/styles", - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "description": "AG Grid Styles and Themes", "main": "_index.scss", "files": [ diff --git a/documentation/ag-grid-docs/package.json b/documentation/ag-grid-docs/package.json index 8a92d1aeda1..9ecc88c7eda 100644 --- a/documentation/ag-grid-docs/package.json +++ b/documentation/ag-grid-docs/package.json @@ -2,7 +2,7 @@ "name": "ag-grid-docs", "description": "Documentation for AG Grid", "type": "module", - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "repository": { "type": "git", "url": "https://github.com/ag-grid/ag-grid.git" @@ -59,11 +59,11 @@ "ag-charts-types": "13.3.0-beta.20260610", "ag-charts-react": "13.3.0-beta.20260610", "ag-charts-vue3": "13.3.0-beta.20260610", - "ag-grid-angular": "35.3.0-beta.20260610.1055", - "ag-grid-community": "35.3.0-beta.20260610.1055", - "ag-grid-enterprise": "35.3.0-beta.20260610.1055", - "ag-grid-react": "35.3.0-beta.20260610.1055", - "ag-grid-vue3": "35.3.0-beta.20260610.1055", + "ag-grid-angular": "35.3.0-beta.20260610.1146", + "ag-grid-community": "35.3.0-beta.20260610.1146", + "ag-grid-enterprise": "35.3.0-beta.20260610.1146", + "ag-grid-react": "35.3.0-beta.20260610.1146", + "ag-grid-vue3": "35.3.0-beta.20260610.1146", "algoliasearch": "^5.51.0", "astro": "6.1.9", "cheerio": "^1.0.0", diff --git a/documentation/update-algolia-indices/package.json b/documentation/update-algolia-indices/package.json index f0f01659374..298369af14e 100644 --- a/documentation/update-algolia-indices/package.json +++ b/documentation/update-algolia-indices/package.json @@ -1,6 +1,6 @@ { "name": "update-algolia-indices", - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "description": "Update algolia indices", "main": "src/index.ts", "type": "module", diff --git a/package.json b/package.json index 5a5ac8e9c33..7be8ac36448 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid", - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "license": "MIT", "scripts": { "compressVideo": "tsx external/ag-website-shared/scripts/compress-video", diff --git a/packages/ag-grid-angular/package.json b/packages/ag-grid-angular/package.json index 65b5f3902bd..9f8fb53f88b 100644 --- a/packages/ag-grid-angular/package.json +++ b/packages/ag-grid-angular/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-angular", - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "description": "AG Grid Angular Component", "scripts": { "clean": "rimraf dist", @@ -15,7 +15,7 @@ "module": "./dist/ag-grid-angular/fesm2022/ag-grid-angular.mjs", "typings": "./dist/ag-grid-angular/index.d.ts", "dependencies": { - "ag-grid-community": "35.3.0-beta.20260610.1055", + "ag-grid-community": "35.3.0-beta.20260610.1146", "@angular/animations": "^20.0.0", "@angular/common": "^20.0.0", "@angular/compiler": "^20.0.0", @@ -27,7 +27,7 @@ "zone.js": "~0.15.1" }, "devDependencies": { - "ag-grid-community": "35.3.0-beta.20260610.1055", + "ag-grid-community": "35.3.0-beta.20260610.1146", "@angular/build": "^20.0.0", "@angular/cli": "^20.0.0", "@angular/forms": "^20.0.0", diff --git a/packages/ag-grid-angular/projects/ag-grid-angular/package.json b/packages/ag-grid-angular/projects/ag-grid-angular/package.json index 748f25e5c14..0d8e69c8d48 100644 --- a/packages/ag-grid-angular/projects/ag-grid-angular/package.json +++ b/packages/ag-grid-angular/projects/ag-grid-angular/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-angular", - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "description": "AG Grid Angular Component", "license": "MIT", "peerDependencies": { @@ -8,7 +8,7 @@ "@angular/core": ">= 20.0.0" }, "dependencies": { - "ag-grid-community": "35.3.0-beta.20260610.1055", + "ag-grid-community": "35.3.0-beta.20260610.1146", "tslib": "^2.8.1" }, "repository": { diff --git a/packages/ag-grid-community/package.json b/packages/ag-grid-community/package.json index 6ab5e81fcad..56a14888768 100644 --- a/packages/ag-grid-community/package.json +++ b/packages/ag-grid-community/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-community", - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "description": "Advanced Data Grid / Data Table supporting Javascript / Typescript / React / Angular / Vue", "main": "./dist/package/main.cjs.js", "types": "./dist/types/src/main.d.ts", @@ -119,7 +119,7 @@ ], "homepage": "https://www.ag-grid.com/", "dependencies": { - "ag-stack": "35.3.0-beta.20260610.1055", + "ag-stack": "35.3.0-beta.20260610.1146", "ag-charts-types": "13.3.0-beta.20260610" }, "devDependencies": { diff --git a/packages/ag-grid-community/src/version.ts b/packages/ag-grid-community/src/version.ts index c1f816adaf7..033f6034e0c 100644 --- a/packages/ag-grid-community/src/version.ts +++ b/packages/ag-grid-community/src/version.ts @@ -1,2 +1,2 @@ // DO NOT UPDATE MANUALLY: Generated from script during build time -export const VERSION = '35.3.0-beta.20260610.1055'; +export const VERSION = '35.3.0-beta.20260610.1146'; diff --git a/packages/ag-grid-enterprise/package.json b/packages/ag-grid-enterprise/package.json index cf414d8911d..b05969b80c4 100644 --- a/packages/ag-grid-enterprise/package.json +++ b/packages/ag-grid-enterprise/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-enterprise", - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "description": "Advanced Data Grid / Data Table supporting Javascript / Typescript / React / Angular / Vue", "main": "./dist/package/main.cjs.js", "types": "./dist/types/src/main.d.ts", @@ -113,8 +113,8 @@ ], "homepage": "https://www.ag-grid.com/", "dependencies": { - "ag-stack": "35.3.0-beta.20260610.1055", - "ag-grid-community": "35.3.0-beta.20260610.1055" + "ag-stack": "35.3.0-beta.20260610.1146", + "ag-grid-community": "35.3.0-beta.20260610.1146" }, "optionalDependencies": { "ag-charts-community": "13.3.0-beta.20260610", diff --git a/packages/ag-grid-enterprise/src/version.ts b/packages/ag-grid-enterprise/src/version.ts index c1f816adaf7..033f6034e0c 100644 --- a/packages/ag-grid-enterprise/src/version.ts +++ b/packages/ag-grid-enterprise/src/version.ts @@ -1,2 +1,2 @@ // DO NOT UPDATE MANUALLY: Generated from script during build time -export const VERSION = '35.3.0-beta.20260610.1055'; +export const VERSION = '35.3.0-beta.20260610.1146'; diff --git a/packages/ag-grid-react/package.json b/packages/ag-grid-react/package.json index cd17099b610..73f72d488b3 100644 --- a/packages/ag-grid-react/package.json +++ b/packages/ag-grid-react/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-react", - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "description": "AG Grid React Component", "main": "./dist/package/index.cjs.js", "types": "./dist/types/src/index.d.ts", @@ -31,7 +31,7 @@ "devDependencies": { "@babel/runtime": "^7.29.2", "prop-types": "^15.6.2", - "ag-grid-community": "35.3.0-beta.20260610.1055", + "ag-grid-community": "35.3.0-beta.20260610.1146", "@babel/plugin-proposal-throw-expressions": "^7.27.1", "@babel/preset-typescript": "^7.28.5", "@types/react": "~18.3.26", @@ -44,7 +44,7 @@ }, "dependencies": { "prop-types": "^15.8.1", - "ag-grid-community": "35.3.0-beta.20260610.1055" + "ag-grid-community": "35.3.0-beta.20260610.1146" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", diff --git a/packages/ag-grid-vue3/package.json b/packages/ag-grid-vue3/package.json index 52f7f88fe6b..9ea819a474d 100644 --- a/packages/ag-grid-vue3/package.json +++ b/packages/ag-grid-vue3/package.json @@ -1,7 +1,7 @@ { "name": "ag-grid-vue3", "description": "AG Grid Vue 3 Component", - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "author": "Sean Landsman ", "license": "MIT", "files": [ @@ -44,7 +44,7 @@ "build-only:watch": "vite build --watch" }, "dependencies": { - "ag-grid-community": "35.3.0-beta.20260610.1055" + "ag-grid-community": "35.3.0-beta.20260610.1146" }, "devDependencies": { "vue": "^3.5.32", diff --git a/packages/ag-stack/package.json b/packages/ag-stack/package.json index 692b7e8f875..0bd04fb1218 100644 --- a/packages/ag-stack/package.json +++ b/packages/ag-stack/package.json @@ -1,6 +1,6 @@ { "name": "ag-stack", - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "description": "Advanced Data Grid / Data Table supporting Javascript / Typescript / React / Angular / Vue", "main": "./dist/package/main.cjs.js", "types": "./dist/types/src/main.d.ts", diff --git a/packages/ag-stack/src/version.ts b/packages/ag-stack/src/version.ts index c1f816adaf7..033f6034e0c 100644 --- a/packages/ag-stack/src/version.ts +++ b/packages/ag-stack/src/version.ts @@ -1,2 +1,2 @@ // DO NOT UPDATE MANUALLY: Generated from script during build time -export const VERSION = '35.3.0-beta.20260610.1055'; +export const VERSION = '35.3.0-beta.20260610.1146'; diff --git a/plugins/ag-grid-generate-code-reference-files/package.json b/plugins/ag-grid-generate-code-reference-files/package.json index 680d24841eb..cc5afefaa77 100644 --- a/plugins/ag-grid-generate-code-reference-files/package.json +++ b/plugins/ag-grid-generate-code-reference-files/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-generate-code-reference-files", - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "private": true, "dependencies": { "ag-shared": "0.0.1", diff --git a/plugins/ag-grid-generate-example-files/package.json b/plugins/ag-grid-generate-example-files/package.json index 3c186c70adc..99250239bc6 100644 --- a/plugins/ag-grid-generate-example-files/package.json +++ b/plugins/ag-grid-generate-example-files/package.json @@ -1,10 +1,10 @@ { "name": "ag-grid-generate-example-files", - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "private": true, "dependencies": { "ag-shared": "0.0.1", - "ag-grid-community": "35.3.0-beta.20260610.1055", + "ag-grid-community": "35.3.0-beta.20260610.1146", "glob": "^11.1.0", "typescript": "~5.8.3", "cheerio": "^1.2.0", diff --git a/plugins/ag-grid-task-autogen/package.json b/plugins/ag-grid-task-autogen/package.json index e26a2469274..8ee0c62e3cf 100644 --- a/plugins/ag-grid-task-autogen/package.json +++ b/plugins/ag-grid-task-autogen/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-task-autogen", - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "private": true, "dependencies": { "@nx/devkit": "20.8.4", diff --git a/testing/accessibility/package.json b/testing/accessibility/package.json index 86717846166..c65f8d33615 100644 --- a/testing/accessibility/package.json +++ b/testing/accessibility/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-accessibility", - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "scripts": { "download-examples": "curl --retry 5 -retry-all-errors https://grid-staging.ag-grid.com/debug/all-examples.json > ./all-examples.json", "download-examples-local": "curl https://localhost:4610/debug/all-examples.json > ./all-examples.json", @@ -18,9 +18,9 @@ "@angular/platform-browser": "^19.0.0", "@angular/platform-browser-dynamic": "^19.0.0", "@angular/router": "^19.0.0", - "ag-grid-angular": "35.3.0-beta.20260610.1055", - "ag-grid-community": "35.3.0-beta.20260610.1055", - "ag-grid-enterprise": "35.3.0-beta.20260610.1055", + "ag-grid-angular": "35.3.0-beta.20260610.1146", + "ag-grid-community": "35.3.0-beta.20260610.1146", + "ag-grid-enterprise": "35.3.0-beta.20260610.1146", "ag-charts-community": "13.3.0-beta.20260610", "ag-charts-enterprise": "13.3.0-beta.20260610", "rxjs": "~7.8.2", diff --git a/testing/angular-tests/package.json b/testing/angular-tests/package.json index d72eac29470..3b776cca68a 100644 --- a/testing/angular-tests/package.json +++ b/testing/angular-tests/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-angular-tests", - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "private": true, "scripts": { "test:e2e": "jest --no-cache" @@ -11,8 +11,8 @@ "@angular/core": "^21.0.0", "@angular/platform-browser": "^21.0.0", "@angular/platform-browser-dynamic": "^21.0.0", - "ag-grid-angular": "35.3.0-beta.20260610.1055", - "ag-grid-community": "35.3.0-beta.20260610.1055", + "ag-grid-angular": "35.3.0-beta.20260610.1146", + "ag-grid-community": "35.3.0-beta.20260610.1146", "rxjs": "~7.8.2", "tslib": "^2.8.1", "zone.js": "~0.15.0" diff --git a/testing/behavioural/package.json b/testing/behavioural/package.json index e8591b0bef4..7776256f6d1 100644 --- a/testing/behavioural/package.json +++ b/testing/behavioural/package.json @@ -1,6 +1,6 @@ { "name": "ag-behavioural-testing", - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "private": true, "description": "Behavioural unit testing for ag-Grid", "dependencies": { @@ -8,9 +8,9 @@ }, "type": "module", "devDependencies": { - "ag-grid-community": "35.3.0-beta.20260610.1055", - "ag-grid-enterprise": "35.3.0-beta.20260610.1055", - "ag-grid-react": "35.3.0-beta.20260610.1055", + "ag-grid-community": "35.3.0-beta.20260610.1146", + "ag-grid-enterprise": "35.3.0-beta.20260610.1146", + "ag-grid-react": "35.3.0-beta.20260610.1146", "@types/react": "^18.3.23", "@types/react-dom": "^18.3.7", "@testing-library/dom": "^10.4.1", diff --git a/testing/behavioural/src/version.ts b/testing/behavioural/src/version.ts index c1f816adaf7..033f6034e0c 100644 --- a/testing/behavioural/src/version.ts +++ b/testing/behavioural/src/version.ts @@ -1,2 +1,2 @@ // DO NOT UPDATE MANUALLY: Generated from script during build time -export const VERSION = '35.3.0-beta.20260610.1055'; +export const VERSION = '35.3.0-beta.20260610.1146'; diff --git a/testing/csp/package.json b/testing/csp/package.json index d5a5972ee5d..aa78a0c0305 100644 --- a/testing/csp/package.json +++ b/testing/csp/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-csp", - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "description": "CSP testing for AG Grid", "main": "index.js", "scripts": {}, diff --git a/testing/module-size-angular/package.json b/testing/module-size-angular/package.json index a0233eb7d5f..5ee15860083 100644 --- a/testing/module-size-angular/package.json +++ b/testing/module-size-angular/package.json @@ -1,6 +1,6 @@ { "name": "ag-grid-module-size-angular", - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "scripts": { "ng": "ng", "start": "ng serve", @@ -20,9 +20,9 @@ "@angular/platform-browser": "^20.0.0", "@angular/platform-browser-dynamic": "^20.0.0", "@angular/router": "^20.0.0", - "ag-grid-angular": "35.3.0-beta.20260610.1055", - "ag-grid-community": "35.3.0-beta.20260610.1055", - "ag-grid-enterprise": "35.3.0-beta.20260610.1055", + "ag-grid-angular": "35.3.0-beta.20260610.1146", + "ag-grid-community": "35.3.0-beta.20260610.1146", + "ag-grid-enterprise": "35.3.0-beta.20260610.1146", "ag-charts-community": "13.3.0-beta.20260610", "ag-charts-enterprise": "13.3.0-beta.20260610", "rxjs": "~7.8.2", diff --git a/testing/module-size/package.json b/testing/module-size/package.json index c460594a52b..a5660915c7b 100644 --- a/testing/module-size/package.json +++ b/testing/module-size/package.json @@ -1,7 +1,7 @@ { "name": "ag-grid-module-size", "private": true, - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "scripts": { "dev": "vite", "cp-app": "cp ./src/App_Src.tsx ./src/App_AUTO.tsx", @@ -14,9 +14,9 @@ "test:e2e": "run-s \"module-combinations -- {1}\" module-validate --" }, "dependencies": { - "ag-grid-react": "35.3.0-beta.20260610.1055", - "ag-grid-community": "35.3.0-beta.20260610.1055", - "ag-grid-enterprise": "35.3.0-beta.20260610.1055", + "ag-grid-react": "35.3.0-beta.20260610.1146", + "ag-grid-community": "35.3.0-beta.20260610.1146", + "ag-grid-enterprise": "35.3.0-beta.20260610.1146", "ag-charts-community": "13.3.0-beta.20260610", "ag-charts-enterprise": "13.3.0-beta.20260610", "ag-shared": "0.0.1", diff --git a/testing/public-recipes/e2e/package.json b/testing/public-recipes/e2e/package.json index 8964cc25abe..c98c08340b9 100644 --- a/testing/public-recipes/e2e/package.json +++ b/testing/public-recipes/e2e/package.json @@ -1,12 +1,12 @@ { "name": "ag-grid-public-e2e-testing-recipes", - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "description": "Public E2E testing recipes for AG Grid", "main": "index.js", "scripts": {}, "license": "MIT", "devDependencies": { - "ag-grid-community": "35.3.0-beta.20260610.1055", + "ag-grid-community": "35.3.0-beta.20260610.1146", "playwright": "^1.59.1", "@playwright/test": "^1.59.1", "@types/node": "^22.15.3" diff --git a/testing/vue3-tests/package.json b/testing/vue3-tests/package.json index 67e5c0be435..08b69d13730 100644 --- a/testing/vue3-tests/package.json +++ b/testing/vue3-tests/package.json @@ -1,7 +1,7 @@ { "name": "ag-grid-vue3-tests", "private": true, - "version": "35.3.0-beta.20260610.1055", + "version": "35.3.0-beta.20260610.1146", "type": "module", "scripts": { "dev": "vite", @@ -15,9 +15,9 @@ "dependencies": { "vue": "^3.5.32", "vue-router": "^5.0.6", - "ag-grid-community": "35.3.0-beta.20260610.1055", - "ag-grid-enterprise": "35.3.0-beta.20260610.1055", - "ag-grid-vue3": "35.3.0-beta.20260610.1055", + "ag-grid-community": "35.3.0-beta.20260610.1146", + "ag-grid-enterprise": "35.3.0-beta.20260610.1146", + "ag-grid-vue3": "35.3.0-beta.20260610.1146", "decimal.js": "^10.6.0" }, "devDependencies": { From 98c3c79cec1b36075d47efb37a41e1fb33c234a7 Mon Sep 17 00:00:00 2001 From: Bernie Sumption Date: Wed, 10 Jun 2026 14:34:15 +0200 Subject: [PATCH 10/13] AG-14740 Prevent pagination panel text from changing size when navigating (#13974) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * AG-14740 Fix pagination panel scrollbar jump when navigating to last page When the pagination panel is scrolled right and the user navigates to the last page, the row-summary text widens (e.g. "1 to 10 of 8,618" → "8,611 to 8,618 of 8,618"), growing scrollWidth without changing scrollLeft, causing the scrollbar thumb to visibly jump left. Fix by pre-reserving the maximum width using an inline-grid layout on the row-summary panel. A ::before pseudo-element holds a visibility:hidden placeholder string (digits replaced with 0s, same locale format as the real text) as one grid item; the real content is the other grid item in the same cell. The grid sizes to the wider of the two, so the panel never grows when the real text widens. * AG-14740 Escape locale strings in CSS custom property value * AG-14740 add legacy themes css * Better CSS string escaping * Fix lint error --- .../src/internal/base/parts/_footer.scss | 17 +++++++ .../src/pagination/paginationComp.css | 17 +++++++ .../src/pagination/rowSummaryComp.ts | 46 ++++++++++++------- 3 files changed, 63 insertions(+), 17 deletions(-) diff --git a/community-modules/styles/src/internal/base/parts/_footer.scss b/community-modules/styles/src/internal/base/parts/_footer.scss index f75f8507bd6..9384dd5e71d 100644 --- a/community-modules/styles/src/internal/base/parts/_footer.scss +++ b/community-modules/styles/src/internal/base/parts/_footer.scss @@ -38,6 +38,23 @@ line-height: 0; } + .ag-paging-row-summary-panel { + display: inline-grid; + + &::before { + content: var(--ag-internal-pagination-width-string); + grid-area: 1/1; + visibility: hidden; + font-weight: 500; + font-variant-numeric: tabular-nums; + } + } + + .ag-paging-row-summary-content { + grid-area: 1/1; + justify-self: center; + } + .ag-status-bar { border-top: var(--ag-borders) var(--ag-border-color); color: var(--ag-disabled-foreground-color); diff --git a/packages/ag-grid-community/src/pagination/paginationComp.css b/packages/ag-grid-community/src/pagination/paginationComp.css index 684e108b538..ec96ec59d51 100644 --- a/packages/ag-grid-community/src/pagination/paginationComp.css +++ b/packages/ag-grid-community/src/pagination/paginationComp.css @@ -54,3 +54,20 @@ /* avoids misalignment of buttons and text */ line-height: 0; } + +.ag-paging-row-summary-panel { + display: inline-grid; +} + +.ag-paging-row-summary-panel::before { + content: var(--ag-internal-pagination-width-string); + grid-area: 1/1; + visibility: hidden; + font-weight: 500; + font-variant-numeric: tabular-nums; +} + +.ag-paging-row-summary-content { + grid-area: 1/1; + justify-self: center; +} diff --git a/packages/ag-grid-community/src/pagination/rowSummaryComp.ts b/packages/ag-grid-community/src/pagination/rowSummaryComp.ts index b213d590e64..41d82ef1d23 100644 --- a/packages/ag-grid-community/src/pagination/rowSummaryComp.ts +++ b/packages/ag-grid-community/src/pagination/rowSummaryComp.ts @@ -35,23 +35,29 @@ export class RowSummaryComp extends Component { children: [ { tag: 'span', - ref: 'lbFirstRowOnPage', - cls: 'ag-paging-row-summary-panel-number', - attrs: { id: `${idPrefix}-first-row` }, - }, - { tag: 'span', attrs: { id: `${idPrefix}-to` }, children: localeTextFunc('to', 'to') }, - { - tag: 'span', - ref: 'lbLastRowOnPage', - cls: 'ag-paging-row-summary-panel-number', - attrs: { id: `${idPrefix}-last-row` }, - }, - { tag: 'span', attrs: { id: `${idPrefix}-of` }, children: localeTextFunc('of', 'of') }, - { - tag: 'span', - ref: 'lbRecordCount', - cls: 'ag-paging-row-summary-panel-number', - attrs: { id: `${idPrefix}-row-count` }, + cls: 'ag-paging-row-summary-content', + children: [ + { + tag: 'span', + ref: 'lbFirstRowOnPage', + cls: 'ag-paging-row-summary-panel-number', + attrs: { id: `${idPrefix}-first-row` }, + }, + { tag: 'span', attrs: { id: `${idPrefix}-to` }, children: localeTextFunc('to', 'to') }, + { + tag: 'span', + ref: 'lbLastRowOnPage', + cls: 'ag-paging-row-summary-panel-number', + attrs: { id: `${idPrefix}-last-row` }, + }, + { tag: 'span', attrs: { id: `${idPrefix}-of` }, children: localeTextFunc('of', 'of') }, + { + tag: 'span', + ref: 'lbRecordCount', + cls: 'ag-paging-row-summary-panel-number', + attrs: { id: `${idPrefix}-row-count` }, + }, + ], }, ], }); @@ -116,5 +122,11 @@ export class RowSummaryComp extends Component { const strTo = localeTextFunc('to', 'to'); const strOf = localeTextFunc('of', 'of'); this.ariaStatus = `${lbFirstRowOnPage} ${strTo} ${lbLastRowOnPage} ${strOf} ${lbRecordCount}`; + + const esc = (s: string) => s.replace(/\\/g, '\\\\').replace(/'/g, "\\'").replace(/\s+/g, ' '); + this.getGui().style.setProperty( + '--ag-internal-pagination-width-string', + `'${lbRecordCount} ${esc(strTo)} ${lbRecordCount} ${esc(strOf)} ${lbRecordCount}'`.replaceAll(/\d/g, '0') + ); } } From e9b9e26d3f25d31f4e4a776d5db66c33a79cb237 Mon Sep 17 00:00:00 2001 From: Stephen Cooper Date: Wed, 10 Jun 2026 13:54:05 +0100 Subject: [PATCH 11/13] AG-17535 - [Fill Handle] - fix readOnlyEdit fill handle using wrong source for boolean/dateString columns (#14012) * AG-17535 - [Fill Handle] - fix readOnlyEdit fill handle using wrong source for boolean/dateString columns * fix nested ternaries in fill handle tests --- .../src/rangeSelection/agFillHandle.ts | 11 +- .../clipboard/clipboard-fill-handle.test.ts | 108 ++++++++++++++++++ 2 files changed, 117 insertions(+), 2 deletions(-) diff --git a/packages/ag-grid-enterprise/src/rangeSelection/agFillHandle.ts b/packages/ag-grid-enterprise/src/rangeSelection/agFillHandle.ts index b82ab4e1731..4054ec0d9bc 100644 --- a/packages/ag-grid-enterprise/src/rangeSelection/agFillHandle.ts +++ b/packages/ag-grid-enterprise/src/rangeSelection/agFillHandle.ts @@ -348,6 +348,10 @@ export class AgFillHandle extends AbstractSelectionHandle { ) => { let currentValue: any; let skipValue: boolean = false; + // ValueContext entries feed the cyclic source lookup in processValues, so a filled + // cell must record the cell its value originated from, not the cell being written. + let valueSourceCol: AgColumn = col; + let valueSourceRowNode: RowNode = rowNode; if (withinInitialRange) { currentValue = valueSvc.getValue(col, rowNode, 'edit'); @@ -369,6 +373,9 @@ export class AgFillHandle extends AbstractSelectionHandle { idx: idx++, }); + valueSourceCol = sourceCol ?? col; + valueSourceRowNode = sourceRowNode ?? rowNode; + currentValue = value; if (col.isCellEditable(rowNode)) { const cellValue = valueSvc.getValue(col, rowNode, 'edit'); @@ -410,8 +417,8 @@ export class AgFillHandle extends AbstractSelectionHandle { if (!skipValue) { currentValues.push({ value: currentValue, - column: col, - rowNode, + column: valueSourceCol, + rowNode: valueSourceRowNode, }); } }; diff --git a/testing/behavioural/src/cell-editing/clipboard/clipboard-fill-handle.test.ts b/testing/behavioural/src/cell-editing/clipboard/clipboard-fill-handle.test.ts index 505519953ce..e8fbaa2083f 100644 --- a/testing/behavioural/src/cell-editing/clipboard/clipboard-fill-handle.test.ts +++ b/testing/behavioural/src/cell-editing/clipboard/clipboard-fill-handle.test.ts @@ -316,4 +316,112 @@ describe('Clipboard Paste Behaviour: fill handle', () => { expect(editRequests).toEqual(['ROW_1:field:Top Value', 'ROW_2:field:Top Value']); }); + + test('readOnlyEdit fill handle uses source cell value for all column types', async () => { + const editRequests: string[] = []; + + const api = await gridMgr.createGridAndWait('clipboardGridReadOnlyFillTypes', { + readOnlyEdit: true, + cellSelection: { + handle: { + mode: 'fill', + }, + }, + columnDefs: [ + { field: 'text', editable: true }, + { field: 'bool', editable: true }, + { field: 'date', editable: true, cellDataType: 'dateString' }, + ], + rowData: [ + { id: 'ROW_0', text: 'Source', bool: true, date: '2024-01-15' }, + { id: 'ROW_1', text: 'Other1', bool: false, date: '2024-06-20' }, + { id: 'ROW_2', text: 'Other2', bool: false, date: '2024-12-25' }, + ], + getRowId: (params) => params.data.id, + onCellEditRequest: (event) => { + editRequests.push(`${event.node?.id ?? 'unknown'}:${event.colDef.field}:${event.newValue}`); + }, + }); + + const gridDiv = getGridElement(api)! as HTMLElement; + + for (const field of ['text', 'bool', 'date']) { + editRequests.length = 0; + + await asyncSetTimeout(1); + const cell = getByTestId(gridDiv, agTestIdFor.cell('ROW_0', field)); + const cellSelectionChanged = waitForEvent('cellSelectionChanged', api); + cell.dispatchEvent(new MouseEvent('touchstart', { bubbles: true })); + await cellSelectionChanged; + await asyncSetTimeout(1); + + const fillHandle = getByTestId(gridDiv, agTestIdFor.fillHandle()); + const fillEnd = waitForEvent('fillEnd', api); + await userEvent.dblClick(fillHandle); + await fillEnd; + + const sourceValues: Record = { text: 'Source', bool: 'true', date: '2024-01-15' }; + const sourceValue = sourceValues[field]; + expect(editRequests, `fill for ${field} column`).toEqual([ + `ROW_1:${field}:${sourceValue}`, + `ROW_2:${field}:${sourceValue}`, + ]); + } + }); + + test('readOnlyEdit fill handle cycles multi-row selection pattern for all column types', async () => { + const editRequests: string[] = []; + + const api = await gridMgr.createGridAndWait('clipboardGridReadOnlyFillCyclic', { + readOnlyEdit: true, + cellSelection: { + handle: { + mode: 'fill', + }, + }, + columnDefs: [ + { field: 'text', editable: true }, + { field: 'bool', editable: true }, + { field: 'date', editable: true, cellDataType: 'dateString' }, + ], + rowData: [ + { id: 'ROW_0', text: 'A', bool: true, date: '2024-01-15' }, + { id: 'ROW_1', text: 'B', bool: false, date: '2024-06-20' }, + { id: 'ROW_2', text: 'X', bool: false, date: '2024-12-25' }, + { id: 'ROW_3', text: 'Y', bool: false, date: '2024-12-31' }, + { id: 'ROW_4', text: 'Z', bool: true, date: '2024-03-01' }, + ], + getRowId: (params) => params.data.id, + onCellEditRequest: (event) => { + editRequests.push(`${event.node?.id ?? 'unknown'}:${event.colDef.field}:${event.newValue}`); + }, + }); + + const gridDiv = getGridElement(api)! as HTMLElement; + + for (const field of ['text', 'bool', 'date']) { + editRequests.length = 0; + api.clearCellSelection(); + + const cellSelectionChanged = waitForEvent('cellSelectionChanged', api); + api.addCellRange({ rowStartIndex: 0, rowEndIndex: 1, columns: [field] }); + await cellSelectionChanged; + await asyncSetTimeout(1); + + const fillHandle = getByTestId(gridDiv, agTestIdFor.fillHandle()); + const fillEnd = waitForEvent('fillEnd', api); + await userEvent.dblClick(fillHandle); + await fillEnd; + + const expectedRow0: Record = { text: 'A', bool: 'true', date: '2024-01-15' }; + const expectedRow1: Record = { text: 'B', bool: 'false', date: '2024-06-20' }; + const val0 = expectedRow0[field]; + const val1 = expectedRow1[field]; + expect(editRequests, `cyclic fill for ${field} column`).toEqual([ + `ROW_2:${field}:${val0}`, + `ROW_3:${field}:${val1}`, + `ROW_4:${field}:${val0}`, + ]); + } + }); }); From 16ed0d3c0fbaefe38a4cbd79dc1fac594088df84 Mon Sep 17 00:00:00 2001 From: Guilherme Lopes Date: Wed, 10 Jun 2026 09:54:38 -0300 Subject: [PATCH 12/13] AG-17413 - [Calculated Columns] - Fixed RTL expression (#14022) --- .../src/internal/base/parts/_calculated-columns.scss | 5 +++++ .../styles/src/internal/base/parts/_toolbar.scss | 10 +--------- .../src/calculatedColumns/calculatedColumns.css | 8 ++++++++ 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/community-modules/styles/src/internal/base/parts/_calculated-columns.scss b/community-modules/styles/src/internal/base/parts/_calculated-columns.scss index 388d8aff703..944fa14de57 100644 --- a/community-modules/styles/src/internal/base/parts/_calculated-columns.scss +++ b/community-modules/styles/src/internal/base/parts/_calculated-columns.scss @@ -29,6 +29,11 @@ } } + .ag-rtl .ag-calculated-column-expression-wrap .ag-text-area-input { + padding-left: var(--ag-input-padding-start); + direction: ltr; + } + .ag-calculated-column-expression-tools { display: flex; gap: calc(var(--ag-grid-size) / 2); diff --git a/community-modules/styles/src/internal/base/parts/_toolbar.scss b/community-modules/styles/src/internal/base/parts/_toolbar.scss index fc2769e50b8..24e2e82929b 100644 --- a/community-modules/styles/src/internal/base/parts/_toolbar.scss +++ b/community-modules/styles/src/internal/base/parts/_toolbar.scss @@ -56,18 +56,15 @@ color: var(--ag-icon-button-hover-color, var(--ag-foreground-color)); } - // stylelint-disable-next-line selector-max-specificity .ag-toolbar-button-wrapper:hover .ag-toolbar-button, .ag-toolbar-button-wrapper:hover .ag-toolbar-button .ag-icon { color: var(--ag-icon-button-hover-color, var(--ag-foreground-color)); } - // stylelint-disable-next-line selector-max-specificity .ag-toolbar > .ag-toolbar-button-wrapper:first-child > .ag-toolbar-button { border-start-start-radius: calc(var(--ag-border-radius) + 1px); } - // stylelint-disable-next-line selector-max-specificity .ag-toolbar > .ag-toolbar-button-wrapper:last-child > .ag-toolbar-button { border-start-end-radius: calc(var(--ag-border-radius) + 1px); } @@ -103,18 +100,15 @@ margin: 0 calc(var(--ag-grid-size) * 2); } - // stylelint-disable-next-line selector-max-specificity .ag-toolbar-input + .ag-toolbar-input { margin-inline-start: 0; } - // stylelint-disable-next-line selector-max-specificity .ag-toolbar > .ag-toolbar-input:first-child, .ag-toolbar-right-start + .ag-toolbar-input { margin-inline-start: var(--ag-grid-size); } - // stylelint-disable-next-line selector-max-specificity .ag-toolbar > .ag-toolbar-input:last-child { margin-inline-end: var(--ag-grid-size); } @@ -146,7 +140,6 @@ // High-specificity padding override — beats theme text-input padding-left rules // (which reach .ag-theme-X .ag-ltr input[class^='ag-'][type='text'] = 0-4-1) .ag-toolbar-input { - // stylelint-disable-next-line selector-max-specificity input[class^='ag-'][type='text'].ag-toolbar-input-field { @include ag.unthemed-rtl( ( @@ -218,8 +211,7 @@ min-width: 0; } - // High-specificity overrides to prevent theme text-input rules reinstating border/shadow - // stylelint-disable-next-line selector-max-specificity + // high-specificity overrides to prevent theme text-input rules reinstating border/shadow .ag-toolbar .ag-toolbar-find input[class^='ag-'][type='text'].ag-toolbar-input-field { border: none; box-shadow: none; diff --git a/packages/ag-grid-enterprise/src/calculatedColumns/calculatedColumns.css b/packages/ag-grid-enterprise/src/calculatedColumns/calculatedColumns.css index 084a2225f2c..c97d8a5c678 100644 --- a/packages/ag-grid-enterprise/src/calculatedColumns/calculatedColumns.css +++ b/packages/ag-grid-enterprise/src/calculatedColumns/calculatedColumns.css @@ -29,6 +29,14 @@ resize: none; } +/* stylelint-disable-next-line selector-max-specificity */ +.ag-rtl .ag-calculated-column-expression-wrap .ag-text-area-input { + /* rtl:ignore */ + padding-left: var(--ag-input-padding-start); + /* rtl:ignore */ + direction: ltr; +} + .ag-calculated-column-expression-tools { display: flex; gap: calc(var(--ag-spacing) / 2); From aa926da4d35657b5cfdad6fde2371b4f3195f383 Mon Sep 17 00:00:00 2001 From: Stephen Cooper Date: Wed, 10 Jun 2026 14:53:43 +0100 Subject: [PATCH 13/13] AG-17360: Add file input overlay for drag-and-drop file import (#13994) * Add support for auto generating columnDefs from rowData * Add stub docs page for new feature * Improve configurability and default handling of objects * Move to a community module * Doc page improvements * rename property * Add file input overlay support * Polish: fix import path, alphabetical ordering, and remove unnecessary casts * Add AutoGenerateColumnsModule to module size definitions * add note to docs * improve empty object support * Add tests for literal dotted keys with and without suppressFieldDotNotation * Rename AutoGenerateColumnDefsConfig to AutoGenerateColumnDefsOptions * Rename objectValues 'flat' to 'include' for consistency with arrayValues and nullishValues * Simplify Docs * prevent infinite loop and validate array returned. * fix sonar * reduce code duplication * Improve out the box behaviour * Add a helper method for looping over leaf columns only * Update an e2e test * fix example * Simplify code * Fix type error * Remove window handles covered by the example generator. * Use xlsx which handles csv for imports * Use a fileProcessor instead of events * File overlay examples * csv icon for now. * small clean ups * update errors * Add Document Icon * Use document icon * Improve legacy theme compatibility * correct material legacy * Avoid hanging processing if no file processor * small tweaks * Address PR feedback: gate file input overlay on fileProcessor, catch sync errors * update icon zips with document * Move example to correct page * build output * simplify code * Fix aria warning * Fix generator * Update example specs * fix lint * Fix lint and tests * Flatten fileProcessor object to processFileInput callback The fileProcessor grid option was a single-method object wrapper (IFileProcessor with processFiles). Flatten it to a direct callback named processFileInput, consistent with the processXxx convention used throughout grid options. * empty array shows no rows * review updates * Fix file input overlay not clearing activeOverlay on success Clear activeOverlay when the file input overlay was shown via activeOverlay and a file is successfully processed. Also watch processFileInput for dynamic changes and update docs/examples to use activeOverlay instead of clearing rowData. * review updates * correct overlay logic add more missing edge cases * code cleanup * Keep the FileInputOverlay in its own module * Fix module size * forward fix for release job * Improve examples * improve docs --- .vscode/settings.json | 2 +- community-modules/locale/src/en-US.ts | 4 + .../styles/_icon-font-codes.scss | 1 + community-modules/styles/icon-fonts/build.js | 1 + .../fonts/agGridAlpine/document.svg | 3 + .../fonts/agGridBalham/document.svg | 3 + .../fonts/agGridClassic/document.svg | 3 + .../fonts/agGridMaterial/document.svg | 3 + .../fonts/agGridQuartz/document.svg | 3 + .../internal/ag/generated/_agGridAlpine.scss | 2 +- .../internal/ag/generated/_agGridBalham.scss | 2 +- .../internal/ag/generated/_agGridClassic.scss | 2 +- .../ag/generated/_agGridMaterial.scss | 2 +- .../internal/ag/generated/_agGridQuartz.scss | 2 +- .../base/parts/_common-structural.scss | 77 ++- .../theme-icons/alpine/alpine-icons.zip | Bin 66466 -> 45889 bytes .../public/theme-icons/alpine/document.svg | 3 + .../theme-icons/balham/balham-icons.zip | Bin 59243 -> 38648 bytes .../public/theme-icons/balham/document.svg | 3 + .../public/theme-icons/base/base-icons.zip | Bin 58967 -> 38421 bytes .../public/theme-icons/base/document.svg | 3 + .../public/theme-icons/material/document.svg | 3 + .../theme-icons/material/material-icons.zip | Bin 57482 -> 36865 bytes .../public/theme-icons/quartz/document.svg | 3 + .../theme-icons/quartz/quartz-icons.zip | Bin 56928 -> 36346 bytes .../framework-templates/lib/Extras.astro | 4 +- .../src/components/icon/IconsPanel.tsx | 1 + .../grid-options/properties.json | 6 + .../customising-columns/example.spec.ts | 22 +- .../file-drop-overlay/example.spec.ts | 35 + .../file-drop-overlay/exampleConfig.json | 3 + .../_examples/file-drop-overlay/index.html | 16 + .../_examples/file-drop-overlay/main.ts | 101 +++ .../_examples/file-drop-overlay/styles.css | 19 + .../_examples/nested-objects/example.spec.ts | 24 +- .../docs/auto-generate-columns/index.mdoc | 29 + .../_examples/excel-import/exampleConfig.json | 2 +- .../_examples/excel-import/index.html | 5 +- .../_examples/excel-import/main.ts | 107 +--- .../src/content/docs/excel-import/index.mdoc | 8 +- .../content/docs/overlays-overview/index.mdoc | 1 + .../file-input-overlay/example.spec.ts | 10 + .../file-input-overlay/exampleConfig.json | 3 + .../_examples/file-input-overlay/index.html | 1 + .../_examples/file-input-overlay/main.ts | 53 ++ .../_examples/file-input-overlay/styles.css | 4 + .../content/docs/overlays-provided/index.mdoc | 31 +- .../src/content/module-mappings/modules.json | 5 + .../src/lib/ag-grid-angular.component.ts | 9 +- .../autoGenerateColumnsModule.ts | 2 + .../ag-grid-community/src/context/context.ts | 1 + .../src/entities/gridOptions.ts | 12 +- .../src/interfaces/iFileProcessor.ts | 10 + .../src/interfaces/iModule.ts | 2 + packages/ag-grid-community/src/main.ts | 7 + .../ag-grid-community/src/propertyKeys.ts | 1 + .../overlays/fileInputOverlayComponent.ts | 262 ++++++++ .../overlays/fileInputOverlayModule.ts | 20 + .../rendering/overlays/overlayComponent.ts | 15 +- .../src/rendering/overlays/overlayService.ts | 25 +- .../overlays/overlayWrapperComponent.css | 69 +- .../alpine/alpine-svg-icons/document.svg | 4 + .../parts/icon-set/alpine/icon-set-alpine.css | 4 + .../balham/balham-svg-icons/document.svg | 4 + .../parts/icon-set/balham/icon-set-balham.css | 4 + .../icon-set/material/icon-set-material.css | 4 + .../material/material-svg-icons/document.svg | 4 + .../parts/icon-set/quartz/quartz-icon-data.ts | 2 + packages/ag-grid-community/src/utils/icon.ts | 3 +- .../src/validation/errorMessages/errorText.ts | 2 + .../rules/gridOptionsValidations.ts | 1 + .../src/validation/rules/iconValidations.ts | 2 + .../validation/rules/userCompValidations.ts | 1 + packages/ag-grid-vue3/src/components/utils.ts | 10 +- packages/ag-stack/src/interfaces/iIcon.ts | 1 + .../grid-vanilla-to-angular.ts | 4 +- .../grid-vanilla-to-vue3.ts | 2 +- .../transformation-scripts/parser-utils.ts | 2 + .../src/overlays/overlays-file-input.test.ts | 601 ++++++++++++++++++ testing/shared/moduleDefinitions.ts | 3 +- 80 files changed, 1590 insertions(+), 118 deletions(-) create mode 100644 community-modules/styles/icon-fonts/fonts/agGridAlpine/document.svg create mode 100644 community-modules/styles/icon-fonts/fonts/agGridBalham/document.svg create mode 100644 community-modules/styles/icon-fonts/fonts/agGridClassic/document.svg create mode 100644 community-modules/styles/icon-fonts/fonts/agGridMaterial/document.svg create mode 100644 community-modules/styles/icon-fonts/fonts/agGridQuartz/document.svg create mode 100644 documentation/ag-grid-docs/public/theme-icons/alpine/document.svg create mode 100644 documentation/ag-grid-docs/public/theme-icons/balham/document.svg create mode 100644 documentation/ag-grid-docs/public/theme-icons/base/document.svg create mode 100644 documentation/ag-grid-docs/public/theme-icons/material/document.svg create mode 100644 documentation/ag-grid-docs/public/theme-icons/quartz/document.svg create mode 100644 documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/file-drop-overlay/example.spec.ts create mode 100644 documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/file-drop-overlay/exampleConfig.json create mode 100644 documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/file-drop-overlay/index.html create mode 100644 documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/file-drop-overlay/main.ts create mode 100644 documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/file-drop-overlay/styles.css create mode 100644 documentation/ag-grid-docs/src/content/docs/overlays-provided/_examples/file-input-overlay/example.spec.ts create mode 100644 documentation/ag-grid-docs/src/content/docs/overlays-provided/_examples/file-input-overlay/exampleConfig.json create mode 100644 documentation/ag-grid-docs/src/content/docs/overlays-provided/_examples/file-input-overlay/index.html create mode 100644 documentation/ag-grid-docs/src/content/docs/overlays-provided/_examples/file-input-overlay/main.ts create mode 100644 documentation/ag-grid-docs/src/content/docs/overlays-provided/_examples/file-input-overlay/styles.css create mode 100644 packages/ag-grid-community/src/interfaces/iFileProcessor.ts create mode 100644 packages/ag-grid-community/src/rendering/overlays/fileInputOverlayComponent.ts create mode 100644 packages/ag-grid-community/src/rendering/overlays/fileInputOverlayModule.ts create mode 100644 packages/ag-grid-community/src/theming/parts/icon-set/alpine/alpine-svg-icons/document.svg create mode 100644 packages/ag-grid-community/src/theming/parts/icon-set/balham/balham-svg-icons/document.svg create mode 100644 packages/ag-grid-community/src/theming/parts/icon-set/material/material-svg-icons/document.svg create mode 100644 testing/behavioural/src/overlays/overlays-file-input.test.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index a0b1d090bb9..4f0e0a8e8d2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -129,7 +129,7 @@ "alasql", "flatpickr", "fontawesome", - "xlsx-style", + "xlsx", "materialdesignicons", "seedrandom" ] diff --git a/community-modules/locale/src/en-US.ts b/community-modules/locale/src/en-US.ts index 13ad46fdd17..b0fa5183983 100644 --- a/community-modules/locale/src/en-US.ts +++ b/community-modules/locale/src/en-US.ts @@ -281,6 +281,10 @@ export const AG_GRID_LOCALE_EN = { noRowsToShow: 'No Rows To Show', noMatchingRows: 'No Matching Rows', exportingOoo: 'Exporting...', + fileInputOverlay: 'Drag & Drop file to import data', + fileInputOverlayBrowse: 'Browse files', + fileInputProcessing: 'Processing ${variable}', + fileInputProcessingFailed: 'Error processing ${variable}', enabled: 'Enabled', // Menu diff --git a/community-modules/styles/_icon-font-codes.scss b/community-modules/styles/_icon-font-codes.scss index f0f2ac9686c..5de922da004 100644 --- a/community-modules/styles/_icon-font-codes.scss +++ b/community-modules/styles/_icon-font-codes.scss @@ -72,4 +72,5 @@ $icon-font-codes: ( filter-add: string.unquote("\"\\") + string.unquote("f144\""), edit: string.unquote("\"\\") + string.unquote("f145\""), search: string.unquote("\"\\") + string.unquote("f146\""), + document: string.unquote("\"\\") + string.unquote("f147\""), ) diff --git a/community-modules/styles/icon-fonts/build.js b/community-modules/styles/icon-fonts/build.js index 1d3d4fc2ad7..2b72e71954b 100644 --- a/community-modules/styles/icon-fonts/build.js +++ b/community-modules/styles/icon-fonts/build.js @@ -81,6 +81,7 @@ const nameToCodepoint = { 'filter-add': 0xf144, edit: 0xf145, search: 0xf146, + document: 0xf147, }; function generateFontFile(fontName) { diff --git a/community-modules/styles/icon-fonts/fonts/agGridAlpine/document.svg b/community-modules/styles/icon-fonts/fonts/agGridAlpine/document.svg new file mode 100644 index 00000000000..8db30d84c2f --- /dev/null +++ b/community-modules/styles/icon-fonts/fonts/agGridAlpine/document.svg @@ -0,0 +1,3 @@ + + + diff --git a/community-modules/styles/icon-fonts/fonts/agGridBalham/document.svg b/community-modules/styles/icon-fonts/fonts/agGridBalham/document.svg new file mode 100644 index 00000000000..b496e2ef7a5 --- /dev/null +++ b/community-modules/styles/icon-fonts/fonts/agGridBalham/document.svg @@ -0,0 +1,3 @@ + + + diff --git a/community-modules/styles/icon-fonts/fonts/agGridClassic/document.svg b/community-modules/styles/icon-fonts/fonts/agGridClassic/document.svg new file mode 100644 index 00000000000..8db30d84c2f --- /dev/null +++ b/community-modules/styles/icon-fonts/fonts/agGridClassic/document.svg @@ -0,0 +1,3 @@ + + + diff --git a/community-modules/styles/icon-fonts/fonts/agGridMaterial/document.svg b/community-modules/styles/icon-fonts/fonts/agGridMaterial/document.svg new file mode 100644 index 00000000000..6552f7fd567 --- /dev/null +++ b/community-modules/styles/icon-fonts/fonts/agGridMaterial/document.svg @@ -0,0 +1,3 @@ + + + diff --git a/community-modules/styles/icon-fonts/fonts/agGridQuartz/document.svg b/community-modules/styles/icon-fonts/fonts/agGridQuartz/document.svg new file mode 100644 index 00000000000..0b8080293c3 --- /dev/null +++ b/community-modules/styles/icon-fonts/fonts/agGridQuartz/document.svg @@ -0,0 +1,3 @@ + + + diff --git a/community-modules/styles/src/internal/ag/generated/_agGridAlpine.scss b/community-modules/styles/src/internal/ag/generated/_agGridAlpine.scss index ef62d139294..49cbb8aa275 100644 --- a/community-modules/styles/src/internal/ag/generated/_agGridAlpine.scss +++ b/community-modules/styles/src/internal/ag/generated/_agGridAlpine.scss @@ -1,3 +1,3 @@ // THIS FILE IS GENERATED, DO NOT EDIT IT! -$data: "data:font/woff2;charset=utf-8;base64,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"; +$data: "data:font/woff2;charset=utf-8;base64,d09GMgABAAAAABiUAAsAAAAAM1gAABhCAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHIwIBmAAjUIKugyvHgE2AiQDgngLgT4ABCAFhEYHhmgbZyyHDCDYOABIyI8H2f//lwRtjNBhnUT9CjVjqxN5lCteMNb8unzV7JuMGs169180jbvbW0XRTVFDiz5FGxY+RBC5c+pTr4OCbdy4GfXX3ukTabjYbCglD/D3e899P5IntAb+Ub1MGnAC4ED3A7/NHnxQaMFCtBlgLgAxpmABH0kRFBQz7k6MOlmky9JV6SK9BYt2kcHCXSxdXQBM5TR3DQe7ln1tLTk5QHbc8jO0cKkTNswNkW9GH+m7+ppDZDpgFkz7ol/f5R+eY7z3V4fox1iLtclIdob+EDNnzH0DVbGtDLLzVNSCcRV0G5DqRPRDT/an5ofrbfaw2Cljtt/3umOQMQmWeEL4SgT8NFev3RSQp/haFgolOjUzmdvNQG4vu59yc0Q5zs+n3BYZNpfCQil3n1gV2LUOUNZ94Ss8C1MpW2Fk1emWFsGzSbeIw10ajDU77dl+7SMyNFAyhkRMkdz3LI4AZA0ngS2UGgO0++37Izac5LoBZDOG+5urLcIsD1eySUB4HxJDoQlRb+ZzIl0ubvmxr43XiuP7m7OXw6MYQkAChUEmT5MpoORklNKpqGG5UIz2qaKhhQ/qobR0WqSMagRCqFwfExteNsrMwgeOQnq8K4IgPBjGjYxecWEWIzMlpRYvi4o1vbHh6KXxahHw0skZKI1fMyjeE1EOVBatDKPiDTwQmFjIqE2urucOz0QHlSEFTkefkheknsS5PYiyEmC6YQCVJb1mUAmlkM1K2bQ5BFkiqJNBRauhWYjIq65igVIbASedTqYbeNAsfggyFaUsMhk1V9fEh8BBmShx4OxNgnLlJpSEUblWk4bd2dl1ZJZ7mTOuHYXEk3p111UbeiczrLu30nAEBM0sYhFslEr7xiOnlcoFSkZBxyCyvZPmQjEMYdCq66/LeQMHF/rX+NJDTqgMjWGMqeaGyIsBau+DN1IxufH6SZiShjmr4zx+lB6Bm8TplG6ehCpzPfC8asf0kVGonDygkMXSFgMohTiuNsuWz8o8nktwOqrSDj1/KTftVE1FKhxESUFG5/Gh9BKRZB/dzILCVaur5ZJKmc2FqAyu8AyGNCrRg2pvWlo0XDXVOdwCry8XAxIm1RAEbEOkIVDRqZSoGZLpU1pLR5n5cTgkbKEEAkxgQeepyfmDUuZQ2zfQtZKfAtsaeNUDDJdCKxCBjEl6e3p5UMF3106nLhgxBmqbvV0ricOYRlorSCXNmPGbhhJdWy3DAB3PxWXSUuxDYFmCYtNIKYWFajUbiVoi1dIyy0PY4HHfbAlIfMrpswhFCFSZO9xMb6bFhbdUo/jmyVwFOhqulQa0eBD9QYIAkZKV2hk+LbNcqPW83ZfmSJYSqVA5gEEjG2qlss2DOnoZsv1hdqxw0VezgwfRR3Qg4JN8++EvIwawACL4GEjmqHNZPHckUSkQZ8AsngL/ynAq6D3A6Y8B+68mE6LT8vawH4RSIkk8iZssah4BFk6UKnXa/8v//+9AkRr1/4FJJ25ASYN+eMTAEdJom0ZZg1Cny7RTql3PnMHNGK+GSY48GFgI6JhrP0L2N47X/bwQjKAYTpAUzbAcL4gSkBVV0w3Tsh3X84MQRHFy/NIsL8rq1P+m7fphnOZlFzckQXIMj/yfXxy0O5VFqVeT2R036lOKVnUybw5nS6PD5AHx3wxsgIMFGgFbVAR2aACcoTZwjjrABaoAl2gBXKEScI16wA2qAXeoD9yjLvCAxsAjagBPqA48oynwisrAG2oB76h6HN/RBz/QZz/Ri1/o1W/0yZ89vrYXiDpAgDpCgDoBGKUzMEYXYJyuwATdgEm6A1P0AKbpCczQC5ilNzBHH2C+L7DQD1gMApaCgeUQYCUUWA0D1sKB9QhgIxLYjAK2ooHtGGAnFtiNA/bigf0E4CAROEwCjgLAcTJwkgKcpgJnacB5OnCRAVxmAldZwHU2cJMD3OYCd3nAfT7wUGCarkIgjyFPIc8BQ5Sa7aYyCEWVQ4AqIECVEKAqCFA1BKgGwDC1wAh1gpzqIUANEKBGCFATBKgZAtQCAWqFALVBgPqDQzu+rar883/869Tf5FyDn49SCUcqldF7BYq+mDgAr3ByUMawEhZT2Et6dRT2kbF6p0kZZL16sCzNZfHVW0laosHQif2nKN2LgkypI0R9xdXSfWRAWbYcUf7w59+fTzX1bfjFU0lPi1hrn2E0A8Ma1EzebGlxzFrHcWN6jSwU64lMmLivqeKkY/BHTEzxlVhySl7VsSx14uRIPUfPIAK8SFZ4GIXSR1wjjcgJUH2AEiBBH2dSF6H7GT8SoaSB91LCDlAeJqyrge/7nEebuQu7aWsiphqvHy9AxTtITOS1TGZSXjF5uzwItEevhP1kIS6UJ43pfr04tXLnjQ9Qf/o2hhgiKIoJZqjPeH0eaKXScjB5+7xWe4WQuw0bVVi1FSGID1qBUK8g1JmblGlmsHRNYSQtKnqIn8oZZS1IgukphWWHqjdleqgJh1t/tJ0/SrUWVRCTm2jU2sTgziY6s38FO5oYaeGslfJmomIPYhigJHYhdY54dQnM0C6/xt8Yb6/CmfqVN+cSnCYp9wW2+2FAnTFn5mwFnEo00Vj8d05pOliqqwHts/EV6huLa1W/N9CNXDi68GM3cqnxmBExqk98Ah7sleimVfuMJdkIr/4Fdfi80qGkmmiSiLFkgqtZZivdd3xGBSOw4J0Inpsp0bxcwLijV8uXSkhMVYrFIaiPX7yLjdsOWqC0yCrFChKXgDZYNqrzcjkjQ7XaLSRWZh8J01goZM7ccGWqckG/WIWeLBcO8rJFUQItQ8ajyJlygVOeC8Ha/owGgiSdLveyClOUY4QLhxLZ4ep1+aDON7UszTSFbUP9J0bKlwEzRt1xsLGjR9yqaedvG3cv6hfuHBafHFNC/5Kk0dxQ5VpQbSHucVdYUzx5og5nhoX1aWyU6ykPWUQa7APaakIzRtdPiCmvw09FJCpQP5ZINhN6qCVCnWa9ayoHL5n7w/tbTGTaNlNCVx16y9xsVSs2eItLqMltEdZ89xR61lOH29khThnOxjVNIlXX6wQ7jjRPy2VKj1Dq45S2alUCiJvBwGEKWiE/xXgLoQnsQhxBTBcX5Sh7cBX4YB/wwzYDcgZ+oshJxCUydRclzZxJnhvt4y2xeCuTovrTj7gia4RJx/DhCaQS9PUhgI33j61H79DIbGovCiA3DoXwkSbW2ueD0uEF5xk/UuTdfAzXjUH382FVciF47SDV6224yEb3ZKrwpuZ8+8kUI2FOKWERyntgLqZvK2LDCsce2HFhNyTvW0CrdBIVDX0Q7+ajfrBGwPMZZa10EYmuHvR7MZAgTrJQLv0qXPzt5i98aFN133Qovrq2+tZOImfqR9fXdi9npOHQRDAv15MX25+FxkPVRf1L53I5gzOh6XlMvW5ZC/4wD5jm9r+Kb9j2wj9zhx1n179Ffo/Fb35d5NRq8uDnHStgMjhwCsV7P5TtSN7PeDj4POZlRHXRUW0JhsxcjCEX4tN8giHuA3jh0JedvRNoO8D8BQI41R7UejZhEzYhk9w54QZzLAzXmCevDrUaa5uLjx1GzrzrA9J1PnHqLnw8APyHsAd1BVK5WLwvmYgm48kkPZ3gXdxcivQxlfKIEWDQ3N781oHTZyeI4pP0lQk6z6761Y+rKKfzttaz6qfm0QmdjLCFGQcIIO/EvCAgqPfBZA+nPb2Wb9Zqc1U0VoEvNpqPHhC/DHeLL/pX47P26TjOkW5rCnOobw8V9KpGGXh8gXSLumpMORzoGg46mhslGvD4uzySt4e9AvZ20Qirdo9qc7PzcqtC4QhbXlpdqst3iPcvMl+XBm0yp6vubrq4tKgo/Pq+6qZ1rLUhtp+EUzS/PK0IRSH1o3UDq4PsVCJC3djFw8e7/Tap+H42LjdpOOUHgWhWD/GcIdPMQEm82rWqGS24dhQ2GJKXOSKQxxgqU3i9PBgkNKOp0hTejcpQiAtKpXyaXG621txfABph/zqugmokAlZ/Ck0DQLizNKtUWuy1DyCUMD7XZThOtsQITOWmjUm5+cL3WPng6UNrm1UPOhfpHqfqMsnOsCaqxj3aPeQXD+BM/SGWusWFlozLQbfPTTFkaOO/Uf9HBpM2yceGhcRb+J/IYt27T/LhdevQ3Wx2iPMDHJP9XamrYKOIxGhY/6HL6fxu/P7K2avGewjCOX+HnQNI93T1de+66jlzULHzc5Ptzn/ewW5vLEnsNFcVlv829OwH9uX9ora7urDgoLfrbAa2YYK+WJn22pKCB3mRUxGTIUzR4+dJP8FBhsvKYy+0hS39TR0lDT7tSX+51D1ZFE+f9ozuvpc9ksQ5/e/+y/vvey0tur91WXf3A/4m3gWHAzrZtOXBfkfp33pnL62T8W6EamOYg0FP92hW/BWvGd/kO7802s5gvUNGu8pcVJjQ7T76XHaccGhwcGrKKJmh2b2+nnCcgxutdd7oX33ZLlOf0zz2lIDA1AW2wth8sTg/tvBpYt9/vrgw9mkB95QlC+aTL0HtAjof4FtCtQvsjkH7N3tzs73FDjHznKSAqKsBs/lqVAC+O8EckqenRtN/at06jbbcmx4RWRfJr2sj1Q0NX/lHaXF4c3Tlyq7iYiw2MaGfC9Z/qn9b4ubNM96YfEJABiE+xrczQHD5m01o6+swI+doXqZaesC7ISq2No15MPhuYB1y6CMHQhRGxccOw7kQ4Ch63ZBzUxQcYNGuc4pz8CHabElJsSSZENAMwzIjEYivvqooa/pjbNoODL+CP4Jfzhcv/l1lnbsu+z5rbp2CuU4ITXK7i/lj5U3KTP+rHm4VI76tSPMMOdGEuHuP5DGJy6ltCY1CuvcuQdD+sqDsbJ9RtGXbaT4sTy9/2tmPTPIMWntl3VsKI4tJW+n9Sbwahno89WJ24Fo8V1Cr4rVPAphUYs7GFC+vtaeYS0fOCN8f5mCFg2cbuVlNwrNE11i/L6LvzWMJLgwlkFYwbbCFEj3qkPhW5sVryUlhQtMIgalcm5gE5W88wiSUJBW15jXwc4OERascC2AaIeT5r1SxzyyN7j4Tva87euk+BMNv0bVoYx++YmT6N5Gyx1FyCESMj8F0tpyZ9+5qv7k1vXpGbbqXlM4I+TLSIrUsv2I8QaAPozDUmtrM1kPzmTNYHqzo7FFZbdGT8QR6EJ0JdY6Yyse+f/4+P6E15x0KhSm0IKs7taHdTxcWLk61HrvgKLMKarKgO62hzVcXH6fSlBYSzqcaRvgkFRaPEaMZKKdneXQEGhYmj4gmuRa0CDOzSIVRqFBo4jk5rKQiiZ4ZgLAUxht/2cyapY7CYp+k+ieNf+6ra2jvTt2i81JhfrsBX13cpO5wZVjYWRN1QbyzyS1L9zvMq0e6LUNyt2YdWHrnLnwWHT5E0WvNXJz9YPxohMFBiV3i6JDapfs76BUJJMUjSCRPUMImiZXEOKQCaUefXWqvVol9sGPj39osjZV2DO7yPmEz/LNTo2gZTy1iBnx3Ontaj/c8lyVh7AOHvZOzXrc+riAmJr9e2DyOeTXOTjanJ0xr1DavGzWDLLzK+gW2IsBWi9Sd3M+fy1OELw9WbkkQqUW7VDlrA5t/IxY4wsuVikGfpKXF/ACDSU7uEz1wvebe0mK5z0TdB8GVOJvEZrdJcW+JDSR9gmuLt988yAfemVG9P5N99sTGwHP/f9Z1nJgcMXF7tgxu83pwZW6kOkKlilBH5sZVcFZdvcrmVKjdkY0TlYMR42u2Xv+p/3liWwiEdC8USnxyxmTO5BB89kUDaLfRvtJuBL19zhwCO147rb/LWV1cOHtjgiTgtr+/qu+pXF5RisexhsTrTlUvWPDsmeP5zGGzdto/dXfn1TNJPj5NJV6uDYz5CxrmkR/f9P732jUY4d5TlxYWluaK+NFyDTctrG5yAUhxBbZ9j4t5jx8gBAuZhIEv5xl0pjD4nz/30RY7jMZMo6OzLjRMLgu3NXY6dleQ0bHkH5HX3BtEsb/ctWNU+0FQ4uyjJV9FqiYc5LdLpQf+7GjH1K7sj90eN7tj9KGOOsWo0bDl394B1e35+fPsFneWW3lm7tSpXDPPel7YeD+wmWvlnecUdymZ8JtVbBGJLGLr3cR5/xaRVXy3MCt8GEirT0mp7wwc2U76j0sd1NMemJrccymr6QnN8NzZeUr5mbdLt8cOSAQSeN5F07AVwnYh6+1poH6ef67mjK2K/eVLSkp8XEBAcjI4km35Nvh3i186XTFOaoTjx3tRDFmc1nU+XlKUEBcyPyd0nTUzk6CoGTtmkaIyKa6/zUfwrZQPJlOgsT4/D0XXrxfu3QeUa75d0sXrtUtj42LpeuzTMINOsfHategsyhV8M8KHBfxybTqZN0jX+jBfEL/6/dh1JnmdUd63V7L3L6OsziRbP9ZHEirTI2VqbG0eI2rZJ93XZ4ywfN0YVmKoSW+MZzWB5/gaKoO6vSV75ZBZjPHwS86kPgBqMBVYgveCxG22v2yMu01NjtWrVq92wCF6WdlZtYaEHZfX3f3JvnPWMLfz5/T6xCLm1D0DbcWF1c6u/iOycAKjCjZtmj+/+pQufggLh68olcuf9qnaWhmOo0dMO3Y4RsYbDP9633xMntcwfwGjwdWrpKmxEYgiOv05nTJWMnaOdIzod5e6A3FevuX4GMkY1DuYG1HktukC/8Lg4H3+fQy/gO/l3bt1u/BxWxj+37y9G+rvt86584D37kI8uAH39UvwF243eJbQI7rMAB8rDGoG6hmtbfrkhOmzcOMeZpKHDv4f3awvNBS2tVIaHNPACDYfUkWrMHLGrCGy7UetUmultHKFtZzg6FHhxYvMSxfTWubLZZ1LfKf0YHqmsJcslsmWRE5hgt+aBaVbSkfqzCZbSs5YJa9TsiVXLFOfykvmcZP5qSsCuyeZm8pfAQyyB9+cxyckCY+6rm937+4+4AlP4nDm4L+D0YXBGtY5WYvFspRCSzzVxGpe/y9Pn/rB6MD/y1qBCV+DYdj3SNT/37lODewNAABJMcmWp5C7q4daC1AjK2msbkVKYUWlyVPbyfbIGOSwNTsKAP7/Ub8j76JrrUDuqT4VMnXsaSrTxK7B5l+i93YUTpeXNtVdgD0Z9/2PvEacsHp52jrWZZiwt9a9zgvEzaaJSK3JugP5E9ZWnkY2o0OrkRpshmC78boMgpA0rxNZh7jrtlMje6uu89borIk6sQZEbTIrs5dHaVOUb5yJjuePXbUjdiUSIP15jVOQqTbZNSzT1ViFXPkn0txB+aZlgwX0hE8EMuIEwOQQnx0aQ07tD40EwH5Tb4NblbPk9H6zrvm2n5bTKSN/8xZ//FRiHK+W/wZsthUnxZcC+M2/0Q1ORRIjwTIXC64zBo5Q2x0Gbs1AhAcyRCAXoICYkzh2Ct6aDO7wGyCAwREBAywYM0JYoMFijtyvuZ7jsOYhhAcvuMldsOY7RIIsDO4XIwMPk8Oj3S/29kuIHuE3uBw0508TfZ3/wMkTFq/Vy775+wUIrAVsUd+L1Ls3kaZomLriJ+GYoxCoiEwfYKRqReL783MTL3BlqHvS7hd7+yVEj/AbZk9eDpolzlTk/ocpT/iuERav1Yuk8YsSqoML/Lao76tw6t2bpG5TLDymjsqfSqkkDymnOxn53geYWFdtDS++P6fn18jqyihhQ8CdIJtU58jHKk03TMv+XZM+XV/8/ne/EIygGE6QFM2wHC+IEpAVVdMN07Id1/ODMIqTNMuLsqqbtusHyVKkSiMjp4BSSqeipqGlo5fBIJORSZZsZhY5clnlyVcQebB2jsFp8YQTzUzXNNTJjPTyXY21hWQmRqOBMDatZtldQTCfNd3KTTPYS+4dPFoQ4M6jFjjsm5hRKrwyFIjL6HfW5enKyB2mhSEU1kbAjgzF+9gwpTQ0qR+aLCPd7hhuY2u2nKiVR9o53KFMQad2SFsnjQ9PaI1djpOMHPs4dkw5joQRMgrQyCR41Jx0Gkhbj27W6Zvv/ANGHWCeGcqYpAg3GSEhLJGk1CHQFew4KkgIw+hxHH1PMosMvaecdnykb4bKOosQltQ021w5HLN3rYyS7mGRuvuB0tIVt7RJagmziprdEoO5nJn7OQgDOFLO89NSBJxltMU3iiGnsQgvMbOCNJeocEHEvglp5VhZtqU7yXjGHVwvXgvBljWJULdgwkJxYVro2eCmHFdb2tDMPb2vXcO8VwuHJyu1tSOwXiYJNJt2ZsnkhnwworRyihUoUV6RQnVVSRllVVCt+lS1uqmyU1lFdVe9atTjCQAAAA=="; diff --git a/community-modules/styles/src/internal/ag/generated/_agGridBalham.scss b/community-modules/styles/src/internal/ag/generated/_agGridBalham.scss index 77b38240db8..7fdae2d9db9 100644 --- a/community-modules/styles/src/internal/ag/generated/_agGridBalham.scss +++ b/community-modules/styles/src/internal/ag/generated/_agGridBalham.scss @@ -1,3 +1,3 @@ // THIS FILE IS GENERATED, DO NOT EDIT IT! -$data: "data:font/woff2;charset=utf-8;base64,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"; +$data: "data:font/woff2;charset=utf-8;base64,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"; diff --git a/community-modules/styles/src/internal/ag/generated/_agGridClassic.scss b/community-modules/styles/src/internal/ag/generated/_agGridClassic.scss index d272de025cc..3ae7326fba6 100644 --- a/community-modules/styles/src/internal/ag/generated/_agGridClassic.scss +++ b/community-modules/styles/src/internal/ag/generated/_agGridClassic.scss @@ -1,3 +1,3 @@ // THIS FILE IS GENERATED, DO NOT EDIT IT! -$data: "data:font/woff2;charset=utf-8;base64,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"; +$data: "data:font/woff2;charset=utf-8;base64,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"; diff --git a/community-modules/styles/src/internal/ag/generated/_agGridMaterial.scss b/community-modules/styles/src/internal/ag/generated/_agGridMaterial.scss index 37bbf131d2e..e5f58894a76 100644 --- a/community-modules/styles/src/internal/ag/generated/_agGridMaterial.scss +++ b/community-modules/styles/src/internal/ag/generated/_agGridMaterial.scss @@ -1,3 +1,3 @@ // THIS FILE IS GENERATED, DO NOT EDIT IT! -$data: "data:font/woff2;charset=utf-8;base64,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"; +$data: "data:font/woff2;charset=utf-8;base64,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"; diff --git a/community-modules/styles/src/internal/ag/generated/_agGridQuartz.scss b/community-modules/styles/src/internal/ag/generated/_agGridQuartz.scss index bdb4f103396..a3f7b88dcbf 100644 --- a/community-modules/styles/src/internal/ag/generated/_agGridQuartz.scss +++ b/community-modules/styles/src/internal/ag/generated/_agGridQuartz.scss @@ -1,3 +1,3 @@ // THIS FILE IS GENERATED, DO NOT EDIT IT! -$data: "data:font/woff2;charset=utf-8;base64,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"; +$data: "data:font/woff2;charset=utf-8;base64,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"; diff --git a/community-modules/styles/src/internal/base/parts/_common-structural.scss b/community-modules/styles/src/internal/base/parts/_common-structural.scss index 38287dffd55..9739040e820 100644 --- a/community-modules/styles/src/internal/base/parts/_common-structural.scss +++ b/community-modules/styles/src/internal/base/parts/_common-structural.scss @@ -1090,11 +1090,86 @@ .ag-overlay-loading-wrapper, .ag-overlay-exporting-wrapper, - .ag-overlay-modal-wrapper { + .ag-overlay-modal-wrapper, + .ag-overlay-file-input-wrapper { // prevent interaction with grid while it's loading pointer-events: all; } + .ag-overlay-file-input-center { + border: solid 1px var(--ag-border-color); + background: var(--ag-background-color); + border-radius: var(--ag-card-radius); + box-shadow: var(--ag-card-shadow); + display: flex; + flex-direction: column; + align-items: center; + gap: calc(var(--ag-grid-size) * 2); + max-width: 420px; + padding: calc(var(--ag-grid-size) * 2); + } + + .ag-file-input-error-banner { + background: color-mix(in srgb, var(--ag-invalid-color) 10%, var(--ag-background-color)); + color: var(--ag-invalid-color); + border-radius: var(--ag-border-radius); + padding: calc(var(--ag-grid-size) * 0.75) calc(var(--ag-grid-size) * 2); + width: 100%; + text-align: center; + font-size: 0.9em; + } + + .ag-file-input-drop-zone { + border: dashed 2px var(--ag-border-color); + border-radius: var(--ag-border-radius); + padding: calc(var(--ag-grid-size) * 4); + display: flex; + flex-direction: column; + align-items: center; + gap: var(--ag-grid-size); + width: 100%; + } + + .ag-file-input-drop-zone-active { + border-color: var(--ag-input-focus-border-color); + background: color-mix(in srgb, var(--ag-input-focus-border-color) 10%, var(--ag-background-color)); + } + + .ag-file-input-processing { + display: flex; + align-items: center; + gap: calc(var(--ag-grid-size) * 0.75); + padding: calc(var(--ag-grid-size) * 4); + + .ag-loading-icon { + @include ag.unthemed-rtl( + ( + padding-right: 0, + ) + ); + } + } + + .ag-file-input-text-row { + display: flex; + align-items: center; + gap: calc(var(--ag-grid-size) * 0.75); + } + + .ag-file-input-text { + font-weight: 600; + } + + .ag-file-input-browse { + cursor: pointer; + border: solid 1px var(--ag-border-color); + background: transparent; + color: var(--ag-text-color); + border-radius: var(--ag-border-radius); + padding: calc(var(--ag-grid-size) * 0.5) calc(var(--ag-grid-size) * 2); + font: inherit; + } + // /** // **************************** // * Popup diff --git a/documentation/ag-grid-docs/public/theme-icons/alpine/alpine-icons.zip b/documentation/ag-grid-docs/public/theme-icons/alpine/alpine-icons.zip index d9b7747e09053a589ae25957cd54fe625307cbd2..d1a462d6c41a558fe27d92a9a456bc44c951f7f3 100644 GIT binary patch delta 10492 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 delta 31244 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 b2fRz6CXm~<9sbxV_`4l0|9k*HtZDxbz9{8* diff --git a/documentation/ag-grid-docs/public/theme-icons/alpine/document.svg b/documentation/ag-grid-docs/public/theme-icons/alpine/document.svg new file mode 100644 index 00000000000..8db30d84c2f --- /dev/null +++ b/documentation/ag-grid-docs/public/theme-icons/alpine/document.svg @@ -0,0 +1,3 @@ + + + diff --git a/documentation/ag-grid-docs/public/theme-icons/balham/balham-icons.zip b/documentation/ag-grid-docs/public/theme-icons/balham/balham-icons.zip index ac382218d1e630608695a2492061905e04aee027..77dbc125f7fd26f55a272719e4a466c74dd4da0b 100644 GIT binary patch delta 10972 zcmb7~3sh9)7J$#pD2T7ngb+wAP0+%875M_eH&mMM$M_hB0}KvxXdZ}W9+6(YvOL+% z%1ra#%A}=Id9SbXdc7BK31kUrDsl_UG9Ot!T0ZXHGjq=Q_b@Z(q-)j^*E%12?|=XM z|IY_MSDCJr8#Bjco0@gtIIacPt$4Tjanr1$Dq!njqcGbXf-Y2(@d@&+}g-j^@VOJGEUIa)KLUMR*O2z5Onut*{#<;4| zyl3SjKbVXhchiIvz=2GfKX6xM30yRzNfzxJ0QY zJ|@w-+?Y;&klHp+m|`G=UGMaJWgrm703jX-gZCzcCp>%iU_&AsLwxUd-@q(70wESM zk%WD*;SuLLcQuS=5$C6Nj&cFwD?mhhi@_H=1xHGbFrT(du#|e=>!GwMFI1I14YYp; z(CmCJt#B~fXWc}@7&f-Ved&ELwvU0l9qtY4uI5BcrGMGU@rNe+*kp!}J&M#S4AenzP_d`6|4VjR6 z%}A=U<^fAJ=F=DQ!K#pXk7LBvbc{&1N7adPY0qRIGPnMF!zW(?!~&4k2obEFLf)Z< zGp;(RU;=ysX8qc6+nxXH-TLJ9mg|e{U9Hdm*4s2K?)XE)Qrn(*q^|#&#Iox*2EO#$ zu1zD3JazT0Q?@}T;z$27U|`vr=r;?+gu6CeF8|ne;X*|77B4mHdgW;G`u(S_#x~sg z>i4pYyS{5&b@`R{*=w%X6t&O1XkWSe;1%b}wp9`79crGlm9LoIcfjPe?f#ZEv*)-8 zNi}2J{Cd=*c&Hr4Ue09vA*{7 z+4!ZuSQ`gT>zwNz@buD`Zm&)|Q(3zF^;s{k?)**4VuN}nm;vi-CoU`Zu07`8OU*qy6?7@YYAS+#Q>9HH8 z;qp==CgzNo`8h0gvVW=hk|K*EhuMxH0+McyKRkj3oiu(iVLxhwc zv%7g`iX}&#G$B%}cz?zcgK|qi){5F?mnH+NAF%Mo;$vyXGOxzI^FFK*8*=fAX9*^|T35Wa)*uhe-QOefC1bMgTkk zHO5f#oC0%Zg`iZ-%z4K^VkvIB%yqEs9AKos0auo8`c_6I=f)W zu{rX{Vh02D5n33?&Z_=L_KEKxE4}5>V|kS=UMdR0|(3 zh!ts7)6rG>80h~Us%r;4SES{szNBy64K(=9&^f^4dw4e>3>A-G|k?81B`_|2zF)#w09hd1RbHV1Dj>jbaqQw!!DlCP3|mNL$;A9%Mrv?zHnNL?{6e>rUUELiCk1=P%dEt~@G{OW`|4sx<8b;p9-4f^0bYmM*xxv5S;ri-r}^XmyU(OMTum8<7+b3 z5_+WH9t?;yXaO9uF5c~iv9CRlo>-qoFCII}K7AEmaqb5iwzsPgW&nNn4OO7c8;+2j zGP~y|7pef&lc30pZz$BNjWuL8^{9W)SPdv_PMl4?sPwIy=bbM}t!CfspN}Q)0W5E= zycud=A0+c%za|avR+htv?->Zf25`f>u4Z$mzxx%*%$YW06xLhL%VD!q-NjA+api?6rq;7*Ob?Qwt((8N?6`0${SELh#7n5$OcY;ERSFpop$ z?P%Q&-k8RYCf2z{U_{z88`hFPY=ADUB*l zmWJZfD?CMCQ)%;>x=xl?-v)Sr<`ba!S{)`x<0`SzOr`_L z9BR?wlP2nV(oBUYo7vu2Y0%!pk$OSYi?X0>_yR4ds24^3D2v+D5sMROOZ8 z#V$xtvFhoe4@-q9OC5T*O2vaj^xwSnaj7|Fxwks0TzS6eVZtt>3YCTK>jKawLRAm8 z(o9twXuP-&)4mBnuADr5ck4_$Fe8xO>YzFo4e8v>|W)x|JV ztI7to{XS&Mjx_{LWQH>iQ>s^4TtO1xRM{GW7l5OlmBlSh2Ar!{o%A{ufC^WZ_GxdR z$@*1aXg)P4%I1}&UFpX$9#$LIRKc>eHV*-f2w5Paki{cNWPTXP9+XYxC5!C#Fe2q2 z&S(dScN1zcWg6taxpYt}$4E`U;ms+`0f{)OGi4mo#DPFl4n&{s6lLG3k4a4@%RHLtWh(PTM+wn*O0Rw%?VkZRhjV^WsY*|M zQBmE=Ms;AM%nTD)G{<%xEQWO93wbcj9E||Qdg_aZ3Qsnkk}({kKf}?YeAiEmCcR3I zrZfv5SHx$y=at9JRC%(|@Q-qwDnP^0m}pj4%h8lQ29GQ1Gu-29Fw}ao!R&e*Xp935 z!)xikn`3brYUFUbjRycLKf@4IfSGDfHX>mH7a&1{6UBh`F;fA`B43*bNTNf7BLj)l zgtElhlQ@wPqxx{viL$t{lOaH2NVSO~&M#_5S)^x*7b$xsZ64yNC1r6{Q#r<&B2Cnu z*3_4>xNoNcPO+!@f}`Fv4rVy~@m*w+W*{y=qw1qlfy&1C!Ay>0bZQ_@^!+YPV9!vK z%JRC;2A=$09!Lugqehj5jkG}iK?JKlE_JIc*D+VYDyB6!b5>yH)UvWr$%;_Lxd!J2 z;G`#x%OhrAE6H&O;#@-#Ma4(p=AgcnMGm!bA?#~NG$B**s*=Uc zrSl5{(SEU`k4z1$O5R+0cpiY&-)0Gl69bQEGj*{nFS3wh%xq8`p*5AVEG@$UG+tC4 zEdbHcYFrPgo@Iek1O&3ORy#z~WLS0TX<6j4B0vUMTOCk1J(rx8Tl>D1J+ zaYedhW|;L2F}WvQLrGL?DR)^XjW@>U^=aAi;RaE!~K#22v?391%Ka*h2L^mf?xd~%pVaH delta 31614 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 diff --git a/documentation/ag-grid-docs/public/theme-icons/balham/document.svg b/documentation/ag-grid-docs/public/theme-icons/balham/document.svg new file mode 100644 index 00000000000..b496e2ef7a5 --- /dev/null +++ b/documentation/ag-grid-docs/public/theme-icons/balham/document.svg @@ -0,0 +1,3 @@ + + + diff --git a/documentation/ag-grid-docs/public/theme-icons/base/base-icons.zip b/documentation/ag-grid-docs/public/theme-icons/base/base-icons.zip index 26fcc7a0e544de2b4b7837b842fd04968b754a43..dcc5e8cecaf99983251d0f19486aa56d625ba9a9 100644 GIT binary patch delta 11173 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 X20h8E1->c642GXAjTvTw-M#xi#OkX6 delta 31901 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 kdlN{hta7wc=Q* + + diff --git a/documentation/ag-grid-docs/public/theme-icons/material/document.svg b/documentation/ag-grid-docs/public/theme-icons/material/document.svg new file mode 100644 index 00000000000..6552f7fd567 --- /dev/null +++ b/documentation/ag-grid-docs/public/theme-icons/material/document.svg @@ -0,0 +1,3 @@ + + + diff --git a/documentation/ag-grid-docs/public/theme-icons/material/material-icons.zip b/documentation/ag-grid-docs/public/theme-icons/material/material-icons.zip index 185f85987eb42d41bfb466076c0a017168380784..59c924b2be77415835220bdc084d1e53e72180d4 100644 GIT binary patch delta 10986 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 Ie;)t!e>=u9F#rGn literal 57482 zcmeFZQ+S{4_U{|pXl&cIZQHilq_Nppjm@S(V;hat*iIUIC;jhtUvqV@+1a^{da#n~ zcO?focrw19fqRT`Kk`z*ASeJ3uiyRB#o7S>@&yTi4`6EH=;Tc6ncE?yoXX~a786UCM4$*kqjqo<534n}rOy+C?M`^4=og(6iyN(%0 zts-~}4&yE|n6}e47#&Fh*9u}{yJNjepdI+nXd`)_if9_W!yDd#LKLfLP$!^FZZ&q>TLIvYiTg+b?%;>=N6aq4KYgSTq9mCZQ8ua9bS(OS`~o{RJf zhie!w!{4iAMa5TM3LN6Y!~tsm>;H)K`p?S$TkD{_T1QV$MnFhTNu7>X?~e?%S^i{U zq>pN3rf;Z!CL^tS2Co__{{bi#9heLO3($c8A>cLwBNQl_fIvW=RJ;_SfeGhZu(!^H+U+?!4E}zkhCs z*XK4ca5DOxsJH*Gs1<5FPS}I6qo-=tHYWy~c@rNF-Tl}MswGj$xjvc4nP@65Pi#DS z^8wUuNt&2No31*`vGL-bRr9@^A5X1spKo4tAIBZJyEpniUY>n#Z|7NQe>@)k)X?vM z4*prF?V*2jYU=p>B6<9#zx&gR=lx^<@%j4Q-JzbHt*)+aJ=#Ls+IDt8$@~gNjXcj`$K{p-iwHe8kk(bd{4<6n;P)| zbF5IA7aGU7CP}Y9R}4k#;NX|m_S1sf9=E-1Z)3vD$|y+chNorlKt&C*@uHX*F9;y|`cSq12`S55QgY6(LF)r)OZ zaQ@gIT}4Xqs}d4)I^g&q7DFP~pP%;UR-ZjuzMAW`Jr19~_%yw`j&JkJ ze-&SwR8+QRgx!41Y7|_&FbV|giiTQdR#Jn=U-mV*aOCy=?b&3uOzO+m0p;& zTJt>4tlw+JOCUsTli348#Xg|IXwqnGH{~Rv6&7%)u6t4uy@^dFd*jN@cE+e4uWqRgaOXH9;Rzra`Hd z&}Gt(j&tGP#nK9?P9 z4j3aF6o8pWRbH^rr!bChX~=N`US<|Qn^a&+^K&%@QMqT%2EzriZ!u%^TSO`IJ3p6q1h%%r&{ zZzx|;om*u1piMPqRRxby6?*%1XJL_-VPW*+EFR+6xCVPn@1rSN#(12}jf*cFBuA>@ zE&mjGtsl`R)&6VO!7vg#J9gT$hrOp{@m;-sJ)e8{w+tr>tUD741^|!-_qz;-{J&=A zKS_3fLt=g_w+xI;exI5DDYq)rWSq1`U|KGy>aWKx%=0J2l}G$qZ>zuV#9|>JH`7Z% zNso*dXNb)pEUTJUl()RUjYkz;gzNt6Y z?`jTy4&46a_;P0d{_*U*`}q89&JG^$xsi8;hu7!+=yI{E3d%;-ID>)h9%hgp}! z;paA38&9~d=$k&!GE1-;H=f?v;41<2$wzvFC=H}>Ye;Lxw3%~;Cu^;UmD#HfvgMtg zXiwfnb^xtwM|gVp`Bk0dW(=|={eY_29p@_aDa!&eS!g#t#rL9T9wsE!J5 z1SmqUfv2X&rLh4rv-1Eta&o>UVi5jXjtgZ?LFFwSZIgp|0oKs@ev@ir>U>$NhjGa1 zEM?La9cRC1@m`sep&4ly+a7G55Zwe(fh6h3wUf-4B(-<zNQ$Ft{m@imTf8SW$)={g@`-{bmlz z5@SEGyrEsf4wpOm)WpJ#Lgws&0EIp$BXU#KlQ{dkHh#1xyy6XVLM~+mBlUzIP zs6}=K5Ic0Ve@8Gc7as*6j4&-hX-wm%!i5F@sJO|QF(JY@n@beNKK3+wR&H0L)p>sz;d&b2)|KQL0u`HY zZLCHv%2A*3t|7T-zNcNvA)l}qgVr%OAdbBQDF-8mV_aFgn$06$k)B6K%+SEL#BhO8 zrlnHg8X|`~jo2`+a!P0DlU*3whPXQTNc3@T+q}0!A~+8gn!MYD8fYOh)0c-X#d|9D z>t;CqO1X@o?+RvmsD3c`ARK>DNfz7;#1+^I+z8%-Cf(7*SY*1AuO`Q^vJA z7$;G4c~}Gc7@aTFoNLD#&H;oo+Y1A;Bjzp~-qhc_hSk3$$ktn)4&N$Rha5#6xU|hj zV(NAREQKzwfja2jM8V845lNZJ<6yo^WN!;Nh*R%6!0?t+_J%A~W&p<{&dgW40Kk%e zmk+HtVCrx6etmESjdfYhYPqymi)!7b#*>OTdvDQgxd5esJa+(_`k^W0?H)WKpgVeX_lm9aas6_3Tr8CfTc=*d-DGJ+zx+=L~ z7E)!31CGhid5J*YkO>`uD0!hnS}4Gwc(fv8EMSo85{s1ijLQI;`zhu)`?rKr33B+C5(lv$#lGEvyq9 zt=DAWL2S2Cin#1-2slvcWBO)U2%Jggz?-n>O;M`h@lEc2eCm$!E(dgZ^8Uf1WvHM^ zdz4c1>Khd&X3*#}oeah{5nsT@1)4{(+(*ez-~Ue!JFVgLt@BdlC4&*gF7cJA${FI(B;9 zib713u)V?opg~a5-$rvv9PY-bz*%4$omynih}A8T7ke7rB()QDp(XQYzKMjYITQJO;%kY0naGv8~>HCPK(_R4!_TkVP=~ z(uK=?-Y2nA>yaT#=B;a1l^?-!>t!96ZErXmLj?lVkhr_!;1MN_oS@n{Wn_Bfk z(*^ro#b_?Y2y_X#BB$lNZ6dw6t8XQeXrdE77)E-4gWp14sif$**@#2JrlY~3N}@Q= zX?g`BRwW&wI4OgrJ3BBF1qnizESEmtWbccm@rT$gf&?+w@^Qa~%`>|9Q7^PUFQcn( zxn0R`w`uG(w@3drxBqhL{-b>PHzarXx8!bS=4fJO;A~-M`zMEQlYi}~#N5{;a!SO# z-z(UP4Y9Y%L1kC1Mx#2OQnQ>?GDtNs18b|36YOYCUuLYvTHl10{dA7KNi76Ia6eR; z9`duL5>i)=Xq#-I%SF6%Sf)rpk{THqp%yi(xy>sGMWj?|^%TiZ>%P%$1x?%9s}+LD zoI(n33I(2}&F9|E&S!6`;nG0qg_ELxboTvdO$5_OeEN8Hpnh2{B-b7x=Diz5zoFQM z`jC;{-sTjB14~Kv9wlvr`oNIt1?ORLiWmmX~kAw3l29 zu_;Eee&j^9*joR}0lwK0hM($Y_A#DQ-VeJS1tKt*d$i(2cMfVVzcXZdYYrdU4+gBPEeoF)DFEsp-Y5xWgz~4aleHs5xgH0voU%I9-_i{&H-kPS4144~8)gYCq z)&vC}_mVD-5Y$XuN8sHDY=UdUBc}TS7;6t`vS_~7K80hz1UdzC?1Ie02an%#vw_yH znO?i5tbvDQMieAzC|AP+#Jd?LxCCDb<|Cb+qxGY(Y}^a?q&e@kBCy%XQ^B32>u2{d-73mjU|Ffn322tO<+sMGy$i(`0-u;iR zCb8qTf%pi0r@Xxh#xXDu6^o)gM+N(xA=Q!zJwu|Q);Ify?K1PWf;;ILJ|nSozBwqo zGsT6ACGXmN*UK0Z8Hg-_6Ot5cci~J~G;I3(d(e>^pJDQ7#81C(2QZxSc!rrCq^xDs z29d3~9NvTOJ_={6H61Rurq%s0bE1I&hf|~uq1MW94WLZ-w4RQwZ4Lh+b?j*lt=J0* zAszoEhhj(>sHjGmf}~~L%W>ST#tIr&GlaQ+DK8(;J+hiP<%YaL(wYyTlVNnyuP?=< z8tlG_wF|54I`o?@!T_cL%@pOPp8&g-1Ysv z>0CX1$V&h`uV}ji99eCO3yi7%DY$p$)7q2&81U}Ze`sf7& zTRg%11bW1Kmv;pTipHM=9F?jyl7D3SvDntH$K*2YPpxv13IHYEsaJxa(H8P8IlyXS z%kM3rQ%mDuS(YDyDTkRX&r?zgrh-=y^6l^zL!lzJ2usZ)h|IKo!0Unk9-?RfTPi?! zkGkYrw5(Cp%andNE_c82Q{TaRp@wg-`V#zB-(PC9KeE{0An)6A8=0FJSsB{7)BOC! z#Q0B~-9}NzE}b6b{b|)1^>NfKFfbsJW=Vb-C2DkcSl z!K&9d$IX4p)u@49o?hXM z$>XXbu4!1V%S-Qco_q*8@+S&KNwy`}`{zwuhc1fNhj7Ho`?fF&oc_2-{}flT)1{UY zv@XR(n+5QMsd(0sYU`ypft zo3{k*k{L|BMq_W~sh(UR2lB{sm0bM$bUvc32}}*i)(3E(6UbMYJyHlk)fUaR^0CC~ zs_4)y-e~qY#x5pomlmryW$oY3whV$YC$vXRI#{h-y&UOYeXc;IW+218(QX4uN8mmr zJ*846y`6v!+x37O204G~FrXmwA;+#BSSS8)nlPT?1X38Q-y--5cs$Ahz~W*2dZc_xo<75_Qr7N#i%|tIO*Fy;rVN*}99e7@3B$=%R|rg^He; z8$~m7gD81ps7;iZc_!g?opWkt5p=^L)>jYb?_8cRd3cw%Rv81y5}u)$B$LZX?$0ma z-cWyvMy$-VLY53Mz!wsa)S2Sa`cg;91%-cwPpm-R$5EmkloM3NT|6{%rWu)Oq%2ie zx!ie}h;2K<+6%*g0;PVt>SZ6fX4)hrclj=oVbv;zcu91>K?(oUsHt;gwE1M62qcqv z#Zmt8HUS>?m16=QWj-_3LD5Z-Uq0FlGxEdAfbg|qdTCm6lx0lfn8pPu**Ez%%mU8+!w>fMnshMA>WfhWKtB}kP|q7+ zKtu`;F!_8ik|h7}K2F}4mpiy88l)L|NB7(t3|!BP7=!cDw+#(3bqomiBYX5kiaqZ0 zuCOpf)@coqSx=T6j4aj@K}D(&RC~zF2Q@R_pJkY13F1@kE6g3gg_-2v!2Dl9@i!p- z?q891vHh20Ov4QsZO7NA7!;W$H^hB;kJi3Mv3<#MTZGJM_S5P=3g{C{yBs<$Cy| zNl~O5VE_n00;V@GyMPW-6J%R9v8~I-!ACMX-csp~!7A~n@|czcn_Zg7dvMMP0?3_l zDqpOHXw2hmQ7ArBb>|9Qe#De%*3HX&a@xa>sW{U*-)eiHU$_;a1AC@E;a)rz>4 zyn^gRW>~m>a{hA$n&wPMVjtH7C7C(-i-rl3+3JXyOIeGvrhzy}ln8bhM>OP_#`M>! zZ0SKAXMs(2-t@_fi_^0AjDae8T+(p*?|*Ppp78{l`ENiy!Vpyg2c5bwQrlw+bp%qO zE9c1#l0zT2p~8wsZobPEpze;zUMAv*d>$7AGb_J~9UFt}UM13A+aCP6d$B90{Uzo< zvP|^@V>`D$>Ivz@cRB{(zZRA6p@O{-->GLKI~A)v0JXXx zVP)2&F_7+@H}gBEWnCKG=(+m3x_!-@pTya%-@;_KN*nxB5ZsvJ zFrujXO_jJ+S#RhIVbbttdqay8A?GotZS2*#4PsUp`BWpC+^f=N3K|bVkBFcW8+75{qx5P-G|EQK94&( z0W(eXPP#Pa+h0HSR(^1w4_5X1X1UkDSv~V|F@GvIELK+Wc_<*hwtbVi&Qo_sw=BkY z>T&kKU`e(;&2-hR)~mL>AFR9%7W%NiIb`aS4Y|tA;lp%86W`5+BfI$(XH?P4I9!Df zpqaHYLL{ghj`~MM*{&5s)sZYkgg%H2v#Rz?B4irxpcFvt?~*#Kfokh!WuBIYH9LA7J?a~Eyy(fm#SxsCpC`+lqd~RRPJ*&H?xh71y|luJ z43P4rrN85YFmx25K$|%m@^?`$Fn~RW>vVJ*xO`!79pPUnG422*4l{!AGsbVr59*3L8FP-rK;yyuR4zyfBfM&m!T(rMbD70h}Pg$f$yQzqzp% zRm16B*3apOXLa__3i_E81!my&vq}mi_ARL@(IZD`OQa;KLfamej1ep?9y@D~rM{93=N@3k<)K!lWegizxqgrLC z!)mPl>*3{)Wl19p)$TeQB(HgJM}(yV6G6(Y{Ja$wtI7V6pg41}YY`XY>mh=`+%({Q zhcOm`1%>dsYtvoL^}qzbR++YI61*1pARS2w4Qzcgr_2(Sz9xHN7!te)bh7)_q+w+G z2%b=sIFVe@0F9o#=4@M3%jI)kfqGi)*{)Uf=Pn;zj(t&uPd_Au@qb|C{Y0!{2GX20KUY`vbnC)VQpZQDQ<3`RVDWjH zX6dHDZf}?{tmmZO4DuF(Wki7MQ3!#G))c_kUtUXu&BBJ zVrdd}=IN2=OPwv5-iLS%0%OZ>m>UBanfRqW(H*8q9sA1|9o0r3<-a{c zKJ0bLoWS0;-ufMhZuiR&zFS#zEJu<&YpIj@%#cu@*PlU?WrMLOn%o@;7eN6-f&=o^ z9gI~a**K{-m7-V}yJDR9$i@^PCP<`_fE7+?@Lfbc(nt9PfPjeb;*>8mTh;0KV1956 z@GeWL18}$M`N9f88}g7v9^M=IK~!vQ=-v?zEdWjXFSy-@KE9``7vH0$m|&;M%bZQ_ z7PC%#ejbRv0jG$#zcM-cTP897_e}n0dH)6=e-@K=)^?6G_7+A~CXRoCq)hCnZNOWE zd=Eu88OYI(rar-Z{5TvJiiehiNDfkJ5`M0ba z7P9#I7VTQ$=4MStR;=gLPy>vXGJJ1JBaaI}O!BuB0tv`tA;PH&SelqA6|lmK@h(6^ zAPbx^DY)m^dZ3&vFeaQy(*1^LO1n3X+;PB`q6+OE{6JqO z#na9vaZOcQ=meSi7gm5&&*s&Fs7By9uGHvFEB)1q&GXzk}j+HopT!h1lKPN_r;)QDoMqD9J2wup2j%;gsYNXdI%?ICe+mKjF%}t|d}7 zHTFqst3zOxgT5IAi*y<1@zTdR!jMg)WQrFZUGs=dSrXEJs?dW`L|8HWYohuOF*;+w zLsQuAj}gdATv2nKnkZ*#r*!vbYX?Jmz^AUd%NSg}l_9S!PoLT{-k*s_UnXRB;dNd@ z^4rAo*1-DLw(_4D?{CohXBlK?>+EP?f~KlT%{yp2 zsAgjK=DZaa+XwZpTHd^V{(WZnwTSp*8^)F2UeY{tja-smk5D7SogzUKnI%64n1 zv#Bjt0o=n$RdfeZi%WKR9}YnYp-s2zQyO~i<8DSB$S)+j>~0wEG)DM|zdDmGZtRW< zFz%IH=`u4tdfeUu%+3ZZE@8A4QssrIMtKx8iwBYEn_u z?e{M+Wda`VjSo)(HBL@sE`v#jJw!A&m9=RVP3joo1jP)(V?EQ;oJEoMo*Mr~sU`a<_jEfpN_!wlmXlDMZ8t756| zCLE}O`~nxfpGhca!b7O{3DNA;ew2KKbh{(UO2*q5_Cm&^c+pTRCr+pAE1a5BaRh#o z)Vw&>y7yI5ncqtK>sb3w%=9;C`nHZ_(8Ahe@#FsoXnKakG8QJ6U!eVzzeP?%nm}N@z5D=xN3;-P_cI>%&6Py1rNIPu*uN zD||MtOT$5U%ZBQ9cCHQS$IIIr{SB*GbG>KIjVmjfiC;V$g=Shlhu6 zk@}XOZSR(!@6UalF1{RLB{$XhemUxD!Lx&Jh^Q1KX}7k8zgec<^=U^xnM-ee=#KMT zDc5UTdEcnr*a<6e|I+)2?Za^S(dH8^UyfFWQ|WNMwzvDdweRz^=&Gice?$eET+AHX zGI-3x)s*K;3$M>=*l2T1TYvhw>5Wgx%EO${%ii+N`nvbaaQD68Q_ISUt)1R7w>2)G z&xP~+sgLd_x1dAc6V|1Or<3I4{o{vGgI3@9%l@F2131k4_Bpriooh#ji^~>txQD~z zspjS9r|pfWD}(mCGjO&hYL-Ihoy%R}pqilA;RO%hM8OK)=ZP(Woz1ItpFPEPc$TcY zwf=f2k{G1n)MWZTZ7>Q0X%P~UeP!D`KCV;Q_HdPg`^4KCE1d7CwD&}_WzSUoDlg00 zzCo~q!{6HXV#;h|dDRFa7?ing3==nJ2D3i3!PmGZ^7c?kY+oiY)|VldogOSo`c93K zt2ug;E2+BoF$W9eN9l-O2lQl*m&NAtOeyfcUhfQ3w{=_6n|oL;>vi1eXqM~gipjZC zMS$Fo3sq?9FO95onUgq9Bx8i{_Dz^(47>~(H!07_bXkoene%eKwpNa(gdxoM^5$=^Rs7^==iwhbW255eoEE7Dt8Q>Akh`FfFQ z<;KOl{=`cVeq+BC|jAf8Q;!pOUEO`|=YZ}{`H`LYQZMFI5ffD`5F9{`yo+)Y zos}mwa+;jz(LuAkONN94IwEdLHZLG2eOcrQ%^}eJGmxXSkk0Xr83hA{W^AibE|ygjsW`@rZxg$mMEcK&YzRN|K3W%wE==@=)dG$qZf_ITh+LEKTS!o}@d+@L zjTKXFi6W7Eqx)qsCgvzX*n&Vi!5rauw`2Gb=p?sw-l{tYYu*~v7%)#K72{$Ja9Ws4 zAwWT-ia3NIF|bWnE;{C>6iknRP7NIXUL*0hok;P4AtJxot#TH^B^oWqZ`?lwzl}k- z63VL)LnthzkzPQY#Cjfmgiv7>Tvi|xy%g=RVArUb=-={mR$T;oNWE)awm>CY1f4cE zXDY>axF0Z29lSRK4%yDs--;8jrOgETqCVbP$!O;^>*GhxAmbzB==}NQ2Qm?>t7&~# zA4_3~rD2@$bN;xdG1Mpm1fqX&M?KV>n5q)|927+dFj2*4SZ+um16D)OtxxQN-`Ch? zf#O25b}JA;rHy`Mgr-nN#WK3g2IicR1K8t_;CM>=bAa8Cz6Z7EHv)(e3=umhPZ~Uk z;?Kmk2BMnEv z2G>Ny0P9GA4UL>0p8?htKRbA^4$mKH#{@9YdPOuP3+wAgX5Vz;8^lCX@h z0PIpvX(M+#*Cx=nx@~{a(@e2Va*3zGCO9@sm75L40W;Mcy#ScK^7y>jiemQ8N6v0u zm@F+5j0yEd@SgiT+~d*%q_eFfg5Z5LifgA~@L{PABM>J+To{3w0TY^aCWR#>fZ2zz zumDq3wIamIGh8k!*V>3YvoA-j+q9ZIOIn@u=D@@|$a*8u+#_W-zQGB|e!W&tn=8qB zk6>?w5TnV<>?1e;!1vczJpB9G_Ll|TKd3GKnli}cx1*zf3R@c`8>_dykT$&>NH8q& zcv;oQcvc$a#uJAs$L2hxHUiEf#m%z0DUlbF1HeZ_R`qI6`D`)7zJe^_HYM58qodD$8%+(QNMy8JZV-(V?BP}-Of%=^&7ZnpuPA7eeL?(%GK3uYT zAx1a7CQPDHvV2NQf`5vr=z*dnh<+Hz27zk6EU;6!x5Qdh+$^pJ4WZ52mjPp7qsYL) zI64t|&S7I|;u@D!Y2fjrR;Fpf+6rcM0NDF*gvWQk2HCR!BB;%5N- zf&@)JVNLxum8QUyyXT3>jf@kxh@rr9J7sm3XU5!BJ8x*2rAMmf>&UV*!7>t``%4Gi zmWQ8nH0E69%MY(@qYRM$#ufiF-+zNEzV#XY^rEv&jLh46WrA*ad!6y6o)#0Q2)!m` z_6bA84Gkc*spbVGz3#<}gF4PkalM&hCg=h?iZn)D;Y|I9;k|X91|JeR;R7S1RyJWK zteYF=qU&XwU$2MFLRG`j%FW37Q&!Hpah~DVqbB}ukD9-95B|hfe~qsHVUy{f z82f*9rPcdSTVHRs`df50F}C=#+!_DXafu%$*o&tZ4iBKG2Aq|sv>Fpl@la5QR8@GC zJXfqxhR+9JQq6$*drafa>ea;|h4gNJ%_-(O>1F>#310HW;T`)jtes8(V1WIZukU!W z)SPz6VGX3+3+>!)<$nM9zS@%P6v)R8d#<|3&t80uD4PtwL zLsvciUh94sj$I^(oJF^OkQ7BoRAQ3N@fHZ<=a8GnZeFli@ONt*!=*js1cKM)6*Z)# zeG?q&*s97#0>rLK(!u$t7FH=ixeQ6UGs}s&A$cq@D;Z(D_EzXryQe3L@@N|#tuug>qn&(~$#knHOnUc&l;uM8v48<1P zUMJJJy>*kXyHn}$2a;)@FF$_fBY)v}{^s5GX&dy}?q&Zq)GCP&5780mLui=1-*l8?bz9R+_l~hZ|Y{#G5D;8@nY|gy$8#PDu1>K-S)5 zA_`6iXl08Cz!O#d{ot!~1FCveF-GH=vDd23Ey2cQ-~&hSV93q$_qea`FD@IA`%Af| zZJ5TtD5n;usWexnk8(eFzxZexZ+xRmzjB;oo#D1xJQ_VzYgk==Qe1gC-_K;nX4{zB zZHV|J87Fh`=%%%ExBQfOd({9hD3!T;>N6%>fBf)7JuX-Dky~TIHT_Yj;k(`841rj0 z2Fe7vn3?9VOZyl-hzIY?p-+Sb#npS#dX?6NYcuEavZ*vLs z38B^{nP$6YOI4h*LY*o*)n?C^$E|N}$8(n9fMtA3O{p%&4Lgqa>NhG4We%ySSj6IM zyRJkBSKMV;sx!36?;EV);B9W$$8nS2tMNT$=l>`K*d+~rrX3hEuYmtZfy<$Vg6V_J z{dw-`^D5Nk!^AuK3Dsfs#kB%I`iVZtGl3NS0_ZJB7(%>)Ea|vwP?Rl|WKpR|%IQGX zM*f-(Jb034(IBz%wJ(U~e#1b>xpiMwV1UB2oIQ3890qrX#h^ihr{BHn3mUfckBo?b zsH4~HK$a$=9`PW^q3{4DtDq;9yj-uN*SFA7f4x0924{cwLy#@K{;v68F`XI@vC$(3 zO;mK(`5-W^(=+OEDU{hTvP3CJc{Y0K>{C{*8Cjz_p0U9u$k&gZXfO3XE7Avb>pSy} z@{{IZtm+_?XY`GN$;>4D9aJ;}eGK2?0EEG2<1wp&;Xx&=C8q-cge#g@O(?Tj-&myJ4<~-9az3-7D(E zL5mvxw836p2sM@lO399da)hCmi)g>?V#hIR95*DLK{1NRQ=6k4UW}}-Cp!gQR2%>| znUzRw!&0`ExXDvee8{2iXXau#v;Yg@bp;t+<3>BI- z>r}JljK8WQ6>qz$Keh#=Z85-WL#$w_n0dQmvSL$xw{>&Z7~s2)wFM>;!sgB1OI!J4 z?socwk{4LZ*8<MXzyNetN@4k1OZa)CQ z-fUb6ZK2}=RBv@1(Lb5?1A$=5U$Bk=!t;e4u^%O>hoW|Dz`tAPszi&~Xy;|g7 zM(QT+e`cJ&K}^^;F+EIZoU9F;%>QI)!=fZpwaEYTRZwxB-=mJ7DnAI(slcC#$%jH9 zk;ox*dOcm?*!{>KV8DtoxzTHsC(wDpGtS(G7tYL;Jr3{jKdNgc>3{!0q&^9Tq|TF1x9qVB!{MBX9Ox* zK7Jp%jeUGTlxE#dBqnR%sYWRQ8no7_B4w}+%2!J6f_KAlIt1_#LDnr)b%b&Rsax|8 zEMgb&_{~i{fGUI&^y$+sE)>Z07OkiRtfEdkEotrA4DPn?8D{GuR z%|iz*qa-FU7rPk>Ei3_>n3m+OoQ{HEWZ|mD68gAtlICQULug2(&T;WMp!DG^_}S&b zrV0(~M(c&{Vf5#P8PW8pntMP1fRNwr6rum(4}Z$n-{25$^UGI<_!C!iod+S58|H@ANb7Y+de;V1y1<5C!q%~i?@CX*q*t7 z#dJOaVAx!CToIDqwm2aTOC$?(vO8sr#meq>CmHXNbywc_^*Rhika%TWA2-JK%$0x_ z1IF_R{HD}4FROjD)c^>De4lTpsBt3GxeTvKcGg)<56J`B*C^uA--NpGH$AMHp4e9V4=M34@MmfYgWKUb509llbNZRyX<(l!x}zl`B5!iaCp?zJfpi0>}IPW zL&1`i!d3=@RK`vvLdJz5g=zBC-E|hBHkIl}kqQ=wZHe3jMhMN2RdOYU-&Cpg5i<}PJ&%bw^|0-~WQCm?3Ew`rx*y*Ed5d4PMSx`IHGS&5YX9$3 z=r5a0e{RgbLH@V5b^Om0|4G>3i5`9p8wjtv`MuMM$v((PD#0Rb3TWQKNZNf!orsb4 z@l{n6lKC3nnK<*fP6C|R?nj2{hZWk)~n8$PSINn?nm%EQ!5ir8Gl$Kpsk~%VBEwnLq=dwFgh2>l zyBO5n6Bsej=R+NPIc&B{7um^fUS+8OfF+k9ca*mFWXqQypW2iMDP3o_*I=-%W);Ic zbUzSFPfaJNCq2jltn;d6&@Un9rQa)74$bBP2S?D!K?Q$*n6SV>upH{wGZr>0_r%;Vg><8isaA{(6@o3&qV zfj2&Pj?=hMjB=CemsfmmimJXdiL$VjcL+MW&D^Q$19gNG&o!(UhbJ$0O+X z6ReTC^F#2)25v2+xqnQ=g_Vr8pDn1#m(L$;P->4y23I>-QTmY6Ip$bKqwTIE7fc1) zT+QZ386srqI_-6F^kqX-vp8U6z!)#mDF{KgKe=6u^kg#WFi zzc~J%Sn01(^gmoI{>SfaV*ZzF0i;q*8(Y=G^EvPnG`7|QZ;CEYjaM$%;PXnHJzNr8 z^q{va^;VjFCh}fc-=xYARBwdun3qqr`J~@)xYIqEw*j?&%|oXZ6TRn&LfAK8G}_Gx zNmGClCKl>LoNQ0=2{Gg9V_v(>4QpGFRtysHG$(2y$`9rxgL*W^+>ykuS%aPPn-UEz zHeB*Dw$UX?R?DL}cDk0T%IDpOLh#aqKrc(U{7J@E;d6;jTvHf#ot>fB89y$lgsy(R z@GhG!81(JMXoUZjtbbstzd_cwTFctP*6PoCPd2abJ$#+#w(L^X`{Sz3=DB7VK75nf z@5GDiBSey@K!D~Nol~1F%ogI0WFBVBTd>hZSf7gAX@WQXaH@C9dAsru#|0m{T$s8; zG_u3V!B;QsIJkE0gj;5N($0pQ36uZ(jiC)2-4E^tGDhajUt6e#qGNqlYGRu+`bs*0c=$ zc#Yx37rkwsnm8M(;z{vj&3Szqf!bhoyfVY(d>Ibo5>5xVB3@Hl|NAUDe+*NQq*|iwHMjesp zFF$Su=w;J4taqo}8voE8o6)Vfh#6>@q)}%2E}a6sC6Rz`s?*jIGu!$it!f?@7g4og z6|eetCh2o={+UU#U?@*OxR1#DAr8wqBqdy1wU6!Ke+jxl7N0&F3pMQSnb|YhH9>IXz z75rMcLDNy~DficU9uKJ@XM+i;sb85I< zyn_0LZk;OA4`S%!Y)CJ?G~@0Zc-l*8lq_92@Ul9s2yzu*d8va+&o{@iiQe;5KPP2_ z(_h`Z`^cg0rKgKdBqbl=W$fN?Uf(+%eRk&8D`S7mC8h`zy(lVSebJYW<*(i^6(>0p zF2ECeQQ10rk$xYzkE5aQa$KKy3G5c1fgjlS^HU*ic!lxDD9_B^jn&8&uH&6vyn-`O zG$y&7BA$iRvZr&?ha@g=BW8#{+egBKHxuP;b%d))8Nv7vD`Eg@nvZ z5$ri%`Tb_cq=}-g$IkVkv9t$ULJ=kk*9O}{W9L>p-@PeM%O2HH>)2>FZ!Ek&C-2;O z)!-?RtUqeB&{~p3U0>WJBB^a&P#{p0H9@EpXs&*PqBt=@7A4BWjoxTNamNy>iIX3|~#9=}wY$d%l?|U=&A}GWde7O20X( zr0VfBgeS!5D47LokZ)|#D?DTAs9{R zpx1w7CZBC37yaNBhEzCL{@nX!FWU`K7cGg6=Npc@{8(vi5`1K+26bPrlFF^Lku13g zdLMRwx?f!X(B{qVNq{MpN~tp+a6Y6cXE9(n4dPEQV94FX4&V#V4(1jGs*+L)3(M4d zi%)WRQY9rhGSuf=ojX+@#2(I>(l(}iRs8GAXUkn;ypCS=-xq9FE>=*X=U(TIV2yZB zo$o<6%O&&F{uzZl7tPrAUxA2iR!AUX9leLAE|YK01_(sh)O%1AM4^c!wD<)OTCrCk zQ}FA3DZj_KHL3Wet4>taSnmO21f%rjdGj)E+R5Zu({W3LIrdQ+Yz0*jld(9KS75lJBXG2nRbwRc0x&@+HDc#iC1|YbFBHK zwC>LW1$Mc=T*J`qY0T9>EjLL5N5czqW|*>KO@U zOK-df_Diy`-=|IkCy^aGyO^jG$G{f4D3 zc!(;_393yiwI`5$qleOQ^UMePhj^NIXW*@Y;BBc76-~7(S(V%Teut zn4`8=hrDuJu-K?{U0$hIuGV=$^Jue4qG>x9{+%eEz4Omr><&$&@%x@+ICvyel79hI z?fuKOdMX$Mm-zk!T|*qMy_qLmrv+Fg=605d+>hL?@(djEWPuWMqlbz8SDU`tR(-d* zjyT|G%>!hw0 zrG(=TN%&4NPWfnd-x7mdRr4(e8(*NjM6#jH^A`)>S<~t1%XZAilf5$313!of2&DjV z`-2D5jl6%w?JcZR_@Dk{*Ir=;;`WZUTlV?gfsUgb#3q@_Dk83mj-6WTS0qPK<9?(R z;YYlFhB0AZ%D;SAEsjH(DI3H@H`Kj2;*~?B!>9U2mAzYii0~3-+>;CV+_0)aqDVgZSO#_e+B?<^FLnZI??+89VB^=c zo3f!<@bByftqd#|JhLo*Fl3vzdpGdayY_%**7UOMZ=W?;6>6=F?OtiC+Mb~sZsTaX zF{jndxhgTYcWLh6nV3Vc$qH4E8~ai3xOJ0XKzl>8I0^6D9h74h0kd#AIc&-xS|&Qe@~hvj$eKsp@N6x}R%)~f?5a=TnC4vTAKR8P{{9$k z*quR4`CZ7aGq>z4{!lP_es0ilPUvJC|GX=R(d^r;uqw%DD;3)-f$rvo@Z3mB-w? z$tT&n=*KD)ynsI!{^ce9)YOzSsOL|xD9A4E2!#3J@(oJLqmcX#pA`+yM_cn>X?623 zJcruKANoqlWT56=QM({ESY#lMKtp4aM!CPEQcF|+gzD$?k4+Tcqpy`^3^r)vI-<6? z6%keQvzy z*vs7U5S!f0kmS$f!kM9_{s8Y5m&HCPn? z)?-L+YS*9HmP~txFVnSw0WCp=w>PU?@9msi$MB?gzF!B-NbHwpbn0jTmrni! z1A?RnIa>X)d+y&K75=N?*#n>@B#BispGc;k;s>KARu6?GH7cs(y~&9hoIeEp_%w}c)M#c$t?G$-jNjjjl( z&SR7(l!pZ-K+lr&TZT?{^BJAH0)FG~3vs(ffBabgzQR5Ef#wMiN~C+sJ~X?~6qd#Q zsxYTpLMJXGMD-mi)1zeX=a>m9#g8!K(c<1(@TA^g#t`^4_Cs;Jsae^QO9}(+4nH-P zwX%3-CS|04TRZ2t)^i?AXBIVl9nxHa+>hdQVIAF}I^vl?)7qF%9&1^-MJASQ_6XRVG68ddeWN>-@&ku-{{%yTbO{Bh+MAiO8aueUI@rN=JCEKnMjc5AS}K`Zz0DIctxi?vByc*r(p#dB4}Ko4jp%J( zd-COd&X`B#(vh2o)v?Id=;D*!x%aqw^Nb!x%X3GLn%m92PNN=awK&b&Znc%V<5U{2 z7B~5Iz4)FPXmA7;`%fS3P6F*9%m%CT_lpE&UlRy~NwCmF3OaJBSQuZuh|7T@f3e5V zxZJcc&8e<^xJ$J)5k9sX~coW`Dt0U;Hb-zYix%93u9NfnES*@j&q z)SfQ!^bf5gmMAT}RA(Gz?x>R;NKe&&A$C_&h?;f7?xG~gIIrLu;g`AA(wCf%b_6-D zYE+cW@Ef3h`TFt36aHJFI_{r46SY3DV7Pb2ANYQJ_uhxg?H+;Tx(k!yR|NC9SR@l1 z)}X%GWNtqN73X_|9S`yzWxQd)-yOPqe%(DA{oGf|YI#eG+xZW%%Lu!@q>FCNE;KvL?}9DC=WzqC%^qztlFlVq$i_-HUg&%)ZKu}i ztLs&JG1S!*{B{iQX%*;KvWGqA0-ZfQ)&jj*D9qbtjh>R0U12O^>)b5b_b5E#<*jLK zCN>tFQkp>TBz*TRuFSy-qpt1AZK_-y8cYK$atCm!{5Td0IO&96#?4OkPCb*!{|W09 zlA8Blq+K20O675juY)X7NY``7A|;elmgsG81}{=-IW0MULxz1$x`kt=&(RJm*BZ>W zy~o*PVw{HT-LH+h+`B(v$7T>s-Nu1!g+O*NTJ*)YmJ+wQ!JJaqcLmp>&FP+St*;gf z+mkle*50+Br61xy*AqnF!i_Ex=^UN(y5WnI!pA_le&@NfKAD1?b$+ZU+O)VDS`tBy zyhp@VOn;_w2`hZXbRz=$bg(-q`pk)t{!6R*<~OeaKlQ%Aw=elLeQO%v#yW$I-++cCzJ*=|f}6_Z`}3r4Rf zY-^vgL=30MG)|GHBMl=%c2sO#xNUx)v#4*Wg*$&4b?vQBJd*6F*GVyXR zMnK(`S#9aSrW=ZgFeSw}ri8J}tH|!EDMJ#w&GfGciI@{R4 zdc=Vz?Q&ilBNAVslJYaTE_a{m+KQpIYGzyicAX^S3mlus1KOE34!KN|6`GYG!Yd!< z$$P@)QzOLe-c{U8Cq@fZb&XQBn<$Wsyb)eR64>;>&R{DkiNAB~PT%c^jrRH`*N0a^ z4(<7o3hav>haG4yO{&1{B8+~s`x<`mt41?m6G1$in{5`NqM6ISEN`P<6f0j|(WP^{QriIOMTSUe^a z61peZSk56_VjKiPj3tUmy@Ny9VtVBSd#QfSbGYuCl1x<<68DBjx6pwPvc9Aq(|pDD z$nwcbZf*>YOW#H!C6xH4k?qqC9ScHBwhm&=dbvvEO4pn}AzwC6Wng!cu@Q{gQT$N; zrFAIFMNgnQ>P^z6OR|&KrfQ7^M&ES2bIB+u1ulmhha)*beEa&y*6Wt%j4Mu!`(Zqb!v@>}Rw zyNNzNzgk~0SP+qvG*)?~QXS6SORr?zX|8i%Ag&BD*FfZSjw}=IHVm z1)d@1Na;srJ~tyHCTo>P9HzQD(fxMw>cn-M%9d}2aq_RO6_YdQm3fP9pM>szG#8}K z0jKnrfZ}1F(oe+#;gRE?pmWG~7e{9^cPj_@^bQoO0r5a!^B0t|n{v`QmtlyCcC85s z*RQmgt_58&Sh)Ji$EQ37d%X9L)R##EUM=)%3iN+C#D4RzAb;sy$p=lcR$#uB`n0L7 zfnmEz;J4vTRlkvUlPrPTsr&JxB}5qbpdLbuSh6V)rzk|NhhDhXvpW9VOS z=sGpIY4!P1k9I>**%qN)IJ?ETib}<}@*R;6*zRL{9Gj;k^Y7tHO66v6i zn|0Us5Fu;#zH*NNq+{rrO4Z;M&7Yu3h}&@nQh6L$jop9?mp!Y4xj8(SE;|()$iTeA zaf3;%q;k1XYK|9vf$GdwujKCC(SC1r80?Rv9~v1!QF^pDG9>wmP;_T((WOhsH@`4? zAC>a$a$qc3W{BvAZ|Vu+>SW$yV@f1=uGukWJ&diKj6_v6?=^iik6U=}Q`w7oy!_BG z-7$FW#sk%e`(>2Vo95WQNAJ-Hl_MN#B@k>(MhK^CR+PJ9J`>dpO6i2#J!HifNN25A zk5IXjL@+{p^BqZ6ZUL*fu=s5k<$m)B9RF?Jg{NYO=!Ts8b;pBZG{slr^xU(zBk-o~ zqR8L14fGb4$&`!zYUKVrTTjP!iK;xwLzj9-(*ddEo`#5NxB61aX!ZR_){)Tc#Dyop zIR_uInA^U+#$Vc3v?#wjt2!EUtR|kVUEQMUehq6dvRFc1Su%r6Z^RC9OH1v;ytunS z);8G~iFEihL)h5$;lLq}kE*kx<$Qi!Vn(;E&Z`Do516nNOnkvt(@w$|C5YT`e~RGT zXTEL2CcJRJ9QqIrRNcb|>qhp9`!uT(U+)O6e@+!~rPLF|_MNK3qYH^`!}EJLm|^)y zlBW3XIX-i&1NOw|n%VKkSB+>E8=L$&N^1l$*L_I^(kO+V-7v_VxjJZ#;lxL!JG}UV zZLGiXq{+1vTTR?B;J6%rxnrFgrFT{<`V*`l;(x)s;R-_8soDU|r69%+X)Z;3S2L7C z!0EhO<@KSAVpo$xbK}N=1zBnLY1>-gSURt(v>5N^^q;vbSJ#j0rr}`oIe)>RqH@Cc~ztRp=3EX`u05|CNO> zFZS*=I@7%V@RU5X9+xlZ7gWNCUGaM=-q9NhCu9D6AM-{3y96q(R8iyii&E}NJXdBZ zR#UW!HI=?rdywjlq!)=L)^%~E(uHt5?nN(YF=9XJYLfrpv@GU7MdUccDDLEq5fLP@ z>q+{F%~MQvO7MBl7=~^ydu!aY*4={JRZqR%D4U)Cn%0kgIam{m(#_eKk-AHK7^N#Z zyIRnBAWEdb%rBY2{XBtWYgX5X&%4Uy^2EX%zEqm#Sh`PH8*~+TA1AOIxS5OLUFUov zF+LvD4ScZw-p>wvWQTi#{Q*CJ;a#4!0F20dC5~k3W?7v*yzpQ0Kld zRV7_^oWy#_K^;-obJJZ|X0&1ZVvTP-Q(&k!Leu+CEGM}Z)Y-&za)F~}DUXTuA_j%# znCRq_>IEI?0>388$ks%&O^bV9=37J~IUZTC;}6scM?|(vKr5r$;~TMOdp=pDlDK$- ze_lthmHc&P1yy3^7aZS=7aiFj)dlEnRPwZl`rW4W%}gB-#x+z3gAdn6i6u+B$pTVA@0=49WFWj2}*^W++B>^;reQ$2IO7ET}$>NAG}7|@GznfGJ6(6N_IS5?*4AYi`n7Jx&M<@`ZQv=Z;lB;Rf3y?&onyp! zv~$daZA*?n=ptennzhaQB1)bKk&=$T=860WrMU$;|E2uW3Qis6;SubgU<8oNe-|?& zXA`*k6zBmn(Gh7*W}*jHvV46#npGH@I!H2<+>>jJkN!2?XAe;hmnTtV*LOqddZOFY zuGP0z7f_u;ds?&Qn0m_72hu3&NNq|32*a_K9Y6ZYk&ymPogslVfcC=AtXnI^u5gEBl=4ujN-q@BF;7GQV(fhhk~8ME#{{zUs@) zP_Esm^{9@ilOn7QtrvcfL|w>tTG-3{RJuNVLi-a`47shjn7O(F>H2WxS=lL<0I9lI zUv@E{iCii%y`UJ)-lssUj>@BL8Eb>7+lnt-d-v03p#+J}dhflvvAo+d3aa^in|Hq@}q0dEYb~fje@u+#%_@QkT*!3xuqKEDVWe@>tTJH}&9E_t~c~q2>l+ zQ2A=C@lZ~P=(w1n;-K>oAdbn~gjC6HK zM8_z-T)-0_SNNl=8LR8k&?kPMy8=>p^=KFdv1w!Yh$Ks!ebQg*4lxF0-UfZm#TJ!S zZSneU)YEGlprQGh!02L18c`By^92(ox+G+5)h_1F8*RekrFvXibKcR0A^0&48M0Adx?C#V5?I z&ct^_R7&pN>Sd}uy#6No7@p5;k$XS0!x)UnhQ5s^_E0o^HI?S9Fy((MIOz?H8@mFT z|H3H*)Y+RS>5*P-_ljC2J>b)@3|&T}F^&*qrpneQRFQw=892{hit)rb+%R&H_3(9L zq9;}~CY|hUpeCDXrX~3CWo~Db>u$Gwr;zpu5&~@!)&Ca|PnH z{0dEjxCZUq&T)t)iID>AO8_k{oL!Uf$mLJaBqXitFWZCb0J;tIr8J9Df|S<>ZKoRZ zcbgqyX)^Xm@n)UJHL_v%vy_xDzPH!(xDc~}Vs@<~Ss6|IYaTV{raUzofQVi z#3n-PNF>SX{DE8Cn9O*udz5S<=>vD$HRVI;evD7IT>1-VZe_&Wk>9PC zF7e?+`*Dr?uh7I)&USh6ziRSSKGhlI@+YYBWWzr3ukaPvE8SFpEXgn1gwqe&ydf(R zGQ;I=h_%E8*|^V5*>~@%O5p|b3XWSyF9S^yoUN?`7QRB7BtVia1@TlYob~T&_Hj|1 zBwH5a40I4J;5A(^;gBXr*;MVq?7X4i8)*6ddEB!NA%FGk!O3RgjH%%wBA`h^7}wK6 z#nXO#gx~MSv{g-lVJcmIQraIS&Y>)efPeM$z zT!c#yJwjsSuzl<4O%hI_{0T~g+^$@KIgaoIQ@Nu$>`#2ESD0BARrL`@9h0;3eAa^B zLj>bSVyg&(tEj0|Ik&Agtu#1C$jXecYL+Z>Ov*2&EU&uYJj9b;KSyeFo)hq@?nyqR z6!En9_O%Usyz|CY%QtQ@DKj%E3TcR=ryioWdi0o8;!&e_?u|Dd+pO{U1nC4IBF8i1 z&c@GA8;;I*ku(_GGb(JJe{QpSiOwoZ?Ay<0RGL!#%P4Z278r@#mLuxllCNLAZ+zJF zIMY8tT%?%W`!EG*pwMm&8RBMrmQ*7@0t!U}PCu}fdg`VGkC6TZg+d&xtFxIItBI|H z3w(LACu!_JTet12#vi6@@+=eVP9~+j;Bh6fepCM9m2b6<6s?i$^#;Ws;^=%TG7Ukw z!HXAezH!8P5hwfrPtCkJ*Do}<=V77b73})yad(r@sCN@riA>_1=o-3T>e>{BZVqOFGU_G}qd#6XH%Pr=w!O66DS%+!|A9M0)hL!YFejZ-uGsFz8|*U8)kBhYh2) zktr}Kjpy_HQpCHR=+(LNYrv#5^$uWCns4!^lMNG%;(7kRfA=`$X3rpwBLt&7K&U zlbR3uqMswdsTw1|UEK&=nedF{kfjz2sVQ0Hsc&jqFqyxt5V`vHmeEpo7FSyQryFhF zF-~L&G?&%Z(T8zc6Zm=<{7ppO|19F^+NGqvNPtJFsKufYd+Wlsl@YPitYQDCIr;-%^%FL$m>}|`Q3Wz{8d~w&2q$YaRJ!|*Z;Ya( zPsm?$8>+Ft+e7oyZSVCHV)EnNeoigKK4sV1b+&IyJFco3 z7ph&lcI#Tv!&e5aBv;uVe{T0kQER=~V~H;PBW$bQ-#2f9V?!qQq(~%EBSHf>= z_w`_t=o!}sJjOt)C?CmNelU46f{i`@@p4?TR;0A8DIUp-mpGci-L+~Lf5bi3Ho1Y- zOIY_jV0r1OjFsRDA4S(VmIqz%w)gqPd>&n;kcYV+_-y;61-UyqSSt11=HDgdZ ze1u+I|4!hNPk;GJDR1|?kBS7dW#nO(Q|0%`MpR6`=<&uQJ8yicYluoJ7|fFEj_?S4 z6hVSnTK7o2B2ShrH#izQ=M#o1R$nc<$*_voWAYwlRmBli zBxBA-bA|b`k|L6p9_fZFn_&Vo+B9)y8Lk{0ugfd~^9Vj*pQA5(k!1deEuK49+yHH6 zj8jO^c<*D>Dj$P^Xt0L{8loepo_pX%M;0TEY&xGcQG^;6Wo)n90Er2 zXnACsusb+ngYzgpRa~cI(U}%TT~0sy`1}cr;P}M(x&%v_>atVhH~n6MpwPsP)r8UDL(U0 zvJ#OF4e>_VM%DIxs^@+_K@lM_(es%9?T4~gw&4%9zecGwWOGS|k6qSJZnl4leLfc5 zC&Cu#G2ZtTHI_L$;|&)aqnE|a!M5cMRZJ7uZ#iyafAc9%T%Ug#wi^;rGZRo(UputA zbIxz9{fgP#qx<^>PkLtNb8ioDIM6VM9(rf^-;n6{k(7QJ_6%!`oS5+{MR7odnzSLk z{%+I~Ut*#KZFfm$IQzV}@vUd6C6B}ep4~`Fv~tn#&%y}GoSkb)f5L4Zo@RWjz7b`r zIU#{z>Keh|=B|!CNI>RtPG!v`x6{8iJzAp6~ z1#>K<$?-1!C~~7EQ$7LaDA43MTGfi~=hNus_6^QM5}V0pcHHeJZg1<0YF9T(Q=XVL zIi0h)_3)_Viy_5wv{PbqQwHzq(Y+*UnYe+?B^|Y;{V0KH=UTOylvjZchSWti1n*r8 zurrOSvNrF(j%+yc@e(0N!+AQxQEGN^(2DOcF~`aGVxf=Py2SBTDg9fjjzn~ckZu}I zhS8Zp=^@$lwV)VnGR+JN)M&eguD8$QwCB<{Ti6gyu5e`7NFlmEV)#CQPiPh&&7xSO zILzG6a;E`R0Ffb~Tf4q6lE?D!f^SNzh0@o>l+0KL}Q^K&pp$A{8v;$(>XHYtF-jUUCtkP z=GSz-^W)2sBALn#n6-JH=`I0b$Hvj=#^zqYlTe-9x0x=(VGUjRjE< z&O!XmZ3Qq~7p{!II`AJefFD8-92M{YD4CoY`6iNne*`K5LJ|%FKpmRs0Dx>{n2V zL`#75a6uAK#0Q94SU8(m7`a+G{PRr!4!YzZP$vQ~-QUCS*`vsWWC=j><}g9{*De60 zot+&#{`u=G9DIpDc=v(Hj?iXsW@uBz%+=#JkN&vIPVMd1|ZMg z|Bxp(2?BzNkv*)TL1&hyCa_|mJ;vb5$t$=!1L@>2=i|Yl0}2o-JKbsWzx4o( zkj?-ffOgY=&|U!^0Eqhp73NppGt>UW@Q<|5`T)ur5e|s7D*)Q~Ai0Dx{ts=~pMK%s zO$mb4Vg5(nXMRFA(o-o&Zdn|Aw{)$7$NX^#DVqhXcdF?nwt2$a#=5d9MFW`?pU{VBc!V`45cGgk50uZ2|IK zY#aCiTk~Zu2w8hqXCo8W-`_jI*389yitq2hJ6?*=*#zh|1EvAKovZ=yCJv5XziSTQ z+le6WDY9n+wtN|5+X&E90%(E{Q5yiTiL-;tnG^;4wugHI%=4_s&;!=Nr{`t>8P+6q zI6N8n^h_!ars?8-7BxYSo(7Zb1aM7Y%$Pni$qXql$+O`?4^jqOrj|4U?CH{QumoG? zT^SI|vtCDG)8vo^Xu=wnd}f*|a$uTg1csgy3zjB^JOTpDfv{($`CS1-^Q^$oV;sTj z{JA1P6Xq;fICz4uG;6oPJkN>@J*5x}v@hi!FSe}VSAf7OX*T4XV9;E`NdD|GE32SBw3^ZtQf@wOMfN7o)7DqZJq$!>iv`m)um#io4RGj&@8HEnZub}6vv_D| zs^G=NVE-Rf&jJkH+8iv^aR3-d#f06|{mfFGaR5{O4RGkz+~6%B&GCdTj7BJMa0PDx zy-ugOo(&ng2Q^sz;m!!K`)|X+6RiF?7Z6XFU94dMLw8sP)0B4wXu@ix3vOuR3_aK^1&-F%Jb({S9#F zwnJcj(S#wK>eBB%XwX9tI_ z$_MXjYEJ>WzwS!_2VwBOW|9ad{9EwQ<>z3^my-Ub{J#l%fGM*k{{!W-!b8_tgHOH- z0Q|odRKp==@X2>O6U=AzZL4i+>KH3bWuA1~7CjDA*JfUH~-zr6d*xD70X~rl6k=X8U{i(4~&x02XD& zf06#}U&6+mC^+=>vb!*##c+>*75)qz?X~gOmNA%wd*J!a#>EcmeNu zp8)h5ukaMvvx7rt?4p8BfExh# p*}M+4RKXWo{9-WCe=ef + + diff --git a/documentation/ag-grid-docs/public/theme-icons/quartz/quartz-icons.zip b/documentation/ag-grid-docs/public/theme-icons/quartz/quartz-icons.zip index 97bfb4da525a8941ee6e825296b15053ba9c1fd4..9578e7d441b1c7cca81d17fe8807df33255126cd 100644 GIT binary patch delta 10910 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 ANdN!< literal 56928 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 Ekv zL?nQmM5IPTpzp+q1o9rqW03P^mS=vUnhQ6^1abaO6n*4CTQ^*hcJDPH)36+d6zGfD zY9CrsW79?6bA@N1ah3AA@yXzRd*mH(>2#S9xID~W>c&-Y_?k~@sQrFeg`X2{H^ow& z3f*Be<<}*&PrzInzAq%g|8Y?ATRHzWh5rT~U+F;LnIbXHkTm&G8kI^k|6x5t+hxG0 zuVzZrxUz{STY`UGWa}I@Lv-0xrLjQKcjWfYPzq_;AtqpVCCd>`;5@(p;D2@Z6;M@f zTic|Bbfk|Lmhbci4bNDC-Pij+wG@AlmD-TiXi zoQ?Mz|8RUd80Y91KI?hsoNKPR=2~k`+f^cDMuA|t+@&b$Tz@pr@EO#0OZqdljbBrO z?1jZI+$!MfFx)N+XsuioZZsw=#PAvWTwW6$R#$x(vUZ3F2|zxqQ?bYZwuNz`Z5?~X z0;jhA1ml7nsM#5LTG?57!<9GIQ<9GX?y(=R1qt)`)4q@LUd?&A-KV3X#g${Nt^Q*p zIfjW6`=c56#$8M z_}#G4x%wu)O|N1+W7qXnAg5yI#_%G^lA5B+l*!=p?>*#HGA#~>CQa93#H}!=w+hdw zlSl;=42py@pHad19wy81Ky{y>T_=C~?ug9XV_7lc2D)$Fmyqa#N0iHzCdrXH8PRjT z33kn0vSXkzL1KIG1c%|_=opuz^JwKWf9=8K%AN53iRkWC!AhH%s=A*(g>v=b*c`CJ zB?7vK9e5r)l7m-}e~jYI?A_RnY~hMOUn=X#Hggi)+0kh6e_*)LKcldzcEX z?f1>?c;#gX#&*|UvZu3rpSvqP%_J~C9-m?AUTx32n7h%HM&XZtY___ddkYaFS}Y)*VUwR7_4%{u3d0F^7M5PzA5-{^Kz<6t>&e^<^kfFAQf+? z2>cRpOCFiMSIl?Bik>bcvW;qEC?ZOs(Z;e6&1NLzw9s;?uBwq+3zC@JCVQ`}<~C9y z#JJ~D*UKf2#mI%Ve{hb9z9w~jmt&O6#I|qrdU=)l=M@23#eszAI(ps>JG#cZL(&|2 z%+Gx^3*O@%rqI3ScXeD7N4CnVj2^E`N?pz^GxIuMY3*n3e_VfVFVcXY zXZWRz0hunI{Qlg=yT+##2St5?0{VhGlRPwKM%JDzLDRee(_^FL!Q7IZwRVwXi#KhG zU;8fbk?d+-uJBM`7#}h8)-G1!sHIt?$WixRPcumsMFx+Epa2v72Bv%OYx4iBDxf=?<>|-5tn^^_He{igo-sV#w5(~`O0@UA&zfb$*n){LCHqNra#F6B-u!A1^~)+3kwAVAu2=}BRkge_Z6 z>@2CRhmpoU?iv@3iikK`X&q%2Me)u6+C0|{5?os!S6u>pMa-a)=abe%m`!P~Dttfq z?etnvwKW;4C<-_Xcj$0mdfqzQP9DXS0@=u_&q^l9y}E0tJULP*N6o?)hep4}io!TS9u>IG^sr}6N3B9^(E;{lnbarrL;iTbwAyI97D52;q%c7Hu|h*pP} z&&U%h%vFr1W1QxdBSZ7zyw3~YQQ|NGw-WD-vyhp3*7{@UFreqm6ZL$2rot(^KS9@! z#1>GK(+#dSZ+fvhkdp$*qq=aTADN*^fS<-0_xH;IP6}{&`Sg4Vt7y4nb$c_f$SGg6 zIXg9p6Cp7>zG>QXTk+s-v`e>g@8z@9=&x)t;!;e}Z+H|t)%ki1$xyY4ns~7>ed-BV zrF$`EdZ@{MtJIq;{Y*}rCZpdErUvisZ;00z|=iO&_@kyo5Gd#TE`N6){w)gefS&M|9i+@8?6gMO{$$O$2k7b?U z63d^ULx{JvH}iyR)&IZsWciqbg+~Z~jKUo3;fl}glyo4@wZ1Fdx8j*UO<1Jjv_7rh zEx9O0V;zjB+xrw(!bU5N`Do4E&8yyT4K)p4#?t8ai5$?s=auC&B&aV0R9`f{#hJ3l z@7>K}F|9YXTk}%n2i`@>wx+V$wCMgRzsaPws87kj8v_>sfk@z~N!9Yp7CGb`)@V&r z*#Nmv!Y(RPlUP@rGqQz#>#?5NWvrqc$(R=kuOF1^VHbKmrtZ~!G(;iO<0mmdFC;ob zgz?7UW-Ob-_p?XOXnnJziB=;+u&gu?q#0Zc9Wf6!%W-aLST$@3K)kCxzJ1FGFfBt* zoR-Ix42R(U1SLbdrPw>T0^zu=g9m)6rzj;IAcF|#y4+VFW~llWMH8}Tz#%bZy4a5g zH)hx6(*kMH%RkWZR2YS-?pUCeHbr^>$9KC@kh7miIoX>k!0{a+dWl1EQpZ`8;vWiQ zo()@VQdIf3J{G1?J{2&Vr@0}Zb?%0=sv@6)T|}P@6}Ph#YOVwkV<(T_b-bifyvvG$ zMyM!KSM{#c;PW$%B3cJM{W4#wws|Cx9Lwae?~eY)e{Z|vBYknAqrQRQy~jb$)EiZ3 z?$NxMGZqnKce(z{JH`zOj%c;5_4oW$ zwm&|5j;`d6ym$W6NQq|u2=OkV$;Dme`urd#=>R@+qX&^JZ7KMw44h&T%WT&x({FY# z#LtMhJ#`N0Fmx7NYrHk8*Qnh;^vy)sX+!fhmAckjJ+1MsuwvUB-g8P<`l`<#`Ey-& z#gEJ3r0skY;OU^Ql?Xvq^S9x~!!gaxg8lAl%NQh3ShhA))xduOKe zZ?TuJMTCah7fL_BPw^tG`O}LRHcJbx*@^~VQHsfCr3}`60+_mzhPuNav&CkQhuhWa zmnNSp!U=L!G0PPalw{NT%2mHeV2fwFi*w`2RoRVV#I?KA3rAvISnrB|NCp|8+$x|9 zvzNXTd7(WS!8^Rig+{G7Z=^bOV**XT$6~*|=dXh(GB=7`NXH(n6Zc@pLISu{{wLTc z;C)rm!b|30=zjBf(oGeV9nx_Y^!Gw^KoSy;XS?weMAT+6FEIQ||ejPhW-@k7_bfIn&&= zt*8A5@_cGA&vZOeZ}dS$KI&|4c>m+)CbFCokJ%kCLEjTi@YsDoIJEjF7$Bt7DnQlV z%#_{O!PV8l4xUtiTf$pN$^W*sJDAP5)A!CZhD#1K`@GRNd~Wn64M9seS8Jes>Sm`? zJ)$^H@7sqRF-QBGhwGzyI~>UqwfW;7bt{K%9#%&p+ha?~1M{`GdJ8NbhpY34j+#5| z15RTe*$p`DJ8lhix|8QLo-S<(>3Ruf8fb6@Jqw&Y-2M1vWzTH*Wzk;gRjF!%E8*f7 z>7uSW@+w;xvr*%6p~_JA8yZ)dwq`pu^?Z1%(iw#xEmRnjD)2SJqJDkB3Cq`E+wju8 zr6P4VMw~5Q1~&Wb#3#ZQel&VFw~`5388z;lE%`COr{Y_2#Cmkumx@8beP}gL+F)SH zlV^UIY>Oq}VbAteQ%vWb9mSUo6W%+sJG=G5`fURrT~{@_alFpRjWenWebVGH_LRGO zuL|=M6^~#=ngY4xGqG^naC#!`*)q?-uqG1m@)Fu6<7jh7oyS2;=iU?E-_;bRVc)Q$ zmLQ!JxVla>G2dBUz!UfVDi@nZRoR@7!I_EamdnXPieWnL?|M_U8ZTnF_a^N7w!Eml z!|QgNK;oMVtK2k#`TTuk6CC#7!O!V@0kX=@w~5~PKZ$$voEd+2S1b zSXw9*gDN<|U<&9dj*%EYsTK51#Wu&Ym9YK|U8L&AUGv zrI1z7vs7H_-74MlC^-}mc-7iYVtjQ*ehR&p=*6e_3I{8UrtV~=bA>uK%H8spU z@*>sL;<)2Nw<{Ls2)+0cWuK(qZ@sGBpGM5j{AAbGbY{C)({|{{qrV~TE$&|ngiBq^ zco=X?A@Rg}g2xKbp33C^gn0_NxBD;Bt`2ZrP;yIXf=tqoe@#*%>09Ch&CcLSN+Yc$ zEo8{N$HTaI#QHAAVU45NY{zHv(#=?>5qo!zF_+tZQ+AgOVraU#u&oft_s2>nd>g26 z+ndd)uKBLvI&?eTzSiKYb@5Viw`=FX`eu0}&<&0tMiDorRHS$8qt|6$U)8C0QQcj#2JX{GNO!Z$qd({z~a`#+=vQkE<9A zEWIfSkikUaB>t!xz0r;b3dNa!IciaqSZ6& zwK~jgb;~x-Eogpx=~rMC;9GnWiOSeQ(gFMdEq-o%G%PoDmL%C+KP9&;WcPKko@|*j z1>18@@r$Jw@v!FPQwp4I?4QPQ;oWdKtBnzbFIz|TjzX7jP-T71&{`$8`~6On1WOK% zP1HWaTsN0=uE`qRS}+lP;{rv0_(E2ssNIVyg@+_)VJfcCDt1%F5>b~UN=bv-{Ot_3 z)6#@`$5jWFLR;-K7vgd85vWJWWqv@k5V&;WZmAf3f@HqL+90*0@5OnyeR$d+rRob1eHPHxL z`JAw`P2rV_DU97qW0!c(x}erX3zLPgY?wuZf+&sZjm!pWCv%N(C|Q+05rGn0@P&tz z(>ByTEU4~!cRtr14Sh%*{Mek;c)1iMsBB1J>CtsxDN!l&CmK|)7>gJ5dL^8dzsld$ ziq5W1m&`af^T<(Dwsf2Jfo1wYbIEJJBHp$<#4hIU=WTRWjQv%Ud(P?g)Il?3SKfzKU zIX_2R_|mpOejaGY33%*1;v|pHY}E2@9Q3T3M`1F#E7+!d5y1s8Hx~-VO>BKqpF?8dLkTHA-*Qo+i+$LJ9@x!ecwH8 zY?}W|W(Il1*z@OSR*c&Vm+*w{Cf`q{AR1oDBBdCj743hl`BnbIoLd=#04YZ2hmvhR z22%DnDnB%s8q3G$tZ7uEdeMS?3T5-(B_GAgy;MUhNhWPm{ZYZBZne19nQW;xR2sy6 zqfYeuX7fHTf#@Sym1{>oPtt->V$&h{`6xiquupZ5Wsu;J+n=Cg$T^Iovzfb<1DtyP zzxy^8UNQU$YJ=nqoPpat4(!Hmz|O~>-ND=(p52e6a(^@-aIT$bIW;R3ZNgko9OU^b zhDF$tjbznTyDtvCr`YG0wzdY$UFs$l)W3XMsl+#* zoNl{spFF?h^_)oO-R{^Y*H@FXYsqdC>;}Wl>+R)Jug;asZ`SK%WejH2e9s}2RoqFO z?T+%MEL3*d6T5apnSh==iK6gPmkl?CZM)ofaM~bwu9!JCo>-p8lMDFRlKL-@93x4d zokt*;CNU;lw5?&D_-YU_9g-YaqlUe3)WMTBGR?xP%JUv$JmeG7OS&qJ?miT{4q7$> z34I;Yx|<)rQn7C#^x#JC=Uh_^iL8|>tdzS%tu+vr|KuvMuRDTOZRtP_F9C%ZrRdE&Z|Hey25-Kf%Z$E)~ohu4I#>@)%_E za6sI&_E0kXVJ;m8=jIEVkB@bzE>46G73}N^SEgf!Sfw$&4gU7=V3y$U)wpj1O{kZa zenZr3ZAqp1j}3Qn#ysAKCg@9BUa2w2V|brwhP&&Rci%3pxKm}>59|&*3e_ugQ)R_8 zn=n?%ge?uSNT0ne=i4e)ycrwzR9I<6m?bRE^=xpZ@srPngYlX4c}%Jd4$_9)Z2ovN zLo81{hlt(e$^BoFh7u#jA|$h>D#?aivkKYi35@QFtT%N7EL^AB=V>W0Y zSdGk9*YqJ{HH8o+?wK5II!tkJ>U|XX#2uia`|75HagEAhxW&Em?9`c;gw&+WYJwj> zCT!cr&q&&ebtD=mH}4@_0PawAvR6*tBfgnC?ldfgtyB8&6}OENVi)@|#dQC4!$&`* zWmnuC#ZHZQ0^Hdz(?=6u2q95))!Y1MzJP^hpBNUM1Jnyun&6b0{u2xo5=#GL8<@Xy zpn6LG?o>TtO4#hVE$Y`OK>xE-b!Illy|DgDVJmM1#k8d7H<91kEZCFWiEK_POCVsB zJQ(2wT2;p*(N(!^k^}=ayzG2*f5=h>wwA0>sef_|KjhJpk2sqiwFA`f3SIgEJb+_A z$4h)Bh=Enn^c!oy-IRzLUvbTNR{jr>pV_=_GFcXH`HJf{l{Sm{Qf&vuUus+?Vr4wK z$|SjpU8ox>7Z=CbjQ^2p^y8Yodg2E1lb=r-50on;>wqYT1<)((DCk%&8!qAe37Uk2 zx-LfUa2>Un#Wq2jHH8?o8e3qYpm!$B)ytM%*;Hr0DDhBwu>4s&O)Pb_`n16rzXs9O z)jgCcjfU~tGh!q9Q2BleDoGCtPzqdn@lbhr?}SkGi5+DZ}N?&Ih;7w4g>QP#LfGLwpl}sv}QS^|62#9_jrFnuc7|cQG?^ zHi4_8h+gbldn7u%wzX@mL3J0WtH<(6!m@@*N7DNXjq%Z^AKv+aB#q0TDzfXlA#u`7C0+N*I#$8)k{( z6Ioc9zs0sABeuCsnXFA-uWgq5+{5L^BLU)mo5XY?6!Ty!3mRmj#_N@rJIu@6Lp=iq zu5V}D9og=ir{hRv+{@25wti0SO8gCJxBaPo{>$k~wlURB`n82c>hF{*V`b_ErbQ|R zy10o8(KL5?*Ii0oT%Vqci-U?+Ml3e$ezZ<%+(dR`wrigBb9FVaayd2 zc{ai22z&?cnTxN@`F8`B-$h>8F1*6S?9{fqk7;D9DB#Gbr-y+Ull`19J#=>PITe+~ z9f6D=h0|kwZ{8-aCCM_83ntxZ2z9dE-F03S+&jFIC89H_IIv|g(6e#Toc$6_{tanX zN}|s|j&b;TVSW(}je*JVx7DFcj&^#BwOPl5DG%G-2>dQ?#(H^eGSs2?TS-?GnV7`X zrD!7co2x@G@+hi<>tr>92odE+QB>c-CKQvlFy?Jtkx=4Ca!$mG z^FkbI)$NyAQWLx4Y0`0~XI)H`lWUBea2C}4Z(K~>_f|Eq&yi~!Zl>pwA$8|z`XXw7mZ6G8 zQgv5ax~pJmGWmm5Q$Y-AIoDmZXY#M?!Vfl6cOJ4S+-?9|7q)6 zz`B`EEZcJIP93~9^C#FiB&Y6T2i*Jk$40Dw#~*evqL7OplBL`|ujEH%5=Y!Wc14jo zGP@5hqy#bWFMhEjMiC|ZzTd91Z}r+SXfILTa-Haridb&KH`Px=G?J`&M2`aE9|n%C z6iUvs#?qkEwV=gJKS<^AGg0P^ExXe&Ug6%rAmPA~P{!|CJ<8(X@L9H0=)Q$;$OZf} z@>XVR>@u-RiL*w-HF{S?r)JEvG~Q!jrVejWg;R7HBh{yPZ#OMHuQ;f9tGU78aLe`0 zruxp$^owof8}UlOSsemDumg`{DOvbM^JgjZpSoQBtxV_=Wp{l{SeX0H*3c`nc50%l zF0R|PMx}J7%S|$Ssc_ifmZE)-%yF_8!ua@d{@SP6@rXwW$|z`oG(r|cOsIkV;tu2P zQ)uUd-76{5y{$8MxkK^BRry7v*#@6hn+(&rVseDdS!IcKMHE?j^}56w-AB;xTGS2F z6O+8fain|E`}{q#i+f>y45MXn$X=2){hTYK_Z~;D@i{;?0%%JIEERzpM?eVE1P^-nJ~vCh-NxJE>5ZHr7A2pXHKQ zNGqM^wY#igK39;kot~{J}kpkT%4zkER!0&?0wS(ITsY0(YBCczsg?L%}fE! z#5>f>$yA@G`Q<~Bc`)CY`sDKks(U6fkY4^OX>&ddgc*wVm~EPpBt3Kd)=1_QDY_DnXeDIXgVs_jx|zod;4zOhGC3x{WbL`ax&oAEy?j zKYpJT<;Tp0x+8m*KS`lilX|@MaG*k(Xe6Nz`?W2LU)_>F0YkxKtmv0hdGvC~_O&vF zjJ$3bsBUMgibktHm6q2vyel^7-EO`!^x+C>sPS^PLliDVon!k(X3zi8mmXgh;grpv zpi9U;&K2k=2~RH6EJi*WxRexJYV0*6h{K8)h0gqdbfM$|d0+zK;A8oisa)6Q$bI_m zwcGb6CeP7d^*iw4SrF4~2)@UqtXipi^A>l76pC0z$TXHr)buiM?Xx!`@jGYc&8kPL zmM+)4{me!#P*pSelFyRHT|WfTh|@D6oZ=3GWatk$w?qQL;2z1M+wzG>tUQ$i5k*Kl zjM8~I(u0#(pRgDCq#l>6>#H7-p;JeXk7W1=QXGkeG`S2#m1Y3Qh5x(Hg|AV zC!DRP$C!I+hnZ)qeEX{xd7ac?uRN*D%bgYr(~R3`+-;UXMZ3Ps>~W;%+So7M_x7nG z<1BAJeO8!1^kwQZQQ#H%&(CiWynnJh;)b5tqN5;zah1_)=sq_t_C+GJB*)j`Hj=$a z7w#o}kLPFfzTq!8N6*`dFF`#*{n04oizB|>;!5l1pL)Z5b%QGx&>QB7dOPMzPa%sx zL4A-ntv@MS0mW8*?Ql8)OV2yOPk&@cqcH?0)zNzSCRyF-~}{i@=pDfgm&TcW#5=E zI;cCUdyqeVnfUGzC9t)2@R#b&3A`~%1yuJL_<R8O2&tFL zGaAD_22`X_rfpF`dkR#f7;-Jfw((obP+7R`@T??+X=KebnM6aTEguMGY<)^0!Axht zMLNa29J4F}PfWzXZ%E&F5zxF7?D6Al=?O&om8s%r1ombpM&~ zxbUP%eep(2d)>~Ifv-NzqPoC(l!u@2HDNuPEQ72yoUykJ*;x$+H0LHKUmdu+Z5_>cc4+4!4n4_TK$;n{GdpF{n}S8tNaqH!Y%`6 zkA=HEq5Do5*PV<8iaedxtq)&V&bdX)_8~r%ycF#hXChx{Lwa0U*BJtgD((ZIjDb14K;^?yjz++_bv7CP?{q63c@zWXI?1QW3wd{Jqe^MnT)b8&~<> zyt!DX@5W^RJxend_01jOr`%r%T#A^^)0YeMy=ajm_*_8|em+ZPk9<_wWI|6M0mXS^ zqNzDLt#~+3x-ZfrC@zu|v%D!ztSU^0=9vRIN#EVK3y~M8)cp1GvKfl0KRfcPWYQwP z6}K%~AjCw2uaLl;gH#^foB%B08agCivySlnzFgX< z47|uQq*wyd>AfEFD2Dw#Wy`|Zd-cKf^=lb(m}ehMN)rNw19@8(MhWXgul214-5eFK zL?#fC#ocVLulh% zp5ODjQRBW;Vqy1sve~y!JeD`i^v!p4hMsS{M)Tk$Qm4Li{dLw7A^nvPk2RMDZ+Zj> zZ^pRs$|jQ7F7>Qu4$3mSwY3lRa};&EsVPd4NL`~gNjYCw{k@wQgUV*$e8h6@L*`1F z7e;Je-KZu*=#=k-KC%;&jf@CH+eSAGcD?3%Fhv%LM)~Y+mD&wMCjH&$6~WY03x>Y3-U!YGA7jPLtg<-KE18$mQmtGx0`o9}b3e~_ zJWS>@kH|JweBFvV)1H{fJi|dSytS)i&$7KYr?r9RA=3T{H-YzEMfuD*leDYjSer^Q z`R+$Y4(vzG8(*3mAX}1K6$lRgkSra>NlWXoTr_+x?oV*Ykj*!jrGuz!@jI)IeSi#I2X_8S?Oxh2h2p`H8?8EPXkD(0)q zK5PzE$lkMj1bJMBUE~r2RXY3}b~of(mUj6n0v<@#+O?>4hSj3r5LQK`eZpgkttLC@ zwd`TFbhVoN;>&$uxbto2#kJ5L{ ztLRhe9p_bxFGb`G;u9xOO0eIn-|;PUX%9O;NE_klt7#3Pb>Rlmr*v)-NVd=_giGKQ&kc5xPz}IRxRFR+&1G# zBH}2Qc82*3I~?HAeG@qmV_?Od`PaRrFL%y_Iz7|W7+|cKpL@o>YR&I=+orF?ootLG zhtE?;*;n;}l%*G)o-OuOH6|7g+36?-c2SiQzfRhF$s&E0EK*@=@fQxg_}vwrXfQA` zcwTPVkV(4E>mYg!|CNu(L0I?Vg#!bTpSde8>kd>%->H-9jX@rfKn3mpESUeFDnvvg zLMB2$2Y$E973eA;>%Wf#8mFh>AOL?u27KCIzj6a0|1~mlG5KZM0~G-g;#rhr!Dw%B zZw9IZ{|=I$B?O_(0AoOjlR>48nU&0OosY=Lc5K=t>{l>h`5Km_J_ zI$RvjDP~C725EpKSe^pJ2nZ%d_ON<2om!p}Bp{xrht_)^W&Hx6Y5`CMPpks~+Qibx z`PX;);b01$SlEDXftpySMvkdh(W?hYq5wA(!N{!uvWcaciH)&?C;QL;fsx~bgEI}t z3T7#easK^5Kzy3yzOq1bsv*^{+qTw};B-P@296d`b=Q zDI}nwjL$)Riktm^sS7#~wgT<1KjXKCSsvW5ume6}0Qdwv&@hB_KR?0U8Myy!3ail| z96F!`p-!GZPX4zB`1*j9;SNCi<$uu5r2jW|pEQ3}o_5Y|Na0H?9L)wm&p1P-8lakjd=VXx_6G2C7Nkre?!RgOcH{*1t?4|! zV0LSYbK8sOat z0Y8MYqu1}619*3mEpUwN>3}B-Ub#{OG)n-Q;2=s}5TNPo;BqQOLGPl#p-$IjFwfH> zL$^W)N6&#m08tnB-xVh~dQKMs(>xt6bcb#*$y?U}k}z6v!{KhhBnw5sBu|G6-GCZw znFeAAu$yqh!4hnl4&oq|r`?XirpY7$(EKj~9579ONifY*0z%B3M_k-Hs|3l+381T^ju)v8E8jZgxpGE}GRsc>! z@oWBq?rET*J3oPa!5RP!yTucXFNbCd_60jy$C$$Erv(EUy1xAlQo#`Z-7IWQ3p@12R47vJS=(XtAK;0s&5C-JgMCGsihiY52pGX;Lz2s!ApRQ!%w;}%89_i6}$wfJ09nHI%Mcf z3RwL(P6)6|TEoE;tbTN75Kow8qG13-mnjC*Yyg1mVbvpsfd<=3S6sj}PYDcNcNctQ zn(GRod2%UYIM{;ETbkXDvHdN4=rXKeTMckWIHANY9CX39YUK%{3%iml3}onHo#3qs zofkk9#-&aeV9+)I-l{BngK3@)7rJI4_=Mo$?Vlw7p&ln3bipSC;l9V|{@w`CwcWsb zEE&K5Ar7lRAsnp1do0SpU$H(VJam0Au;q>b@URPs!NC@6xiUe=*utt02Ll4Cs0%;HgI+ z4Uo68u>4=TY{3@;rhHmt=xQC{skZ_k!z{}IhhczqMjHp>d0JrTniJs7<1hexLU9Q= zh=Mndi1A>eu#0`bfQBv}01m}#0q7H}1i(Oqo^D_-F`Iad>@_*$O zz>zOo`Y$-28Xx+-FW8d50Qi5I#_8@XKpO_wl7D3Ug7N9Vp*pBoYQX^xGEjnpc&JaMC+H z7?v+Mfl&SLvb$hUajxhX+0%nV-|asGiU2 = { fontawesome: { styles: ['https://use.fontawesome.com/releases/v5.6.3/css/all.css'], }, - 'xlsx-style': { - scripts: ['https://cdn.jsdelivr.net/npm/xlsx-style@0.8.13/dist/xlsx.full.min.js'], + xlsx: { + scripts: ['https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js'], }, materialdesignicons: { styles: ['https://cdn.jsdelivr.net/npm/@mdi/font/css/materialdesignicons.css'], diff --git a/documentation/ag-grid-docs/src/components/icon/IconsPanel.tsx b/documentation/ag-grid-docs/src/components/icon/IconsPanel.tsx index 76de2dc1ed7..d483185043f 100644 --- a/documentation/ag-grid-docs/src/components/icon/IconsPanel.tsx +++ b/documentation/ag-grid-docs/src/components/icon/IconsPanel.tsx @@ -27,6 +27,7 @@ const ICONS = [ 'cross', 'csv', 'desc', + 'document', 'down', 'edit', 'excel', diff --git a/documentation/ag-grid-docs/src/content/api-documentation/grid-options/properties.json b/documentation/ag-grid-docs/src/content/api-documentation/grid-options/properties.json index 2dd460c7da7..82907331419 100644 --- a/documentation/ag-grid-docs/src/content/api-documentation/grid-options/properties.json +++ b/documentation/ag-grid-docs/src/content/api-documentation/grid-options/properties.json @@ -1018,6 +1018,12 @@ "name": "Overlay Component", "url": "./overlays/" } + }, + "processFileInput": { + "more": { + "name": "File Input Overlay", + "url": "./overlays-overview/#file-input-overlay" + } } }, "nav": { diff --git a/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/customising-columns/example.spec.ts b/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/customising-columns/example.spec.ts index ed79767b830..57b8aa2f0fb 100644 --- a/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/customising-columns/example.spec.ts +++ b/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/customising-columns/example.spec.ts @@ -1,11 +1,19 @@ -import { clickAllButtons, ensureGridReady, test, waitForGridContent } from '@utils/grid/test-utils'; +import { expect, test } from '@utils/grid/test-utils'; test.agExample(import.meta, () => { - test.eachFramework('Example', async ({ page }) => { - // PLACEHOLDER - MINIMAL TEST TO ENSURE GRID LOADS WITHOUT ERRORS - await ensureGridReady(page); - await waitForGridContent(page); - await clickAllButtons(page); - // END PLACEHOLDER + test.eachFramework('Example', async ({ agIdFor }) => { + // Auto-generated headers + await expect(agIdFor.headerCell('product')).toBeVisible(); + await expect(agIdFor.headerCell('region')).toBeVisible(); + await expect(agIdFor.headerCell('profit')).toBeVisible(); + await expect(agIdFor.headerCell('profitMargin')).toBeVisible(); + + // Profit columns display with £ currency formatting via currencyColumn type + await expect(agIdFor.cell('0', 'profit')).toContainText('£12,500'); + await expect(agIdFor.cell('0', 'profitMargin')).toContainText('£0.15'); + + // Non-profit columns display without formatting + await expect(agIdFor.cell('0', 'product')).toContainText('Widget A'); + await expect(agIdFor.cell('0', 'region')).toContainText('North'); }); }); diff --git a/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/file-drop-overlay/example.spec.ts b/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/file-drop-overlay/example.spec.ts new file mode 100644 index 00000000000..b9674ff7647 --- /dev/null +++ b/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/file-drop-overlay/example.spec.ts @@ -0,0 +1,35 @@ +import { ensureGridReady, expect, test } from '@utils/grid/test-utils'; + +test.agExample(import.meta, () => { + test.eachFramework('loads sample data via select', async ({ agIdFor, page }) => { + await ensureGridReady(page); + await page.locator('#sampleData').selectOption('small-row-data.json'); + + await expect(agIdFor.headerCell('make')).toBeVisible(); + await expect(agIdFor.headerCell('model')).toBeVisible(); + await expect(agIdFor.headerCell('price')).toBeVisible(); + + await expect(agIdFor.cell('0', 'make')).toContainText('Toyota'); + }); + + test.eachFramework('switches to different dataset', async ({ agIdFor, page }) => { + await ensureGridReady(page); + await page.locator('#sampleData').selectOption('small-row-data.json'); + await expect(agIdFor.headerCell('make')).toBeVisible(); + + await page.locator('#sampleData').selectOption('small-olympic-winners.json'); + await expect(agIdFor.headerCell('athlete')).toBeVisible({ timeout: 10000 }); + await expect(agIdFor.headerCell('sport')).toBeVisible(); + }); + + test.eachFramework('upload file toolbar button shows file input overlay', async ({ agIdFor, page }) => { + await ensureGridReady(page); + await page.locator('#sampleData').selectOption('small-row-data.json'); + await expect(agIdFor.headerCell('make')).toBeVisible(); + + await page.locator('.ag-toolbar-button-wrapper').getByText('Upload File').click(); + + await expect(page.locator('.ag-overlay-file-input-center')).toBeVisible(); + await expect(page.locator('.ag-file-input-drop-zone')).toBeVisible(); + }); +}); diff --git a/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/file-drop-overlay/exampleConfig.json b/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/file-drop-overlay/exampleConfig.json new file mode 100644 index 00000000000..ffbeed4eefa --- /dev/null +++ b/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/file-drop-overlay/exampleConfig.json @@ -0,0 +1,3 @@ +{ + "extras": ["xlsx"] +} diff --git a/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/file-drop-overlay/index.html b/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/file-drop-overlay/index.html new file mode 100644 index 00000000000..d94787a4b17 --- /dev/null +++ b/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/file-drop-overlay/index.html @@ -0,0 +1,16 @@ +
+
+ +
+
+
diff --git a/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/file-drop-overlay/main.ts b/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/file-drop-overlay/main.ts new file mode 100644 index 00000000000..6ecd58e4fac --- /dev/null +++ b/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/file-drop-overlay/main.ts @@ -0,0 +1,101 @@ +import type { GridApi, GridOptions, ProcessFileInputParams, ToolbarItemActionParams } from 'ag-grid-community'; +import { + AutoGenerateColumnsModule, + ClientSideRowModelModule, + ModuleRegistry, + NumberFilterModule, + TextFilterModule, + ValidationModule, + createGrid, +} from 'ag-grid-community'; +import { ToolbarModule } from 'ag-grid-enterprise'; + +declare let XLSX: any; + +ModuleRegistry.registerModules([ + ClientSideRowModelModule, + AutoGenerateColumnsModule, + TextFilterModule, + NumberFilterModule, + ToolbarModule, + ...(process.env.NODE_ENV !== 'production' ? [ValidationModule] : []), +]); + +let gridApi: GridApi; + +function parseWorkbook(workbook: any): Record[] { + const firstSheetName = workbook.SheetNames[0]; + const worksheet = workbook.Sheets[firstSheetName]; + return XLSX.utils.sheet_to_json(worksheet); +} + +function processFileInput(params: ProcessFileInputParams): void { + const file = params.files[0]; + if (!file) return; + + const reader = new FileReader(); + reader.onerror = () => { + params.fail('Failed to read file'); + }; + reader.onload = (e) => { + try { + const workbook = XLSX.read(new Uint8Array(e.target?.result as ArrayBuffer)); + params.success(parseWorkbook(workbook)); + } catch (error) { + console.error(error); + params.fail('Failed to parse file'); + } + }; + reader.readAsArrayBuffer(file); +} + +const gridOptions: GridOptions = { + autoGenerateColumnDefs: true, + processFileInput: processFileInput, + defaultColDef: { + minWidth: 80, + flex: 1, + }, + toolbar: { + items: [ + { + label: 'Upload File', + icon: 'document', + alignment: 'right', + action: (params: ToolbarItemActionParams) => { + const curr = params.api.getGridOption('activeOverlay'); + params.api.setGridOption( + 'activeOverlay', + curr === 'agFileInputOverlay' ? undefined : 'agFileInputOverlay' + ); + }, + }, + ], + }, +}; + +function onLoadSampleData(): void { + const select = document.getElementById('sampleData') as HTMLSelectElement; + const value = select.value; + if (!value) return; + + if (value.endsWith('.xlsx')) { + fetch(`https://www.ag-grid.com/example-assets/${value}`) + .then((response) => response.arrayBuffer()) + .then((data: ArrayBuffer) => { + const workbook = XLSX.read(new Uint8Array(data)); + gridApi.updateGridOptions({ activeOverlay: undefined, rowData: parseWorkbook(workbook) }); + }); + } else { + fetch(`https://www.ag-grid.com/example-assets/${value}`) + .then((response) => response.json()) + .then((rows) => { + gridApi.updateGridOptions({ activeOverlay: undefined, rowData: rows }); + }); + } +} + +document.addEventListener('DOMContentLoaded', () => { + const gridDiv = document.querySelector('#myGrid')!; + gridApi = createGrid(gridDiv, gridOptions); +}); diff --git a/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/file-drop-overlay/styles.css b/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/file-drop-overlay/styles.css new file mode 100644 index 00000000000..7a08451a02b --- /dev/null +++ b/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/file-drop-overlay/styles.css @@ -0,0 +1,19 @@ +.example-wrapper { + display: flex; + flex-direction: column; + height: 100%; +} + +#myGrid { + flex: 1 1 0px; + width: 100%; +} + +.example-header { + font-family: Verdana, Geneva, Tahoma, sans-serif; + font-size: 13px; + margin-bottom: 5px; + display: flex; + gap: 16px; + align-items: center; +} diff --git a/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/nested-objects/example.spec.ts b/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/nested-objects/example.spec.ts index ed79767b830..d9024ff55ae 100644 --- a/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/nested-objects/example.spec.ts +++ b/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/_examples/nested-objects/example.spec.ts @@ -1,11 +1,21 @@ -import { clickAllButtons, ensureGridReady, test, waitForGridContent } from '@utils/grid/test-utils'; +import { expect, test } from '@utils/grid/test-utils'; test.agExample(import.meta, () => { - test.eachFramework('Example', async ({ page }) => { - // PLACEHOLDER - MINIMAL TEST TO ENSURE GRID LOADS WITHOUT ERRORS - await ensureGridReady(page); - await waitForGridContent(page); - await clickAllButtons(page); - // END PLACEHOLDER + test.eachFramework('Example', async ({ agIdFor, page }) => { + // Column group headers for nested objects + await expect(page.locator('.ag-header-group-cell').filter({ hasText: 'Address' })).toBeVisible(); + await expect(page.locator('.ag-header-group-cell').filter({ hasText: 'Scores' })).toBeVisible(); + + // Leaf column headers + await expect(agIdFor.headerCell('name')).toBeVisible(); + await expect(agIdFor.headerCell('address.city')).toBeVisible(); + await expect(agIdFor.headerCell('address.country')).toBeVisible(); + await expect(agIdFor.headerCell('scores.maths')).toBeVisible(); + await expect(agIdFor.headerCell('scores.science')).toBeVisible(); + + // Cell data + await expect(agIdFor.cell('0', 'name')).toContainText('Alice'); + await expect(agIdFor.cell('0', 'address.city')).toContainText('London'); + await expect(agIdFor.cell('0', 'scores.maths')).toContainText('92'); }); }); diff --git a/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/index.mdoc b/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/index.mdoc index d310268d949..47eb7a7f56b 100644 --- a/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/index.mdoc +++ b/documentation/ag-grid-docs/src/content/docs/auto-generate-columns/index.mdoc @@ -143,3 +143,32 @@ const gridOptions = { The example below uses [Column Types](./column-definitions/#column-types) to apply a `currencyColumn` type to any column whose field contains `"profit"`: {% gridExampleRunner title="Customising Columns" name="customising-columns" exampleHeight=300 /%} + +## File Drop Overlay + +When `autoGenerateColumnDefs` is enabled and no `rowData` is present, a file drop overlay is shown automatically when `processFileInput` is provided. Files can be dragged onto the overlay or selected via a browse button. See [Overlays](./overlays-overview/) for more on grid overlays. + +Provide a `processFileInput` callback. The `params` object contains the selected `files` array along with `success` and `fail` callbacks. Call `success(rowData)` to load the parsed data into the grid, or `fail(message)` to display an error in the overlay using the `fileInputProcessingFailed` locale. + +```js +const gridOptions = { + autoGenerateColumnDefs: true, + processFileInput: (params) => { + const file = params.files[0]; + const reader = new FileReader(); + reader.onload = (e) => { + try { + const rowData = parseCsv(e.target.result); + params.success(rowData); + } catch { + params.fail('Failed to parse file'); + } + }; + reader.readAsText(file); + }, +}; +``` + +The example below auto-generates columns from various data sources. Files can be dragged onto the overlay, selected via the browse button, or loaded from the sample data dropdown. The toolbar **Upload File** button re-shows the overlay by setting `activeOverlay` to `'agFileInputOverlay'`. + +{% gridExampleRunner title="Auto-Generate Columns" name="file-drop-overlay" exampleHeight=500 /%} diff --git a/documentation/ag-grid-docs/src/content/docs/excel-import/_examples/excel-import/exampleConfig.json b/documentation/ag-grid-docs/src/content/docs/excel-import/_examples/excel-import/exampleConfig.json index f521b8bbf84..ffbeed4eefa 100644 --- a/documentation/ag-grid-docs/src/content/docs/excel-import/_examples/excel-import/exampleConfig.json +++ b/documentation/ag-grid-docs/src/content/docs/excel-import/_examples/excel-import/exampleConfig.json @@ -1,3 +1,3 @@ { - "extras": ["xlsx-style"] + "extras": ["xlsx"] } diff --git a/documentation/ag-grid-docs/src/content/docs/excel-import/_examples/excel-import/index.html b/documentation/ag-grid-docs/src/content/docs/excel-import/_examples/excel-import/index.html index ef1fce268cb..514751a14c0 100644 --- a/documentation/ag-grid-docs/src/content/docs/excel-import/_examples/excel-import/index.html +++ b/documentation/ag-grid-docs/src/content/docs/excel-import/_examples/excel-import/index.html @@ -1,4 +1,7 @@
- +
+ + +
diff --git a/documentation/ag-grid-docs/src/content/docs/excel-import/_examples/excel-import/main.ts b/documentation/ag-grid-docs/src/content/docs/excel-import/_examples/excel-import/main.ts index 7de9b8acebd..f687d7a910c 100644 --- a/documentation/ag-grid-docs/src/content/docs/excel-import/_examples/excel-import/main.ts +++ b/documentation/ag-grid-docs/src/content/docs/excel-import/_examples/excel-import/main.ts @@ -1,11 +1,18 @@ -import type { GridApi, GridOptions } from 'ag-grid-community'; -import { ClientSideRowModelModule, ModuleRegistry, ValidationModule, createGrid } from 'ag-grid-community'; +import type { GridApi, GridOptions, ProcessFileInputParams } from 'ag-grid-community'; +import { + AutoGenerateColumnsModule, + ClientSideRowModelModule, + ModuleRegistry, + ValidationModule, + createGrid, +} from 'ag-grid-community'; import { ColumnMenuModule, ContextMenuModule, ExcelExportModule } from 'ag-grid-enterprise'; declare let XLSX: any; ModuleRegistry.registerModules([ ClientSideRowModelModule, + AutoGenerateColumnsModule, ExcelExportModule, ColumnMenuModule, ContextMenuModule, @@ -15,99 +22,51 @@ ModuleRegistry.registerModules([ let gridApi: GridApi; const gridOptions: GridOptions = { - columnDefs: [ - { field: 'athlete', minWidth: 180 }, - { field: 'age' }, - { field: 'country', minWidth: 150 }, - { field: 'year' }, - { field: 'date', minWidth: 130 }, - { field: 'sport', minWidth: 100 }, - { field: 'gold' }, - { field: 'silver' }, - { field: 'bronze' }, - { field: 'total' }, - ], + autoGenerateColumnDefs: true, defaultColDef: { minWidth: 80, flex: 1, }, - rowData: [], + processFileInput: (params: ProcessFileInputParams) => { + const file = params.files[0]; + if (!file) return; + const reader = new FileReader(); + reader.onerror = () => params.fail('Failed to read file'); + reader.onload = (e) => { + try { + const workbook = XLSX.read(new Uint8Array(e.target?.result as ArrayBuffer)); + params.success(parseWorkbook(workbook)); + } catch { + params.fail('Failed to parse file'); + } + }; + reader.readAsArrayBuffer(file); + }, }; -// read the raw data and convert it to a XLSX workbook -function convertDataToWorkbook(dataRows: ArrayBuffer) { - /* convert data to binary string */ - const data = new Uint8Array(dataRows); - const arr = []; - - for (let i = 0; i !== data.length; ++i) { - arr[i] = String.fromCharCode(data[i]); - } - - const bstr = arr.join(''); - - return XLSX.read(bstr, { type: 'binary' }); -} - -// pull out the values we're after, converting it into an array of rowData - -function populateGrid(api: GridApi, workbook: any) { - // our data is in the first sheet +function parseWorkbook(workbook: any): Record[] { const firstSheetName = workbook.SheetNames[0]; const worksheet = workbook.Sheets[firstSheetName]; + return XLSX.utils.sheet_to_json(worksheet); +} - // we expect the following columns to be present - const columns: Record = { - A: 'athlete', - B: 'age', - C: 'country', - D: 'year', - E: 'date', - F: 'sport', - G: 'gold', - H: 'silver', - I: 'bronze', - J: 'total', - }; - - const rowData = []; - - // start at the 2nd row - the first row are the headers - let rowIndex = 2; - - // iterate over the worksheet pulling out the columns we're expecting - while (worksheet['A' + rowIndex]) { - var row: any = {}; - Object.keys(columns).forEach((column) => { - row[columns[column]] = worksheet[column + rowIndex].w; - }); - - rowData.push(row); - - rowIndex++; - } - - // finally, set the imported rowData into the grid - api.setGridOption('rowData', rowData); +function uploadFile() { + const curr = gridApi.getGridOption('activeOverlay'); + gridApi.setGridOption('activeOverlay', curr === 'agFileInputOverlay' ? undefined : 'agFileInputOverlay'); } function importExcel() { fetch('https://www.ag-grid.com/example-assets/olympic-data.xlsx') .then((response) => response.arrayBuffer()) .then((data: ArrayBuffer) => { - const workbook = convertDataToWorkbook(data); - populateGrid(gridApi, workbook); + const workbook = XLSX.read(new Uint8Array(data)); + gridApi.updateGridOptions({ rowData: parseWorkbook(workbook), activeOverlay: undefined }); }); } -// wait for the document to be loaded, otherwise -// AG Grid will not find the div in the document. document.addEventListener('DOMContentLoaded', function () { - // lookup the container we want the Grid to use const eGridDiv = document.querySelector('#myGrid')!; - - // create the grid passing in the div to use together with the columns & data we want to use gridApi = createGrid(eGridDiv, gridOptions); }); diff --git a/documentation/ag-grid-docs/src/content/docs/excel-import/index.mdoc b/documentation/ag-grid-docs/src/content/docs/excel-import/index.mdoc index 4939a4726f8..9d169b5b162 100644 --- a/documentation/ag-grid-docs/src/content/docs/excel-import/index.mdoc +++ b/documentation/ag-grid-docs/src/content/docs/excel-import/index.mdoc @@ -2,13 +2,11 @@ title: "Excel Import" --- -Below we illustrate how you might import an Excel spreadsheet into AG Grid using a third-party library - in this example we're using [xlsx-style](https://github.com/protobi/js-xlsx). +Below we illustrate how you might import an Excel spreadsheet into AG Grid using a third-party library - in this example we're using [xlsx](https://www.jsdelivr.com/package/npm/xlsx). -In this example we're providing a simple Excel file for importing but in your application you could allow uploading of Excel files by end users. +[Auto-Generate Columns](./auto-generate-columns/) is used so no column definitions need to be provided upfront — columns are created from the imported data. The `processFileInput` callback parses dropped Excel files using the same library. -The spreadsheet contains a few rows of simple data, which the example parses and sets as row data. - -The spreadsheet can be downloaded [here](https://www.ag-grid.com/example-assets/olympic-data.xlsx). +Click **Load Sample Excel** to fetch a sample spreadsheet, or drag your own `.xlsx` file onto the grid. Click **Upload File** to re-show the file input overlay. The spreadsheet can also be downloaded [here](https://www.ag-grid.com/example-assets/olympic-data.xlsx). ## Example Import diff --git a/documentation/ag-grid-docs/src/content/docs/overlays-overview/index.mdoc b/documentation/ag-grid-docs/src/content/docs/overlays-overview/index.mdoc index 505dd8fe044..94d2dbb2117 100644 --- a/documentation/ag-grid-docs/src/content/docs/overlays-overview/index.mdoc +++ b/documentation/ag-grid-docs/src/content/docs/overlays-overview/index.mdoc @@ -17,6 +17,7 @@ The grid provides the following overlays that will be shown automatically based - [No Rows](./overlays-provided/#no-rows) - shown when there are no rows to display - [No Matching Rows](./overlays-provided/#no-matching-rows) - shown when no rows match the current filter - [Exporting](./overlays-provided/#exporting) - shown when data is exporting to CSV / Excel +- [File Input](./overlays-provided/#file-input) - shown when `processFileInput` is provided and no row data is present For details about the provided overlays and how to customise them see: [Provided Overlays](./overlays-provided). diff --git a/documentation/ag-grid-docs/src/content/docs/overlays-provided/_examples/file-input-overlay/example.spec.ts b/documentation/ag-grid-docs/src/content/docs/overlays-provided/_examples/file-input-overlay/example.spec.ts new file mode 100644 index 00000000000..b50305e3bbb --- /dev/null +++ b/documentation/ag-grid-docs/src/content/docs/overlays-provided/_examples/file-input-overlay/example.spec.ts @@ -0,0 +1,10 @@ +import { expect } from '@playwright/test'; +import { ensureGridReady, test } from '@utils/grid/test-utils'; + +test.agExample(import.meta, () => { + test.eachFramework('shows file input overlay when no row data', async ({ page }) => { + await ensureGridReady(page); + await expect(page.locator('.ag-overlay-file-input-center')).toBeVisible(); + await expect(page.locator('.ag-file-input-drop-zone')).toBeVisible(); + }); +}); diff --git a/documentation/ag-grid-docs/src/content/docs/overlays-provided/_examples/file-input-overlay/exampleConfig.json b/documentation/ag-grid-docs/src/content/docs/overlays-provided/_examples/file-input-overlay/exampleConfig.json new file mode 100644 index 00000000000..ffbeed4eefa --- /dev/null +++ b/documentation/ag-grid-docs/src/content/docs/overlays-provided/_examples/file-input-overlay/exampleConfig.json @@ -0,0 +1,3 @@ +{ + "extras": ["xlsx"] +} diff --git a/documentation/ag-grid-docs/src/content/docs/overlays-provided/_examples/file-input-overlay/index.html b/documentation/ag-grid-docs/src/content/docs/overlays-provided/_examples/file-input-overlay/index.html new file mode 100644 index 00000000000..411a9161bbd --- /dev/null +++ b/documentation/ag-grid-docs/src/content/docs/overlays-provided/_examples/file-input-overlay/index.html @@ -0,0 +1 @@ +
diff --git a/documentation/ag-grid-docs/src/content/docs/overlays-provided/_examples/file-input-overlay/main.ts b/documentation/ag-grid-docs/src/content/docs/overlays-provided/_examples/file-input-overlay/main.ts new file mode 100644 index 00000000000..46ed4740fb5 --- /dev/null +++ b/documentation/ag-grid-docs/src/content/docs/overlays-provided/_examples/file-input-overlay/main.ts @@ -0,0 +1,53 @@ +import type { GridOptions, ProcessFileInputParams } from 'ag-grid-community'; +import { + AutoGenerateColumnsModule, + ClientSideRowModelModule, + ModuleRegistry, + ValidationModule, + createGrid, +} from 'ag-grid-community'; + +declare let XLSX: any; + +ModuleRegistry.registerModules([ + ClientSideRowModelModule, + AutoGenerateColumnsModule, + ...(process.env.NODE_ENV !== 'production' ? [ValidationModule] : []), +]); + +function parseWorkbook(workbook: any): Record[] { + const firstSheetName = workbook.SheetNames[0]; + const worksheet = workbook.Sheets[firstSheetName]; + return XLSX.utils.sheet_to_json(worksheet); +} + +function processFileInput(params: ProcessFileInputParams): void { + const file = params.files[0]; + if (!file) return; + + const reader = new FileReader(); + reader.onerror = () => params.fail('Failed to read file'); + reader.onload = (e) => { + try { + const workbook = XLSX.read(new Uint8Array(e.target?.result as ArrayBuffer)); + params.success(parseWorkbook(workbook)); + } catch { + params.fail('Failed to parse file'); + } + }; + reader.readAsArrayBuffer(file); +} + +const gridOptions: GridOptions = { + autoGenerateColumnDefs: true, + processFileInput, + defaultColDef: { + flex: 1, + minWidth: 100, + }, +}; + +document.addEventListener('DOMContentLoaded', () => { + const gridDiv = document.querySelector('#myGrid')!; + createGrid(gridDiv, gridOptions); +}); diff --git a/documentation/ag-grid-docs/src/content/docs/overlays-provided/_examples/file-input-overlay/styles.css b/documentation/ag-grid-docs/src/content/docs/overlays-provided/_examples/file-input-overlay/styles.css new file mode 100644 index 00000000000..97daf67ef66 --- /dev/null +++ b/documentation/ag-grid-docs/src/content/docs/overlays-provided/_examples/file-input-overlay/styles.css @@ -0,0 +1,4 @@ +#myGrid { + height: 100%; + width: 100%; +} diff --git a/documentation/ag-grid-docs/src/content/docs/overlays-provided/index.mdoc b/documentation/ag-grid-docs/src/content/docs/overlays-provided/index.mdoc index 7a3483218ed..ba347f0ee61 100644 --- a/documentation/ag-grid-docs/src/content/docs/overlays-provided/index.mdoc +++ b/documentation/ag-grid-docs/src/content/docs/overlays-provided/index.mdoc @@ -4,7 +4,7 @@ title: "Provided Overlays" The grid shows built-in overlays when data is loading or being exported and when there is no data or no rows match the current filter. -The following example demonstrates all the provided overlays. +The following example demonstrates most of the provided overlays. - Toggle the loading state to show/hide the loading overlay. - Note that the loading overlay takes precedence over the other provided overlays if they are shown at the same time. @@ -32,6 +32,34 @@ The no-matching-rows overlay is displayed when the grid has rows but none of the The exporting overlay is displayed when data is being exported from the grid to CSV or Excel. +## File Input + +When `processFileInput` is provided and `rowData` is not set, the grid shows a built-in file input overlay. Users can drag a file onto the overlay or click the browse button to select one. + +Provide a `processFileInput` callback. The `params` object contains the selected `files` array along with `success` and `fail` callbacks. Call `success(rowData)` to load the parsed data, or `fail(message)` to display an error in the overlay. + +```{% frameworkTransform=true %} +const gridOptions = { + processFileInput: ({ files, success, fail }) => { + const file = files[0]; + const reader = new FileReader(); + reader.onload = (e) => { + try { + const rowData = parseFile(e) + success(rowData); + } catch { + fail('Failed to parse file'); + } + }; + reader.readAsArrayBuffer(file); + }, +}; +``` + +The example below shows the file input overlay, using [Auto-Generate Columns](./auto-generate-columns) to create the column definitions from the loaded file. Drag a file onto the overlay or use the browse button to load it. + +{% gridExampleRunner title="File Input Overlay" name="file-input-overlay" exampleHeight=400 /%} + ## Customisation The provided overlays can be customised to change their content or completely replaced with custom components. The grid still manages the timing of when the overlays are displayed based on grid state. @@ -49,6 +77,7 @@ const gridOptions = { noRows: { overlayText: 'This grid has no data!' }, noMatchingRows: { overlayText: 'Current Filter Matches No Rows' }, exporting: { overlayText: 'Exporting your data...' }, + fileInput: { overlayText: 'Provide a file...' }, } }; ``` diff --git a/documentation/ag-grid-docs/src/content/module-mappings/modules.json b/documentation/ag-grid-docs/src/content/module-mappings/modules.json index 1879fc4d21e..f11788320df 100644 --- a/documentation/ag-grid-docs/src/content/module-mappings/modules.json +++ b/documentation/ag-grid-docs/src/content/module-mappings/modules.json @@ -28,6 +28,11 @@ "name": "Auto-Generate Columns", "path": "auto-generate-columns" }, + { + "moduleName": "FileInputOverlayModule", + "name": "File Input Overlay", + "path": "auto-generate-columns/#file-drop-overlay" + }, { "moduleName": "CalculatedColumnsModule", "name": "Calculated Columns", diff --git a/packages/ag-grid-angular/projects/ag-grid-angular/src/lib/ag-grid-angular.component.ts b/packages/ag-grid-angular/projects/ag-grid-angular/src/lib/ag-grid-angular.component.ts index 09ffe72b364..868a0fceba6 100644 --- a/packages/ag-grid-angular/projects/ag-grid-angular/src/lib/ag-grid-angular.component.ts +++ b/packages/ag-grid-angular/projects/ag-grid-angular/src/lib/ag-grid-angular.component.ts @@ -183,6 +183,7 @@ import type { ProcessCellForClipboard, ProcessCellFromClipboard, ProcessDataFromClipboard, + ProcessFileInputParams, ProcessGroupHeaderForClipboard, ProcessHeaderForClipboard, ProcessPivotResultColDef, @@ -1076,7 +1077,7 @@ export class AgGridAngular = ColDef = ColDef) => void) | undefined = undefined; /** Set whether pagination is enabled. * @default false * @agModule `PaginationModule` diff --git a/packages/ag-grid-community/src/autoGenerateColumns/autoGenerateColumnsModule.ts b/packages/ag-grid-community/src/autoGenerateColumns/autoGenerateColumnsModule.ts index b4342882766..0212bfa0394 100644 --- a/packages/ag-grid-community/src/autoGenerateColumns/autoGenerateColumnsModule.ts +++ b/packages/ag-grid-community/src/autoGenerateColumns/autoGenerateColumnsModule.ts @@ -1,4 +1,5 @@ import type { _ModuleWithoutApi } from '../interfaces/iModule'; +import { FileInputOverlayModule } from '../rendering/overlays/fileInputOverlayModule'; import { VERSION } from '../version'; import { AutoGenerateColumnsService } from './autoGenerateColumnsService'; @@ -10,4 +11,5 @@ export const AutoGenerateColumnsModule: _ModuleWithoutApi = { moduleName: 'AutoGenerateColumns', version: VERSION, beans: [AutoGenerateColumnsService], + dependsOn: [FileInputOverlayModule], }; diff --git a/packages/ag-grid-community/src/context/context.ts b/packages/ag-grid-community/src/context/context.ts index 5e480bf3a18..3ee1f0c7ed1 100644 --- a/packages/ag-grid-community/src/context/context.ts +++ b/packages/ag-grid-community/src/context/context.ts @@ -206,6 +206,7 @@ export type UserComponentName = | 'agExportingOverlay' | 'agNoRowsOverlay' | 'agNoMatchingRowsOverlay' + | 'agFileInputOverlay' | 'agTooltipComponent' | 'agReadOnlyFloatingFilter' | 'agTextColumnFilter' diff --git a/packages/ag-grid-community/src/entities/gridOptions.ts b/packages/ag-grid-community/src/entities/gridOptions.ts index a82df784cc9..b2cf824e13d 100644 --- a/packages/ag-grid-community/src/entities/gridOptions.ts +++ b/packages/ag-grid-community/src/entities/gridOptions.ts @@ -183,6 +183,7 @@ import type { import type { AgGridCommon } from '../interfaces/iCommon'; import type { IDatasource } from '../interfaces/iDatasource'; import type { ExcelExportParams, ExcelStyle } from '../interfaces/iExcelCreator'; +import type { ProcessFileInputParams } from '../interfaces/iFileProcessor'; import type { AlwaysPassFilter, FilterHandlers, QuickFilterMatcher, QuickFilterParser } from '../interfaces/iFilter'; import type { FindOptions } from '../interfaces/iFind'; import type { ILoadingCellRendererParams } from '../interfaces/iLoadingCellRenderer'; @@ -1048,7 +1049,7 @@ export interface GridOptions { suppressNoRowsOverlay?: boolean; /** - * List of provided overlay names to suppress. One of `loading`, `noRows`, `noMatchingRows`, `exporting`. + * List of provided overlay names to suppress. One of `loading`, `noRows`, `noMatchingRows`, `exporting`, `fileInput`. */ suppressOverlays?: OverlayType[]; @@ -1085,6 +1086,15 @@ export interface GridOptions { */ activeOverlayParams?: any; + // *** File Input *** // + /** + * Callback to handle files received via the file input overlay (drag-and-drop or file browser). + * When provided, the file input overlay is shown when there is no row data. + * Call `params.success(rowData)` to load parsed data into the grid, or `params.fail(message)` to show an error. + * @agModule `FileInputOverlayModule` + */ + processFileInput?: (params: ProcessFileInputParams) => void; + // *** Pagination *** // /** * Set whether pagination is enabled. diff --git a/packages/ag-grid-community/src/interfaces/iFileProcessor.ts b/packages/ag-grid-community/src/interfaces/iFileProcessor.ts new file mode 100644 index 00000000000..86aeb28aba4 --- /dev/null +++ b/packages/ag-grid-community/src/interfaces/iFileProcessor.ts @@ -0,0 +1,10 @@ +import type { AgGridCommon } from './iCommon'; + +export interface ProcessFileInputParams extends AgGridCommon { + /** The files received via drag-and-drop or file browser on the File Input Overlay. */ + files: File[]; + /** Call with parsed row data to load it into the grid. */ + success(rowData: TData[]): void; + /** Call to show the error state in the overlay. Optionally provide a custom `errorMessage` to be displayed in the File Input Overlay. */ + fail(errorMessage?: string): void; +} diff --git a/packages/ag-grid-community/src/interfaces/iModule.ts b/packages/ag-grid-community/src/interfaces/iModule.ts index 6fbe57972f3..b53210afe05 100644 --- a/packages/ag-grid-community/src/interfaces/iModule.ts +++ b/packages/ag-grid-community/src/interfaces/iModule.ts @@ -155,6 +155,7 @@ export type CommunityModuleName = | 'DragAndDrop' | 'EventApi' | 'ExternalFilter' + | 'FileInputOverlay' | 'GridState' | 'HighlightChanges' | 'InfiniteRowModel' @@ -244,6 +245,7 @@ export type AgModuleName = | 'DragAndDropModule' | 'EventApiModule' | 'ExternalFilterModule' + | 'FileInputOverlayModule' | 'GridStateModule' | 'RowGroupingEditModule' | 'HighlightChangesModule' diff --git a/packages/ag-grid-community/src/main.ts b/packages/ag-grid-community/src/main.ts index e8b76a1d06b..ec39e0e1c6f 100644 --- a/packages/ag-grid-community/src/main.ts +++ b/packages/ag-grid-community/src/main.ts @@ -461,8 +461,12 @@ export type { IToolPanelParams, } from './interfaces/iToolPanel'; +// File Processor +export type { ProcessFileInputParams } from './interfaces/iFileProcessor'; + // Overlays export type { IExportingOverlay, IExportingOverlayComp } from './rendering/overlays/exportingOverlayComponent'; +export type { IFileInputOverlay, IFileInputOverlayComp } from './rendering/overlays/fileInputOverlayComponent'; export type { ILoadingOverlay, ILoadingOverlayComp } from './rendering/overlays/loadingOverlayComponent'; export type { INoMatchingRowsOverlay, @@ -471,7 +475,9 @@ export type { export type { INoRowsOverlay, INoRowsOverlayComp } from './rendering/overlays/noRowsOverlayComponent'; export type { ExportingOverlayUserParams, + FileInputOverlayUserParams, IExportingOverlayParams, + IFileInputOverlayParams, ILoadingOverlayParams, INoMatchingRowsOverlayParams, INoRowsOverlayParams, @@ -992,6 +998,7 @@ export type { export { AlignedGridsModule } from './alignedGrids/alignedGridsModule'; export { AllCommunityModule } from './allCommunityModule'; export { AutoGenerateColumnsModule } from './autoGenerateColumns/autoGenerateColumnsModule'; +export { FileInputOverlayModule } from './rendering/overlays/fileInputOverlayModule'; export { forEachColDef } from './columns/columnUtils'; export { RowApiModule, ScrollApiModule } from './api/apiModule'; export { ClientSideRowModelApiModule, ClientSideRowModelModule } from './clientSideRowModel/clientSideRowModelModule'; diff --git a/packages/ag-grid-community/src/propertyKeys.ts b/packages/ag-grid-community/src/propertyKeys.ts index edb21fe1766..921f5a961cd 100644 --- a/packages/ag-grid-community/src/propertyKeys.ts +++ b/packages/ag-grid-community/src/propertyKeys.ts @@ -350,6 +350,7 @@ export const _FUNCTION_GRID_OPTIONS: (CallbackKeys | FunctionKeys)[] = [ 'doesExternalFilterPass', 'processPivotResultColDef', 'processPivotResultColGroupDef', + 'processFileInput', 'getBusinessKeyForNode', 'isRowSelectable', 'rowDragText', diff --git a/packages/ag-grid-community/src/rendering/overlays/fileInputOverlayComponent.ts b/packages/ag-grid-community/src/rendering/overlays/fileInputOverlayComponent.ts new file mode 100644 index 00000000000..6fb3d54a7da --- /dev/null +++ b/packages/ag-grid-community/src/rendering/overlays/fileInputOverlayComponent.ts @@ -0,0 +1,262 @@ +import { RefPlaceholder, _clearElement } from 'ag-stack'; + +import type { GridOptions } from '../../entities/gridOptions'; +import { _addGridCommonParams } from '../../gridOptionsUtils'; +import type { ProcessFileInputParams } from '../../interfaces/iFileProcessor'; +import type { ElementParams } from '../../utils/element'; +import { _createElement } from '../../utils/element'; +import { _createIconNoSpan } from '../../utils/icon'; +import { _warn } from '../../validation/logging'; +import type { + IFileInputOverlayParams, + IOverlay, + IOverlayComp, + IOverlayParams, + OverlayComponentUserParams, +} from './overlayComponent'; +import { OverlayComponent } from './overlayComponent'; + +export interface IFileInputOverlay extends IOverlay< + TData, + TContext, + IFileInputOverlayParams +> {} + +export interface IFileInputOverlayComp extends IOverlayComp< + TData, + TContext, + IFileInputOverlayParams +> {} + +type FileInputState = 'ready' | 'processing' | 'error'; + +const FileInputOverlayElement: ElementParams = { + tag: 'div', + cls: 'ag-overlay-file-input-center', + children: [ + { tag: 'div', ref: 'eErrorBanner', cls: 'ag-file-input-error-banner' }, + { tag: 'div', ref: 'eDropZone', cls: 'ag-file-input-drop-zone' }, + { tag: 'div', ref: 'eProcessingState', cls: 'ag-file-input-processing' }, + ], +}; + +export class FileInputOverlayComponent + extends OverlayComponent + implements IFileInputOverlayComp +{ + private readonly eErrorBanner: HTMLElement = RefPlaceholder; + private readonly eDropZone: HTMLElement = RefPlaceholder; + private readonly eProcessingState: HTMLElement = RefPlaceholder; + + private state: FileInputState = 'ready'; + private dragCounter: number = 0; + private processingToken: number = 0; + + public init(params: IFileInputOverlayParams & OverlayComponentUserParams): void { + this.setTemplate(FileInputOverlayElement); + this.buildDropZone(params); + this.showState('ready'); + this.setupDragListeners(); + if (!this.gos.get('processFileInput')) { + _warn(305); + this.showError('gridOptions.processFileInput is missing'); + } + } + + private buildDropZone(params: IFileInputOverlayParams & OverlayComponentUserParams): void { + const { beans } = this; + const localeTextFunc = this.getLocaleTextFunc(); + + const text = + params.fileInput?.overlayText ?? localeTextFunc('fileInputOverlay', 'Drag & Drop file to import data'); + + const icon = _createIconNoSpan('document', beans, null); + const textSpan = { tag: 'span', cls: 'ag-file-input-text', children: text } as const; + const eTextRow = _createElement({ + tag: 'div', + cls: 'ag-file-input-text-row', + children: icon ? [() => icon, textSpan] : [textSpan], + }); + + this.eDropZone.appendChild(eTextRow); + this.appendBrowseButton(this.eDropZone); + + beans.ariaAnnounce.announceValue(text, 'overlay'); + } + + private updateProcessingState(fileName: string): void { + const { beans } = this; + const localeTextFunc = this.getLocaleTextFunc(); + + _clearElement(this.eProcessingState); + + const eIcon = _createIconNoSpan('overlayLoading', beans, null); + if (eIcon) { + eIcon.classList.add('ag-loading-icon'); + this.eProcessingState.appendChild(eIcon); + } + + const text = localeTextFunc('fileInputProcessing', `Processing ${fileName}`, [fileName]); + const eText = _createElement({ + tag: 'span', + cls: 'ag-file-input-text', + children: text, + }); + this.eProcessingState.appendChild(eText); + + beans.ariaAnnounce.announceValue(text, 'overlay'); + } + + private showError(message: string): void { + this.eErrorBanner.textContent = message; + this.showState('error'); + this.beans.ariaAnnounce.announceValue(message, 'overlay'); + } + + private appendBrowseButton(parent: HTMLElement): void { + const localeTextFunc = this.getLocaleTextFunc(); + + const eFileInput = _createElement({ + tag: 'input', + cls: 'ag-file-input-input', + attrs: { type: 'file', style: 'display:none' }, + }); + this.addManagedElementListeners(eFileInput, { change: () => this.onFileInputChange(eFileInput) }); + parent.appendChild(eFileInput); + + const eButton = _createElement({ + tag: 'button', + cls: 'ag-file-input-browse', + attrs: { type: 'button' }, + children: localeTextFunc('fileInputOverlayBrowse', 'Browse files'), + }); + this.addManagedElementListeners(eButton, { click: () => eFileInput.click() }); + parent.appendChild(eButton); + } + + private showState(state: FileInputState): void { + this.state = state; + const eGui = this.getGui(); + _clearElement(eGui); + switch (state) { + case 'error': + eGui.appendChild(this.eErrorBanner); + eGui.appendChild(this.eDropZone); + break; + case 'processing': + eGui.appendChild(this.eProcessingState); + break; + default: + eGui.appendChild(this.eDropZone); + break; + } + } + + private setupDragListeners(): void { + const eGui = this.getGui(); + + this.addManagedElementListeners(eGui, { + dragenter: (e: DragEvent) => { + if (!this.isFileDrag(e)) { + return; + } + e.preventDefault(); + this.dragCounter++; + if (this.dragCounter === 1) { + this.eDropZone.classList.add('ag-file-input-drop-zone-active'); + } + }, + dragover: (e: DragEvent) => { + if (!this.isFileDrag(e)) { + return; + } + e.preventDefault(); + if (e.dataTransfer) { + e.dataTransfer.dropEffect = 'copy'; + } + }, + dragleave: (e: DragEvent) => { + if (!this.isFileDrag(e)) { + return; + } + e.preventDefault(); + this.dragCounter--; + if (this.dragCounter <= 0) { + this.dragCounter = 0; + this.eDropZone.classList.remove('ag-file-input-drop-zone-active'); + } + }, + drop: (e: DragEvent) => { + if (!this.isFileDrag(e)) { + return; + } + e.preventDefault(); + this.dragCounter = 0; + this.eDropZone.classList.remove('ag-file-input-drop-zone-active'); + + this.handleFileList(e.dataTransfer?.files); + }, + }); + } + + private isFileDrag(e: DragEvent): boolean { + return e.dataTransfer?.types?.includes('Files') ?? false; + } + + private onFileInputChange(eFileInput: HTMLInputElement): void { + this.handleFileList(eFileInput.files); + eFileInput.value = ''; + } + + private handleFileList(files: FileList | null | undefined): void { + if (files && files.length > 0) { + this.handleFiles(Array.from(files)); + } + } + + private handleFiles(files: File[]): void { + if (this.state === 'processing') { + return; + } + + const { gos } = this; + const processFileInput = gos.get('processFileInput'); + + const fileName = files[0].name; + this.updateProcessingState(fileName); + this.showState('processing'); + + const token = ++this.processingToken; + + const success = (rowData: any[]) => { + if (!this.isAlive() || token !== this.processingToken) { + return; + } + const options: GridOptions = { rowData }; + if (gos.get('activeOverlay') === 'agFileInputOverlay') { + options.activeOverlay = undefined; + } + gos.updateGridOptions({ options, source: 'api' }); + }; + + const fail = (errorMessage?: string) => { + if (!this.isAlive() || token !== this.processingToken) { + return; + } + const localeTextFunc = this.getLocaleTextFunc(); + const message = + errorMessage ?? localeTextFunc('fileInputProcessingFailed', `Error processing ${fileName}`, [fileName]); + this.showError(message); + }; + + if (!processFileInput) { + fail(); + } else { + try { + processFileInput(_addGridCommonParams(gos, { files, success, fail })); + } catch (error) { + fail(error instanceof Error ? error.message : undefined); + } + } + } +} diff --git a/packages/ag-grid-community/src/rendering/overlays/fileInputOverlayModule.ts b/packages/ag-grid-community/src/rendering/overlays/fileInputOverlayModule.ts new file mode 100644 index 00000000000..705d6b58e3f --- /dev/null +++ b/packages/ag-grid-community/src/rendering/overlays/fileInputOverlayModule.ts @@ -0,0 +1,20 @@ +import type { _ModuleWithoutApi } from '../../interfaces/iModule'; +import { VERSION } from '../../version'; +import { FileInputOverlayComponent } from './fileInputOverlayComponent'; +import { OverlayModule } from './overlayModule'; + +/** + * @feature Accessories -> File Input Overlay + * @gridOption processFileInput + */ +export const FileInputOverlayModule: _ModuleWithoutApi = { + moduleName: 'FileInputOverlay', + version: VERSION, + userComponents: { + agFileInputOverlay: FileInputOverlayComponent, + }, + icons: { + document: 'document', + }, + dependsOn: [OverlayModule], +}; diff --git a/packages/ag-grid-community/src/rendering/overlays/overlayComponent.ts b/packages/ag-grid-community/src/rendering/overlays/overlayComponent.ts index 7c5aa6f0e5e..10be5e6cdbd 100644 --- a/packages/ag-grid-community/src/rendering/overlays/overlayComponent.ts +++ b/packages/ag-grid-community/src/rendering/overlays/overlayComponent.ts @@ -3,7 +3,7 @@ import type { IComponent } from 'ag-stack'; import type { AgGridCommon } from '../../interfaces/iCommon'; import { Component } from '../../widgets/component'; -export type OverlayType = 'loading' | 'noRows' | 'noMatchingRows' | 'exporting'; +export type OverlayType = 'loading' | 'noRows' | 'noMatchingRows' | 'exporting' | 'fileInput'; interface ProvidedOverlayUserParams { /** @@ -16,6 +16,7 @@ export interface LoadingOverlayUserParams extends ProvidedOverlayUserParams {} export interface ExportingOverlayUserParams extends ProvidedOverlayUserParams {} export interface NoRowsOverlayUserParams extends ProvidedOverlayUserParams {} export interface NoMatchingRowsOverlayUserParams extends ProvidedOverlayUserParams {} +export interface FileInputOverlayUserParams extends ProvidedOverlayUserParams {} export interface ILoadingOverlayParams extends AgGridCommon { /** @@ -43,6 +44,13 @@ export interface INoMatchingRowsOverlayParams exten overlayType: 'noMatchingRows'; } +export interface IFileInputOverlayParams extends AgGridCommon { + /** + * The default overlay the grid would show in the given state. + */ + overlayType: 'fileInput'; +} + /** * Parameters available to configure the provided overlays. */ @@ -55,13 +63,16 @@ export interface OverlayComponentUserParams { noMatchingRows?: NoMatchingRowsOverlayUserParams; /** Parameters to customise the provided exporting overlay. */ exporting?: ExportingOverlayUserParams; + /** Parameters to customise the provided file drop overlay. */ + fileInput?: FileInputOverlayUserParams; } export type IOverlayParams = | ILoadingOverlayParams | IExportingOverlayParams | INoRowsOverlayParams - | INoMatchingRowsOverlayParams; + | INoMatchingRowsOverlayParams + | IFileInputOverlayParams; export interface IOverlay< TData = any, diff --git a/packages/ag-grid-community/src/rendering/overlays/overlayService.ts b/packages/ag-grid-community/src/rendering/overlays/overlayService.ts index c5db94ebc50..bdc528af970 100644 --- a/packages/ag-grid-community/src/rendering/overlays/overlayService.ts +++ b/packages/ag-grid-community/src/rendering/overlays/overlayService.ts @@ -21,6 +21,7 @@ type OverlayCompType = | 'agNoRowsOverlay' | 'agNoMatchingRowsOverlay' | 'agExportingOverlay' + | 'agFileInputOverlay' | 'activeOverlay'; type OverlayDef = Readonly<{ @@ -74,6 +75,14 @@ const ExportingOverlayDef: OverlayDef = { exclusive: true, }; +const FileInputOverlayDef: OverlayDef = { + id: 'agFileInputOverlay', + overlayType: 'fileInput', + comp: overlayCompType('fileInputOverlayComponent'), + wrapperCls: 'ag-overlay-file-input-wrapper', + exclusive: true, +}; + const CustomOverlayDef: Readonly = { id: 'activeOverlay', comp: overlayCompType('activeOverlay'), @@ -92,6 +101,7 @@ const getActiveOverlayDef = (activeOverlay: any): OverlayDef | null => { agNoRowsOverlay: NoRowsOverlayDef, agNoMatchingRowsOverlay: NoMatchingRowsOverlayDef, agExportingOverlay: ExportingOverlayDef, + agFileInputOverlay: FileInputOverlayDef, } as Record )[activeOverlay] ?? CustomOverlayDef ); @@ -106,6 +116,7 @@ const getOverlayDefForType = (overlayType: OverlayType | null): OverlayDef | nul noRows: NoRowsOverlayDef, noMatchingRows: NoMatchingRowsOverlayDef, exporting: ExportingOverlayDef, + fileInput: FileInputOverlayDef, } as Record )[overlayType]; }; @@ -157,6 +168,8 @@ export class OverlayService extends BeanStub implements NamedBean { 'overlayComponentParams', 'loadingOverlayComponentParams', 'noRowsOverlayComponentParams', + 'autoGenerateColumnDefs', + 'processFileInput', ], (params) => this.onPropChange(new Set(params.changeSet?.properties)) ); @@ -388,9 +401,15 @@ export class OverlayService extends BeanStub implements NamedBean { return LoadingOverlayDef; } } else if (this.showInitialOverlay) { - if (!this.isDisabled(LoadingOverlayDef) && (!gos.get('columnDefs') || !gos.get('rowData'))) { - // if no columns or no row data, we show the initial loading overlay - return LoadingOverlayDef; + const noColumnDefs = !gos.get('columnDefs') && !gos.get('autoGenerateColumnDefs'); + const noRowData = !gos.get('rowData'); + if (noColumnDefs || noRowData) { + if (noRowData && gos.get('processFileInput') && !this.isDisabled(FileInputOverlayDef)) { + return FileInputOverlayDef; + } + if (!this.isDisabled(LoadingOverlayDef)) { + return LoadingOverlayDef; + } } this.disableInitialOverlay(); } else { diff --git a/packages/ag-grid-community/src/rendering/overlays/overlayWrapperComponent.css b/packages/ag-grid-community/src/rendering/overlays/overlayWrapperComponent.css index 52274309c67..2ef8c0b4a70 100644 --- a/packages/ag-grid-community/src/rendering/overlays/overlayWrapperComponent.css +++ b/packages/ag-grid-community/src/rendering/overlays/overlayWrapperComponent.css @@ -25,7 +25,8 @@ .ag-overlay-loading-wrapper, .ag-overlay-exporting-wrapper, -.ag-overlay-modal-wrapper { +.ag-overlay-modal-wrapper, +.ag-overlay-file-input-wrapper { /* prevent interaction with grid while it's loading */ pointer-events: all; } @@ -39,3 +40,69 @@ padding: var(--ag-spacing); display: flex; } + +.ag-overlay-file-input-center { + background: var(--ag-background-color); + border: solid var(--ag-border-width) var(--ag-border-color); + border-radius: var(--ag-border-radius); + box-shadow: var(--ag-popup-shadow); + display: flex; + flex-direction: column; + align-items: center; + gap: calc(var(--ag-spacing) * 2); + max-width: 420px; + padding: calc(var(--ag-spacing) * 2); +} + +.ag-file-input-error-banner { + background: color-mix(in srgb, var(--ag-invalid-color) 10%, var(--ag-background-color)); + color: var(--ag-invalid-color); + border-radius: var(--ag-border-radius); + padding: calc(var(--ag-spacing) * 0.75) calc(var(--ag-spacing) * 2); + width: 100%; + text-align: center; + font-size: 0.9em; +} + +.ag-file-input-drop-zone { + border: dashed calc(var(--ag-border-width) * 2) var(--ag-border-color); + border-radius: var(--ag-border-radius); + padding: calc(var(--ag-spacing) * 4); + display: flex; + flex-direction: column; + align-items: center; + gap: var(--ag-spacing); + width: 100%; +} + +.ag-file-input-drop-zone-active { + border-color: var(--ag-accent-color); + background: var(--ag-row-hover-color); +} + +.ag-file-input-processing { + display: flex; + align-items: center; + gap: calc(var(--ag-spacing) * 0.75); + padding: calc(var(--ag-spacing) * 4); +} + +.ag-file-input-text-row { + display: flex; + align-items: center; + gap: calc(var(--ag-spacing) * 0.75); +} + +.ag-file-input-text { + font-weight: 600; +} + +.ag-file-input-browse { + cursor: pointer; + border: solid var(--ag-border-width) var(--ag-border-color); + background: transparent; + color: var(--ag-text-color); + border-radius: var(--ag-border-radius); + padding: calc(var(--ag-spacing) * 0.5) calc(var(--ag-spacing) * 2); + font: inherit; +} diff --git a/packages/ag-grid-community/src/theming/parts/icon-set/alpine/alpine-svg-icons/document.svg b/packages/ag-grid-community/src/theming/parts/icon-set/alpine/alpine-svg-icons/document.svg new file mode 100644 index 00000000000..c53b44bda30 --- /dev/null +++ b/packages/ag-grid-community/src/theming/parts/icon-set/alpine/alpine-svg-icons/document.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/ag-grid-community/src/theming/parts/icon-set/alpine/icon-set-alpine.css b/packages/ag-grid-community/src/theming/parts/icon-set/alpine/icon-set-alpine.css index 841fe8c758d..666a70b21cd 100644 --- a/packages/ag-grid-community/src/theming/parts/icon-set/alpine/icon-set-alpine.css +++ b/packages/ag-grid-community/src/theming/parts/icon-set/alpine/icon-set-alpine.css @@ -62,6 +62,10 @@ mask-image: url('./alpine-svg-icons/adesc.svg'); } +.ag-icon-document::before { + mask-image: url('./alpine-svg-icons/document.svg'); +} + .ag-icon-down::before { mask-image: url('./alpine-svg-icons/down.svg'); } diff --git a/packages/ag-grid-community/src/theming/parts/icon-set/balham/balham-svg-icons/document.svg b/packages/ag-grid-community/src/theming/parts/icon-set/balham/balham-svg-icons/document.svg new file mode 100644 index 00000000000..3f84039bd05 --- /dev/null +++ b/packages/ag-grid-community/src/theming/parts/icon-set/balham/balham-svg-icons/document.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/ag-grid-community/src/theming/parts/icon-set/balham/icon-set-balham.css b/packages/ag-grid-community/src/theming/parts/icon-set/balham/icon-set-balham.css index b91cbb24528..1a117570924 100644 --- a/packages/ag-grid-community/src/theming/parts/icon-set/balham/icon-set-balham.css +++ b/packages/ag-grid-community/src/theming/parts/icon-set/balham/icon-set-balham.css @@ -61,6 +61,10 @@ mask-image: url('./balham-svg-icons/adesc.svg'); } +.ag-icon-document::before { + mask-image: url('./balham-svg-icons/document.svg'); +} + .ag-icon-down::before { mask-image: url('./balham-svg-icons/down.svg'); } diff --git a/packages/ag-grid-community/src/theming/parts/icon-set/material/icon-set-material.css b/packages/ag-grid-community/src/theming/parts/icon-set/material/icon-set-material.css index f2ad8de25a8..0c09742c8fd 100644 --- a/packages/ag-grid-community/src/theming/parts/icon-set/material/icon-set-material.css +++ b/packages/ag-grid-community/src/theming/parts/icon-set/material/icon-set-material.css @@ -62,6 +62,10 @@ mask-image: url('./material-svg-icons/adesc.svg'); } +.ag-icon-document::before { + mask-image: url('./material-svg-icons/document.svg'); +} + .ag-icon-down::before { mask-image: url('./material-svg-icons/down.svg'); } diff --git a/packages/ag-grid-community/src/theming/parts/icon-set/material/material-svg-icons/document.svg b/packages/ag-grid-community/src/theming/parts/icon-set/material/material-svg-icons/document.svg new file mode 100644 index 00000000000..99db7860a04 --- /dev/null +++ b/packages/ag-grid-community/src/theming/parts/icon-set/material/material-svg-icons/document.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/ag-grid-community/src/theming/parts/icon-set/quartz/quartz-icon-data.ts b/packages/ag-grid-community/src/theming/parts/icon-set/quartz/quartz-icon-data.ts index 996e149d7fa..30dee74ff98 100644 --- a/packages/ag-grid-community/src/theming/parts/icon-set/quartz/quartz-icon-data.ts +++ b/packages/ag-grid-community/src/theming/parts/icon-set/quartz/quartz-icon-data.ts @@ -75,6 +75,8 @@ const iconNameToFullSvg: Record = { '', 'column-arrow': '', + document: + '', edit: '', 'filter-add': '', diff --git a/packages/ag-grid-community/src/utils/icon.ts b/packages/ag-grid-community/src/utils/icon.ts index 2f7feab7694..18b0d56a7bd 100644 --- a/packages/ag-grid-community/src/utils/icon.ts +++ b/packages/ag-grid-community/src/utils/icon.ts @@ -125,7 +125,8 @@ export type IconName = | 'checkboxUnchecked' // deprecated v33 | 'radioButtonOn' // deprecated v33 | 'radioButtonOff' // deprecated v33 - | 'search'; + | 'search' + | 'document'; export type Icons = { [key: string]: ((...args: any[]) => any) | string }; diff --git a/packages/ag-grid-community/src/validation/errorMessages/errorText.ts b/packages/ag-grid-community/src/validation/errorMessages/errorText.ts index e4fbf5fd9a0..68aa6dcd95f 100644 --- a/packages/ag-grid-community/src/validation/errorMessages/errorText.ts +++ b/packages/ag-grid-community/src/validation/errorMessages/errorText.ts @@ -802,6 +802,8 @@ export const AG_GRID_ERRORS = { `Multiple toolbar items share the explicit key '${key}'. Only the first item is rendered.` as const, 304: ({ dataType }: { dataType: string }) => `Invalid calculatedColumns.dataTypes entry "${dataType}" - it must be a built-in data type or registered via dataTypeDefinitions. It has been ignored.` as const, + 305: () => + `The file input overlay is shown but no 'processFileInput' is configured. The overlay will not work without a 'processFileInput'.` as const, }; export type ErrorMap = typeof AG_GRID_ERRORS; diff --git a/packages/ag-grid-community/src/validation/rules/gridOptionsValidations.ts b/packages/ag-grid-community/src/validation/rules/gridOptionsValidations.ts index 79a6efa8036..2b5c0994d43 100644 --- a/packages/ag-grid-community/src/validation/rules/gridOptionsValidations.ts +++ b/packages/ag-grid-community/src/validation/rules/gridOptionsValidations.ts @@ -107,6 +107,7 @@ function toConstrainedNum(key: keyof GridOptions, value: any, min: number): stri export const GRID_OPTIONS_MODULES: Partial>> = { autoGenerateColumnDefs: 'AutoGenerateColumns', + processFileInput: 'FileInputOverlay', alignedGrids: 'AlignedGrids', allowContextMenuWithControlKey: 'ContextMenu', autoSizeStrategy: 'ColumnAutoSize', diff --git a/packages/ag-grid-community/src/validation/rules/iconValidations.ts b/packages/ag-grid-community/src/validation/rules/iconValidations.ts index 4c1ce7a2dca..146e438b74d 100644 --- a/packages/ag-grid-community/src/validation/rules/iconValidations.ts +++ b/packages/ag-grid-community/src/validation/rules/iconValidations.ts @@ -44,6 +44,7 @@ export const ICON_VALUES: Record = { save: 1, csv: 1, excel: 1, + document: 1, 'small-down': 1, 'small-left': 1, 'small-right': 1, @@ -192,6 +193,7 @@ export const ICON_MODULES: Record = new Set([ diff --git a/packages/ag-grid-community/src/validation/rules/userCompValidations.ts b/packages/ag-grid-community/src/validation/rules/userCompValidations.ts index 6fc9153ead5..6f7c1ee9243 100644 --- a/packages/ag-grid-community/src/validation/rules/userCompValidations.ts +++ b/packages/ag-grid-community/src/validation/rules/userCompValidations.ts @@ -27,6 +27,7 @@ export const USER_COMP_MODULES: Record agExportingOverlay: 'Overlay', agNoRowsOverlay: 'Overlay', agNoMatchingRowsOverlay: 'Overlay', + agFileInputOverlay: 'FileInputOverlay', agTooltipComponent: 'Tooltip', agReadOnlyFloatingFilter: 'CustomFilter', agTextColumnFilter: 'TextFilter', diff --git a/packages/ag-grid-vue3/src/components/utils.ts b/packages/ag-grid-vue3/src/components/utils.ts index 7b9575ee096..3f8adc684fa 100644 --- a/packages/ag-grid-vue3/src/components/utils.ts +++ b/packages/ag-grid-vue3/src/components/utils.ts @@ -88,6 +88,7 @@ import type { ProcessCellForClipboard, ProcessCellFromClipboard, ProcessDataFromClipboard, + ProcessFileInputParams, ProcessGroupHeaderForClipboard, ProcessHeaderForClipboard, ProcessPivotResultColDef, @@ -901,7 +902,7 @@ export interface Props { * @initial */ suppressNoRowsOverlay?: boolean, - /** List of provided overlay names to suppress. One of `loading`, `noRows`, `noMatchingRows`, `exporting`. + /** List of provided overlay names to suppress. One of `loading`, `noRows`, `noMatchingRows`, `exporting`, `fileInput`. */ suppressOverlays?: OverlayType[], /** Provide a custom overlay component to be used for all grid provided overlays (loading, no rows, no matching rows, exporting etc). @@ -927,6 +928,12 @@ export interface Props { /** Custom parameters to be supplied to the `activeOverlay` component in addition to `IOverlayParams`. Updating the params will trigger a refresh of the active overlay. */ activeOverlayParams?: any, + /** Callback to handle files received via the file input overlay (drag-and-drop or file browser). + * When provided, the file input overlay is shown when there is no row data. + * Call `params.success(rowData)` to load parsed data into the grid, or `params.fail(message)` to show an error. + * @agModule `FileInputOverlayModule` + */ + processFileInput?: (params: ProcessFileInputParams) => void, /** Set whether pagination is enabled. * @default false * @agModule `PaginationModule` @@ -2249,6 +2256,7 @@ export function getProps() { overlayComponentSelector: undefined, activeOverlay: undefined, activeOverlayParams: undefined, + processFileInput: undefined, pagination: undefined, paginationPageSize: undefined, paginationPageSizeSelector: undefined, diff --git a/packages/ag-stack/src/interfaces/iIcon.ts b/packages/ag-stack/src/interfaces/iIcon.ts index 1e00c077c89..48f17393264 100644 --- a/packages/ag-stack/src/interfaces/iIcon.ts +++ b/packages/ag-stack/src/interfaces/iIcon.ts @@ -40,6 +40,7 @@ export type IconValue = | 'save' | 'csv' | 'excel' + | 'document' | 'small-down' | 'small-left' | 'small-right' diff --git a/plugins/ag-grid-generate-example-files/src/executors/generate/generator/transformation-scripts/grid-vanilla-to-angular.ts b/plugins/ag-grid-generate-example-files/src/executors/generate/generator/transformation-scripts/grid-vanilla-to-angular.ts index 8c5e39ee769..5df6d210507 100644 --- a/plugins/ag-grid-generate-example-files/src/executors/generate/generator/transformation-scripts/grid-vanilla-to-angular.ts +++ b/plugins/ag-grid-generate-example-files/src/executors/generate/generator/transformation-scripts/grid-vanilla-to-angular.ts @@ -189,7 +189,9 @@ export function vanillaToAngular( propertyAttributes.push('[rowData]="rowData"'); } - if (!propertyAssignments.find((item) => item.indexOf('rowData') >= 0)) { + if ( + !propertyAssignments.find((item) => item.replace(/setGridOption\('rowData'/g, '').indexOf('rowData') >= 0) + ) { propertyAssignments.push(`rowData!: ${rowDataType}[];`); } diff --git a/plugins/ag-grid-generate-example-files/src/executors/generate/generator/transformation-scripts/grid-vanilla-to-vue3.ts b/plugins/ag-grid-generate-example-files/src/executors/generate/generator/transformation-scripts/grid-vanilla-to-vue3.ts index b1214f21efb..44bce7bc7d9 100644 --- a/plugins/ag-grid-generate-example-files/src/executors/generate/generator/transformation-scripts/grid-vanilla-to-vue3.ts +++ b/plugins/ag-grid-generate-example-files/src/executors/generate/generator/transformation-scripts/grid-vanilla-to-vue3.ts @@ -117,7 +117,7 @@ function getPropertyBindings( propertyNames.push('rowData'); } - if (!propertyAssignments.find((item) => item.indexOf('rowData') >= 0)) { + if (!propertyAssignments.find((item) => item.replace(/setGridOption\('rowData'/g, '').indexOf('rowData') >= 0)) { propertyAssignments.push(`const rowData = ref<${rowDataType}[]>(null);`); } diff --git a/plugins/ag-grid-generate-example-files/src/executors/generate/generator/transformation-scripts/parser-utils.ts b/plugins/ag-grid-generate-example-files/src/executors/generate/generator/transformation-scripts/parser-utils.ts index 11c77417620..71d7ec605b0 100644 --- a/plugins/ag-grid-generate-example-files/src/executors/generate/generator/transformation-scripts/parser-utils.ts +++ b/plugins/ag-grid-generate-example-files/src/executors/generate/generator/transformation-scripts/parser-utils.ts @@ -409,6 +409,8 @@ export function findAllAccessedProperties(node) { // Do nothing for Class declarations as this is likely a cell renderer setup } else if (ts.isTypeReferenceNode(node)) { // Do nothing for Type references + } else if (ts.isStringLiteral(node) || ts.isNumericLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) { + // Do nothing for literals — they are values, not property accesses } else if (node instanceof Array) { node.forEach((element) => { properties = [...properties, ...findAllAccessedProperties(element)]; diff --git a/testing/behavioural/src/overlays/overlays-file-input.test.ts b/testing/behavioural/src/overlays/overlays-file-input.test.ts new file mode 100644 index 00000000000..082501f50d8 --- /dev/null +++ b/testing/behavioural/src/overlays/overlays-file-input.test.ts @@ -0,0 +1,601 @@ +import type { MockInstance } from 'vitest'; + +import type { ProcessFileInputParams } from 'ag-grid-community'; +import { AutoGenerateColumnsModule, ClientSideRowModelModule } from 'ag-grid-community'; + +import { GridRows, TestGridsManager, initPointerEventPolyfill, isAgHtmlElementVisible } from '../test-utils'; + +describe('ag-grid file input overlay', () => { + const gridsManager = new TestGridsManager({ + modules: [ClientSideRowModelModule, AutoGenerateColumnsModule], + }); + let consoleWarnSpy: MockInstance; + + function hasFileInputOverlay() { + return isAgHtmlElementVisible(document.querySelector('.ag-overlay-file-input-center')); + } + + function hasFileInputOverlayWrapper() { + return isAgHtmlElementVisible('.ag-overlay-file-input-wrapper'); + } + + function hasLoadingOverlay() { + return isAgHtmlElementVisible(document.querySelector('.ag-overlay-loading-center')); + } + + function hasLoadingOverlayWrapper() { + return isAgHtmlElementVisible('.ag-overlay-loading-wrapper'); + } + + function hasNoRowsOverlay() { + return isAgHtmlElementVisible(document.querySelector('.ag-overlay-no-rows-center')); + } + + function hasNoRowsOverlayWrapper() { + return isAgHtmlElementVisible('.ag-overlay-no-rows-wrapper'); + } + + function hasDropZone() { + return isAgHtmlElementVisible(document.querySelector('.ag-file-input-drop-zone')); + } + + function hasProcessingState() { + return isAgHtmlElementVisible(document.querySelector('.ag-file-input-processing')); + } + + function hasErrorBanner() { + return isAgHtmlElementVisible(document.querySelector('.ag-file-input-error-banner')); + } + + function getErrorBannerText(): string { + return document.querySelector('.ag-file-input-error-banner')?.textContent ?? ''; + } + + function getProcessingText(): string { + return document.querySelector('.ag-file-input-processing .ag-file-input-text')?.textContent ?? ''; + } + + function getDropZoneText(): string { + return document.querySelector('.ag-file-input-drop-zone .ag-file-input-text')?.textContent ?? ''; + } + + function hasBrowseButton() { + return !!document.querySelector('.ag-file-input-browse'); + } + + function hasActiveDropZone() { + return document.querySelector('.ag-file-input-drop-zone')?.classList.contains('ag-file-input-drop-zone-active'); + } + + function makeProcessFileInput( + handler?: (params: ProcessFileInputParams) => void + ): (params: ProcessFileInputParams) => void { + return handler ?? (() => {}); + } + + function createFileDragEvent(type: string, files?: File[]): DragEvent { + const dt = new DataTransfer(); + dt.types.push('Files'); + if (files) { + for (const file of files) { + dt.items.add(file); + (dt.files as unknown as File[]).push(file); + } + } + return new DragEvent(type, { dataTransfer: dt, bubbles: true, cancelable: true }); + } + + function createNonFileDragEvent(type: string): DragEvent { + const dt = new DataTransfer(); + dt.setData('text/plain', 'some text'); + return new DragEvent(type, { dataTransfer: dt, bubbles: true, cancelable: true }); + } + + function getOverlayGui(): HTMLElement { + const wrapper = document.querySelector('.ag-overlay-file-input-wrapper'); + const center = wrapper?.querySelector('.ag-overlay-file-input-center'); + return center as HTMLElement; + } + + beforeEach(() => { + initPointerEventPolyfill(); + consoleWarnSpy = vitest.spyOn(console, 'warn').mockImplementation(() => {}); + gridsManager.reset(); + }); + + afterEach(() => { + gridsManager.reset(); + consoleWarnSpy.mockRestore(); + expect(hasFileInputOverlayWrapper()).toBeFalsy(); + expect(hasLoadingOverlayWrapper()).toBeFalsy(); + expect(hasNoRowsOverlayWrapper()).toBeFalsy(); + }); + + describe('visibility', () => { + test('shows file input overlay with explicit columnDefs, null rowData, and processFileInput', () => { + gridsManager.createGrid('myGrid', { + columnDefs: [{ field: 'a' }], + rowData: null as any, + processFileInput: makeProcessFileInput(), + }); + expect(hasFileInputOverlay()).toBeTruthy(); + expect(hasLoadingOverlay()).toBeFalsy(); + }); + + test('shows no-rows overlay when processFileInput set with empty rowData', () => { + gridsManager.createGrid('myGrid', { + columnDefs: [{ field: 'a' }], + rowData: [], + processFileInput: makeProcessFileInput(), + }); + expect(hasNoRowsOverlay()).toBeTruthy(); + expect(hasFileInputOverlay()).toBeFalsy(); + }); + + test('shows no-rows overlay when processFileInput set and rowData cleared to empty', () => { + const api = gridsManager.createGrid('myGrid', { + columnDefs: [{ field: 'a' }], + rowData: [{ a: 1 }], + processFileInput: makeProcessFileInput(), + }); + expect(hasFileInputOverlay()).toBeFalsy(); + + api.setGridOption('rowData', []); + expect(hasNoRowsOverlay()).toBeTruthy(); + expect(hasFileInputOverlay()).toBeFalsy(); + }); + + test('shows file input overlay when processFileInput set with undefined rowData and autoGenerateColumnDefs', () => { + gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + processFileInput: makeProcessFileInput(), + }); + expect(hasFileInputOverlay()).toBeTruthy(); + expect(hasLoadingOverlay()).toBeFalsy(); + }); + + test('does not show file input overlay when autoGenerateColumnDefs with rowData provided', () => { + gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + rowData: [{ a: 1 }], + processFileInput: makeProcessFileInput(), + }); + expect(hasFileInputOverlay()).toBeFalsy(); + expect(hasLoadingOverlay()).toBeFalsy(); + expect(hasNoRowsOverlay()).toBeFalsy(); + }); + + test('shows no-rows overlay when autoGenerateColumnDefs with empty rowData and processFileInput', () => { + gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + rowData: [], + processFileInput: makeProcessFileInput(), + }); + expect(hasNoRowsOverlay()).toBeTruthy(); + expect(hasFileInputOverlay()).toBeFalsy(); + expect(hasLoadingOverlay()).toBeFalsy(); + }); + + test('shows loading overlay when autoGenerateColumnDefs without processFileInput', () => { + gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + }); + expect(hasLoadingOverlay()).toBeTruthy(); + expect(hasFileInputOverlay()).toBeFalsy(); + }); + + test('shows loading overlay without processFileInput when rowData undefined', () => { + gridsManager.createGrid('myGrid', { + columnDefs: [{ field: 'a' }], + }); + expect(hasLoadingOverlay()).toBeTruthy(); + expect(hasFileInputOverlay()).toBeFalsy(); + }); + + test('does not show file input overlay when rowData has rows', () => { + gridsManager.createGrid('myGrid', { + columnDefs: [{ field: 'a' }], + rowData: [{ a: 1 }], + processFileInput: makeProcessFileInput(), + }); + expect(hasFileInputOverlay()).toBeFalsy(); + expect(hasLoadingOverlay()).toBeFalsy(); + expect(hasNoRowsOverlay()).toBeFalsy(); + }); + + test('hides file input overlay when rowData is set with rows', async () => { + const api = gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + processFileInput: makeProcessFileInput(), + }); + expect(hasFileInputOverlay()).toBeTruthy(); + + api.setGridOption('rowData', [{ a: 1 }]); + expect(hasFileInputOverlay()).toBeFalsy(); + + await new GridRows(api, 'after rowData set').check(` + ROOT id:ROOT_NODE_ID + └── LEAF id:0 a:1 + `); + }); + + test('shows file input overlay on demand via activeOverlay over existing data', () => { + const api = gridsManager.createGrid('myGrid', { + columnDefs: [{ field: 'a' }], + rowData: [{ a: 1 }], + processFileInput: makeProcessFileInput(), + }); + expect(hasFileInputOverlay()).toBeFalsy(); + + api.setGridOption('activeOverlay', 'agFileInputOverlay'); + expect(hasFileInputOverlay()).toBeTruthy(); + }); + + test('shows file input overlay via activeOverlay without autoGenerateColumnDefs', () => { + gridsManager.createGrid('myGrid', { + columnDefs: [{ field: 'a' }], + rowData: [{ a: 1 }], + processFileInput: makeProcessFileInput(), + activeOverlay: 'agFileInputOverlay', + }); + expect(hasFileInputOverlay()).toBeTruthy(); + expect(hasFileInputOverlayWrapper()).toBeTruthy(); + expect(hasLoadingOverlay()).toBeFalsy(); + expect(hasNoRowsOverlay()).toBeFalsy(); + }); + + test('activeOverlay shows file input even without processFileInput', () => { + gridsManager.createGrid('myGrid', { + columnDefs: [{ field: 'a' }], + rowData: [{ a: 1 }], + activeOverlay: 'agFileInputOverlay', + }); + expect(hasFileInputOverlay()).toBeTruthy(); + expect(hasErrorBanner()).toBeTruthy(); + expect(getErrorBannerText()).toBe('gridOptions.processFileInput is missing'); + }); + + test('shows no-rows overlay with explicit columnDefs and empty rowData even with processFileInput', () => { + gridsManager.createGrid('myGrid', { + columnDefs: [{ field: 'a' }], + rowData: [], + processFileInput: makeProcessFileInput(), + }); + expect(hasNoRowsOverlay()).toBeTruthy(); + expect(hasFileInputOverlay()).toBeFalsy(); + }); + + test('loading=true takes precedence over processFileInput', () => { + gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + processFileInput: makeProcessFileInput(), + loading: true, + }); + expect(hasLoadingOverlay()).toBeTruthy(); + expect(hasFileInputOverlay()).toBeFalsy(); + }); + }); + + describe('drop zone content', () => { + test('shows default overlay text', () => { + gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + processFileInput: makeProcessFileInput(), + }); + expect(getDropZoneText()).toBe('Drag & Drop file to import data'); + }); + + test('shows custom overlay text from overlayComponentParams', () => { + gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + processFileInput: makeProcessFileInput(), + overlayComponentParams: { + fileInput: { overlayText: 'Drop CSV here' }, + }, + }); + expect(getDropZoneText()).toBe('Drop CSV here'); + }); + + test('shows browse button', () => { + gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + processFileInput: makeProcessFileInput(), + }); + expect(hasBrowseButton()).toBeTruthy(); + }); + }); + + describe('error state', () => { + test('shows error when processFileInput is missing', () => { + gridsManager.createGrid('myGrid', { + columnDefs: [{ field: 'a' }], + rowData: [], + processFileInput: undefined, + }); + + // Without processFileInput, the overlay is not shown via the service + expect(hasFileInputOverlay()).toBeFalsy(); + }); + + test('shows error banner when processFileInput calls fail', () => { + let capturedParams: ProcessFileInputParams | undefined; + gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + processFileInput: makeProcessFileInput((params) => { + capturedParams = params; + }), + }); + expect(hasFileInputOverlay()).toBeTruthy(); + + const file = new File(['data'], 'test.csv', { type: 'text/csv' }); + const eGui = getOverlayGui(); + eGui.dispatchEvent(createFileDragEvent('drop', [file])); + + expect(capturedParams).toBeDefined(); + capturedParams!.fail('Custom error message'); + + expect(hasErrorBanner()).toBeTruthy(); + expect(getErrorBannerText()).toBe('Custom error message'); + expect(hasDropZone()).toBeTruthy(); + expect(hasProcessingState()).toBeFalsy(); + }); + + test('shows default error message when fail called without argument', () => { + let capturedParams: ProcessFileInputParams | undefined; + gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + processFileInput: makeProcessFileInput((params) => { + capturedParams = params; + }), + }); + + const file = new File(['data'], 'report.xlsx', { type: 'application/vnd.ms-excel' }); + const eGui = getOverlayGui(); + eGui.dispatchEvent(createFileDragEvent('drop', [file])); + + capturedParams!.fail(); + + expect(hasErrorBanner()).toBeTruthy(); + expect(getErrorBannerText()).toBe('Error processing report.xlsx'); + }); + + test('shows error when processFileInput throws synchronously', () => { + gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + processFileInput: makeProcessFileInput(() => { + throw new Error('sync error'); + }), + }); + + const file = new File(['data'], 'bad.csv', { type: 'text/csv' }); + const eGui = getOverlayGui(); + eGui.dispatchEvent(createFileDragEvent('drop', [file])); + + expect(hasErrorBanner()).toBeTruthy(); + expect(hasDropZone()).toBeTruthy(); + expect(hasProcessingState()).toBeFalsy(); + }); + }); + + describe('processing state', () => { + test('shows processing state when file is dropped', () => { + gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + processFileInput: makeProcessFileInput(), + }); + + const file = new File(['data'], 'test.csv', { type: 'text/csv' }); + const eGui = getOverlayGui(); + eGui.dispatchEvent(createFileDragEvent('drop', [file])); + + expect(hasProcessingState()).toBeTruthy(); + expect(hasDropZone()).toBeFalsy(); + expect(getProcessingText()).toBe('Processing test.csv'); + }); + + test('ignores additional drops while processing', () => { + let callCount = 0; + gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + processFileInput: makeProcessFileInput(() => { + callCount++; + }), + }); + + const eGui = getOverlayGui(); + eGui.dispatchEvent(createFileDragEvent('drop', [new File(['a'], 'first.csv')])); + eGui.dispatchEvent(createFileDragEvent('drop', [new File(['b'], 'second.csv')])); + + expect(callCount).toBe(1); + expect(getProcessingText()).toBe('Processing first.csv'); + }); + }); + + describe('successful file processing', () => { + test('updates grid rowData on success', async () => { + let capturedParams: ProcessFileInputParams | undefined; + const api = gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + processFileInput: makeProcessFileInput((params) => { + capturedParams = params; + }), + }); + + const file = new File(['data'], 'test.csv', { type: 'text/csv' }); + const eGui = getOverlayGui(); + eGui.dispatchEvent(createFileDragEvent('drop', [file])); + + expect(capturedParams).toBeDefined(); + expect(capturedParams!.files).toHaveLength(1); + expect(capturedParams!.files[0].name).toBe('test.csv'); + + capturedParams!.success([{ a: 10 }, { a: 20 }]); + + expect(hasFileInputOverlay()).toBeFalsy(); + await new GridRows(api, 'after success').check(` + ROOT id:ROOT_NODE_ID + ├── LEAF id:0 a:10 + └── LEAF id:1 a:20 + `); + }); + + test('clears activeOverlay when file input overlay success is called via activeOverlay', async () => { + let capturedParams: ProcessFileInputParams | undefined; + const api = gridsManager.createGrid('myGrid', { + columnDefs: [{ field: 'a' }], + rowData: [{ a: 1 }], + processFileInput: makeProcessFileInput((params) => { + capturedParams = params; + }), + }); + expect(hasFileInputOverlay()).toBeFalsy(); + + api.setGridOption('activeOverlay', 'agFileInputOverlay'); + expect(hasFileInputOverlay()).toBeTruthy(); + + const file = new File(['data'], 'test.csv', { type: 'text/csv' }); + const eGui = getOverlayGui(); + eGui.dispatchEvent(createFileDragEvent('drop', [file])); + + capturedParams!.success([{ a: 10 }, { a: 20 }]); + + expect(hasFileInputOverlay()).toBeFalsy(); + expect(api.getGridOption('activeOverlay')).toBeUndefined(); + await new GridRows(api, 'after success via activeOverlay').check(` + ROOT id:ROOT_NODE_ID + ├── LEAF id:0 a:10 + └── LEAF id:1 a:20 + `); + }); + + test('shows no-rows overlay when success is called with empty array', () => { + let capturedParams: ProcessFileInputParams | undefined; + gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + processFileInput: makeProcessFileInput((params) => { + capturedParams = params; + }), + }); + + const file = new File([''], 'empty.csv', { type: 'text/csv' }); + const eGui = getOverlayGui(); + eGui.dispatchEvent(createFileDragEvent('drop', [file])); + + capturedParams!.success([]); + + expect(hasNoRowsOverlay()).toBeTruthy(); + expect(hasFileInputOverlay()).toBeFalsy(); + }); + }); + + describe('drag and drop interactions', () => { + test('adds active class on dragenter with file', () => { + gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + processFileInput: makeProcessFileInput(), + }); + + const eGui = getOverlayGui(); + eGui.dispatchEvent(createFileDragEvent('dragenter')); + + expect(hasActiveDropZone()).toBeTruthy(); + }); + + test('removes active class on dragleave', () => { + gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + processFileInput: makeProcessFileInput(), + }); + + const eGui = getOverlayGui(); + eGui.dispatchEvent(createFileDragEvent('dragenter')); + expect(hasActiveDropZone()).toBeTruthy(); + + eGui.dispatchEvent(createFileDragEvent('dragleave')); + expect(hasActiveDropZone()).toBeFalsy(); + }); + + test('handles nested dragenter/dragleave via counter', () => { + gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + processFileInput: makeProcessFileInput(), + }); + + const eGui = getOverlayGui(); + + // Enter outer, then enter inner child + eGui.dispatchEvent(createFileDragEvent('dragenter')); + eGui.dispatchEvent(createFileDragEvent('dragenter')); + expect(hasActiveDropZone()).toBeTruthy(); + + // Leave inner child — should stay active + eGui.dispatchEvent(createFileDragEvent('dragleave')); + expect(hasActiveDropZone()).toBeTruthy(); + + // Leave outer — now inactive + eGui.dispatchEvent(createFileDragEvent('dragleave')); + expect(hasActiveDropZone()).toBeFalsy(); + }); + + test('resets drag state on drop', () => { + gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + processFileInput: makeProcessFileInput(), + }); + + const eGui = getOverlayGui(); + eGui.dispatchEvent(createFileDragEvent('dragenter')); + expect(hasActiveDropZone()).toBeTruthy(); + + const file = new File(['data'], 'test.csv', { type: 'text/csv' }); + eGui.dispatchEvent(createFileDragEvent('drop', [file])); + expect(hasActiveDropZone()).toBeFalsy(); + }); + + test('ignores non-file drag events', () => { + gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + processFileInput: makeProcessFileInput(), + }); + + const eGui = getOverlayGui(); + eGui.dispatchEvent(createNonFileDragEvent('dragenter')); + + expect(hasActiveDropZone()).toBeFalsy(); + }); + + test('does not process drop without files', () => { + let called = false; + gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + processFileInput: makeProcessFileInput(() => { + called = true; + }), + }); + + const eGui = getOverlayGui(); + eGui.dispatchEvent(createFileDragEvent('drop')); + + expect(called).toBeFalsy(); + expect(hasDropZone()).toBeTruthy(); + }); + }); + + describe('file input (browse button)', () => { + test('browse button and hidden file input are rendered', () => { + gridsManager.createGrid('myGrid', { + autoGenerateColumnDefs: true, + processFileInput: makeProcessFileInput(), + }); + + const eFileInput = document.querySelector('.ag-file-input-input'); + expect(eFileInput).toBeTruthy(); + expect(eFileInput!.type).toBe('file'); + expect(eFileInput!.style.display).toBe('none'); + + const eBrowse = document.querySelector('.ag-file-input-browse'); + expect(eBrowse).toBeTruthy(); + expect(eBrowse!.textContent).toBe('Browse files'); + }); + }); +}); diff --git a/testing/shared/moduleDefinitions.ts b/testing/shared/moduleDefinitions.ts index b79ab4a06cb..237cf635de3 100644 --- a/testing/shared/moduleDefinitions.ts +++ b/testing/shared/moduleDefinitions.ts @@ -5,7 +5,7 @@ import type { } from '../../packages/ag-grid-community/src/interfaces/iModule'; // Use satisfies for type safety (catches typos) while allowing extra modules not in release types -export const AllGridCommunityModules: Record<`${CommunityModuleName}Module` | 'BigIntFilterModule', number> = { +export const AllGridCommunityModules: Record<`${CommunityModuleName}Module` | 'FileInputOverlayModule', number> = { AlignedGridsModule: 6.88, AllCommunityModule: 511.54, AutoGenerateColumnsModule: 5, @@ -51,6 +51,7 @@ export const AllGridCommunityModules: Record<`${CommunityModuleName}Module` | 'B UndoRedoEditModule: 74.12, ValidationModule: 74.37, ValueCacheModule: 0.65, + FileInputOverlayModule: 5, }; export const AllEnterpriseModules: Record<`${EnterpriseModuleName}Module`, number> = { AdvancedFilterModule: 223.75,