Skip to content

Commit 942cca2

Browse files
3.0 sorting (#54)
* - fix undefined/null sort - integrate sort with virtualization * - basic unit tests coverage for sorting - refactor header's sorting and sort update (more flexible)
1 parent 2a27a40 commit 942cca2

File tree

12 files changed

+504
-145
lines changed

12 files changed

+504
-145
lines changed

packages/dash-table/README.md

+21-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

3939
## RC5 (Conditional Style, Conditional Dropdown, Filter)
4040
New props
41-
- filtering -> ['fe', 'be'] (default: 'fe')
41+
- filtering -> ['fe', 'be', true, false] (default: false)
4242
- filtering_settings -> AST query string (default: '')
4343
- column_conditional_dropdowns
4444
- column_static_dropdown
@@ -49,4 +49,23 @@
4949
Deprecated
5050
- column style
5151
- column options
52-
- dropdown_properties
52+
- dropdown_properties
53+
54+
## Towards RC6
55+
* First steps to make sorting work from both FE and BE *
56+
* and consistent with Virtualization settings *
57+
58+
New Props
59+
- sorting -> ['fe', 'be', true, false] (default: false) -- replaces 'sortable' prop
60+
- sorting_settings -> array of { field, ascending } -- replaces 'sort' prop
61+
- virtual_dataframe (READONLY)
62+
- virtual_dataframe_indices (READONLY; not officially supported yet -- IN DEVELOPMENT)
63+
Deprecated
64+
- sortable
65+
- sort
66+
- dataframe behavior on sort (see below)
67+
68+
virtual_dataframe vs. dataframe
69+
- the virtual dataframe is the content of the viewport for the user (e.g. user has a 10k rows dataframe with FE/250 lines paging, on 1st page -> the virtual_dataframe contains items [0,250[ of the dataframe); the dataframe still contains 10k items
70+
- 10k rows, no paging, sorting and filtering -> the virtual dataframe contains items visible in the viewport, in the visible order; the dataframe still contains 10k items
71+
- if the user modifies a cell, the dataframe and the virtual_dataframe are updated with the new data

packages/dash-table/dash_table/bundle.js

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/dash-table/dash_table/demo.js

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/dash-table/dash_table/metadata.json

+65-39
Original file line numberDiff line numberDiff line change
@@ -182,24 +182,6 @@
182182
"required": false,
183183
"description": ""
184184
},
185-
"sort": {
186-
"type": {
187-
"name": "array"
188-
},
189-
"required": false,
190-
"description": "",
191-
"defaultValue": {
192-
"value": "[]",
193-
"computed": false
194-
}
195-
},
196-
"sortable": {
197-
"type": {
198-
"name": "bool"
199-
},
200-
"required": false,
201-
"description": ""
202-
},
203185
"start_cell": {
204186
"type": {
205187
"name": "arrayOf",
@@ -492,13 +474,21 @@
492474
{
493475
"value": "'be'",
494476
"computed": false
477+
},
478+
{
479+
"value": "true",
480+
"computed": false
481+
},
482+
{
483+
"value": "false",
484+
"computed": false
495485
}
496486
]
497487
},
498488
"required": false,
499489
"description": "",
500490
"defaultValue": {
501-
"value": "'fe'",
491+
"value": "false",
502492
"computed": false
503493
}
504494
},
@@ -515,36 +505,72 @@
515505
},
516506
"sorting": {
517507
"type": {
518-
"name": "shape",
519-
"value": {
520-
"type": {
521-
"name": "string",
522-
"required": false
508+
"name": "enum",
509+
"value": [
510+
{
511+
"value": "'fe'",
512+
"computed": false
523513
},
524-
"options": {
525-
"name": "arrayOf",
526-
"value": {
527-
"name": "shape",
528-
"value": {
529-
"field": {
530-
"name": "string",
531-
"required": false
514+
{
515+
"value": "'be'",
516+
"computed": false
517+
},
518+
{
519+
"value": "true",
520+
"computed": false
521+
},
522+
{
523+
"value": "false",
524+
"computed": false
525+
}
526+
]
527+
},
528+
"required": false,
529+
"description": "",
530+
"defaultValue": {
531+
"value": "false",
532+
"computed": false
533+
}
534+
},
535+
"sorting_settings": {
536+
"type": {
537+
"name": "arrayOf",
538+
"value": {
539+
"name": "shape",
540+
"value": {
541+
"columnId": {
542+
"name": "union",
543+
"value": [
544+
{
545+
"name": "string"
532546
},
533-
"ascending": {
534-
"name": "custom",
535-
"raw": "PropTypes.boolean",
536-
"required": false
547+
{
548+
"name": "number"
537549
}
538-
}
550+
],
551+
"required": false
539552
},
540-
"required": false
553+
"direction": {
554+
"name": "enum",
555+
"value": [
556+
{
557+
"value": "'asc'",
558+
"computed": false
559+
},
560+
{
561+
"value": "'desc'",
562+
"computed": false
563+
}
564+
],
565+
"required": false
566+
}
541567
}
542568
}
543569
},
544570
"required": false,
545571
"description": "",
546572
"defaultValue": {
547-
"value": "{\n type: 'fe',\n options: []\n}",
573+
"value": "[]",
548574
"computed": false
549575
}
550576
},

packages/dash-table/demo/App.js

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
/* eslint no-magic-numbers: 0 */
2+
import * as R from 'ramda';
23
import React, {Component} from 'react';
34
import PropTypes from 'prop-types';
45
import {Table} from 'dash-table';
56
import {mockData} from './data';
6-
import {merge} from 'ramda';
77
import { memoizeOne } from 'core/memoizer';
88

99
const clone = o => JSON.parse(JSON.stringify(o));
@@ -12,21 +12,23 @@ class App extends Component {
1212
constructor() {
1313
super();
1414

15+
const dataframe: any[] = clone(mockData.dataframe);
16+
1517
this.state = {
1618
filter: '',
1719
tableProps: {
1820
id: 'table',
19-
dataframe: clone(mockData.dataframe),
20-
columns: clone(mockData.columns).map(col => merge(col, {
21+
dataframe: dataframe,
22+
columns: clone(mockData.columns).map(col => R.merge(col, {
2123
editable_name: true,
2224
deletable: true,
2325
// type: 'dropdown'
2426
})),
2527
editable: true,
28+
filtering: true,
29+
sorting: true,
2630
// n_fixed_rows: 3,
2731
// n_fixed_columns: 2,
28-
sortable: false,
29-
sort: [],
3032
merge_duplicate_headers: true,
3133
row_deletable: true,
3234
row_selectable: 'single',
@@ -46,7 +48,7 @@ class App extends Component {
4648
return newProps => {
4749
console.info('--->', newProps);
4850
this.setState({
49-
tableProps: merge(this.state.tableProps, newProps),
51+
tableProps: R.merge(this.state.tableProps, newProps),
5052
});
5153
};
5254
});

packages/dash-table/npm-shrinkwrap.json

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import * as R from 'ramda';
2+
import Logger from 'core/Logger';
3+
4+
export interface ISortSetting {
5+
columnId: string | number;
6+
direction: SortDirection;
7+
}
8+
9+
export enum SortDirection {
10+
Ascending = 'asc',
11+
Descending = 'desc',
12+
None = 'none'
13+
}
14+
15+
export type SortSettings = ISortSetting[];
16+
17+
export function updateSettings(
18+
settings: SortSettings,
19+
setting: ISortSetting
20+
): SortSettings {
21+
Logger.trace('updateSettings', settings, setting);
22+
23+
settings = R.clone(settings);
24+
25+
if (setting.direction === SortDirection.None) {
26+
const currentIndex = R.findIndex(s => s.columnId === setting.columnId, settings);
27+
28+
if (currentIndex !== -1) {
29+
settings.splice(currentIndex, 1);
30+
}
31+
} else {
32+
const currentSetting = R.find(s => s.columnId === setting.columnId, settings);
33+
34+
if (currentSetting) {
35+
currentSetting.direction = setting.direction;
36+
} else {
37+
settings.push(setting);
38+
}
39+
}
40+
41+
return settings;
42+
}
43+
44+
export default (dataframe: any[], settings: SortSettings): any[] => {
45+
if (!settings.length) {
46+
return dataframe;
47+
}
48+
49+
return R.sortWith(
50+
R.map(setting => {
51+
return setting.direction === SortDirection.Descending ?
52+
R.comparator((d1: any, d2: any) => {
53+
const id = setting.columnId;
54+
55+
const prop1 = d1[id];
56+
const prop2 = d2[id];
57+
58+
if (prop1 === undefined || prop1 === null) {
59+
return false;
60+
} else if (prop2 === undefined || prop2 === null) {
61+
return true;
62+
}
63+
64+
return prop1 > prop2;
65+
}) :
66+
R.comparator((d1: any, d2: any) => {
67+
const id = setting.columnId;
68+
69+
const prop1 = d1[id];
70+
const prop2 = d2[id];
71+
72+
if (prop1 === undefined || prop1 === null) {
73+
return false;
74+
} else if (prop2 === undefined || prop2 === null) {
75+
return true;
76+
}
77+
78+
return prop1 < prop2;
79+
});
80+
}, settings),
81+
dataframe
82+
);
83+
};

0 commit comments

Comments
 (0)