Skip to content

Commit 25d5410

Browse files
Fix: React implementation, lint, and build
1 parent 2371a23 commit 25d5410

File tree

12 files changed

+157
-395
lines changed

12 files changed

+157
-395
lines changed

React/orig_package.json

Lines changed: 0 additions & 46 deletions
This file was deleted.

React/src/App.css

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,43 @@
1-
.main {
1+
.demo-container {
22
margin: 50px;
3-
width: 90vw;
4-
}
3+
width: 90vh;
4+
}
5+
6+
.demo-header {
7+
display: flex;
8+
justify-content: space-between;
9+
}
10+
11+
#toggle-container {
12+
padding-top: 20px;
13+
}
14+
15+
#clean-after-drop-switch {
16+
vertical-align: text-bottom;
17+
}
18+
19+
#toggle-container span {
20+
padding-right: 10px;
21+
}
22+
23+
.drag-container {
24+
padding: 10px;
25+
}
26+
27+
.drag-container td {
28+
padding: 0 10px;
29+
}
30+
31+
.tables {
32+
display: flex;
33+
}
34+
35+
.column:first-child {
36+
width: 50%;
37+
padding-right: 15px;
38+
}
39+
40+
.column:last-child {
41+
width: 50%;
42+
padding-left: 15px;
43+
}

React/src/App.tsx

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,47 @@
1-
import { useCallback, useState } from 'react';
21
import './App.css';
32
import 'devextreme/dist/css/dx.material.blue.light.compact.css';
4-
import Button from 'devextreme-react/button';
3+
import { useCallback, useState } from 'react';
4+
import * as AspNetData from 'devextreme-aspnet-data-nojquery';
5+
import Switch from 'devextreme-react/switch';
6+
import { type ValueChangedEvent } from 'devextreme/ui/switch';
7+
import Grid from './Grid';
8+
9+
const url = 'https://js.devexpress.com/Demos/Mvc/api/DnDBetweenGrids';
10+
11+
const tasksStore = AspNetData.createStore({
12+
key: 'ID',
13+
loadUrl: `${url}/Tasks`,
14+
updateUrl: `${url}/UpdateTask`,
15+
onBeforeSend(_method, ajaxOptions) {
16+
ajaxOptions.xhrFields = { withCredentials: true };
17+
},
18+
});
519

620
function App(): JSX.Element {
7-
var [count, setCount] = useState<number>(0);
8-
const clickHandler = useCallback(() => {
9-
setCount((prev) => prev + 1);
10-
}, [setCount]);
21+
const [shouldClearSelection, setShouldClearSelection] = useState(false);
22+
23+
const switchValueChanged = useCallback((e: ValueChangedEvent) => {
24+
setShouldClearSelection(e.value);
25+
}, []);
26+
1127
return (
12-
<div className="main">
13-
<Button text={`Click count: ${count}`} onClick={clickHandler} />
28+
<div className="demo-container">
29+
<div className="demo-header">
30+
{/* eslint-disable-next-line react/no-unescaped-entities */}
31+
<h3>DataGrid - Select multiple items and drag'n'drop between grids</h3>
32+
<div id="toggle-container">
33+
<span>Clear selection of dropped items</span>
34+
<Switch id="clean-after-drop-switch" value={shouldClearSelection} onValueChanged={switchValueChanged}></Switch>
35+
</div>
36+
</div>
37+
<div className="tables">
38+
<div className="column">
39+
<Grid tasksStore={tasksStore} status={1} shouldClearSelection={shouldClearSelection} />
40+
</div>
41+
<div className="column">
42+
<Grid tasksStore={tasksStore} status={2} shouldClearSelection={shouldClearSelection} />
43+
</div>
44+
</div>
1445
</div>
1546
);
1647
}

React/src/Grid.tsx

Lines changed: 55 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,88 @@
1-
import { useState, useMemo, useCallback} from 'react';
2-
import DataGrid, { Column, RowDragging, Scrolling, Lookup, Selection } from 'devextreme-react/data-grid';
3-
import dxDataGrid, { RowDraggingStartEvent, Column as DxColumn, RowDraggingAddEvent, Row } from 'devextreme/ui/data_grid';
4-
import { DragTemplateData } from 'devextreme/ui/draggable';
1+
import { useState, useMemo, useCallback } from 'react';
2+
import DataGrid, {
3+
Column, RowDragging, Scrolling, Lookup, Selection,
4+
} from 'devextreme-react/data-grid';
5+
import type { DataGridTypes } from 'devextreme-react/data-grid';
6+
import type dxDataGrid from 'devextreme/ui/data_grid';
7+
import type { DragTemplateData } from 'devextreme/ui/draggable';
58
import CustomStore from 'devextreme/data/custom_store';
6-
import { Task, priorities } from './data';
9+
import notify from 'devextreme/ui/notify';
10+
import { type Task, priorities } from './data';
11+
12+
type CellValue = Task[keyof Task] | string | undefined;
713

814
interface GridDemoComponentProps {
915
status?: number;
1016
tasksStore?: CustomStore;
1117
shouldClearSelection: boolean;
1218
}
1319

14-
function draggedItemsRender(data: DragTemplateData) {
20+
function draggedItemsRender(data: DragTemplateData): JSX.Element {
1521
const draggedItems = data.itemData.map((item: Task, rowIndex: number) => {
16-
const cellValues = (Object.keys(item) as (keyof Task)[]).map((key: keyof Task, dataIndex: number) =>
17-
<td key={"key" + dataIndex}>{item[key]}</td>
18-
);
19-
return (<tr key={"row" + rowIndex}>{cellValues}</tr>)
22+
const cellValues = (Object.keys(item) as (keyof Task)[]).map((key: keyof Task, dataIndex: number) => <td key={`key${dataIndex}`}>{item[key]}</td>);
23+
return (<tr key={`row${rowIndex}`}>{cellValues}</tr>);
2024
});
2125
return (<table className="drag-container">
22-
<tbody>{draggedItems}</tbody>
26+
<tbody>{draggedItems}</tbody>
2327
</table>);
2428
}
2529

26-
function getVisibleRowValues(rowsData: Task[], grid: dxDataGrid) {
27-
const visibleColumns = grid.getVisibleColumns();
28-
const selectedData = rowsData.map((rowData: Task) => {
29-
const visibleValues: any = {};
30-
visibleColumns.forEach((column: DxColumn) => {
31-
if (column.dataField)
32-
visibleValues[column.dataField] = getVisibleCellValue(column, rowData);
33-
});
34-
return visibleValues;
30+
function getVisibleRowValues(rowsData: Task[], grid: dxDataGrid): Record<string, CellValue>[] {
31+
const visibleColumns = grid.getVisibleColumns();
32+
const selectedData = rowsData.map((rowData: Task) => {
33+
const visibleValues: Record<string, CellValue> = {};
34+
visibleColumns.forEach((column: DataGridTypes.Column) => {
35+
if (column.dataField) { visibleValues[column.dataField] = getVisibleCellValue(column, rowData); }
3536
});
36-
return selectedData;
37+
return visibleValues;
38+
});
39+
return selectedData;
3740
}
3841

39-
function getVisibleCellValue(column: DxColumn, rowData: Task) {
40-
if (column.dataField) {
41-
const propKey = column.dataField as (keyof Task);
42-
const cellValue = rowData[propKey];
43-
return column.lookup && column.lookup.calculateCellValue ? column.lookup.calculateCellValue(cellValue) : cellValue;
44-
}
42+
function getVisibleCellValue(column: DataGridTypes.Column, rowData: Task): CellValue {
43+
if (column.dataField) {
44+
const propKey = column.dataField as keyof Task;
45+
const cellValue = rowData[propKey];
46+
return column?.lookup?.calculateCellValue
47+
? column.lookup.calculateCellValue(cellValue) as CellValue
48+
: cellValue as CellValue;
49+
}
50+
return undefined;
4551
}
4652

47-
export default function Grid({ status, tasksStore, shouldClearSelection }: GridDemoComponentProps) {
53+
export default function Grid({ status, tasksStore, shouldClearSelection }: GridDemoComponentProps): JSX.Element {
4854
const [updateInProgress, setUpdateInProgress] = useState(false);
4955

50-
const filterExpr = useMemo(() => {
51-
return ['Status', '=', status];
52-
}, [status]);
56+
const filterExpr = useMemo(() => ['Status', '=', status], [status]);
5357

54-
const dataSource = useMemo(() => {
55-
return {
56-
store: tasksStore,
57-
reshapeOnPush: true,
58-
};
59-
}, [tasksStore]);
58+
const dataSource = useMemo(() => ({
59+
store: tasksStore,
60+
reshapeOnPush: true,
61+
}), [tasksStore]);
6062

61-
const canDrag = useCallback((e: RowDraggingStartEvent) => {
63+
const canDrag = useCallback((e: DataGridTypes.RowDraggingStartEvent): boolean => {
6264
if (updateInProgress) return false;
6365
const visibleRows = e.component.getVisibleRows();
64-
return visibleRows.some((r: Row) => r.isSelected && r.rowIndex === e.fromIndex);
66+
return visibleRows.some((r: DataGridTypes.Row) => r.isSelected && r.rowIndex === e.fromIndex);
6567
}, [updateInProgress]);
6668

67-
const onDragStart = useCallback((e: RowDraggingStartEvent) => {
69+
const onDragStart = useCallback((e: DataGridTypes.RowDraggingStartEvent): void => {
6870
const selectedData: Task[] = e.component.getSelectedRowsData();
6971
e.itemData = getVisibleRowValues(selectedData, e.component);
7072
e.cancel = !canDrag(e);
7173
}, [canDrag]);
7274

73-
const onAdd = useCallback((e: RowDraggingAddEvent) => {
75+
// eslint-disable-next-line @typescript-eslint/space-before-function-paren
76+
const onAdd = useCallback(async(e: DataGridTypes.RowDraggingAddEvent): Promise<void> => {
7477
const fromGrid = e.fromComponent as dxDataGrid;
7578
const toGrid = e.toComponent as dxDataGrid;
7679
const selectedRowKeys: (keyof Task)[] = fromGrid.getSelectedRowKeys();
7780
const updateProcess: (Promise<any> | undefined)[] = [];
7881
const changes: any[] = [];
7982

8083
setUpdateInProgress(true);
81-
fromGrid.beginCustomLoading("Loading...");
82-
toGrid.beginCustomLoading("Loading...");
84+
fromGrid.beginCustomLoading('Loading...');
85+
toGrid.beginCustomLoading('Loading...');
8386
for (let key of selectedRowKeys) {
8487
const values = { Status: e.toData };
8588
updateProcess.push(tasksStore?.update(key, values));
@@ -89,17 +92,20 @@ export default function Grid({ status, tasksStore, shouldClearSelection }: GridD
8992
data: values,
9093
});
9194
}
92-
Promise.all(updateProcess).then(() => {
95+
try {
96+
await Promise.all(updateProcess);
9397
tasksStore?.push(changes);
9498
fromGrid.endCustomLoading();
9599
toGrid.endCustomLoading();
96100
setUpdateInProgress(false);
97101

98102
fromGrid.clearSelection();
99103
if (!shouldClearSelection) {
100-
toGrid.selectRows(selectedRowKeys, true);
104+
await toGrid.selectRows(selectedRowKeys, true);
101105
}
102-
});
106+
} catch (error: unknown) {
107+
notify(error, 'error', 1000);
108+
}
103109
}, [tasksStore, shouldClearSelection]);
104110

105111
return (
@@ -112,8 +118,8 @@ export default function Grid({ status, tasksStore, shouldClearSelection }: GridD
112118
<RowDragging
113119
data={status}
114120
group="tasksGroup"
115-
onAdd={onAdd}
116-
onDragStart={onDragStart}
121+
onAdd={onAdd as unknown as () => void}
122+
onDragStart={onDragStart as () => void}
117123
dragRender={draggedItemsRender}
118124
/>
119125
<Selection mode="multiple" />
@@ -138,7 +144,6 @@ export default function Grid({ status, tasksStore, shouldClearSelection }: GridD
138144
dataType="number"
139145
visible={false}
140146
/>
141-
142147
</DataGrid>
143148
);
144-
};
149+
}

React/src/data.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
export interface Task {
2+
ID?: number;
3+
Priority?: number;
4+
Status?: number;
5+
Subject?: string;
6+
}
7+
8+
interface Priority {
9+
id?: number;
10+
text?: string;
11+
}
12+
13+
export const priorities: Priority[] = [{
14+
id: 1, text: 'Low',
15+
}, {
16+
id: 2, text: 'Normal',
17+
}, {
18+
id: 3, text: 'High',
19+
}, {
20+
id: 4, text: 'Urgent',
21+
}];

React/src/orig_App.css

Lines changed: 0 additions & 34 deletions
This file was deleted.

React/src/orig_App.test.tsx

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)