@zengrid/core 1.2.1 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs.js +564 -159
- package/dist/index.esm.js +564 -159
- package/dist/package.json +2 -2
- package/dist/src/data/data-manager.d.ts.map +1 -1
- package/dist/src/features/filtering/filter-ast-compiler.d.ts +1 -1
- package/dist/src/features/filtering/filter-ast-compiler.d.ts.map +1 -1
- package/dist/src/features/filtering/filter-ast.d.ts +6 -8
- package/dist/src/features/filtering/filter-ast.d.ts.map +1 -1
- package/dist/src/features/filtering/filter-execution-error.d.ts +2 -0
- package/dist/src/features/filtering/filter-execution-error.d.ts.map +1 -0
- package/dist/src/features/filtering/filter-expression.d.ts.map +1 -1
- package/dist/src/features/filtering/filter-manager/filter-core.d.ts +12 -4
- package/dist/src/features/filtering/filter-manager/filter-core.d.ts.map +1 -1
- package/dist/src/features/filtering/filter-manager/filter-query.d.ts +6 -1
- package/dist/src/features/filtering/filter-manager/filter-query.d.ts.map +1 -1
- package/dist/src/features/filtering/filter-manager/index.d.ts +1 -0
- package/dist/src/features/filtering/filter-manager/index.d.ts.map +1 -1
- package/dist/src/features/filtering/filter-signature.d.ts +6 -0
- package/dist/src/features/filtering/filter-signature.d.ts.map +1 -0
- package/dist/src/features/query/query-signature.d.ts +3 -0
- package/dist/src/features/query/query-signature.d.ts.map +1 -0
- package/dist/src/grid/api/filter-api.d.ts.map +1 -1
- package/dist/src/grid/api/sort-api.d.ts.map +1 -1
- package/dist/src/grid/filter-ui.d.ts +1 -0
- package/dist/src/grid/filter-ui.d.ts.map +1 -1
- package/dist/src/grid/grid-context.d.ts +2 -0
- package/dist/src/grid/grid-context.d.ts.map +1 -1
- package/dist/src/grid/grid-core.d.ts.map +1 -1
- package/dist/src/grid/grid-setup.d.ts.map +1 -1
- package/dist/src/grid/options-manager.d.ts +14 -0
- package/dist/src/grid/options-manager.d.ts.map +1 -0
- package/dist/src/grid/plugin-host.d.ts +3 -2
- package/dist/src/grid/plugin-host.d.ts.map +1 -1
- package/dist/src/grid/query-mode.d.ts +4 -0
- package/dist/src/grid/query-mode.d.ts.map +1 -0
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/plugins/data-plugin.d.ts.map +1 -1
- package/dist/src/plugins/filter-plugin.d.ts.map +1 -1
- package/dist/src/plugins/filter-ui/filter-ui-plugin.d.ts +1 -1
- package/dist/src/plugins/filter-ui/filter-ui-plugin.d.ts.map +1 -1
- package/dist/src/plugins/sort-plugin.d.ts.map +1 -1
- package/dist/src/reactive/index.d.ts +1 -1
- package/dist/src/reactive/index.d.ts.map +1 -1
- package/dist/src/reactive/types.d.ts +16 -1
- package/dist/src/reactive/types.d.ts.map +1 -1
- package/dist/src/types/data.d.ts +1 -0
- package/dist/src/types/data.d.ts.map +1 -1
- package/dist/src/types/filter.d.ts +12 -13
- package/dist/src/types/filter.d.ts.map +1 -1
- package/dist/src/types/grid.d.ts +5 -4
- package/dist/src/types/grid.d.ts.map +1 -1
- package/dist/src/types/query.d.ts +3 -43
- package/dist/src/types/query.d.ts.map +1 -1
- package/dist/src/utils/stable-hash.d.ts +2 -0
- package/dist/src/utils/stable-hash.d.ts.map +1 -0
- package/package.json +2 -2
package/dist/index.cjs.js
CHANGED
|
@@ -11575,10 +11575,18 @@ class GridApiImpl {
|
|
|
11575
11575
|
}
|
|
11576
11576
|
|
|
11577
11577
|
class PluginHost {
|
|
11578
|
-
constructor(store, api) {
|
|
11578
|
+
constructor(store, api, setupContext) {
|
|
11579
11579
|
this.store = store;
|
|
11580
11580
|
this.api = api;
|
|
11581
11581
|
this.plugins = new Map();
|
|
11582
|
+
const options = setupContext?.options ?? {};
|
|
11583
|
+
this.setupContext = setupContext ?? {
|
|
11584
|
+
options,
|
|
11585
|
+
getOptions: () => options,
|
|
11586
|
+
getOptionsSnapshot: () => ({ ...options }),
|
|
11587
|
+
updateOptions: () => null,
|
|
11588
|
+
subscribeOptions: () => () => { },
|
|
11589
|
+
};
|
|
11582
11590
|
}
|
|
11583
11591
|
use(plugin) {
|
|
11584
11592
|
if (this.plugins.has(plugin.name)) {
|
|
@@ -11594,7 +11602,7 @@ class PluginHost {
|
|
|
11594
11602
|
const entry = { plugin };
|
|
11595
11603
|
this.plugins.set(plugin.name, entry);
|
|
11596
11604
|
const start = performance.now();
|
|
11597
|
-
const disposable = plugin.setup(this.store, this.api);
|
|
11605
|
+
const disposable = plugin.setup(this.store, this.api, this.setupContext);
|
|
11598
11606
|
const duration = performance.now() - start;
|
|
11599
11607
|
recordPluginTiming(plugin.name, duration);
|
|
11600
11608
|
if (disposable) {
|
|
@@ -11659,6 +11667,13 @@ function createCorePlugin(options) {
|
|
|
11659
11667
|
};
|
|
11660
11668
|
}
|
|
11661
11669
|
|
|
11670
|
+
function resolveQueryExecutionMode(mode) {
|
|
11671
|
+
return mode === 'backend' ? 'backend' : 'frontend';
|
|
11672
|
+
}
|
|
11673
|
+
function shouldDelegateQueryState(mode) {
|
|
11674
|
+
return resolveQueryExecutionMode(mode) === 'backend';
|
|
11675
|
+
}
|
|
11676
|
+
|
|
11662
11677
|
function toggleSortState(currentState, column, enableMultiSort, additive) {
|
|
11663
11678
|
const nextState = currentState.map((entry) => ({ ...entry }));
|
|
11664
11679
|
if (!enableMultiSort || !additive) {
|
|
@@ -11695,7 +11710,7 @@ function createSortPlugin(options) {
|
|
|
11695
11710
|
name: 'sort',
|
|
11696
11711
|
phase: 10,
|
|
11697
11712
|
dependencies: ['core'],
|
|
11698
|
-
setup(store, api) {
|
|
11713
|
+
setup(store, api, context) {
|
|
11699
11714
|
const usePipeline = options?.usePipeline !== false;
|
|
11700
11715
|
const initialSort = normalizeSortState(options?.initialSort ?? []);
|
|
11701
11716
|
const enableMultiSort = options?.enableMultiSort ?? false;
|
|
@@ -11713,9 +11728,8 @@ function createSortPlugin(options) {
|
|
|
11713
11728
|
initialSort,
|
|
11714
11729
|
});
|
|
11715
11730
|
}
|
|
11716
|
-
function
|
|
11717
|
-
|
|
11718
|
-
return getMode ? getMode() : 'frontend';
|
|
11731
|
+
function getQueryMode() {
|
|
11732
|
+
return resolveQueryExecutionMode(context.options.dataMode);
|
|
11719
11733
|
}
|
|
11720
11734
|
function syncToStore() {
|
|
11721
11735
|
if (!usePipeline || !mgr) {
|
|
@@ -11800,7 +11814,7 @@ function createSortPlugin(options) {
|
|
|
11800
11814
|
return sortState.find((entry) => entry.column === column)?.direction ?? null;
|
|
11801
11815
|
},
|
|
11802
11816
|
getIcons: () => ({ asc: '▲', desc: '▼' }),
|
|
11803
|
-
getMode: () =>
|
|
11817
|
+
getMode: () => getQueryMode(),
|
|
11804
11818
|
});
|
|
11805
11819
|
if (usePipeline && initialSort.length) {
|
|
11806
11820
|
syncToStore();
|
|
@@ -11812,6 +11826,13 @@ function createSortPlugin(options) {
|
|
|
11812
11826
|
};
|
|
11813
11827
|
}
|
|
11814
11828
|
|
|
11829
|
+
function buildUnexecutableFilterError(warnings = []) {
|
|
11830
|
+
const detail = warnings.filter(Boolean).join(' ');
|
|
11831
|
+
return new Error(detail
|
|
11832
|
+
? `Structured filter cannot be executed in frontend mode. ${detail}`
|
|
11833
|
+
: 'Structured filter cannot be executed in frontend mode.');
|
|
11834
|
+
}
|
|
11835
|
+
|
|
11815
11836
|
/**
|
|
11816
11837
|
* FilterCompiler - Compiles filter conditions to optimized predicates
|
|
11817
11838
|
*
|
|
@@ -12225,10 +12246,16 @@ function buildFilterAstFromModels(models, options = {}) {
|
|
|
12225
12246
|
return null;
|
|
12226
12247
|
}
|
|
12227
12248
|
const children = models
|
|
12228
|
-
.map((model) =>
|
|
12249
|
+
.map((model) => buildFilterAstNodeFromModel(model, options))
|
|
12229
12250
|
.filter((node) => node !== null);
|
|
12230
12251
|
return createFilterAst(children, 'AND', 'model');
|
|
12231
12252
|
}
|
|
12253
|
+
function buildFilterAstNodeFromModel(model, options = {}) {
|
|
12254
|
+
return modelToAstNode(model, options.columns);
|
|
12255
|
+
}
|
|
12256
|
+
function buildFilterAstFromNodes(nodes, options = {}) {
|
|
12257
|
+
return createFilterAst(nodes ?? [], options.logic ?? 'AND', options.source ?? 'api');
|
|
12258
|
+
}
|
|
12232
12259
|
function buildFilterAstFromFieldState(state, options = {}) {
|
|
12233
12260
|
if (!state?.root) {
|
|
12234
12261
|
return null;
|
|
@@ -12238,24 +12265,6 @@ function buildFilterAstFromFieldState(state, options = {}) {
|
|
|
12238
12265
|
root: fieldGroupToAstGroup(state.root, options.columns),
|
|
12239
12266
|
};
|
|
12240
12267
|
}
|
|
12241
|
-
function buildFilterAstFromSqlQuery(query, options = {}) {
|
|
12242
|
-
const node = {
|
|
12243
|
-
kind: 'sql',
|
|
12244
|
-
source: 'sql',
|
|
12245
|
-
sql: query.sql,
|
|
12246
|
-
boundSql: options.boundSql,
|
|
12247
|
-
params: options.params ? [...options.params] : undefined,
|
|
12248
|
-
};
|
|
12249
|
-
return {
|
|
12250
|
-
version: 1,
|
|
12251
|
-
root: {
|
|
12252
|
-
kind: 'group',
|
|
12253
|
-
logic: 'AND',
|
|
12254
|
-
children: [node],
|
|
12255
|
-
source: 'sql',
|
|
12256
|
-
},
|
|
12257
|
-
};
|
|
12258
|
-
}
|
|
12259
12268
|
function buildFilterAst(options) {
|
|
12260
12269
|
const nodes = [];
|
|
12261
12270
|
const baseAst = options.ast?.root
|
|
@@ -12264,12 +12273,7 @@ function buildFilterAst(options) {
|
|
|
12264
12273
|
? buildFilterAstFromFieldState(options.fieldState, options)
|
|
12265
12274
|
: options.models && options.models.length > 0
|
|
12266
12275
|
? buildFilterAstFromModels(options.models, options)
|
|
12267
|
-
:
|
|
12268
|
-
? buildFilterAstFromSqlQuery(options.sqlQuery, {
|
|
12269
|
-
boundSql: options.boundSql,
|
|
12270
|
-
params: options.params,
|
|
12271
|
-
})
|
|
12272
|
-
: null;
|
|
12276
|
+
: null;
|
|
12273
12277
|
if (baseAst?.root) {
|
|
12274
12278
|
nodes.push(baseAst.root);
|
|
12275
12279
|
}
|
|
@@ -12552,7 +12556,7 @@ function collectActiveFields(group, activeFields) {
|
|
|
12552
12556
|
}
|
|
12553
12557
|
}
|
|
12554
12558
|
function normalizeConditionValue(operator, value) {
|
|
12555
|
-
if (operator === 'between' && Array.isArray(value)) {
|
|
12559
|
+
if (operator === 'between' && Array.isArray(value) && value.length >= 2) {
|
|
12556
12560
|
return {
|
|
12557
12561
|
value: value[0],
|
|
12558
12562
|
valueTo: value[1],
|
|
@@ -12663,7 +12667,12 @@ class FilterAstCompiler {
|
|
|
12663
12667
|
this.conditionCompiler = new FilterCompiler();
|
|
12664
12668
|
this.colCount = options.colCount;
|
|
12665
12669
|
this.getValue = options.getValue;
|
|
12666
|
-
this.
|
|
12670
|
+
this.fieldToColumn = new Map();
|
|
12671
|
+
options.columns?.forEach((column, index) => {
|
|
12672
|
+
if (column.field) {
|
|
12673
|
+
this.fieldToColumn.set(column.field, index);
|
|
12674
|
+
}
|
|
12675
|
+
});
|
|
12667
12676
|
}
|
|
12668
12677
|
compile(ast) {
|
|
12669
12678
|
const warnings = [];
|
|
@@ -12708,9 +12717,6 @@ class FilterAstCompiler {
|
|
|
12708
12717
|
}
|
|
12709
12718
|
return (row) => !child(row);
|
|
12710
12719
|
}
|
|
12711
|
-
case 'sql':
|
|
12712
|
-
warnings.push('SQL AST nodes cannot be executed in frontend filtering.');
|
|
12713
|
-
return null;
|
|
12714
12720
|
}
|
|
12715
12721
|
}
|
|
12716
12722
|
compilePredicateNode(node, warnings) {
|
|
@@ -12735,15 +12741,33 @@ class FilterAstCompiler {
|
|
|
12735
12741
|
if (!columns || columns.length === 0) {
|
|
12736
12742
|
return null;
|
|
12737
12743
|
}
|
|
12744
|
+
const requiresJoinedSearch = /\s/.test(query);
|
|
12745
|
+
if (!requiresJoinedSearch) {
|
|
12746
|
+
return (row) => {
|
|
12747
|
+
for (const column of columns) {
|
|
12748
|
+
const value = this.getValue(row, column);
|
|
12749
|
+
if (value !== undefined &&
|
|
12750
|
+
value !== null &&
|
|
12751
|
+
String(value).toLowerCase().includes(query)) {
|
|
12752
|
+
return true;
|
|
12753
|
+
}
|
|
12754
|
+
}
|
|
12755
|
+
return false;
|
|
12756
|
+
};
|
|
12757
|
+
}
|
|
12738
12758
|
return (row) => {
|
|
12739
|
-
|
|
12759
|
+
let searchableText = '';
|
|
12740
12760
|
for (const column of columns) {
|
|
12741
12761
|
const value = this.getValue(row, column);
|
|
12742
12762
|
if (value !== undefined && value !== null) {
|
|
12743
|
-
|
|
12763
|
+
const normalized = String(value).toLowerCase();
|
|
12764
|
+
if (normalized.includes(query)) {
|
|
12765
|
+
return true;
|
|
12766
|
+
}
|
|
12767
|
+
searchableText = searchableText ? `${searchableText} ${normalized}` : normalized;
|
|
12744
12768
|
}
|
|
12745
12769
|
}
|
|
12746
|
-
return
|
|
12770
|
+
return searchableText.includes(query);
|
|
12747
12771
|
};
|
|
12748
12772
|
}
|
|
12749
12773
|
resolveSearchColumns(targets, warnings) {
|
|
@@ -12751,13 +12775,17 @@ class FilterAstCompiler {
|
|
|
12751
12775
|
return Array.from({ length: this.colCount }, (_, index) => index);
|
|
12752
12776
|
}
|
|
12753
12777
|
const columns = [];
|
|
12778
|
+
const seenColumns = new Set();
|
|
12754
12779
|
for (const target of targets) {
|
|
12755
12780
|
const column = this.resolveColumn(target);
|
|
12756
12781
|
if (column === undefined) {
|
|
12757
12782
|
warnings.push('AST search target is missing a column reference for frontend execution.');
|
|
12758
12783
|
return null;
|
|
12759
12784
|
}
|
|
12760
|
-
|
|
12785
|
+
if (!seenColumns.has(column)) {
|
|
12786
|
+
seenColumns.add(column);
|
|
12787
|
+
columns.push(column);
|
|
12788
|
+
}
|
|
12761
12789
|
}
|
|
12762
12790
|
return columns;
|
|
12763
12791
|
}
|
|
@@ -12765,11 +12793,10 @@ class FilterAstCompiler {
|
|
|
12765
12793
|
if (typeof target.column === 'number') {
|
|
12766
12794
|
return target.column;
|
|
12767
12795
|
}
|
|
12768
|
-
if (!target.field
|
|
12796
|
+
if (!target.field) {
|
|
12769
12797
|
return undefined;
|
|
12770
12798
|
}
|
|
12771
|
-
|
|
12772
|
-
return column >= 0 ? column : undefined;
|
|
12799
|
+
return this.fieldToColumn.get(target.field);
|
|
12773
12800
|
}
|
|
12774
12801
|
toFilterCondition(node, warnings) {
|
|
12775
12802
|
const sourceOperator = typeof node.sourceOperator === 'string' && isSupportedFilterOperator(node.sourceOperator)
|
|
@@ -12808,6 +12835,120 @@ function dedupeWarnings$1(warnings) {
|
|
|
12808
12835
|
return Array.from(new Set(warnings));
|
|
12809
12836
|
}
|
|
12810
12837
|
|
|
12838
|
+
const FNV_OFFSET_BASIS = 0x811c9dc5;
|
|
12839
|
+
const FNV_PRIME = 0x01000193;
|
|
12840
|
+
function stableHashValue(value) {
|
|
12841
|
+
const hasher = new StableHasher();
|
|
12842
|
+
const seen = new WeakSet();
|
|
12843
|
+
hashValue(hasher, value, seen);
|
|
12844
|
+
return hasher.digest();
|
|
12845
|
+
}
|
|
12846
|
+
class StableHasher {
|
|
12847
|
+
constructor() {
|
|
12848
|
+
this.hash = FNV_OFFSET_BASIS;
|
|
12849
|
+
}
|
|
12850
|
+
write(token) {
|
|
12851
|
+
for (let index = 0; index < token.length; index += 1) {
|
|
12852
|
+
this.hash ^= token.charCodeAt(index);
|
|
12853
|
+
this.hash = Math.imul(this.hash, FNV_PRIME);
|
|
12854
|
+
}
|
|
12855
|
+
}
|
|
12856
|
+
digest() {
|
|
12857
|
+
return (this.hash >>> 0).toString(16).padStart(8, '0');
|
|
12858
|
+
}
|
|
12859
|
+
}
|
|
12860
|
+
function hashValue(hasher, value, seen) {
|
|
12861
|
+
if (value === null) {
|
|
12862
|
+
hasher.write('null');
|
|
12863
|
+
return;
|
|
12864
|
+
}
|
|
12865
|
+
if (value === undefined) {
|
|
12866
|
+
hasher.write('undefined');
|
|
12867
|
+
return;
|
|
12868
|
+
}
|
|
12869
|
+
if (value instanceof Date) {
|
|
12870
|
+
hasher.write('date');
|
|
12871
|
+
hasher.write(value.toISOString());
|
|
12872
|
+
return;
|
|
12873
|
+
}
|
|
12874
|
+
if (Array.isArray(value)) {
|
|
12875
|
+
hasher.write('array[');
|
|
12876
|
+
for (const item of value) {
|
|
12877
|
+
hashValue(hasher, item, seen);
|
|
12878
|
+
hasher.write(',');
|
|
12879
|
+
}
|
|
12880
|
+
hasher.write(']');
|
|
12881
|
+
return;
|
|
12882
|
+
}
|
|
12883
|
+
switch (typeof value) {
|
|
12884
|
+
case 'string':
|
|
12885
|
+
hasher.write('string');
|
|
12886
|
+
hasher.write(value);
|
|
12887
|
+
return;
|
|
12888
|
+
case 'number':
|
|
12889
|
+
hasher.write('number');
|
|
12890
|
+
hasher.write(Number.isFinite(value) ? value.toString() : String(value));
|
|
12891
|
+
return;
|
|
12892
|
+
case 'boolean':
|
|
12893
|
+
hasher.write(value ? 'true' : 'false');
|
|
12894
|
+
return;
|
|
12895
|
+
case 'bigint':
|
|
12896
|
+
hasher.write('bigint');
|
|
12897
|
+
hasher.write(value.toString());
|
|
12898
|
+
return;
|
|
12899
|
+
case 'symbol':
|
|
12900
|
+
hasher.write('symbol');
|
|
12901
|
+
hasher.write(value.description ?? '');
|
|
12902
|
+
return;
|
|
12903
|
+
case 'function':
|
|
12904
|
+
hasher.write('function');
|
|
12905
|
+
hasher.write(value.name);
|
|
12906
|
+
return;
|
|
12907
|
+
case 'object':
|
|
12908
|
+
break;
|
|
12909
|
+
default:
|
|
12910
|
+
hasher.write(String(value));
|
|
12911
|
+
return;
|
|
12912
|
+
}
|
|
12913
|
+
if (seen.has(value)) {
|
|
12914
|
+
hasher.write('[Circular]');
|
|
12915
|
+
return;
|
|
12916
|
+
}
|
|
12917
|
+
seen.add(value);
|
|
12918
|
+
hasher.write('{');
|
|
12919
|
+
const entries = Object.entries(value).sort(([left], [right]) => left.localeCompare(right));
|
|
12920
|
+
for (const [key, nested] of entries) {
|
|
12921
|
+
hasher.write(key);
|
|
12922
|
+
hasher.write(':');
|
|
12923
|
+
hashValue(hasher, nested, seen);
|
|
12924
|
+
hasher.write(';');
|
|
12925
|
+
}
|
|
12926
|
+
hasher.write('}');
|
|
12927
|
+
seen.delete(value);
|
|
12928
|
+
}
|
|
12929
|
+
|
|
12930
|
+
const filterAstSignatureCache = new WeakMap();
|
|
12931
|
+
function getFilterAstSignature(ast) {
|
|
12932
|
+
if (!ast?.root) {
|
|
12933
|
+
return '';
|
|
12934
|
+
}
|
|
12935
|
+
const cached = filterAstSignatureCache.get(ast);
|
|
12936
|
+
if (cached) {
|
|
12937
|
+
return cached;
|
|
12938
|
+
}
|
|
12939
|
+
const signature = stableHashValue(ast.root);
|
|
12940
|
+
filterAstSignatureCache.set(ast, signature);
|
|
12941
|
+
return signature;
|
|
12942
|
+
}
|
|
12943
|
+
function buildFilterStateSignature(executionMode, models, ast) {
|
|
12944
|
+
if (executionMode === 'none' && models.length === 0 && !ast?.root) {
|
|
12945
|
+
return '';
|
|
12946
|
+
}
|
|
12947
|
+
const modelSignature = models.length > 0 ? stableHashValue(models) : '';
|
|
12948
|
+
const astSignature = executionMode === 'column' || executionMode === 'none' ? '' : getFilterAstSignature(ast);
|
|
12949
|
+
return `mode:${executionMode}|models:${modelSignature}|ast:${astSignature}`;
|
|
12950
|
+
}
|
|
12951
|
+
|
|
12811
12952
|
/**
|
|
12812
12953
|
* FilterCore - Core filter state management
|
|
12813
12954
|
*
|
|
@@ -12817,7 +12958,9 @@ function dedupeWarnings$1(warnings) {
|
|
|
12817
12958
|
class FilterCore {
|
|
12818
12959
|
constructor(colCount, getValue, columns, events, onFilterStateChange) {
|
|
12819
12960
|
this.columnFilters = new Map();
|
|
12961
|
+
this.columnAstNodes = new Map();
|
|
12820
12962
|
this.filterState = [];
|
|
12963
|
+
this.filterStateSnapshot = [];
|
|
12821
12964
|
this.filterStateHash = '';
|
|
12822
12965
|
this.filterAst = null;
|
|
12823
12966
|
this.astProjectionWarnings = [];
|
|
@@ -12829,6 +12972,7 @@ class FilterCore {
|
|
|
12829
12972
|
this.columns = columns;
|
|
12830
12973
|
this.events = events;
|
|
12831
12974
|
this.onFilterStateChange = onFilterStateChange;
|
|
12975
|
+
this.astCompiler = this.createAstCompiler();
|
|
12832
12976
|
}
|
|
12833
12977
|
/**
|
|
12834
12978
|
* Initialize with filter models
|
|
@@ -12848,8 +12992,9 @@ class FilterCore {
|
|
|
12848
12992
|
this.clearColumnFilter(column);
|
|
12849
12993
|
return;
|
|
12850
12994
|
}
|
|
12851
|
-
|
|
12852
|
-
this.
|
|
12995
|
+
const filter = this.createColumnFilter(column, conditions, logic);
|
|
12996
|
+
this.columnFilters.set(column, filter);
|
|
12997
|
+
this.syncStateFromColumnModel(filter.getModel());
|
|
12853
12998
|
this.emitFilterChange();
|
|
12854
12999
|
}
|
|
12855
13000
|
/**
|
|
@@ -12857,18 +13002,25 @@ class FilterCore {
|
|
|
12857
13002
|
*/
|
|
12858
13003
|
setFilterModels(models, options = {}) {
|
|
12859
13004
|
this.columnFilters.clear();
|
|
13005
|
+
this.columnAstNodes.clear();
|
|
13006
|
+
const nextState = [];
|
|
12860
13007
|
for (const model of models) {
|
|
12861
13008
|
if (!model.conditions || model.conditions.length === 0) {
|
|
12862
13009
|
continue;
|
|
12863
13010
|
}
|
|
12864
13011
|
this.assertColumnInBounds(model.column);
|
|
12865
|
-
|
|
12866
|
-
|
|
12867
|
-
|
|
13012
|
+
const filter = this.createColumnFilter(model.column, model.conditions, model.logic ?? 'AND');
|
|
13013
|
+
const nextModel = filter.getModel();
|
|
13014
|
+
this.columnFilters.set(nextModel.column, filter);
|
|
13015
|
+
this.upsertFilterState(nextModel, nextState);
|
|
13016
|
+
this.upsertColumnAstNode(nextModel);
|
|
13017
|
+
}
|
|
13018
|
+
this.filterState = nextState;
|
|
13019
|
+
this.refreshFilterStateSnapshot();
|
|
12868
13020
|
this.filterAst =
|
|
12869
13021
|
options.ast !== undefined
|
|
12870
13022
|
? options.ast
|
|
12871
|
-
:
|
|
13023
|
+
: buildFilterAstFromNodes(Array.from(this.columnAstNodes.values()), { source: 'model' });
|
|
12872
13024
|
this.astProjectionWarnings = dedupeWarnings(options.projectionWarnings ?? []);
|
|
12873
13025
|
this.syncExecutionState();
|
|
12874
13026
|
this.filterStateHash = this.buildFilterStateHash();
|
|
@@ -12892,16 +13044,40 @@ class FilterCore {
|
|
|
12892
13044
|
*/
|
|
12893
13045
|
setColumns(columns) {
|
|
12894
13046
|
this.columns = columns;
|
|
13047
|
+
this.astCompiler = this.createAstCompiler();
|
|
12895
13048
|
if (this.filterAst) {
|
|
13049
|
+
if (this.executionMode === 'column' && this.filterState.length > 0) {
|
|
13050
|
+
this.rebuildColumnAstNodes();
|
|
13051
|
+
this.filterAst = buildFilterAstFromNodes(Array.from(this.columnAstNodes.values()), {
|
|
13052
|
+
source: 'model',
|
|
13053
|
+
});
|
|
13054
|
+
this.filterStateHash = this.buildFilterStateHash();
|
|
13055
|
+
return;
|
|
13056
|
+
}
|
|
12896
13057
|
this.setFilterAst(this.filterAst);
|
|
12897
13058
|
return;
|
|
12898
13059
|
}
|
|
12899
13060
|
if (this.filterState.length > 0) {
|
|
12900
|
-
this.
|
|
12901
|
-
this.
|
|
13061
|
+
this.rebuildColumnAstNodes();
|
|
13062
|
+
this.filterAst = buildFilterAstFromNodes(Array.from(this.columnAstNodes.values()), {
|
|
13063
|
+
source: 'model',
|
|
13064
|
+
});
|
|
12902
13065
|
this.filterStateHash = this.buildFilterStateHash();
|
|
12903
13066
|
}
|
|
12904
13067
|
}
|
|
13068
|
+
setColCount(colCount) {
|
|
13069
|
+
this.colCount = colCount;
|
|
13070
|
+
this.astCompiler = this.createAstCompiler();
|
|
13071
|
+
if (!this.filterAst) {
|
|
13072
|
+
return;
|
|
13073
|
+
}
|
|
13074
|
+
if (this.executionMode === 'column') {
|
|
13075
|
+
this.filterStateHash = this.buildFilterStateHash();
|
|
13076
|
+
return;
|
|
13077
|
+
}
|
|
13078
|
+
this.syncExecutionState();
|
|
13079
|
+
this.filterStateHash = this.buildFilterStateHash();
|
|
13080
|
+
}
|
|
12905
13081
|
/**
|
|
12906
13082
|
* Clear filter for a column
|
|
12907
13083
|
* @param column - Column index
|
|
@@ -12909,7 +13085,7 @@ class FilterCore {
|
|
|
12909
13085
|
clearColumnFilter(column) {
|
|
12910
13086
|
if (this.columnFilters.has(column)) {
|
|
12911
13087
|
this.columnFilters.delete(column);
|
|
12912
|
-
this.
|
|
13088
|
+
this.removeColumnState(column);
|
|
12913
13089
|
this.emitFilterChange();
|
|
12914
13090
|
}
|
|
12915
13091
|
}
|
|
@@ -12918,7 +13094,9 @@ class FilterCore {
|
|
|
12918
13094
|
*/
|
|
12919
13095
|
clearAll() {
|
|
12920
13096
|
this.columnFilters.clear();
|
|
13097
|
+
this.columnAstNodes.clear();
|
|
12921
13098
|
this.filterState = [];
|
|
13099
|
+
this.refreshFilterStateSnapshot();
|
|
12922
13100
|
this.filterStateHash = '';
|
|
12923
13101
|
this.filterAst = null;
|
|
12924
13102
|
this.astProjectionWarnings = [];
|
|
@@ -12934,9 +13112,12 @@ class FilterCore {
|
|
|
12934
13112
|
* @returns True if row passes filter
|
|
12935
13113
|
*/
|
|
12936
13114
|
testRow(row) {
|
|
12937
|
-
if (this.executionMode === 'none'
|
|
13115
|
+
if (this.executionMode === 'none') {
|
|
12938
13116
|
return true;
|
|
12939
13117
|
}
|
|
13118
|
+
if (this.executionMode === 'unexecutable') {
|
|
13119
|
+
throw buildUnexecutableFilterError(this.astExecutionWarnings);
|
|
13120
|
+
}
|
|
12940
13121
|
if (this.executionMode === 'ast') {
|
|
12941
13122
|
return this.compiledAstPredicate ? this.compiledAstPredicate(row) : true;
|
|
12942
13123
|
}
|
|
@@ -12954,6 +13135,9 @@ class FilterCore {
|
|
|
12954
13135
|
* @returns Array of visible row indices
|
|
12955
13136
|
*/
|
|
12956
13137
|
getVisibleRowsBasic(rowCount) {
|
|
13138
|
+
if (this.executionMode === 'unexecutable') {
|
|
13139
|
+
throw buildUnexecutableFilterError(this.astExecutionWarnings);
|
|
13140
|
+
}
|
|
12957
13141
|
const visible = [];
|
|
12958
13142
|
for (let row = 0; row < rowCount; row++) {
|
|
12959
13143
|
if (this.testRow(row)) {
|
|
@@ -12966,7 +13150,7 @@ class FilterCore {
|
|
|
12966
13150
|
* Get current legacy FilterModel state
|
|
12967
13151
|
*/
|
|
12968
13152
|
getFilterState() {
|
|
12969
|
-
return
|
|
13153
|
+
return this.filterStateSnapshot;
|
|
12970
13154
|
}
|
|
12971
13155
|
/**
|
|
12972
13156
|
* Get the canonical filter AST state
|
|
@@ -12996,7 +13180,7 @@ class FilterCore {
|
|
|
12996
13180
|
* Check if any frontend-evaluable filters are active
|
|
12997
13181
|
*/
|
|
12998
13182
|
hasActiveFilters() {
|
|
12999
|
-
return this.executionMode
|
|
13183
|
+
return this.executionMode !== 'none';
|
|
13000
13184
|
}
|
|
13001
13185
|
/**
|
|
13002
13186
|
* Check if any canonical filters are active, even if the current frontend evaluator
|
|
@@ -13047,23 +13231,12 @@ class FilterCore {
|
|
|
13047
13231
|
previousFilterState: [],
|
|
13048
13232
|
});
|
|
13049
13233
|
}
|
|
13050
|
-
/**
|
|
13051
|
-
* Rebuild legacy models and the canonical AST from column filters.
|
|
13052
|
-
*/
|
|
13053
|
-
syncStateFromColumnFilters() {
|
|
13054
|
-
this.filterState = Array.from(this.columnFilters.values()).map((filter) => filter.getModel());
|
|
13055
|
-
this.filterAst = buildFilterAstFromModels(this.filterState, { columns: this.columns });
|
|
13056
|
-
this.astProjectionWarnings = [];
|
|
13057
|
-
this.syncExecutionState();
|
|
13058
|
-
this.filterStateHash = this.buildFilterStateHash();
|
|
13059
|
-
this.notifyFilterStateChange();
|
|
13060
|
-
}
|
|
13061
13234
|
createColumnFilter(column, conditions, logic) {
|
|
13062
13235
|
return new ColumnFilter({
|
|
13063
13236
|
column,
|
|
13064
13237
|
conditions,
|
|
13065
13238
|
logic,
|
|
13066
|
-
onChange: () => this.
|
|
13239
|
+
onChange: (model) => this.syncStateFromColumnModel(model),
|
|
13067
13240
|
});
|
|
13068
13241
|
}
|
|
13069
13242
|
syncExecutionState() {
|
|
@@ -13077,11 +13250,7 @@ class FilterCore {
|
|
|
13077
13250
|
this.executionMode = 'column';
|
|
13078
13251
|
return;
|
|
13079
13252
|
}
|
|
13080
|
-
const compiled =
|
|
13081
|
-
colCount: this.colCount,
|
|
13082
|
-
getValue: this.getValue,
|
|
13083
|
-
columns: this.columns,
|
|
13084
|
-
}).compile(this.filterAst);
|
|
13253
|
+
const compiled = this.astCompiler.compile(this.filterAst);
|
|
13085
13254
|
this.astExecutionWarnings = compiled.warnings;
|
|
13086
13255
|
if (compiled.predicate) {
|
|
13087
13256
|
this.compiledAstPredicate = compiled.predicate;
|
|
@@ -13091,14 +13260,7 @@ class FilterCore {
|
|
|
13091
13260
|
this.executionMode = 'unexecutable';
|
|
13092
13261
|
}
|
|
13093
13262
|
buildFilterStateHash() {
|
|
13094
|
-
|
|
13095
|
-
return '';
|
|
13096
|
-
}
|
|
13097
|
-
return JSON.stringify({
|
|
13098
|
-
mode: this.executionMode,
|
|
13099
|
-
models: this.filterState,
|
|
13100
|
-
ast: this.filterAst,
|
|
13101
|
-
});
|
|
13263
|
+
return buildFilterStateSignature(this.executionMode, this.filterState, this.filterAst);
|
|
13102
13264
|
}
|
|
13103
13265
|
assertColumnInBounds(column) {
|
|
13104
13266
|
if (column < 0 || column >= this.colCount) {
|
|
@@ -13110,6 +13272,64 @@ class FilterCore {
|
|
|
13110
13272
|
this.onFilterStateChange();
|
|
13111
13273
|
}
|
|
13112
13274
|
}
|
|
13275
|
+
syncStateFromColumnModel(model) {
|
|
13276
|
+
this.upsertFilterState(model);
|
|
13277
|
+
this.upsertColumnAstNode(model);
|
|
13278
|
+
this.syncColumnDerivedState();
|
|
13279
|
+
}
|
|
13280
|
+
removeColumnState(column) {
|
|
13281
|
+
const index = this.filterState.findIndex((model) => model.column === column);
|
|
13282
|
+
if (index >= 0) {
|
|
13283
|
+
this.filterState.splice(index, 1);
|
|
13284
|
+
}
|
|
13285
|
+
this.columnAstNodes.delete(column);
|
|
13286
|
+
this.syncColumnDerivedState();
|
|
13287
|
+
}
|
|
13288
|
+
syncColumnDerivedState() {
|
|
13289
|
+
this.filterAst = buildFilterAstFromNodes(Array.from(this.columnAstNodes.values()), {
|
|
13290
|
+
source: 'model',
|
|
13291
|
+
});
|
|
13292
|
+
this.astProjectionWarnings = [];
|
|
13293
|
+
this.astExecutionWarnings = [];
|
|
13294
|
+
this.compiledAstPredicate = null;
|
|
13295
|
+
this.executionMode = this.filterState.length === 0 ? 'none' : 'column';
|
|
13296
|
+
this.refreshFilterStateSnapshot();
|
|
13297
|
+
this.filterStateHash = this.buildFilterStateHash();
|
|
13298
|
+
this.notifyFilterStateChange();
|
|
13299
|
+
}
|
|
13300
|
+
upsertFilterState(model, target = this.filterState) {
|
|
13301
|
+
const index = target.findIndex((candidate) => candidate.column === model.column);
|
|
13302
|
+
if (index >= 0) {
|
|
13303
|
+
target[index] = model;
|
|
13304
|
+
return;
|
|
13305
|
+
}
|
|
13306
|
+
target.push(model);
|
|
13307
|
+
}
|
|
13308
|
+
upsertColumnAstNode(model) {
|
|
13309
|
+
const astNode = buildFilterAstNodeFromModel(model, { columns: this.columns });
|
|
13310
|
+
if (astNode) {
|
|
13311
|
+
this.columnAstNodes.set(model.column, astNode);
|
|
13312
|
+
}
|
|
13313
|
+
else {
|
|
13314
|
+
this.columnAstNodes.delete(model.column);
|
|
13315
|
+
}
|
|
13316
|
+
}
|
|
13317
|
+
rebuildColumnAstNodes() {
|
|
13318
|
+
this.columnAstNodes.clear();
|
|
13319
|
+
for (const model of this.filterState) {
|
|
13320
|
+
this.upsertColumnAstNode(model);
|
|
13321
|
+
}
|
|
13322
|
+
}
|
|
13323
|
+
refreshFilterStateSnapshot() {
|
|
13324
|
+
this.filterStateSnapshot = Object.freeze([...this.filterState]);
|
|
13325
|
+
}
|
|
13326
|
+
createAstCompiler() {
|
|
13327
|
+
return new FilterAstCompiler({
|
|
13328
|
+
colCount: this.colCount,
|
|
13329
|
+
getValue: this.getValue,
|
|
13330
|
+
columns: this.columns,
|
|
13331
|
+
});
|
|
13332
|
+
}
|
|
13113
13333
|
}
|
|
13114
13334
|
function dedupeWarnings(warnings) {
|
|
13115
13335
|
return Array.from(new Set(warnings));
|
|
@@ -15593,12 +15813,14 @@ function inferValueType(value, valueTo) {
|
|
|
15593
15813
|
* FilterQueryHandler - SQL-like query parsing and expression management.
|
|
15594
15814
|
*/
|
|
15595
15815
|
class FilterQueryHandler {
|
|
15596
|
-
constructor(core, columnNames, columns, events) {
|
|
15816
|
+
constructor(core, columnNames, columns, events, getFieldFilterState, getFilterExport) {
|
|
15597
15817
|
this.currentExpression = null;
|
|
15598
15818
|
this.core = core;
|
|
15599
15819
|
this.columnNames = columnNames;
|
|
15600
15820
|
this.columns = columns;
|
|
15601
15821
|
this.events = events;
|
|
15822
|
+
this.getFieldFilterState = getFieldFilterState;
|
|
15823
|
+
this.getFilterExport = getFilterExport;
|
|
15602
15824
|
this.parser = new FilterQueryParser();
|
|
15603
15825
|
if (this.columnNames.length > 0) {
|
|
15604
15826
|
const columnMapping = {};
|
|
@@ -15618,16 +15840,17 @@ class FilterQueryHandler {
|
|
|
15618
15840
|
return;
|
|
15619
15841
|
}
|
|
15620
15842
|
try {
|
|
15621
|
-
const
|
|
15843
|
+
const parsedExpression = this.parseFilterInput(filter);
|
|
15844
|
+
this.core.setFilterAst(parsedExpression.ast ?? null);
|
|
15845
|
+
const expression = this.buildCurrentExpression(parsedExpression);
|
|
15622
15846
|
this.currentExpression = expression;
|
|
15623
|
-
this.core.setFilterAst(expression.ast ?? null);
|
|
15624
15847
|
if (this.events) {
|
|
15625
15848
|
this.events.emit('filter:start', {
|
|
15626
15849
|
timestamp: Date.now(),
|
|
15627
15850
|
filter: expression,
|
|
15628
15851
|
});
|
|
15629
15852
|
}
|
|
15630
|
-
await this.applyFrontendFilter(
|
|
15853
|
+
await this.applyFrontendFilter();
|
|
15631
15854
|
if (this.events) {
|
|
15632
15855
|
this.events.emit('filter:end', {
|
|
15633
15856
|
timestamp: Date.now(),
|
|
@@ -15658,6 +15881,20 @@ class FilterQueryHandler {
|
|
|
15658
15881
|
models: filter,
|
|
15659
15882
|
};
|
|
15660
15883
|
}
|
|
15884
|
+
buildCurrentExpression(parsedExpression) {
|
|
15885
|
+
const hasColumns = Array.isArray(this.columns) && this.columns.length > 0;
|
|
15886
|
+
return {
|
|
15887
|
+
type: parsedExpression.type,
|
|
15888
|
+
ast: this.core.getFilterAst(),
|
|
15889
|
+
sql: parsedExpression.sql,
|
|
15890
|
+
boundSql: parsedExpression.boundSql,
|
|
15891
|
+
params: parsedExpression.params,
|
|
15892
|
+
models: this.core.getFilterState(),
|
|
15893
|
+
quickFilter: parsedExpression.quickFilter,
|
|
15894
|
+
fieldState: hasColumns ? (this.getFieldFilterState?.() ?? null) : null,
|
|
15895
|
+
filterExport: hasColumns ? (this.getFilterExport?.() ?? null) : null,
|
|
15896
|
+
};
|
|
15897
|
+
}
|
|
15661
15898
|
/**
|
|
15662
15899
|
* Type guard for FilterQuery.
|
|
15663
15900
|
*/
|
|
@@ -15667,18 +15904,11 @@ class FilterQueryHandler {
|
|
|
15667
15904
|
/**
|
|
15668
15905
|
* Apply frontend filtering (in-memory).
|
|
15669
15906
|
*/
|
|
15670
|
-
async applyFrontendFilter(
|
|
15907
|
+
async applyFrontendFilter() {
|
|
15671
15908
|
const projectionWarnings = this.core.getAstProjectionWarnings();
|
|
15672
15909
|
const executionWarnings = this.core.getAstExecutionWarnings();
|
|
15673
15910
|
if (this.core.hasUnexecutableFilters()) {
|
|
15674
|
-
|
|
15675
|
-
console.warn('Frontend SQL filtering remains compatibility-only. ' +
|
|
15676
|
-
'The canonical filter is preserved in filter.ast and filter.expression.');
|
|
15677
|
-
}
|
|
15678
|
-
for (const warning of executionWarnings) {
|
|
15679
|
-
console.warn(`FilterQueryHandler: ${warning}`);
|
|
15680
|
-
}
|
|
15681
|
-
return;
|
|
15911
|
+
throw buildUnexecutableFilterError(executionWarnings);
|
|
15682
15912
|
}
|
|
15683
15913
|
if (!this.core.isUsingAstExecution() || projectionWarnings.length === 0) {
|
|
15684
15914
|
return;
|
|
@@ -15720,8 +15950,8 @@ class FilterQueryHandler {
|
|
|
15720
15950
|
class FilterManager {
|
|
15721
15951
|
constructor(options) {
|
|
15722
15952
|
this.core = new FilterCore(options.colCount, options.getValue, options.columns, options.events, () => this.optimizer?.invalidateCache());
|
|
15723
|
-
this.query = new FilterQueryHandler(this.core, options.columnNames || [], options.columns, options.events);
|
|
15724
15953
|
this.exporter = new FilterExporter(this.core, options.enableExport ?? true, options.columns, options.exportConfig);
|
|
15954
|
+
this.query = new FilterQueryHandler(this.core, options.columnNames || [], options.columns, options.events, () => this.exporter.getFieldFilterState(), () => this.exporter.getFilterExport());
|
|
15725
15955
|
this.optimizer = new FilterOptimizer(this.core, options.getValue, options.enableOptimizations ?? true, {
|
|
15726
15956
|
enableCache: options.enableCache,
|
|
15727
15957
|
cacheCapacity: options.cacheCapacity,
|
|
@@ -15818,6 +16048,9 @@ class FilterManager {
|
|
|
15818
16048
|
this.query.setColumns(columns);
|
|
15819
16049
|
this.exporter.setColumns(columns);
|
|
15820
16050
|
}
|
|
16051
|
+
setColCount(colCount) {
|
|
16052
|
+
this.core.setColCount(colCount);
|
|
16053
|
+
}
|
|
15821
16054
|
// ==================== Optimization Methods ====================
|
|
15822
16055
|
setDataVersion(version) {
|
|
15823
16056
|
this.optimizer.setDataVersion(version);
|
|
@@ -15865,22 +16098,23 @@ function createFilterPlugin(options) {
|
|
|
15865
16098
|
name: 'filter',
|
|
15866
16099
|
phase: 20,
|
|
15867
16100
|
dependencies: ['core'],
|
|
15868
|
-
setup(store, api) {
|
|
16101
|
+
setup(store, api, context) {
|
|
15869
16102
|
store.extend('filter.state', [], 'filter');
|
|
15870
16103
|
store.extend('filter.ast', null, 'filter');
|
|
15871
16104
|
store.extend('filter.quickFilter', { query: '', columns: null }, 'filter');
|
|
15872
16105
|
store.extend('filter.expression', null, 'filter');
|
|
15873
16106
|
store.extend('pipeline.filter', undefined, 'filter', 20);
|
|
15874
16107
|
const usePipeline = options?.usePipeline !== false;
|
|
15875
|
-
|
|
16108
|
+
const getColumns = () => context.options.columns ?? options?.columns;
|
|
16109
|
+
const getColCount = () => context.options.colCount ?? options?.colCount ?? 0;
|
|
16110
|
+
let mgr = createManager(getColCount());
|
|
15876
16111
|
// Quick filter state
|
|
15877
16112
|
let quickFilterQuery = '';
|
|
15878
16113
|
let quickFilterColumns = null;
|
|
15879
16114
|
let quickFilterCache = null;
|
|
15880
16115
|
let quickFilterCacheKey = null;
|
|
15881
|
-
function
|
|
15882
|
-
|
|
15883
|
-
return getMode ? getMode() : 'frontend';
|
|
16116
|
+
function getQueryMode() {
|
|
16117
|
+
return resolveQueryExecutionMode(context.options.dataMode);
|
|
15884
16118
|
}
|
|
15885
16119
|
function createManager(colCount, dataAccessor) {
|
|
15886
16120
|
const getValue = dataAccessor
|
|
@@ -15892,7 +16126,7 @@ function createFilterPlugin(options) {
|
|
|
15892
16126
|
return new FilterManager({
|
|
15893
16127
|
colCount,
|
|
15894
16128
|
getValue,
|
|
15895
|
-
columns:
|
|
16129
|
+
columns: getColumns(),
|
|
15896
16130
|
enableExport: options?.enableExport ?? true,
|
|
15897
16131
|
});
|
|
15898
16132
|
}
|
|
@@ -15907,14 +16141,15 @@ function createFilterPlugin(options) {
|
|
|
15907
16141
|
};
|
|
15908
16142
|
}
|
|
15909
16143
|
function buildExpression() {
|
|
15910
|
-
const
|
|
16144
|
+
const columns = getColumns();
|
|
16145
|
+
const hasColumns = Array.isArray(columns) && columns.length > 0;
|
|
15911
16146
|
return buildModelFilterExpression({
|
|
15912
16147
|
models: mgr.getFilterState(),
|
|
15913
16148
|
quickFilter: getQuickFilterState(),
|
|
15914
16149
|
fieldState: hasColumns ? mgr.getFieldFilterState() : null,
|
|
15915
16150
|
filterExport: hasColumns ? mgr.getFilterExport() : null,
|
|
15916
16151
|
ast: mgr.getFilterAst(),
|
|
15917
|
-
columns
|
|
16152
|
+
columns,
|
|
15918
16153
|
});
|
|
15919
16154
|
}
|
|
15920
16155
|
function persistState() {
|
|
@@ -15939,12 +16174,22 @@ function createFilterPlugin(options) {
|
|
|
15939
16174
|
if (quickFilterColumns && quickFilterColumns.length > 0) {
|
|
15940
16175
|
return quickFilterColumns;
|
|
15941
16176
|
}
|
|
15942
|
-
const
|
|
15943
|
-
|
|
15944
|
-
|
|
16177
|
+
const columns = getColumns();
|
|
16178
|
+
const colCount = getColCount();
|
|
16179
|
+
if (columns && columns.length > 0) {
|
|
16180
|
+
return columns.map((_c, index) => index);
|
|
15945
16181
|
}
|
|
15946
16182
|
return Array.from({ length: colCount }, (_, i) => i);
|
|
15947
16183
|
}
|
|
16184
|
+
const unsubscribeOptions = context.subscribeOptions((change) => {
|
|
16185
|
+
if (!change.changedKeys.includes('columns') && !change.changedKeys.includes('colCount')) {
|
|
16186
|
+
return;
|
|
16187
|
+
}
|
|
16188
|
+
mgr.setColumns(getColumns() ?? []);
|
|
16189
|
+
mgr.setColCount(getColCount());
|
|
16190
|
+
clearQuickFilterCache();
|
|
16191
|
+
applyFilter();
|
|
16192
|
+
});
|
|
15948
16193
|
function ensureQuickFilterCache(columns) {
|
|
15949
16194
|
const cacheKey = columns.join(',');
|
|
15950
16195
|
if (quickFilterCache && quickFilterCacheKey === cacheKey) {
|
|
@@ -15991,23 +16236,31 @@ function createFilterPlugin(options) {
|
|
|
15991
16236
|
return matches;
|
|
15992
16237
|
}
|
|
15993
16238
|
function applyFilter() {
|
|
15994
|
-
const
|
|
16239
|
+
const hasStructuredFilters = mgr.hasStructuredFilters();
|
|
15995
16240
|
const hasQuickFilter = quickFilterQuery.trim().length > 0;
|
|
15996
16241
|
const expression = persistState();
|
|
15997
16242
|
if (!usePipeline) {
|
|
15998
16243
|
store.set('pipeline.filter', undefined);
|
|
15999
16244
|
return expression;
|
|
16000
16245
|
}
|
|
16001
|
-
if (!
|
|
16246
|
+
if (!hasStructuredFilters && !hasQuickFilter) {
|
|
16002
16247
|
store.set('pipeline.filter', undefined);
|
|
16003
16248
|
warnOnStructuredProjection();
|
|
16004
16249
|
return expression;
|
|
16005
16250
|
}
|
|
16251
|
+
if (mgr.hasUnexecutableFilters()) {
|
|
16252
|
+
const error = buildUnexecutableFilterError(mgr.getAstExecutionWarnings());
|
|
16253
|
+
api.fireEvent('filter:error', {
|
|
16254
|
+
timestamp: Date.now(),
|
|
16255
|
+
error,
|
|
16256
|
+
});
|
|
16257
|
+
throw error;
|
|
16258
|
+
}
|
|
16006
16259
|
const rowCount = store.get('rows.count');
|
|
16007
16260
|
const input = store.getUnphased('pipeline.sort') ??
|
|
16008
16261
|
store.get('rows.indices');
|
|
16009
16262
|
let result = input;
|
|
16010
|
-
if (
|
|
16263
|
+
if (hasStructuredFilters) {
|
|
16011
16264
|
const visibleSet = new Set(mgr.getVisibleRows(rowCount));
|
|
16012
16265
|
result = result.filter((idx) => visibleSet.has(idx));
|
|
16013
16266
|
}
|
|
@@ -16022,7 +16275,10 @@ function createFilterPlugin(options) {
|
|
|
16022
16275
|
const prev = mgr.getFilterState();
|
|
16023
16276
|
mgr.setColumnFilter(col, conditions, logic);
|
|
16024
16277
|
applyFilter();
|
|
16025
|
-
api.fireEvent('filter:change', {
|
|
16278
|
+
api.fireEvent('filter:change', {
|
|
16279
|
+
filterState: mgr.getFilterState(),
|
|
16280
|
+
previousFilterState: prev,
|
|
16281
|
+
});
|
|
16026
16282
|
}, 'filter');
|
|
16027
16283
|
store.action('filter:clear', () => {
|
|
16028
16284
|
const prev = mgr.getFilterState();
|
|
@@ -16038,7 +16294,10 @@ function createFilterPlugin(options) {
|
|
|
16038
16294
|
const prev = mgr.getFilterState();
|
|
16039
16295
|
mgr.clearColumnFilter(col);
|
|
16040
16296
|
applyFilter();
|
|
16041
|
-
api.fireEvent('filter:change', {
|
|
16297
|
+
api.fireEvent('filter:change', {
|
|
16298
|
+
filterState: mgr.getFilterState(),
|
|
16299
|
+
previousFilterState: prev,
|
|
16300
|
+
});
|
|
16042
16301
|
}, 'filter');
|
|
16043
16302
|
store.action('filter:reapply', () => {
|
|
16044
16303
|
applyFilter();
|
|
@@ -16055,7 +16314,10 @@ function createFilterPlugin(options) {
|
|
|
16055
16314
|
quickFilterColumns = columns ?? null;
|
|
16056
16315
|
store.set('filter.quickFilter', { query: quickFilterQuery, columns: quickFilterColumns });
|
|
16057
16316
|
applyFilter();
|
|
16058
|
-
api.fireEvent('filter:change', {
|
|
16317
|
+
api.fireEvent('filter:change', {
|
|
16318
|
+
filterState: mgr.getFilterState(),
|
|
16319
|
+
previousFilterState: prev,
|
|
16320
|
+
});
|
|
16059
16321
|
}, 'filter');
|
|
16060
16322
|
store.action('filter:clearQuickFilter', () => {
|
|
16061
16323
|
const prev = mgr.getFilterState();
|
|
@@ -16064,7 +16326,10 @@ function createFilterPlugin(options) {
|
|
|
16064
16326
|
clearQuickFilterCache();
|
|
16065
16327
|
store.set('filter.quickFilter', { query: '', columns: null });
|
|
16066
16328
|
applyFilter();
|
|
16067
|
-
api.fireEvent('filter:change', {
|
|
16329
|
+
api.fireEvent('filter:change', {
|
|
16330
|
+
filterState: mgr.getFilterState(),
|
|
16331
|
+
previousFilterState: prev,
|
|
16332
|
+
});
|
|
16068
16333
|
}, 'filter');
|
|
16069
16334
|
store.action('filter:setState', (models) => {
|
|
16070
16335
|
const prev = mgr.getFilterState();
|
|
@@ -16073,13 +16338,19 @@ function createFilterPlugin(options) {
|
|
|
16073
16338
|
mgr.setColumnFilter(model.column, model.conditions, model.logic ?? 'AND');
|
|
16074
16339
|
}
|
|
16075
16340
|
applyFilter();
|
|
16076
|
-
api.fireEvent('filter:change', {
|
|
16341
|
+
api.fireEvent('filter:change', {
|
|
16342
|
+
filterState: mgr.getFilterState(),
|
|
16343
|
+
previousFilterState: prev,
|
|
16344
|
+
});
|
|
16077
16345
|
}, 'filter');
|
|
16078
16346
|
store.action('filter:setFieldState', (state) => {
|
|
16079
16347
|
const prev = mgr.getFilterState();
|
|
16080
16348
|
mgr.setFieldFilter(state);
|
|
16081
16349
|
applyFilter();
|
|
16082
|
-
api.fireEvent('filter:change', {
|
|
16350
|
+
api.fireEvent('filter:change', {
|
|
16351
|
+
filterState: mgr.getFilterState(),
|
|
16352
|
+
previousFilterState: prev,
|
|
16353
|
+
});
|
|
16083
16354
|
}, 'filter');
|
|
16084
16355
|
persistState();
|
|
16085
16356
|
api.register('filter', {
|
|
@@ -16094,9 +16365,9 @@ function createFilterPlugin(options) {
|
|
|
16094
16365
|
getFilterExports: () => mgr.getFilterExport(),
|
|
16095
16366
|
getQuickFilter: () => store.get('filter.quickFilter'),
|
|
16096
16367
|
getExpression: () => store.get('filter.expression'),
|
|
16097
|
-
getMode: () =>
|
|
16368
|
+
getMode: () => getQueryMode(),
|
|
16098
16369
|
});
|
|
16099
|
-
return { teardown: [() => mgr.destroy()] };
|
|
16370
|
+
return { teardown: [unsubscribeOptions, () => mgr.destroy()] };
|
|
16100
16371
|
},
|
|
16101
16372
|
};
|
|
16102
16373
|
}
|
|
@@ -24179,6 +24450,37 @@ function buildQueryState(options = {}) {
|
|
|
24179
24450
|
};
|
|
24180
24451
|
}
|
|
24181
24452
|
|
|
24453
|
+
const querySignatureCache = new WeakMap();
|
|
24454
|
+
function getQueryStateSignature(query) {
|
|
24455
|
+
if (!query) {
|
|
24456
|
+
return 'version:1';
|
|
24457
|
+
}
|
|
24458
|
+
const cached = querySignatureCache.get(query);
|
|
24459
|
+
if (cached) {
|
|
24460
|
+
return cached;
|
|
24461
|
+
}
|
|
24462
|
+
const signature = [
|
|
24463
|
+
`version:${query.version ?? 1}`,
|
|
24464
|
+
`sort:${getSortSignature(query.sort)}`,
|
|
24465
|
+
`filter:${getFilterAstSignature(query.filter)}`,
|
|
24466
|
+
`pagination:${getPaginationSignature(query.pagination)}`,
|
|
24467
|
+
].join('|');
|
|
24468
|
+
querySignatureCache.set(query, signature);
|
|
24469
|
+
return signature;
|
|
24470
|
+
}
|
|
24471
|
+
function getSortSignature(sort) {
|
|
24472
|
+
if (!sort || sort.length === 0) {
|
|
24473
|
+
return '';
|
|
24474
|
+
}
|
|
24475
|
+
return stableHashValue(sort);
|
|
24476
|
+
}
|
|
24477
|
+
function getPaginationSignature(pagination) {
|
|
24478
|
+
if (!pagination) {
|
|
24479
|
+
return '';
|
|
24480
|
+
}
|
|
24481
|
+
return [pagination.page, pagination.pageSize, pagination.offset, pagination.cursor ?? ''].join(':');
|
|
24482
|
+
}
|
|
24483
|
+
|
|
24182
24484
|
function createAbortError(message) {
|
|
24183
24485
|
const error = new Error(message);
|
|
24184
24486
|
error.name = 'AbortError';
|
|
@@ -24363,7 +24665,7 @@ class DataManager extends shared.OperationModeManager {
|
|
|
24363
24665
|
pagination: buildRangeQueryPaginationState(startRow, endRow),
|
|
24364
24666
|
});
|
|
24365
24667
|
// Generate cache key
|
|
24366
|
-
const cacheKey = `${startRow}-${endRow}-${
|
|
24668
|
+
const cacheKey = `${startRow}-${endRow}-${getQueryStateSignature(effectiveQuery)}`;
|
|
24367
24669
|
// Check cache first
|
|
24368
24670
|
if (this.cachedRanges.has(cacheKey)) {
|
|
24369
24671
|
const cachedData = this.cachedRanges.get(cacheKey);
|
|
@@ -24682,7 +24984,7 @@ function createDataPlugin(opts) {
|
|
|
24682
24984
|
name: 'data',
|
|
24683
24985
|
phase: 35,
|
|
24684
24986
|
dependencies: ['core', 'dom', 'rendering'],
|
|
24685
|
-
setup(store, api) {
|
|
24987
|
+
setup(store, api, context) {
|
|
24686
24988
|
const { options, state, container, events, setDataAccessor } = opts;
|
|
24687
24989
|
const mode = shared.resolveOperationMode({
|
|
24688
24990
|
mode: options.dataMode,
|
|
@@ -24727,6 +25029,9 @@ function createDataPlugin(opts) {
|
|
|
24727
25029
|
function getStatus() {
|
|
24728
25030
|
return store.get('data.status');
|
|
24729
25031
|
}
|
|
25032
|
+
function delegatesQueryState() {
|
|
25033
|
+
return shouldDelegateQueryState(context.options.dataMode);
|
|
25034
|
+
}
|
|
24730
25035
|
function setStatus(partial) {
|
|
24731
25036
|
store.set('data.status', {
|
|
24732
25037
|
...getStatus(),
|
|
@@ -24844,15 +25149,19 @@ function createDataPlugin(opts) {
|
|
|
24844
25149
|
function syncManagerData() {
|
|
24845
25150
|
const data = dataManager.getData();
|
|
24846
25151
|
const totalRows = dataManager.getTotalRows();
|
|
25152
|
+
const previousTotalRows = knownTotalRows;
|
|
24847
25153
|
const { top, left } = state.scrollPosition;
|
|
24848
25154
|
knownTotalRows = totalRows;
|
|
25155
|
+
context.updateOptions({ rowCount: totalRows });
|
|
24849
25156
|
state.data = data;
|
|
24850
25157
|
setDataAccessor(new ArrayAccessor(data));
|
|
24851
25158
|
store.exec('core:setData', data);
|
|
24852
25159
|
store.exec('rendering:setRowCount', totalRows);
|
|
24853
25160
|
store.exec('rendering:updateCanvasSize');
|
|
24854
25161
|
store.exec('rendering:clearCache');
|
|
24855
|
-
|
|
25162
|
+
if (totalRows !== previousTotalRows) {
|
|
25163
|
+
store.exec('rendering:renderCells', top, left);
|
|
25164
|
+
}
|
|
24856
25165
|
store.exec('rendering:refresh');
|
|
24857
25166
|
if (api.getMethod('pagination', 'update')) {
|
|
24858
25167
|
store.exec('pagination:update');
|
|
@@ -24924,8 +25233,12 @@ function createDataPlugin(opts) {
|
|
|
24924
25233
|
};
|
|
24925
25234
|
}
|
|
24926
25235
|
function buildRequest(range) {
|
|
24927
|
-
const sortState =
|
|
24928
|
-
|
|
25236
|
+
const sortState = delegatesQueryState()
|
|
25237
|
+
? (store.get('sort.state') ?? [])
|
|
25238
|
+
: null;
|
|
25239
|
+
const filterAst = delegatesQueryState()
|
|
25240
|
+
? (store.get('filter.ast') ?? null)
|
|
25241
|
+
: null;
|
|
24929
25242
|
return {
|
|
24930
25243
|
startRow: range.startRow,
|
|
24931
25244
|
endRow: range.endRow,
|
|
@@ -25050,12 +25363,12 @@ function createDataPlugin(opts) {
|
|
|
25050
25363
|
}
|
|
25051
25364
|
void ensureVisibleRange('scroll', payload.visibleRange);
|
|
25052
25365
|
}), events.on('sort:change', () => {
|
|
25053
|
-
if (!isRendered()) {
|
|
25366
|
+
if (!isRendered() || !delegatesQueryState()) {
|
|
25054
25367
|
return;
|
|
25055
25368
|
}
|
|
25056
25369
|
void reloadCurrentContext('sort');
|
|
25057
25370
|
}), events.on('filter:change', () => {
|
|
25058
|
-
if (!isRendered()) {
|
|
25371
|
+
if (!isRendered() || !delegatesQueryState()) {
|
|
25059
25372
|
return;
|
|
25060
25373
|
}
|
|
25061
25374
|
void reloadCurrentContext('filter');
|
|
@@ -26774,6 +27087,11 @@ class GridFilterUI {
|
|
|
26774
27087
|
});
|
|
26775
27088
|
this.renderFilterChips();
|
|
26776
27089
|
}
|
|
27090
|
+
setColumns(columns) {
|
|
27091
|
+
this.columns = [...columns];
|
|
27092
|
+
this.closePopup();
|
|
27093
|
+
this.renderFilterChips();
|
|
27094
|
+
}
|
|
26777
27095
|
openFilterPopup(payload) {
|
|
26778
27096
|
const dataCol = this.mapVisualToDataCol(payload.columnIndex);
|
|
26779
27097
|
const columnDef = this.getColumnDef(dataCol);
|
|
@@ -26794,9 +27112,9 @@ class GridFilterUI {
|
|
|
26794
27112
|
logicRow.innerHTML = `<label>Match</label>`;
|
|
26795
27113
|
const logicSelect = document.createElement('select');
|
|
26796
27114
|
logicSelect.className = 'zg-filter-popup__select';
|
|
26797
|
-
logicSelect.innerHTML = `
|
|
26798
|
-
<option value="AND">AND</option>
|
|
26799
|
-
<option value="OR">OR</option>
|
|
27115
|
+
logicSelect.innerHTML = `
|
|
27116
|
+
<option value="AND">AND</option>
|
|
27117
|
+
<option value="OR">OR</option>
|
|
26800
27118
|
`;
|
|
26801
27119
|
logicSelect.value = existing?.logic ?? 'AND';
|
|
26802
27120
|
logicRow.appendChild(logicSelect);
|
|
@@ -27358,7 +27676,7 @@ function createFilterUIPlugin(options) {
|
|
|
27358
27676
|
name: 'filter-ui',
|
|
27359
27677
|
phase: 25,
|
|
27360
27678
|
dependencies: ['filter'],
|
|
27361
|
-
setup(store, api) {
|
|
27679
|
+
setup(store, api, context) {
|
|
27362
27680
|
let filterUI = null;
|
|
27363
27681
|
store.action('filterUI:attach', (container, events) => {
|
|
27364
27682
|
if (filterUI) {
|
|
@@ -27367,7 +27685,7 @@ function createFilterUIPlugin(options) {
|
|
|
27367
27685
|
filterUI = new GridFilterUI({
|
|
27368
27686
|
container,
|
|
27369
27687
|
events,
|
|
27370
|
-
columns: options.
|
|
27688
|
+
columns: options.getColumns(),
|
|
27371
27689
|
getFilterState: () => store.get('filter.state'),
|
|
27372
27690
|
getFilterExpression: () => store.get('filter.expression'),
|
|
27373
27691
|
setColumnFilter: (column, conditions, logic) => {
|
|
@@ -27398,6 +27716,12 @@ function createFilterUIPlugin(options) {
|
|
|
27398
27716
|
},
|
|
27399
27717
|
});
|
|
27400
27718
|
}, 'filter-ui');
|
|
27719
|
+
const unsubscribeOptions = context.subscribeOptions((change) => {
|
|
27720
|
+
if (!change.changedKeys.includes('columns')) {
|
|
27721
|
+
return;
|
|
27722
|
+
}
|
|
27723
|
+
filterUI?.setColumns(options.getColumns() ?? []);
|
|
27724
|
+
});
|
|
27401
27725
|
api.register('filterUI', {
|
|
27402
27726
|
destroy: () => {
|
|
27403
27727
|
if (filterUI) {
|
|
@@ -27408,6 +27732,7 @@ function createFilterUIPlugin(options) {
|
|
|
27408
27732
|
});
|
|
27409
27733
|
return {
|
|
27410
27734
|
teardown: [
|
|
27735
|
+
unsubscribeOptions,
|
|
27411
27736
|
() => {
|
|
27412
27737
|
if (filterUI) {
|
|
27413
27738
|
filterUI.destroy();
|
|
@@ -27740,6 +28065,65 @@ function createLifecyclePlugin(opts) {
|
|
|
27740
28065
|
};
|
|
27741
28066
|
}
|
|
27742
28067
|
|
|
28068
|
+
class GridOptionsManager {
|
|
28069
|
+
constructor(options) {
|
|
28070
|
+
this.options = options;
|
|
28071
|
+
this.listeners = new Set();
|
|
28072
|
+
}
|
|
28073
|
+
getOptions() {
|
|
28074
|
+
return this.options;
|
|
28075
|
+
}
|
|
28076
|
+
getOptionsSnapshot() {
|
|
28077
|
+
return { ...this.options };
|
|
28078
|
+
}
|
|
28079
|
+
update(patch) {
|
|
28080
|
+
const changedKeys = Object.keys(patch).filter((key) => {
|
|
28081
|
+
const optionKey = key;
|
|
28082
|
+
return !Object.is(this.options[optionKey], patch[optionKey]);
|
|
28083
|
+
});
|
|
28084
|
+
if (changedKeys.length === 0) {
|
|
28085
|
+
return null;
|
|
28086
|
+
}
|
|
28087
|
+
const previousOptions = this.getOptionsSnapshot();
|
|
28088
|
+
const changedPatch = {};
|
|
28089
|
+
const mutableOptions = this.options;
|
|
28090
|
+
const mutablePatch = changedPatch;
|
|
28091
|
+
for (const key of changedKeys) {
|
|
28092
|
+
const value = patch[key];
|
|
28093
|
+
mutableOptions[key] = value;
|
|
28094
|
+
mutablePatch[key] = value;
|
|
28095
|
+
}
|
|
28096
|
+
const change = {
|
|
28097
|
+
currentOptions: this.options,
|
|
28098
|
+
previousOptions,
|
|
28099
|
+
changedKeys,
|
|
28100
|
+
patch: changedPatch,
|
|
28101
|
+
};
|
|
28102
|
+
for (const listener of this.listeners) {
|
|
28103
|
+
listener(change);
|
|
28104
|
+
}
|
|
28105
|
+
return change;
|
|
28106
|
+
}
|
|
28107
|
+
subscribe(listener) {
|
|
28108
|
+
this.listeners.add(listener);
|
|
28109
|
+
return () => {
|
|
28110
|
+
this.listeners.delete(listener);
|
|
28111
|
+
};
|
|
28112
|
+
}
|
|
28113
|
+
createPluginSetupContext() {
|
|
28114
|
+
return {
|
|
28115
|
+
options: this.options,
|
|
28116
|
+
getOptions: () => this.getOptions(),
|
|
28117
|
+
getOptionsSnapshot: () => this.getOptionsSnapshot(),
|
|
28118
|
+
updateOptions: (patch) => this.update(patch),
|
|
28119
|
+
subscribeOptions: (listener) => this.subscribe(listener),
|
|
28120
|
+
};
|
|
28121
|
+
}
|
|
28122
|
+
destroy() {
|
|
28123
|
+
this.listeners.clear();
|
|
28124
|
+
}
|
|
28125
|
+
}
|
|
28126
|
+
|
|
27743
28127
|
function createSlimContext(container, options) {
|
|
27744
28128
|
if (!container)
|
|
27745
28129
|
throw new Error('Container element is required');
|
|
@@ -27761,13 +28145,20 @@ function createSlimContext(container, options) {
|
|
|
27761
28145
|
};
|
|
27762
28146
|
const store = new GridStoreImpl();
|
|
27763
28147
|
const gridApi = new GridApiImpl(store, events);
|
|
27764
|
-
const
|
|
28148
|
+
const optionsManager = new GridOptionsManager(normalizedOptions);
|
|
28149
|
+
const pluginHost = new PluginHost(store, gridApi, optionsManager.createPluginSetupContext());
|
|
27765
28150
|
const pipelineRegistry = new PipelineRegistry();
|
|
27766
28151
|
pipelineRegistry.registerPhase('sort', 10, 'pipeline.sort');
|
|
27767
28152
|
pipelineRegistry.registerPhase('filter', 20, 'pipeline.filter');
|
|
28153
|
+
gridApi.register('options', {
|
|
28154
|
+
get: () => optionsManager.getOptions(),
|
|
28155
|
+
getSnapshot: () => optionsManager.getOptionsSnapshot(),
|
|
28156
|
+
subscribe: (listener) => optionsManager.subscribe(listener),
|
|
28157
|
+
});
|
|
27768
28158
|
return {
|
|
27769
28159
|
container,
|
|
27770
28160
|
options: normalizedOptions,
|
|
28161
|
+
optionsManager,
|
|
27771
28162
|
state,
|
|
27772
28163
|
events,
|
|
27773
28164
|
store,
|
|
@@ -27779,12 +28170,6 @@ function createSlimContext(container, options) {
|
|
|
27779
28170
|
}
|
|
27780
28171
|
function installAllPlugins(ctx) {
|
|
27781
28172
|
const { options, events, pluginHost, store } = ctx;
|
|
27782
|
-
const resolvedDataMode = shared.resolveOperationMode({
|
|
27783
|
-
mode: options.dataMode,
|
|
27784
|
-
callback: options.onDataRequest,
|
|
27785
|
-
}, {
|
|
27786
|
-
rowCount: options.rowCount,
|
|
27787
|
-
});
|
|
27788
28173
|
// Phase 0: Core
|
|
27789
28174
|
pluginHost.use(createCorePlugin());
|
|
27790
28175
|
// Phase 5: DOM
|
|
@@ -27793,13 +28178,13 @@ function installAllPlugins(ctx) {
|
|
|
27793
28178
|
pluginHost.use(createSortPlugin({
|
|
27794
28179
|
enableMultiSort: true,
|
|
27795
28180
|
columns: options.columns,
|
|
27796
|
-
usePipeline:
|
|
28181
|
+
usePipeline: resolveQueryExecutionMode(options.dataMode) !== 'backend',
|
|
27797
28182
|
}));
|
|
27798
28183
|
// Phase 20: Filter
|
|
27799
28184
|
pluginHost.use(createFilterPlugin({
|
|
27800
28185
|
colCount: options.colCount,
|
|
27801
28186
|
columns: options.columns,
|
|
27802
|
-
usePipeline:
|
|
28187
|
+
usePipeline: resolveQueryExecutionMode(options.dataMode) !== 'backend',
|
|
27803
28188
|
}));
|
|
27804
28189
|
// Phase 30: Rendering
|
|
27805
28190
|
let columnModel = null;
|
|
@@ -27819,7 +28204,9 @@ function installAllPlugins(ctx) {
|
|
|
27819
28204
|
state: ctx.state,
|
|
27820
28205
|
container: ctx.container,
|
|
27821
28206
|
events,
|
|
27822
|
-
setDataAccessor: (da) => {
|
|
28207
|
+
setDataAccessor: (da) => {
|
|
28208
|
+
dataAccessor = da;
|
|
28209
|
+
},
|
|
27823
28210
|
}));
|
|
27824
28211
|
// Phase 40: Selection
|
|
27825
28212
|
if (options.enableSelection !== false) {
|
|
@@ -27866,14 +28253,22 @@ function installAllPlugins(ctx) {
|
|
|
27866
28253
|
container: ctx.container,
|
|
27867
28254
|
events,
|
|
27868
28255
|
getDataAccessor: () => dataAccessor,
|
|
27869
|
-
setColumnModel: (cm) => {
|
|
28256
|
+
setColumnModel: (cm) => {
|
|
28257
|
+
columnModel = cm;
|
|
28258
|
+
},
|
|
27870
28259
|
}));
|
|
27871
28260
|
// Setup pipeline computeds
|
|
27872
28261
|
ctx.pipelineRegistry.setupCoreComputeds(store);
|
|
27873
28262
|
// Expose closures for late-binding references
|
|
27874
|
-
ctx._setColumnModel = (cm) => {
|
|
27875
|
-
|
|
27876
|
-
|
|
28263
|
+
ctx._setColumnModel = (cm) => {
|
|
28264
|
+
columnModel = cm;
|
|
28265
|
+
};
|
|
28266
|
+
ctx._setDataAccessor = (da) => {
|
|
28267
|
+
dataAccessor = da;
|
|
28268
|
+
};
|
|
28269
|
+
ctx._setSelectionChecker = (sc) => {
|
|
28270
|
+
selectionChecker = sc;
|
|
28271
|
+
};
|
|
27877
28272
|
ctx._getColumnModel = () => columnModel;
|
|
27878
28273
|
ctx._getDataAccessor = () => dataAccessor;
|
|
27879
28274
|
// Wire selection checker updates from lifecycle plugin
|
|
@@ -27881,9 +28276,12 @@ function installAllPlugins(ctx) {
|
|
|
27881
28276
|
selectionChecker = checker;
|
|
27882
28277
|
});
|
|
27883
28278
|
// Install filter UI if columns + filter are present
|
|
27884
|
-
if (options.columns &&
|
|
28279
|
+
if (options.columns &&
|
|
28280
|
+
options.columns.length > 0 &&
|
|
28281
|
+
pluginHost.has('filter') &&
|
|
28282
|
+
!pluginHost.has('filter-ui')) {
|
|
27885
28283
|
pluginHost.use(createFilterUIPlugin({
|
|
27886
|
-
|
|
28284
|
+
getColumns: () => options.columns,
|
|
27887
28285
|
getColumnDef: (dataCol) => options.columns?.[dataCol],
|
|
27888
28286
|
getColumnModel: () => columnModel,
|
|
27889
28287
|
getContainer: () => ctx.container,
|
|
@@ -27917,7 +28315,12 @@ function installAllPlugins(ctx) {
|
|
|
27917
28315
|
},
|
|
27918
28316
|
getDOM: () => {
|
|
27919
28317
|
const domApi = ctx.gridApi.getMethod('dom', 'getCanvas');
|
|
27920
|
-
return domApi
|
|
28318
|
+
return domApi
|
|
28319
|
+
? {
|
|
28320
|
+
canvas: domApi(),
|
|
28321
|
+
updateCanvasSize: (w, h) => store.exec('dom:updateCanvasSize', w, h),
|
|
28322
|
+
}
|
|
28323
|
+
: null;
|
|
27921
28324
|
},
|
|
27922
28325
|
setData: (data) => {
|
|
27923
28326
|
store.exec('core:setData', data);
|
|
@@ -27927,7 +28330,7 @@ function installAllPlugins(ctx) {
|
|
|
27927
28330
|
},
|
|
27928
28331
|
getState: () => ({ data: ctx.state.data, rowCount: options.rowCount }),
|
|
27929
28332
|
setRowCount: (count) => {
|
|
27930
|
-
|
|
28333
|
+
ctx.optionsManager.update({ rowCount: count });
|
|
27931
28334
|
},
|
|
27932
28335
|
}));
|
|
27933
28336
|
}
|
|
@@ -28759,10 +29162,7 @@ function createSortApi(ctx) {
|
|
|
28759
29162
|
const getMode = ctx.gridApi.getMethod('sort', 'getMode');
|
|
28760
29163
|
if (getMode)
|
|
28761
29164
|
return getMode();
|
|
28762
|
-
|
|
28763
|
-
if (mode === 'auto')
|
|
28764
|
-
return ctx.options.onDataRequest ? 'backend' : 'frontend';
|
|
28765
|
-
return mode;
|
|
29165
|
+
return resolveQueryExecutionMode(ctx.options.dataMode);
|
|
28766
29166
|
},
|
|
28767
29167
|
};
|
|
28768
29168
|
}
|
|
@@ -28831,10 +29231,7 @@ function createFilterApi(ctx) {
|
|
|
28831
29231
|
const api = ctx.gridApi.getMethod('filter', 'getMode');
|
|
28832
29232
|
if (api)
|
|
28833
29233
|
return api();
|
|
28834
|
-
|
|
28835
|
-
if (mode === 'auto')
|
|
28836
|
-
return ctx.options.onDataRequest ? 'backend' : 'frontend';
|
|
28837
|
-
return mode;
|
|
29234
|
+
return resolveQueryExecutionMode(ctx.options.dataMode);
|
|
28838
29235
|
},
|
|
28839
29236
|
setQuick(query, columns) {
|
|
28840
29237
|
if (!hasFilterPlugin())
|
|
@@ -29244,7 +29641,7 @@ class Grid {
|
|
|
29244
29641
|
setData(data) {
|
|
29245
29642
|
this.ctx.store.exec('core:setData', data);
|
|
29246
29643
|
this.ctx.state.data = data;
|
|
29247
|
-
this.ctx.
|
|
29644
|
+
this.ctx.optionsManager.update({ rowCount: data.length });
|
|
29248
29645
|
const dataAccessor = new ArrayAccessor(data);
|
|
29249
29646
|
this.ctx._setDataAccessor?.(dataAccessor);
|
|
29250
29647
|
if (this.ctx.pluginHost.has('infinite-scroll'))
|
|
@@ -29312,7 +29709,8 @@ class Grid {
|
|
|
29312
29709
|
if (this.ctx.isDestroyed)
|
|
29313
29710
|
return;
|
|
29314
29711
|
this._theme.destroyAutoTheme();
|
|
29315
|
-
this.ctx.pluginHost
|
|
29712
|
+
this.ctx.pluginHost?.destroy?.();
|
|
29713
|
+
this.ctx.optionsManager?.destroy?.();
|
|
29316
29714
|
this.ctx.container.innerHTML = '';
|
|
29317
29715
|
this.ctx.container.classList.remove('zg-grid');
|
|
29318
29716
|
this.ctx.state.data = [];
|
|
@@ -29324,7 +29722,9 @@ class Grid {
|
|
|
29324
29722
|
this.ctx.store.exec('rendering:registerRenderer', name, renderer);
|
|
29325
29723
|
}
|
|
29326
29724
|
updateOptions(options) {
|
|
29327
|
-
|
|
29725
|
+
const change = this.ctx.optionsManager.update(options);
|
|
29726
|
+
if (!change)
|
|
29727
|
+
return;
|
|
29328
29728
|
this.ctx.store.exec('rendering:updateScroller');
|
|
29329
29729
|
this.ctx.store.exec('rendering:refresh');
|
|
29330
29730
|
}
|
|
@@ -29361,7 +29761,12 @@ class Grid {
|
|
|
29361
29761
|
getSlidingWindowStats() {
|
|
29362
29762
|
if (this.ctx.pluginHost.has('infinite-scroll'))
|
|
29363
29763
|
return this.ctx.store.get('infiniteScroll.stats');
|
|
29364
|
-
return {
|
|
29764
|
+
return {
|
|
29765
|
+
virtualOffset: 0,
|
|
29766
|
+
rowsInMemory: this.ctx.state.data.length,
|
|
29767
|
+
totalRowsLoaded: 0,
|
|
29768
|
+
prunedRows: 0,
|
|
29769
|
+
};
|
|
29365
29770
|
}
|
|
29366
29771
|
// --- Theme ---
|
|
29367
29772
|
setTheme(nameOrObject) {
|