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