diff --git a/documentation/ag-grid-docs/src/components/reference-documentation/components/Property.tsx b/documentation/ag-grid-docs/src/components/reference-documentation/components/Property.tsx
index 5506a30c008..eb49034bd53 100644
--- a/documentation/ag-grid-docs/src/components/reference-documentation/components/Property.tsx
+++ b/documentation/ag-grid-docs/src/components/reference-documentation/components/Property.tsx
@@ -260,9 +260,13 @@ export const Property: FunctionComponent<{
return (
-
+
-
+
diff --git a/documentation/ag-grid-docs/src/components/reference-documentation/components/Section.tsx b/documentation/ag-grid-docs/src/components/reference-documentation/components/Section.tsx
index 310b2eb6fa3..497219c23e6 100644
--- a/documentation/ag-grid-docs/src/components/reference-documentation/components/Section.tsx
+++ b/documentation/ag-grid-docs/src/components/reference-documentation/components/Section.tsx
@@ -198,6 +198,7 @@ export const Section: FunctionComponent = ({
/>
)}
diff --git a/documentation/ag-grid-docs/src/components/reference-documentation/types.d.ts b/documentation/ag-grid-docs/src/components/reference-documentation/types.d.ts
index ddbf4bbc8ba..6ac3ce36511 100644
--- a/documentation/ag-grid-docs/src/components/reference-documentation/types.d.ts
+++ b/documentation/ag-grid-docs/src/components/reference-documentation/types.d.ts
@@ -14,8 +14,6 @@ interface MetaTag {
};
type?: string;
isEvent?: boolean;
- /** Suppress the missing property check. Needed for events as they are dynamic and so do not appear in src code */
- suppressMissingPropCheck?: true;
}
export type DocEntryMap = Record;
type DocEntry = {
@@ -173,9 +171,6 @@ export interface Config {
headerLevel?: number;
/** Set the margin-bottom value to override the default of 3em */
overrideBottomMargin?: string;
- /** Suppress the missing property check. Needed for events as they are dynamic and so do not appear in src code */
- suppressMissingPropCheck?: true;
-
/** A regular expression limiting the names that should appear */
namePattern: string;
diff --git a/documentation/ag-grid-docs/src/components/reference-documentation/utils/getPropertiesFromSource.ts b/documentation/ag-grid-docs/src/components/reference-documentation/utils/getPropertiesFromSource.ts
index b2c62d21cd5..73aa0708b8f 100644
--- a/documentation/ag-grid-docs/src/components/reference-documentation/utils/getPropertiesFromSource.ts
+++ b/documentation/ag-grid-docs/src/components/reference-documentation/utils/getPropertiesFromSource.ts
@@ -14,7 +14,7 @@ export const getPropertiesFromSource = async ({
sources: string[];
}) => {
const sources = source ? [source] : sourcesProp;
- const propertiesFromFilesPromises = sources.map(async (s: string) => {
+ const fileEntryPromises = sources.map(async (s: string) => {
// NOTE: Need to remove `.json` for getEntry
const fileName = s.replace('.json', '');
const fileEntry = await getEntry('apiDocumentation', fileName);
@@ -26,35 +26,45 @@ export const getPropertiesFromSource = async ({
} else {
throw new Error(message);
}
- } else {
- return fileEntry.data;
}
+ return fileEntry;
});
- const propertiesFromFiles = (await Promise.all(propertiesFromFilesPromises)).filter(Boolean);
+ const fileEntries = await Promise.all(fileEntryPromises);
- const propertyConfigs = propertiesFromFiles
- .map((p) => {
- const config = p['_config_'];
- if (!config) {
- // eslint-disable-next-line no-console
- console.warn(`ApiDocumentation: _config_ property missing from source ${sources.join()}.`);
- }
- return config;
- })
- .filter(Boolean);
- const codeConfigEntries = propertyConfigs
- .map((config) => config.codeSrc)
- .map((fileName) => {
- const referenceFileName = `reference/${fileName}`;
- const file = getJsonFile(referenceFileName);
- return [fileName, file];
- });
- const codeConfigs = Object.fromEntries(codeConfigEntries);
+ const propertiesFromFiles: any[] = [];
+ const propertyConfigs: any[] = [];
+ const codeConfigs: Record = {};
+
+ for (let i = 0; i < sources.length; i++) {
+ const fileEntry = fileEntries[i];
+ if (!fileEntry) {
+ continue;
+ }
- // Validate that theming-api/properties.json keys match the theming-api.AUTO.json keys
- // Only run when actually processing the theming-api source
- if (sources.some((s) => s.includes('theming-api'))) {
- validateThemingApiProperties(propertiesFromFiles, codeConfigs);
+ const s = sources[i];
+ const propsFile = fileEntry.data;
+ propertiesFromFiles.push(propsFile);
+
+ const config = propsFile['_config_'];
+ if (!config) {
+ // eslint-disable-next-line no-console
+ console.warn(`ApiDocumentation: _config_ property missing from source ${s}.`);
+ continue;
+ }
+ propertyConfigs.push(config);
+
+ const codeSrc = config.codeSrc;
+ if (codeSrc && !(codeSrc in codeConfigs)) {
+ codeConfigs[codeSrc] = getJsonFile(`reference/${codeSrc}`);
+ }
+
+ if (config.validate) {
+ const codeConfig = codeConfigs[codeSrc];
+ if (!codeConfig) {
+ throw new Error(`${s} codeSrc file not found: ${codeSrc}`);
+ }
+ validateDocumentedProperties(propsFile, codeConfig, s);
+ }
}
return {
@@ -65,32 +75,54 @@ export const getPropertiesFromSource = async ({
};
};
-function validateThemingApiProperties(properties: any[], codeConfigs: any) {
- const codeSrc = 'theming-api.AUTO.json';
- const propsFile = properties.find((p) => p['_config_']?.codeSrc === codeSrc);
- if (!propsFile) {
- throw new Error(`No properties.json with codeSrc: "${codeSrc}"`);
- }
- const codeConfig = codeConfigs[codeSrc];
- if (!codeConfig) {
- throw new Error(`Theme params codeSrc file not found: ${codeSrc}`);
- }
- const codeKeys = new Set(Object.keys(codeConfig));
- const propsKeys = Object.entries(propsFile)
+function validateDocumentedProperties(propsFile: any, codeConfig: any, source: string) {
+ const config = propsFile['_config_'];
+ const codeSrc = config.codeSrc;
+ const undocumentedProperties = config.undocumentedProperties ?? {};
+
+ const keysToDocument = new Set(
+ Object.keys(codeConfig).filter((k) => {
+ if (k in undocumentedProperties) {
+ return false;
+ }
+ const entry = codeConfig[k];
+ if (entry?.meta?.tags?.some((t: any) => t.name === 'deprecated')) {
+ return false;
+ }
+ if (config.excludeEvents && entry?.meta?.isEvent) {
+ return false;
+ }
+ if (config.onlyEvents) {
+ if (!entry?.meta?.isEvent) {
+ return false;
+ }
+ // Events like onCellClicked are the grid option callback form;
+ // event docs use the unprefixed name (cellClicked)
+ if (/^on[A-Z]/.test(k)) {
+ return false;
+ }
+ }
+ return true;
+ })
+ );
+
+ const documentedKeys = Object.entries(propsFile)
.filter(([k]) => k !== '_config_')
.flatMap(([, section]) => Object.keys(section as object).filter((k) => k !== 'meta'));
- const missing = propsKeys.filter((k) => !codeKeys.has(k));
- const extra = [...codeKeys].filter((k) => !propsKeys.includes(k));
- if (missing.length || extra.length) {
+
+ const stale = documentedKeys.filter((k) => !keysToDocument.has(k));
+ const undocumented = [...keysToDocument].filter((k) => !documentedKeys.includes(k));
+
+ if (stale.length || undocumented.length) {
const msgs: string[] = [];
- if (missing.length) {
+ if (stale.length) {
msgs.push(
- `These theme params are documented in theming-api/properties.json but not in the API (checking ${codeSrc}): ${missing.join(', ')}`
+ `These ${source} keys are documented but not in the API (checking ${codeSrc}): ${stale.join(', ')}`
);
}
- if (extra.length) {
+ if (undocumented.length) {
msgs.push(
- `These theme params are present in the API (checking ${codeSrc}) but not documented in theming-api/properties.json: ${extra.join(', ')}`
+ `These ${source} keys are present in the API (checking ${codeSrc}) but not documented: ${undocumented.join(', ')}`
);
}
throw new Error(msgs.join('\n'));
diff --git a/documentation/ag-grid-docs/src/content/api-documentation/aggregation-filtering/properties.json b/documentation/ag-grid-docs/src/content/api-documentation/aggregation-filtering/properties.json
deleted file mode 100644
index 37e9b8ba4c9..00000000000
--- a/documentation/ag-grid-docs/src/content/api-documentation/aggregation-filtering/properties.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "_config_": {
- "codeSrc": "row-node.AUTO.json"
- },
- "rowNodeAttributes": {
- "meta": {
- "displayName": "RowNode attributes"
- },
- "level": {},
- "group": {},
- "leafGroup": {},
- "rowGroupColumn": {}
- }
-}
diff --git a/documentation/ag-grid-docs/src/content/api-documentation/column-events/events.json b/documentation/ag-grid-docs/src/content/api-documentation/column-events/events.json
index 42a50990381..d06f994028a 100644
--- a/documentation/ag-grid-docs/src/content/api-documentation/column-events/events.json
+++ b/documentation/ag-grid-docs/src/content/api-documentation/column-events/events.json
@@ -5,8 +5,7 @@
"events": {
"meta": {
"displayName": "Events on Column",
- "isEvent": true,
- "suppressMissingPropCheck": true
+ "isEvent": true
},
"filterActiveChanged": {
"description": "The filter active value has changed.",
diff --git a/documentation/ag-grid-docs/src/content/api-documentation/column-object-group/properties.json b/documentation/ag-grid-docs/src/content/api-documentation/column-object-group/properties.json
index 2f8b617c93d..f206d665df9 100644
--- a/documentation/ag-grid-docs/src/content/api-documentation/column-object-group/properties.json
+++ b/documentation/ag-grid-docs/src/content/api-documentation/column-object-group/properties.json
@@ -1,6 +1,11 @@
{
"_config_": {
- "codeSrc": "columnGroup.AUTO.json"
+ "codeSrc": "columnGroup.AUTO.json",
+ "validate": true,
+ "undocumentedProperties": {
+ "getDefinition": "Alias of getColGroupDef, the specific version is preferred",
+ "getUniqueId": "Alias of getColId on the underlying columns"
+ }
},
"ColumnGroup": {
"getColGroupDef": {},
@@ -15,6 +20,14 @@
"isExpanded": {},
"isPadding": {},
"getPaddingLevel": {},
- "isColumn": {}
+ "isColumn": {},
+ "getActualWidth": {},
+ "getMinWidth": {},
+ "getLeft": {},
+ "getColumnGroupShow": {},
+ "getParent": {},
+ "isEmptyGroup": {},
+ "isMoving": {},
+ "getPinned": {}
}
}
diff --git a/documentation/ag-grid-docs/src/content/api-documentation/column-object-group/provided-properties.json b/documentation/ag-grid-docs/src/content/api-documentation/column-object-group/provided-properties.json
index 2d9d9b25aac..05a4b8239a8 100644
--- a/documentation/ag-grid-docs/src/content/api-documentation/column-object-group/provided-properties.json
+++ b/documentation/ag-grid-docs/src/content/api-documentation/column-object-group/provided-properties.json
@@ -1,6 +1,10 @@
{
"_config_": {
- "codeSrc": "providedColumnGroup.AUTO.json"
+ "codeSrc": "providedColumnGroup.AUTO.json",
+ "validate": true,
+ "undocumentedProperties": {
+ "getId": "Alias of getGroupId"
+ }
},
"ProvidedColumnGroup": {
"getOriginalParent": {},
@@ -12,6 +16,8 @@
"getChildren": {},
"getColGroupDef": {},
"getLeafColumns": {},
- "isColumn": {}
+ "isColumn": {},
+ "isVisible": {},
+ "getColumnGroupShow": {}
}
}
diff --git a/documentation/ag-grid-docs/src/content/api-documentation/column-object/properties.json b/documentation/ag-grid-docs/src/content/api-documentation/column-object/properties.json
index 83060b8a42c..b477487d012 100644
--- a/documentation/ag-grid-docs/src/content/api-documentation/column-object/properties.json
+++ b/documentation/ag-grid-docs/src/content/api-documentation/column-object/properties.json
@@ -1,6 +1,13 @@
{
"_config_": {
- "codeSrc": "column.AUTO.json"
+ "codeSrc": "column.AUTO.json",
+ "validate": true,
+ "undocumentedProperties": {
+ "getDefinition": "Alias of getColDef, the specific version is preferred",
+ "getUniqueId": "Alias of getColId",
+ "getId": "Alias of getColId",
+ "getRowSpan": "Same functionality as rowSpan"
+ }
},
"definitions": {
"meta": {
@@ -155,5 +162,11 @@
"displayName": "Keyboard"
},
"isSuppressNavigable": {}
+ },
+ "formulas": {
+ "meta": {
+ "displayName": "Formulas"
+ },
+ "isAllowFormula": {}
}
}
diff --git a/documentation/ag-grid-docs/src/content/api-documentation/column-properties/properties.json b/documentation/ag-grid-docs/src/content/api-documentation/column-properties/properties.json
index 1a5544722ec..ebe99bfda22 100644
--- a/documentation/ag-grid-docs/src/content/api-documentation/column-properties/properties.json
+++ b/documentation/ag-grid-docs/src/content/api-documentation/column-properties/properties.json
@@ -1,6 +1,13 @@
{
"_config_": {
- "codeSrc": "column-options.AUTO.json"
+ "codeSrc": "column-options.AUTO.json",
+ "validate": true,
+ "undocumentedProperties": {
+ "pivotKeys": "Internal use only, doc comment says 'Never set this'",
+ "pivotValueColumn": "Internal use only, doc comment says 'Never set this'",
+ "pivotTotalColumnIds": "Internal use only, doc comment says 'Never set this'",
+ "rowSpan": "Old API, not deprecated, but not encouraged either"
+ }
},
"columns": {
"meta": {
@@ -466,6 +473,8 @@
"cellEditorPopup": {},
"cellEditorPopupPosition": {},
"singleClickEdit": {},
+ "groupRowEditable": {},
+ "groupRowValueSetter": {},
"useValueParserForImport": {
"more": {
"name": "Using Value Parsers with Other Grid Features",
diff --git a/documentation/ag-grid-docs/src/content/api-documentation/grid-api/api.json b/documentation/ag-grid-docs/src/content/api-documentation/grid-api/api.json
index 79e9f8127b1..914a3bd29af 100644
--- a/documentation/ag-grid-docs/src/content/api-documentation/grid-api/api.json
+++ b/documentation/ag-grid-docs/src/content/api-documentation/grid-api/api.json
@@ -1,6 +1,16 @@
{
"_config_": {
- "codeSrc": "grid-api.AUTO.json"
+ "codeSrc": "grid-api.AUTO.json",
+ "validate": true,
+ "undocumentedProperties": {
+ "sortChanged": "TODO: undocumented property, to resolve in AG-16879",
+ "flushAllAnimationFrames": "TODO: undocumented property, to resolve in AG-16879",
+ "getColumnDef": "TODO: undocumented property, to resolve in AG-16879",
+ "filterChanged": "TODO: undocumented property, to resolve in AG-16879",
+ "getInfiniteRowCount": "TODO: undocumented property, to resolve in AG-16879",
+ "flushServerSideAsyncTransactions": "TODO: undocumented property, to resolve in AG-16879",
+ "dispatchEvent": "TODO: undocumented property, to resolve in AG-16879"
+ }
},
"gridOptions": {
"meta": {
diff --git a/documentation/ag-grid-docs/src/content/api-documentation/grid-events/events.json b/documentation/ag-grid-docs/src/content/api-documentation/grid-events/events.json
index fd2cc5721dc..0177f6db7ab 100644
--- a/documentation/ag-grid-docs/src/content/api-documentation/grid-events/events.json
+++ b/documentation/ag-grid-docs/src/content/api-documentation/grid-events/events.json
@@ -1,6 +1,15 @@
{
"_config_": {
- "codeSrc": "grid-options.AUTO.json"
+ "codeSrc": "grid-options.AUTO.json",
+ "validate": true,
+ "onlyEvents": true,
+ "undocumentedProperties": {
+ "bulkEditingStarted": "TODO: undocumented property, to resolve in AG-16879",
+ "bulkEditingStopped": "TODO: undocumented property, to resolve in AG-16879",
+ "dragCancelled": "TODO: undocumented property, to resolve in AG-16879",
+ "rowResizeStarted": "TODO: undocumented property, to resolve in AG-16879",
+ "rowResizeEnded": "TODO: undocumented property, to resolve in AG-16879"
+ }
},
"accessories": {
"meta": {
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 a74b9e01619..d78e3f4bd04 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
@@ -1,6 +1,12 @@
{
"_config_": {
- "codeSrc": "grid-options.AUTO.json"
+ "codeSrc": "grid-options.AUTO.json",
+ "validate": true,
+ "excludeEvents": true,
+ "undocumentedProperties": {
+ "renderingMode": "React-only, so needs to be omitted from grid-options/properties.json (it is documented in grid-options/react-grid-options.json)",
+ "enableGroupEdit": "AG-2995 - 'Remove the grid option enableGroupEdit from docs API page to discourage its use'"
+ }
},
"accessories": {
"meta": {
@@ -1152,6 +1158,12 @@
"url": "./pivoting-totals/#row-totals"
}
},
+ "pivotColumnGroupTotals": {
+ "more": {
+ "name": "Pivot Column Group Totals",
+ "url": "./pivoting-totals/#column-group-totals"
+ }
+ },
"pivotSuppressAutoColumn": {
"description": "If `true`, the grid will not swap in the grouping column when pivoting. Useful if pivoting using [Server Side Row Model](./server-side-model/) or [Viewport Row Model](./viewport/) and you want full control of all columns including the group column."
},
@@ -1265,7 +1277,8 @@
"name": "Row Spanning",
"url": "./row-spanning/"
}
- }
+ },
+ "suppressRowTransform": {}
},
"rowDragging": {
"meta": {
@@ -1358,6 +1371,12 @@
"name": "Embedded Full Width Rows",
"url": "./full-width-rows/#embedded-full-width-rows"
}
+ },
+ "isFullWidthRow": {
+ "more": {
+ "name": "Full Width Rows",
+ "url": "./full-width-rows/"
+ }
}
},
"rowGrouping": {
@@ -1536,6 +1555,7 @@
"url": "./tree-data/"
}
},
+ "treeDataDisplayType": {},
"autoGroupColumnDef": {
"more": {
"name": "Group Column Configuration",
diff --git a/documentation/ag-grid-docs/src/content/api-documentation/row-events/events.json b/documentation/ag-grid-docs/src/content/api-documentation/row-events/events.json
index b6212f330e4..b309ca94cc9 100644
--- a/documentation/ag-grid-docs/src/content/api-documentation/row-events/events.json
+++ b/documentation/ag-grid-docs/src/content/api-documentation/row-events/events.json
@@ -1,7 +1,6 @@
{
"_config_": {
- "codeSrc": "row-node.AUTO.json",
- "suppressMissingPropCheck": true
+ "codeSrc": "row-node.AUTO.json"
},
"rowNodeEvents": {
"meta": {
diff --git a/documentation/ag-grid-docs/src/content/api-documentation/row-object/properties.json b/documentation/ag-grid-docs/src/content/api-documentation/row-object/properties.json
index 7391d53586d..25c9a8bbbb0 100644
--- a/documentation/ag-grid-docs/src/content/api-documentation/row-object/properties.json
+++ b/documentation/ag-grid-docs/src/content/api-documentation/row-object/properties.json
@@ -1,6 +1,7 @@
{
"_config_": {
- "codeSrc": "row-node.AUTO.json"
+ "codeSrc": "row-node.AUTO.json",
+ "validate": true
},
"display": {
"meta": {
diff --git a/documentation/ag-grid-docs/src/content/api-documentation/theming-api/properties.json b/documentation/ag-grid-docs/src/content/api-documentation/theming-api/properties.json
index fda3e4bc7b6..232293261b5 100644
--- a/documentation/ag-grid-docs/src/content/api-documentation/theming-api/properties.json
+++ b/documentation/ag-grid-docs/src/content/api-documentation/theming-api/properties.json
@@ -1,6 +1,7 @@
{
"_config_": {
"codeSrc": "theming-api.AUTO.json",
+ "validate": true,
"codeWordsMode": "cssVariable"
},
"colorsAndDarkMode": {
diff --git a/documentation/ag-grid-docs/src/content/interface-documentation/excel-export-api/excel-api.json b/documentation/ag-grid-docs/src/content/interface-documentation/excel-export-api/excel-api.json
index 66c21869176..0631fe1b1b9 100644
--- a/documentation/ag-grid-docs/src/content/interface-documentation/excel-export-api/excel-api.json
+++ b/documentation/ag-grid-docs/src/content/interface-documentation/excel-export-api/excel-api.json
@@ -48,8 +48,7 @@
},
"ExcelHeaderFooter": {
"meta": {
- "description": "Properties available on the `ExcelHeaderFooter` interface. At least one of header or footer is required or both.",
- "suppressMissingPropCheck": true
+ "description": "Properties available on the `ExcelHeaderFooter` interface. At least one of header or footer is required or both."
},
"header": {
"description": "An array of maximum 3 items (`Left`, `Center`, `Right`), containing header configurations.",
diff --git a/documentation/ag-grid-docs/src/content/matrix-table/row-models.json b/documentation/ag-grid-docs/src/content/matrix-table/row-models.json
index 804c0554363..b60c7305698 100644
--- a/documentation/ag-grid-docs/src/content/matrix-table/row-models.json
+++ b/documentation/ag-grid-docs/src/content/matrix-table/row-models.json
@@ -114,9 +114,9 @@
{
"feature": "[Row Spanning](./row-spanning)",
"clientSide": true,
- "infinite": true,
+ "infinite": false,
"serverSide": true,
- "viewport": true
+ "viewport": false
},
{
"feature": "[Column Pinning](./column-pinning)",
diff --git a/documentation/update-algolia-indices/src/config.ts b/documentation/update-algolia-indices/src/config.ts
index c366b7f389a..8c524c73b36 100644
--- a/documentation/update-algolia-indices/src/config.ts
+++ b/documentation/update-algolia-indices/src/config.ts
@@ -54,8 +54,9 @@ export const TYPE_PROPERTY_INDEXING: Record {
// and shouldn't be searchable
text = text.replace(/.*?<\/style>/gs, '');
+ // Remove tags without replacing with space, so that camelCase words
+ // split for display (e.g. processCellCallback) are rejoined
+ text = text.replace(//gi, '');
+
// strip all HTML tags so that names and content of attributes aren't searchable
text = text.replace(/<.*?>/gs, ' ');
@@ -57,12 +61,14 @@ export const getAllDocPages = (): FlattenedMenuItem[] => {
const apiMenu = getApiMenuData();
pageRank = 0;
- const allSections = [...docsMenu.sections, ...apiMenu.sections];
-
- const flattenedMenuItems = getFlattenedMenuItems(allSections);
- const flattenedDocMigrationItems = getFlattenedDocMigrationItems();
-
- return [...flattenedMenuItems, ...flattenedDocMigrationItems];
+ return [
+ ...getFlattenedMenuItems(docsMenu.sections),
+ ...getFlattenedMenuItems(apiMenu.sections).map((item) => ({
+ ...item,
+ isApiPage: true,
+ })),
+ ...getFlattenedDocMigrationItems(),
+ ];
};
function getHeadingContent(heading: Element) {
@@ -146,6 +152,39 @@ export const parseDocPage = async (item: FlattenedMenuItem) => {
continue;
}
+ // Process API reference tables by extracting each property as a
+ // separate record with the property name as a subHeading
+ if (currentTag.hasAttribute?.('data-api-reference-table')) {
+ if (item.isApiPage) {
+ continue;
+ }
+ for (const prop of currentTag.querySelectorAll('[data-api-property]')) {
+ const nameEl = prop.querySelector('[data-api-property-name]');
+ if (!nameEl) continue;
+ const propertyName = getHeadingContent(nameEl);
+ const anchor = nameEl.id;
+ const descEl = prop.querySelector('[data-api-property-description]');
+ const descHtml = descEl?.innerHTML ?? '';
+ const descCodeWords = extractCodeWords(descHtml);
+ const positionInPage = position++;
+ const propertyPath = anchor ? `${path}#${anchor}` : path;
+ records.push({
+ source: 'docs',
+ objectID: `${propertyPath}:${positionInPage}`,
+ breadcrumb,
+ title: pageTitle || title,
+ heading: [subHeading || heading, propertyName].filter(Boolean).join(' > ') || undefined,
+ subHeading: propertyName,
+ path: propertyPath,
+ text: truncateAtWordBoundary(cleanContents(descHtml), 120, 250),
+ codeWords: descCodeWords.length > 0 ? descCodeWords : undefined,
+ rank,
+ positionInPage,
+ });
+ }
+ continue;
+ }
+
switch (currentTag.nodeName) {
// split records based on H2 and H3 tags
case 'H2': {
@@ -164,9 +203,10 @@ export const parseDocPage = async (item: FlattenedMenuItem) => {
break;
}
- case 'DIV': {
+ case 'DIV':
+ case 'ASTRO-ISLAND': {
createPreviousRecord();
- // process content inside div containers
+ // process content inside div/astro-island containers
recursivelyParseContent(currentTag.firstChild as Element | null);
break;
}
@@ -244,6 +284,7 @@ export interface FlattenedMenuItem {
path: string;
rank: number;
breadcrumb: string;
+ isApiPage?: boolean;
}
const getFlattenedMenuItems = (
diff --git a/documentation/update-algolia-indices/src/utils/output.ts b/documentation/update-algolia-indices/src/utils/output.ts
index 75ab30afc16..339e378f124 100644
--- a/documentation/update-algolia-indices/src/utils/output.ts
+++ b/documentation/update-algolia-indices/src/utils/output.ts
@@ -62,6 +62,8 @@ export const updateAlgolia = async (indexName: string, records: Record = ColDef {
deltaSort?: boolean;
/**
+ * Specifies how tree data should be displayed.
+ *
+ * The options are:
+ *
+ * - `'auto'`: group column automatically added by the grid.
+ * - `'custom'`: informs the grid that group columns will be provided.
+ * @agModule `TreeDataModule`
*/
treeDataDisplayType?: TreeDataDisplayType;
diff --git a/packages/ag-grid-community/src/filter/provided/date/dateFilter.ts b/packages/ag-grid-community/src/filter/provided/date/dateFilter.ts
index d09d20de3ea..4db3e85db05 100644
--- a/packages/ag-grid-community/src/filter/provided/date/dateFilter.ts
+++ b/packages/ag-grid-community/src/filter/provided/date/dateFilter.ts
@@ -9,7 +9,7 @@ import { _warn } from '../../../validation/logging';
import type { FilterLocaleTextKey } from '../../filterLocaleText';
import type { ICombinedSimpleModel, Tuple } from '../iSimpleFilter';
import { SimpleFilter } from '../simpleFilter';
-import { removeItems } from '../simpleFilterUtils';
+import { getNumberOfInputs, removeItems } from '../simpleFilterUtils';
import { DateCompWrapper } from './dateCompWrapper';
import { DEFAULT_DATE_FILTER_OPTIONS } from './dateFilterConstants';
import { mapValuesFromDateFilterModel } from './dateFilterUtils';
@@ -104,9 +104,11 @@ export class DateFilter extends SimpleFilter= 2 ? getRangeValidityMessageKey(fromDate, toDate, isFrom) : null;
const message = localeKey ? this.translate(localeKey, [String(isFrom ? toDate : fromDate)]) : '';
// FF seems to handle cursors/focus sufficiently well for the validation to be left as synchronous.
@@ -356,7 +358,7 @@ export class DateFilter extends SimpleFilter Validations = () => {
enableRangeSelection: { required: [true] },
},
},
+ enableCellSpan: {
+ supportedRowModels: ['clientSide', 'serverSide'],
+ },
enableRangeSelection: {
dependencies: {
rowDragEntireRow: { required: [false, undefined] },
diff --git a/packages/ag-grid-vue3/src/components/utils.ts b/packages/ag-grid-vue3/src/components/utils.ts
index 06f0f70fdaf..8733e6bcdcd 100644
--- a/packages/ag-grid-vue3/src/components/utils.ts
+++ b/packages/ag-grid-vue3/src/components/utils.ts
@@ -1638,7 +1638,14 @@ export interface Props {
* @default false
*/
deltaSort?: boolean,
- /**/
+ /** Specifies how tree data should be displayed.
+ *
+ * The options are:
+ *
+ * - `'auto'`: group column automatically added by the grid.
+ * - `'custom'`: informs the grid that group columns will be provided.
+ * @agModule `TreeDataModule`
+ */
treeDataDisplayType?: TreeDataDisplayType,
/** @initial
*/
diff --git a/testing/behavioural/src/filters/date-filter-range-validation.test.ts b/testing/behavioural/src/filters/date-filter-range-validation.test.ts
index 7acee2d2b84..a4e732d4e5b 100644
--- a/testing/behavioural/src/filters/date-filter-range-validation.test.ts
+++ b/testing/behavioural/src/filters/date-filter-range-validation.test.ts
@@ -1,6 +1,7 @@
-import { getByTestId, waitFor } from '@testing-library/dom';
+import { getAllByTestId, getByTestId, waitFor } from '@testing-library/dom';
import { userEvent } from '@testing-library/user-event';
+import type { DateFilterModel } from 'ag-grid-community';
import {
ClientSideRowModelModule,
DateFilterModule,
@@ -101,3 +102,187 @@ describe('Number Range Filter', () => {
expect(toNumberInput).toHaveAttribute('aria-invalid', 'false');
});
});
+
+async function selectFilterOption(gridDiv: HTMLElement, userSession: any, optionText: string): Promise {
+ const pickerDisplay = getAllByTestId(
+ gridDiv,
+ agTestIdFor.filterInstancePickerDisplay({ source: 'column-filter' })
+ )[0];
+ await userSession.click(pickerDisplay);
+
+ await asyncSetTimeout(0);
+
+ const listItems = document.querySelectorAll('.ag-list-item');
+ let targetItem: Element | null = null;
+ listItems.forEach((item) => {
+ if (item.textContent?.trim() === optionText) {
+ targetItem = item;
+ }
+ });
+ expect(targetItem).not.toBeNull();
+ await userSession.click(targetItem!);
+
+ await asyncSetTimeout(0);
+}
+
+describe('Date Range Filter', () => {
+ const gridsManager = new TestGridsManager({
+ modules: [DateFilterModule, ClientSideRowModelModule, TextFilterModule],
+ });
+
+ beforeAll(() => setupAgTestIds());
+ afterEach(() => gridsManager.reset());
+
+ test('Switching from inRange to equals clears range validation on the from input', async () => {
+ const userSession = userEvent.setup();
+
+ const api = await gridsManager.createGridAndWait('grid1', {
+ columnDefs: [
+ {
+ field: 'date',
+ filter: 'agDateColumnFilter',
+ filterParams: {
+ filterOptions: ['inRange', 'equals'],
+ },
+ },
+ ],
+ rowData: [{ date: '2024-01-15' }, { date: '2024-06-15' }, { date: '2024-12-15' }],
+ });
+
+ const gridDiv = getGridElement(api)! as HTMLElement;
+
+ await asyncSetTimeout(0);
+
+ // Open the filter popup
+ const filterBtn = getByTestId(gridDiv, agTestIdFor.headerFilterButton('date'));
+ await userSession.click(filterBtn);
+
+ await asyncSetTimeout(0);
+
+ // Enter dates into the inRange inputs: from=2024-01-15, to=2024-06-15
+ const fromDateInput = getByTestId(
+ gridDiv,
+ agTestIdFor.dateFilterInstanceInput({ source: 'column-filter', index: 0 })
+ );
+ const toDateInput = getByTestId(
+ gridDiv,
+ agTestIdFor.dateFilterInstanceInput({ source: 'column-filter', index: 1 })
+ );
+
+ // Use fireEvent to set date values (userEvent.type doesn't work well with date inputs)
+ fromDateInput.valueAsDate = new Date('2024-01-15');
+ fromDateInput.dispatchEvent(new Event('input', { bubbles: true }));
+ fromDateInput.dispatchEvent(new Event('change', { bubbles: true }));
+
+ toDateInput.valueAsDate = new Date('2024-06-15');
+ toDateInput.dispatchEvent(new Event('input', { bubbles: true }));
+ toDateInput.dispatchEvent(new Event('change', { bubbles: true }));
+
+ await asyncSetTimeout(0);
+
+ // Both inputs should be valid (from < to)
+ expect(fromDateInput.validity.valid).toBe(true);
+ expect(toDateInput.validity.valid).toBe(true);
+
+ await waitFor(() => {
+ const model = api.getFilterModel()?.date as DateFilterModel;
+ expect(model).toBeTruthy();
+ expect(model.type).toBe('inRange');
+ });
+
+ // Switch to "equals" via the filter type picker
+ await selectFilterOption(gridDiv, userSession, 'Equals');
+
+ // Now the filter is "equals" - the to input is hidden but still has its value.
+ // Change the from date to match what was in the to date.
+ const fromDateInputEquals = getByTestId(
+ gridDiv,
+ agTestIdFor.dateFilterInstanceInput({ source: 'column-filter' })
+ );
+
+ fromDateInputEquals.valueAsDate = new Date('2024-06-15');
+ fromDateInputEquals.dispatchEvent(new Event('input', { bubbles: true }));
+ fromDateInputEquals.dispatchEvent(new Event('change', { bubbles: true }));
+
+ await asyncSetTimeout(0);
+
+ // The from input should be valid - no range validation should apply for "equals"
+ expect(fromDateInputEquals.validity.valid).toBe(true);
+ });
+
+ test('Switching from equals back to inRange re-enables range validation', async () => {
+ const userSession = userEvent.setup();
+
+ const api = await gridsManager.createGridAndWait('grid1', {
+ columnDefs: [
+ {
+ field: 'date',
+ filter: 'agDateColumnFilter',
+ filterParams: {
+ filterOptions: ['inRange', 'equals'],
+ },
+ },
+ ],
+ rowData: [{ date: '2024-01-15' }, { date: '2024-06-15' }, { date: '2024-12-15' }],
+ });
+
+ const gridDiv = getGridElement(api)! as HTMLElement;
+
+ await asyncSetTimeout(0);
+
+ // Open the filter popup
+ const filterBtn = getByTestId(gridDiv, agTestIdFor.headerFilterButton('date'));
+ await userSession.click(filterBtn);
+
+ await asyncSetTimeout(0);
+
+ // Enter valid inRange dates: from=2024-01-15, to=2024-06-15
+ const fromDateInput = getByTestId(
+ gridDiv,
+ agTestIdFor.dateFilterInstanceInput({ source: 'column-filter', index: 0 })
+ );
+ const toDateInput = getByTestId(
+ gridDiv,
+ agTestIdFor.dateFilterInstanceInput({ source: 'column-filter', index: 1 })
+ );
+
+ fromDateInput.valueAsDate = new Date('2024-01-15');
+ fromDateInput.dispatchEvent(new Event('input', { bubbles: true }));
+ toDateInput.valueAsDate = new Date('2024-06-15');
+ toDateInput.dispatchEvent(new Event('input', { bubbles: true }));
+
+ await asyncSetTimeout(0);
+
+ // Switch to "equals"
+ await selectFilterOption(gridDiv, userSession, 'Equals');
+
+ // Change the from date to be after what was in the to date
+ const fromDateInputEquals = getByTestId(
+ gridDiv,
+ agTestIdFor.dateFilterInstanceInput({ source: 'column-filter' })
+ );
+
+ fromDateInputEquals.valueAsDate = new Date('2024-12-15');
+ fromDateInputEquals.dispatchEvent(new Event('input', { bubbles: true }));
+
+ await asyncSetTimeout(0);
+
+ // Valid in "equals" mode - no range validation
+ expect(fromDateInputEquals.validity.valid).toBe(true);
+
+ // Switch back to "inRange" - the from date (2024-12-15) is now after the to date (2024-06-15)
+ await selectFilterOption(gridDiv, userSession, 'Between');
+
+ // Trigger validation by interacting with the from input
+ const fromDateInputRange = getByTestId(
+ gridDiv,
+ agTestIdFor.dateFilterInstanceInput({ source: 'column-filter', index: 0 })
+ );
+ fromDateInputRange.dispatchEvent(new Event('focusin', { bubbles: true }));
+
+ await asyncSetTimeout(0);
+
+ // Range validation should now be active again - from > to is invalid
+ expect(fromDateInputRange.validity.valid).toBe(false);
+ });
+});
diff --git a/testing/behavioural/src/grouping-data/grouping-show-columns-when-expanded.test.ts b/testing/behavioural/src/grouping-data/grouping-show-columns-when-expanded.test.ts
index 53d2100c26a..9eda4f62845 100644
--- a/testing/behavioural/src/grouping-data/grouping-show-columns-when-expanded.test.ts
+++ b/testing/behavioural/src/grouping-data/grouping-show-columns-when-expanded.test.ts
@@ -1,5 +1,5 @@
import type { GridApi } from 'ag-grid-community';
-import { ClientSideRowModelModule, QuickFilterModule } from 'ag-grid-community';
+import { ClientSideRowModelModule, QuickFilterModule, getGridElement } from 'ag-grid-community';
import { PivotModule, RowGroupingModule } from 'ag-grid-enterprise';
import { GridRows, TestGridsManager, cachedJSONObjects } from '../test-utils';
@@ -11,6 +11,19 @@ function getVisibleAutoGroupColIds(api: GridApi): string[] {
.map((col) => col.getColId());
}
+/** Returns col-id attributes from the first data row's cells in DOM order */
+function getCellColIdsFromDom(api: GridApi): string[] {
+ const gridElement = getGridElement(api);
+ if (!gridElement) {
+ return [];
+ }
+ const firstRow = gridElement.querySelector('[role="row"][row-index="0"]');
+ if (!firstRow) {
+ return [];
+ }
+ return Array.from(firstRow.querySelectorAll('[role="gridcell"]')).map((cell) => cell.getAttribute('col-id') ?? '');
+}
+
describe('ag-grid groupHideColumnsUntilExpanded', () => {
const gridsManager = new TestGridsManager({
modules: [ClientSideRowModelModule, RowGroupingModule, QuickFilterModule],
@@ -865,6 +878,40 @@ describe('ag-grid groupHideColumnsUntilExpanded', () => {
expect(getVisibleAutoGroupColIds(api)).toEqual(['ag-Grid-AutoColumn']);
});
+ test('DOM order of cells matches display order when group columns are revealed', async () => {
+ const api = gridsManager.createGrid('myGrid', {
+ columnDefs: [
+ { field: 'country', rowGroup: true },
+ { field: 'year', rowGroup: true },
+ { field: 'athlete' },
+ { field: 'gold' },
+ ],
+ groupDisplayType: 'multipleColumns',
+ groupHideColumnsUntilExpanded: true,
+ groupDefaultExpanded: 0,
+ ensureDomOrder: true,
+ rowData: twoLevelRowData,
+ getRowId: (params) => params.data.id,
+ });
+
+ // Initially only the country auto-group column is visible
+ expect(getCellColIdsFromDom(api)).toEqual(['ag-Grid-AutoColumn-country', 'country', 'year', 'athlete', 'gold']);
+
+ // Expand Ireland - year auto-group column becomes visible
+ api.setRowNodeExpanded(api.getRowNode('row-group-country-Ireland')!, true, false, true);
+
+ // The newly revealed auto-group-year column should appear in the correct DOM position
+ // (after auto-group-country, before the data columns)
+ expect(getCellColIdsFromDom(api)).toEqual([
+ 'ag-Grid-AutoColumn-country',
+ 'ag-Grid-AutoColumn-year',
+ 'country',
+ 'year',
+ 'athlete',
+ 'gold',
+ ]);
+ });
+
test('has no effect with groupRows display type', async () => {
const api = gridsManager.createGrid('myGrid', {
columnDefs: [
|