Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .github/workflows/module-size-vs-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ on:
workflow_dispatch:
inputs:
release_tag:
description: 'Release tag to compare against (e.g., b35.1.0)'
description: 'Release tag to compare against (e.g., b35.1.0) or leave empty to auto-detect latest release'
type: string
required: true
required: false

env:
NX_NO_CLOUD: true
Expand Down Expand Up @@ -57,12 +57,13 @@ jobs:
per_page: 10
});

// Find the latest non-prerelease tag matching bXX.X.X pattern
const release = releases.find(r => !r.prerelease && /^b\d+\.\d+\.\d+$/.test(r.tag_name));
// Find the latest non-prerelease tag matching release-XX.X.X pattern
const release = releases.find(r => !r.prerelease && /^release-\d+\.\d+\.\d+$/.test(r.tag_name));
if (!release) {
core.setFailed('Could not find a valid release tag');
return;
}
// Use the latest release tag
releaseTag = release.tag_name;
console.log(`Using latest release tag: ${releaseTag}`);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export const parseDocPage = async (item: FlattenedMenuItem) => {

objectID: hashPath,
breadcrumb,
title,
title: pageTitle || title,
heading,
subHeading,
path: hashPath,
Expand Down
1 change: 1 addition & 0 deletions packages/ag-grid-community/src/interfaces/formulas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,5 @@ export interface IFormulaService extends Bean {
}): string;
refreshFormulas(refreshRows: boolean): void;
getFunction(name: string): ((params: FormulaFunctionParams) => unknown) | undefined;
getFunctionNames(): string[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ export class AgAutocompleteList extends AgPopupComponent<
autocompleteEntries: AutocompleteEntry[];
onConfirmed: () => void;
useFuzzySearch?: boolean;
useStartsWithSearch?: boolean;
autoSizeList?: boolean;
maxVisibleItems?: number;
forceLastSelection?: (lastSelection: AutocompleteEntry, searchString: string) => boolean;
}
) {
Expand All @@ -75,6 +78,7 @@ export class AgAutocompleteList extends AgPopupComponent<
});

this.setSelectedValue(0);
this.updateListHeight();
}

public onNavigationKeyDown(event: any, key: string): void {
Expand All @@ -95,6 +99,7 @@ export class AgAutocompleteList extends AgPopupComponent<
this.autocompleteEntries = this.params.autocompleteEntries;
this.virtualList.refresh();
this.checkSetSelectedValue(0);
this.updateListHeight();
}
this.updateSearchInList();
}
Expand Down Expand Up @@ -129,8 +134,20 @@ export class AgAutocompleteList extends AgPopupComponent<
return { topMatch, allMatches };
}

private runStartsWithSearch(
searchString: string,
searchStrings: string[]
): { topMatch: string | undefined; allMatches: string[] } {
const lowerCaseSearchString = searchString.toLocaleLowerCase();
const allMatches = searchStrings.filter((string) =>
string.toLocaleLowerCase().startsWith(lowerCaseSearchString)
);
const topMatch = allMatches[0];
return { topMatch, allMatches };
}

private runSearch() {
const { autocompleteEntries, useFuzzySearch, forceLastSelection } = this.params;
const { autocompleteEntries, useFuzzySearch, useStartsWithSearch, forceLastSelection } = this.params;
const searchStrings = autocompleteEntries.map((v) => v.displayValue ?? v.key);

let matchingStrings: string[];
Expand All @@ -143,9 +160,11 @@ export class AgAutocompleteList extends AgPopupComponent<
}).values;
topSuggestion = matchingStrings.length ? matchingStrings[0] : undefined;
} else {
const containsMatches = this.runContainsSearch(this.searchString, searchStrings);
matchingStrings = containsMatches.allMatches;
topSuggestion = containsMatches.topMatch;
const matches = useStartsWithSearch
? this.runStartsWithSearch(this.searchString, searchStrings)
: this.runContainsSearch(this.searchString, searchStrings);
matchingStrings = matches.allMatches;
topSuggestion = matches.topMatch;
}

let filteredEntries = autocompleteEntries.filter(({ key, displayValue }) =>
Expand All @@ -160,6 +179,7 @@ export class AgAutocompleteList extends AgPopupComponent<
}
this.autocompleteEntries = filteredEntries;
this.virtualList.refresh();
this.updateListHeight();

if (!topSuggestion) {
return;
Expand All @@ -174,6 +194,24 @@ export class AgAutocompleteList extends AgPopupComponent<
this.virtualList.forEachRenderedRow((row: AgAutocompleteRow) => row.setSearchString(this.searchString));
}

private updateListHeight(): void {
if (!this.params.autoSizeList) {
return;
}

const rowCount = this.autocompleteEntries.length;
const rowHeight = this.virtualList.getRowHeight();
const maxItems = this.params.maxVisibleItems ?? rowCount;
const visibleCount = Math.min(rowCount, maxItems);
let height = visibleCount * rowHeight;

if (rowCount === 0) {
height = rowHeight;
}

this.eList.style.height = `${height}px`;
}

private checkSetSelectedValue(index: number): void {
if (index >= 0 && index < this.autocompleteEntries.length) {
this.setSelectedValue(index);
Expand Down
25 changes: 25 additions & 0 deletions packages/ag-grid-enterprise/src/formula/formulaService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type { Addr } from './functions/resolver';
import { evalAst, unresolvedDeps } from './functions/resolver';
import SUPPORTED_FUNCTIONS from './functions/supportedFuncs';
import { shiftNode } from './functions/utils';
import { isFormulaIdentChar, isFormulaIdentStart } from './refUtils';

/**
* Cell Formula Cache
Expand Down Expand Up @@ -106,6 +107,7 @@ export class FormulaService extends BeanStub implements IFormulaService, NamedBe

/** Built-in operations (extendable via gridOptions.formulaFuncs). */
private supportedOperations: Map<string, (params: FormulaFunctionParams) => unknown>;
private functionNames: string[] | null = null;

// Track the active editor instance per grid/cell to avoid overlapping syncs on editor restarts.
public activeEditor: number | null = null;
Expand Down Expand Up @@ -224,6 +226,7 @@ export class FormulaService extends BeanStub implements IFormulaService, NamedBe
private setupFunctions() {
// eslint-disable-next-line no-restricted-properties
this.supportedOperations = new Map(Object.entries(SUPPORTED_FUNCTIONS));
this.functionNames = null;

// Register custom functions, not reactive.
const customFuncs = this.gos.get('formulaFuncs');
Expand All @@ -234,6 +237,28 @@ export class FormulaService extends BeanStub implements IFormulaService, NamedBe
}
}

public getFunctionNames(): string[] {
if (this.functionNames) {
return this.functionNames;
}

const names: string[] = [];

for (const name of this.supportedOperations.keys()) {
if (!isFormulaIdentStart(name[0])) {
continue;
}
if (![...name].every((char) => isFormulaIdentChar(char))) {
continue;
}
names.push(name);
}

names.sort((a, b) => a.localeCompare(b));
this.functionNames = names;
return names;
}

private setupColRefMap() {
if (!this.active) {
this.colRefMap = new Map();
Expand Down
30 changes: 15 additions & 15 deletions packages/ag-grid-enterprise/src/widgets/agFormulaInputField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ import type {
} from 'ag-grid-community';
import { AgContentEditableField, _createElement, _getDocument, _getWindow } from 'ag-grid-community';

import { agAutocompleteCSS } from '../advancedFilter/autocomplete/agAutocomplete.css-GENERATED';
import { getRefTokenMatches } from '../formula/refUtils';
import { agFormulaInputFieldCSS } from './agFormulaInputField.css-GENERATED';
import { FormulaInputAutocompleteFeature } from './formulaInputAutocompleteFeature';
import { FormulaInputRangeSyncFeature } from './formulaInputRangeSyncFeature';
import { TOKEN_INSERT_AFTER_CHARS, getPreviousNonSpaceChar } from './formulaInputTokenUtils';
import { getColorClassesForRef } from './formulaRangeUtils';

const FORMULA_TOKEN_COLOR_COUNT = 7;
Expand All @@ -26,9 +29,6 @@ type RangeInsertAction = 'insert' | 'replace' | 'none';
type TokenMatch = { ref: string; start: number; end: number; index: number };
type TokenInsertResult = { previousRef?: string; tokenIndex?: number | null };

// only insert new refs after operators/argument separators; otherwise treat clicks as normal edit completion.
const TOKEN_INSERT_AFTER_CHARS = new Set(['=', '+', '-', '*', '/', '^', ',', '(', ';', '<', '>', '&']);

export class AgFormulaInputField extends AgContentEditableField<
BeanCollection,
GridOptionsWithDefaults,
Expand All @@ -46,13 +46,16 @@ export class AgFormulaInputField extends AgContentEditableField<
private lastTokenCaretOffset: number | null = null;
private lastTokenRef?: string;
private rangeSyncFeature?: FormulaInputRangeSyncFeature;
private autocompleteFeature?: FormulaInputAutocompleteFeature;
// fallback color assignment per ref when a token index is unavailable.

private readonly formulaColorByRef = new Map<string, number>();

constructor() {
// keep renderValueToElement false so we fully control DOM rendering.
super({ renderValueToElement: false, className: 'ag-formula-input-field' } as any);
this.registerCSS(agFormulaInputFieldCSS);
this.registerCSS(agAutocompleteCSS);
}

public override postConstruct(): void {
Expand All @@ -63,6 +66,7 @@ export class AgFormulaInputField extends AgContentEditableField<
});

this.rangeSyncFeature = this.createManagedBean(new FormulaInputRangeSyncFeature(this));
this.autocompleteFeature = this.createManagedBean(new FormulaInputAutocompleteFeature(this));
}

public override setValue(value?: string | null, silent?: boolean): this {
Expand Down Expand Up @@ -384,6 +388,10 @@ export class AgFormulaInputField extends AgContentEditableField<
});
}

public getCaretOffsetsForAutocomplete(value: string): { caretOffset: number; valueOffset: number } | null {
return this.getCaretOffsets(value);
}

private getCaretOffsets(
value: string,
options: { useCachedCaret: boolean; useCachedValueOffset: boolean } = {
Expand Down Expand Up @@ -445,6 +453,7 @@ export class AgFormulaInputField extends AgContentEditableField<
if (params.dispatch) {
this.dispatchValueChanged();
}
this.autocompleteFeature?.onPlainValueUpdated();
}

private applyFormulaValue(
Expand All @@ -463,9 +472,10 @@ export class AgFormulaInputField extends AgContentEditableField<
if (params.dispatch) {
this.dispatchValueChanged();
}
this.autocompleteFeature?.onFormulaValueUpdated();
}

private applyFormulaValueChange(params: {
public applyFormulaValueChange(params: {
currentValue: string;
nextValue: string;
caret: number;
Expand All @@ -480,6 +490,7 @@ export class AgFormulaInputField extends AgContentEditableField<
caret: params.caret,
});
this.dispatchValueChanged();
this.autocompleteFeature?.onFormulaValueUpdated();
}

public replaceTokenRef(
Expand Down Expand Up @@ -580,17 +591,6 @@ const shouldInsertTokenAtOffset = (value: string, offset: number): boolean => {
return previousChar == null || TOKEN_INSERT_AFTER_CHARS.has(previousChar);
};

const getPreviousNonSpaceChar = (value: string, offset: number): string | null => {
// skip whitespace to detect the meaningful character before the caret.
for (let i = offset - 1; i >= 0; i--) {
const char = value[i];
if (char != null && char.trim() !== '') {
return char;
}
}
return null;
};

// Rendering & caret helpers
const tokenize = (
beans: BeanCollection,
Expand Down
Loading
Loading