Skip to content

Commit c6332a4

Browse files
authored
Data source adapter, virtual data loader, TreeList data controller and data source adapter - type TreeList data controller (#35568)
1 parent 96a0fd9 commit c6332a4

6 files changed

Lines changed: 120 additions & 55 deletions

File tree

‎packages/devextreme/js/__internal/grids/tree_list/columns_controller.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type { RawItemData } from '@ts/grids/grid_core/data_source_adapter/types'
55

66
import treeListCore from './core';
77

8-
class TreeListColumnsController extends ColumnsController {
8+
export class TreeListColumnsController extends ColumnsController {
99
public _getFirstItems(dataSourceAdapter?: DataSourceAdapter): RawItemData[] {
1010
// @ts-expect-error TreeList nodes have data that the base adapter does not type
1111
return super._getFirstItems(dataSourceAdapter).map((node) => node.data);

‎packages/devextreme/js/__internal/grids/tree_list/data_controller/m_data_controller.ts‎

Lines changed: 76 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,61 @@
11
import { equalByValue } from '@js/core/utils/common';
2+
import type { DeferredObj } from '@js/core/utils/deferred';
23
import { Deferred } from '@js/core/utils/deferred';
34
import { extend } from '@js/core/utils/extend';
45
import { DataController, dataControllerModule } from '@ts/grids/grid_core/data_controller/data_controller';
6+
import type { ProcessedItem } from '@ts/grids/grid_core/data_controller/types';
57
import type { RowKey } from '@ts/grids/grid_core/types';
8+
import type { NodeCallback, OperationTypes, TreeNode } from '@ts/grids/tree_list/data_source_adapter/types';
69

10+
import type { TreeListColumnsController } from '../columns_controller';
711
import treeListCore from '../core';
812
import type { TreeListDataSourceController } from '../data_source/data_source_controller';
13+
import type {
14+
ExpandedKeysCache,
15+
RowExpandArgs,
16+
TreeListDataControllerOptionChanged,
17+
TreeListGeneratedItem,
18+
TreeListItemProcessingOptions,
19+
TreeListProcessedItem,
20+
} from './types';
21+
22+
const getNodeLevel = (node: TreeNode): number => {
23+
let level = -1;
24+
let current = node;
25+
while (current.parent) {
26+
if (current.visible) {
27+
level += 1;
28+
}
29+
current = current.parent;
30+
}
31+
return level;
32+
};
933

1034
export class TreeListDataController extends DataController {
1135
protected declare dataSourceController: TreeListDataSourceController;
1236

13-
private _getNodeLevel(node) {
14-
let level = -1;
15-
while (node.parent) {
16-
if (node.visible) {
17-
level++;
18-
}
19-
node = node.parent;
20-
}
21-
return level;
22-
}
37+
public declare _columnsController: TreeListColumnsController;
2338

24-
protected _generateDataItem(node?: any, options?: any): any {
39+
protected _generateDataItem(
40+
node: TreeNode,
41+
options?: TreeListItemProcessingOptions,
42+
): TreeListGeneratedItem {
2543
return {
2644
rowType: 'data',
2745
node,
2846
key: node.key,
47+
// @ts-expect-error a data node always has data, only the root node has none
2948
data: node.data,
3049
isExpanded: this.isRowExpanded(node.key, options),
31-
level: this._getNodeLevel(node),
50+
level: getNodeLevel(node),
3251
};
3352
}
3453

35-
private _loadOnOptionChange() {
36-
this.dataSourceController.getAdapter()!.load();
54+
protected _loadOnOptionChange(): void {
55+
this.dataSourceController.getAdapter()?.load();
3756
}
3857

39-
protected isSameRowState(item1, item2): boolean {
58+
protected isSameRowState(item1: TreeListProcessedItem, item2: TreeListProcessedItem): boolean {
4059
if (item1.isSelected !== item2.isSelected) {
4160
return false;
4261
}
@@ -52,42 +71,47 @@ export class TreeListDataController extends DataController {
5271
return super.isSameRowState(item1, item2);
5372
}
5473

55-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
56-
protected _isCellChanged(oldRow, newRow, visibleRowIndex, columnIndex, isLiveUpdate) {
57-
// @ts-expect-error
74+
protected _isCellChanged(
75+
oldRow: ProcessedItem,
76+
newRow: ProcessedItem,
77+
visibleRowIndex: number,
78+
columnIndex: number,
79+
isLiveUpdate?: boolean,
80+
): boolean {
5881
const firstDataColumnIndex = this._columnsController.getFirstDataColumnIndex();
5982

6083
if (columnIndex === firstDataColumnIndex && oldRow.isSelected !== newRow.isSelected) {
6184
return true;
6285
}
6386

64-
return super._isCellChanged.apply(this, arguments as any);
87+
return super._isCellChanged(oldRow, newRow, visibleRowIndex, columnIndex, isLiveUpdate);
6588
}
6689

67-
public init() {
90+
public init(): void {
6891
this.createAction('onRowExpanding');
6992
this.createAction('onRowExpanded');
7093
this.createAction('onRowCollapsing');
7194
this.createAction('onRowCollapsed');
7295

73-
super.init.apply(this, arguments as any);
96+
super.init();
7497
}
7598

76-
public publicMethods() {
77-
return super.publicMethods().concat(['expandRow', 'collapseRow', 'isRowExpanded', 'getRootNode', 'getNodeByKey', 'loadDescendants', 'forEachNode']);
99+
public publicMethods(): string[] {
100+
return super.publicMethods().concat([
101+
'expandRow', 'collapseRow', 'isRowExpanded', 'getRootNode',
102+
'getNodeByKey', 'loadDescendants', 'forEachNode',
103+
]);
78104
}
79105

80-
protected override needUpdateDimensions(operationTypes) {
81-
return super.needUpdateDimensions(operationTypes) || (
82-
operationTypes && operationTypes.nodeExpanding
83-
);
106+
protected override needUpdateDimensions(operationTypes?: OperationTypes): boolean {
107+
return super.needUpdateDimensions(operationTypes) || Boolean(operationTypes?.nodeExpanding);
84108
}
85109

86-
private changeRowExpand(key) {
110+
private changeRowExpand(key: RowKey): DeferredObj<unknown> {
87111
const dataSourceAdapter = this.dataSourceController.getAdapter();
88112

89113
if (dataSourceAdapter) {
90-
const args: any = {
114+
const args: RowExpandArgs = {
91115
key,
92116
};
93117
const isExpanded = this.isRowExpanded(key);
@@ -101,35 +125,32 @@ export class TreeListDataController extends DataController {
101125
}
102126
}
103127

104-
// @ts-expect-error
105-
return new Deferred().resolve();
128+
return Deferred<unknown>().resolve();
106129
}
107130

108-
private isRowExpanded(key, cache?) {
131+
private isRowExpanded(key: RowKey, cache?: ExpandedKeysCache): boolean | undefined {
109132
return this.dataSourceController.getAdapter()?.isRowExpanded(key, cache);
110133
}
111134

112-
private expandRow(key) {
135+
private expandRow(key: RowKey): DeferredObj<unknown> {
113136
if (!this.isRowExpanded(key)) {
114137
return this.changeRowExpand(key);
115138
}
116-
// @ts-expect-error
117-
return new Deferred().resolve();
139+
return Deferred<unknown>().resolve();
118140
}
119141

120-
private collapseRow(key) {
142+
private collapseRow(key: RowKey): DeferredObj<unknown> {
121143
if (this.isRowExpanded(key)) {
122144
return this.changeRowExpand(key);
123145
}
124-
// @ts-expect-error
125-
return new Deferred().resolve();
146+
return Deferred<unknown>().resolve();
126147
}
127148

128-
private getRootNode() {
149+
private getRootNode(): TreeNode | undefined {
129150
return this.dataSourceController.getAdapter()?.getRootNode();
130151
}
131152

132-
public optionChanged(args) {
153+
public optionChanged(args: TreeListDataControllerOptionChanged): void {
133154
switch (args.name) {
134155
case 'rootValue':
135156
case 'parentIdExpr':
@@ -147,8 +168,11 @@ export class TreeListDataController extends DataController {
147168
case 'expandedRowKeys':
148169
case 'onNodesInitialized': {
149170
const dataSourceAdapter = this.dataSourceController.getAdapter();
171+
const isReloadNeeded = dataSourceAdapter
172+
&& !dataSourceAdapter._isNodesInitializing
173+
&& !equalByValue(args.value, args.previousValue);
150174

151-
if (dataSourceAdapter && !dataSourceAdapter._isNodesInitializing && !equalByValue(args.value, args.previousValue)) {
175+
if (isReloadNeeded) {
152176
this._loadOnOptionChange();
153177
}
154178
args.handled = true;
@@ -162,20 +186,24 @@ export class TreeListDataController extends DataController {
162186
}
163187
}
164188

165-
private getNodeByKey(key) {
189+
private getNodeByKey(key: RowKey): TreeNode | undefined {
166190
return this.dataSourceController.getAdapter()?.getNodeByKey(key);
167191
}
168192

169-
private getChildNodeKeys(parentKey) {
193+
private getChildNodeKeys(parentKey: RowKey): RowKey[] | undefined {
170194
return this.dataSourceController.getAdapter()?.getChildNodeKeys(parentKey);
171195
}
172196

173-
private loadDescendants(keys, childrenOnly) {
197+
private loadDescendants(
198+
keys?: RowKey | RowKey[],
199+
childrenOnly?: boolean,
200+
): DeferredObj<unknown> | undefined {
174201
return this.dataSourceController.getAdapter()?.loadDescendants(keys, childrenOnly);
175202
}
176203

177-
private forEachNode() {
178-
this.dataSourceController.getAdapter()!.forEachNode.apply(this, arguments as any);
204+
private forEachNode(...args: [NodeCallback] | [TreeNode | TreeNode[], NodeCallback]): void {
205+
// @ts-expect-error adapter is set; a spread argument can't match the overloads of forEachNode()
206+
this.dataSourceController.getAdapter().forEachNode(...args);
179207
}
180208

181209
// Collect keys by walking the loaded node tree (depth-first, parent before
@@ -193,7 +221,8 @@ export class TreeListDataController extends DataController {
193221

194222
treeListCore.registerModule('data', {
195223
defaultOptions() {
196-
return extend({}, (dataControllerModule as any).defaultOptions(), {
224+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return -- extend() returns any
225+
return extend({}, dataControllerModule.defaultOptions?.(), {
197226
itemsExpr: 'items',
198227
parentIdExpr: 'parentId',
199228
rootValue: 0,
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import type { Properties as TreeListProperties, RowExpandingEvent } from '@js/ui/tree_list';
2+
import type { GeneratedItem, ItemProcessingOptions, ProcessedItem } from '@ts/grids/grid_core/data_controller/types';
3+
import type { OptionChanged, OptionChangedFor, RowKey } from '@ts/grids/grid_core/types';
4+
import type { LoadOperation, TreeNode } from '@ts/grids/tree_list/data_source_adapter/types';
5+
6+
export interface TreeListGeneratedItem extends GeneratedItem {
7+
node: TreeNode;
8+
isExpanded?: boolean;
9+
level: number;
10+
}
11+
12+
export interface TreeListProcessedItem extends ProcessedItem {
13+
node?: TreeNode;
14+
level?: number;
15+
}
16+
17+
export type ExpandedKeysCache = Pick<LoadOperation, 'isExpandedByKey'>;
18+
19+
export type TreeListItemProcessingOptions = ItemProcessingOptions & ExpandedKeysCache;
20+
21+
export type RowExpandArgs = Pick<RowExpandingEvent<unknown, RowKey>, 'key' | 'cancel'>;
22+
23+
interface TreeListDataControllerOptions extends Pick<TreeListProperties<unknown, RowKey>,
24+
'rootValue'
25+
| 'parentIdExpr'
26+
| 'itemsExpr'
27+
| 'filterMode'
28+
| 'expandNodesOnFiltering'
29+
| 'autoExpandAll'
30+
| 'hasItemsExpr'
31+
| 'dataStructure'
32+
> {
33+
maxFilterLengthInRequest?: number;
34+
}
35+
36+
export type TreeListDataControllerOptionChanged = OptionChanged
37+
| OptionChangedFor<TreeListDataControllerOptions>;

‎packages/devextreme/js/__internal/grids/tree_list/data_source_adapter/m_data_source_adapter.ts‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,6 @@ export class DataSourceAdapterTreeList extends DataSourceAdapter {
403403

404404
if ((!parentNode.parent || this.isRowExpanded(parentNode.key))
405405
&& change.index !== undefined) {
406-
// @ts-expect-error items() is typed as loaded items, but holds tree nodes here
407406
let index = this.items().indexOf(parentNode) + 1;
408407

409408
index += change.index >= 0
@@ -509,7 +508,6 @@ export class DataSourceAdapterTreeList extends DataSourceAdapter {
509508
(key) => this.isRowExpanded(key, options),
510509
);
511510

512-
// @ts-expect-error rows are nodes here, not the loaded items
513511
options.data = resultData;
514512
this._totalItemsCount = resultData.length;
515513
}

‎packages/devextreme/js/__internal/grids/tree_list/data_source_adapter/types.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,16 @@ export type DataSetter = (data: unknown, value: unknown) => void;
2828

2929
export type KeyExpr = StoreKey | ((item: unknown, value?: unknown) => unknown);
3030

31-
export interface TreeNode {
31+
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions -- alias fits RawItemData
32+
export type TreeNode = {
3233
key: RowKey;
3334
children: TreeNode[];
3435
data?: RawItemData;
3536
parent?: TreeNode;
3637
level?: number;
3738
visible?: boolean;
3839
hasChildren?: boolean;
39-
}
40+
};
4041

4142
export type NodeByKey = Record<string, TreeNode>;
4243

‎packages/devextreme/js/__internal/grids/tree_list/m_virtual_scrolling.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { DataController } from '@ts/grids/grid_core/data_controller/data_co
44
import type { DataSourceController } from '@ts/grids/grid_core/data_source/data_source_controller';
55
import type DataSourceAdapter from '@ts/grids/grid_core/data_source_adapter/m_data_source_adapter';
66
import gridCoreUtils from '@ts/grids/grid_core/m_utils';
7-
import type { ModuleType } from '@ts/grids/grid_core/types';
7+
import type { ModuleType, RowKey } from '@ts/grids/grid_core/types';
88
import type { RowsView } from '@ts/grids/grid_core/views/m_rows_view';
99
import {
1010
dataSourceAdapterExtender as virtualScrollingDataSourceAdapterExtender,
@@ -42,13 +42,13 @@ virtualScrollingModule.extenders.controllers.data = (Base: ModuleType<DataContro
4242
const virtualScrollController = this.dataSourceController.getAdapter()?._virtualScrollController;
4343

4444
virtualScrollController?.reset();
45-
// @ts-expect-error
45+
// @ts-expect-error _loadOnOptionChange() is added by the TreeList data controller
4646
super._loadOnOptionChange();
4747
}
4848
};
4949

5050
const dataSourceAdapterExtender = (Base: ModuleType<DataSourceAdapter>) => class VirtualScrollingDataSourceAdapterExtender extends virtualScrollingDataSourceAdapterExtender(Base) {
51-
public changeRowExpand(path?: unknown) {
51+
public changeRowExpand(path: RowKey) {
5252
return super.changeRowExpand(path)?.done(() => {
5353
const viewportItemIndex = this.getViewportItemIndex();
5454

0 commit comments

Comments
 (0)