Skip to content
This repository was archived by the owner on Jun 4, 2024. It is now read-only.

Commit e9dd645

Browse files
author
Marc-André Rivet
committed
Merge branch 'exp-dynamic' of github.com:plotly/dash-table into exp-dynamic
2 parents b76e26a + bb90b16 commit e9dd645

File tree

6 files changed

+116
-32
lines changed

6 files changed

+116
-32
lines changed

CHANGELOG.md

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@
22
All notable changes to this project will be documented in this file.
33
This project adheres to [Semantic Versioning](http://semver.org/).
44

5-
## Unreleased
5+
## [4.4.1] - 2019-08-17
66
### Fixed
7-
8-
- [#618](https://github.com/plotly/dash-table/issues/618) Fix a bug with keyboard navigation not
9-
working correctly in certain circumstances when the table contains `readonly` columns.
10-
11-
- [#206](https://github.com/plotly/dash-table/issues/206) Fix a bug with copy/paste to and from
12-
column filters not working.
7+
- [#618](https://github.com/plotly/dash-table/issues/618) Fix a bug with keyboard navigation not working correctly in certain circumstances when the table contains `readonly` columns.
8+
- [#206](https://github.com/plotly/dash-table/issues/206) Fix a bug with copy/paste to and from column filters not working.
9+
- [#561](https://github.com/plotly/dash-table/issues/561) Fix an incorrect React PureComponent usage causing warnings in DevTools.
10+
- [#611](https://github.com/plotly/dash-table/issues/611) Fix a bug with copy/paste causing hidden columns to be removed from the table
1311

1412
## Unreleased
1513
### Changed

src/dash-table/components/ControlledTable/fragments/TableTooltip.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { PureComponent } from 'react';
1+
import React, { Component } from 'react';
22

33
import Tooltip, { ITooltipProps, Arrow } from 'dash-table/components/Tooltip';
44
import tooltipHelper from 'dash-table/components/tooltipHelper';
@@ -10,7 +10,7 @@ interface IState {
1010
cell?: any;
1111
}
1212

13-
export default class TableTooltip extends PureComponent<ITooltipProps, IState> {
13+
export default class TableTooltip extends Component<ITooltipProps, IState> {
1414
constructor(props: ITooltipProps) {
1515
super(props);
1616

src/dash-table/components/ControlledTable/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,7 @@ export default class ControlledTable extends PureComponent<ControlledTableProps>
587587
onPaste = (e: any) => {
588588
const {
589589
active_cell,
590+
columns,
590591
data,
591592
editable,
592593
filter_query,
@@ -606,6 +607,7 @@ export default class ControlledTable extends PureComponent<ControlledTableProps>
606607
e,
607608
active_cell,
608609
viewport.indices,
610+
columns,
609611
visibleColumns,
610612
data,
611613
true,

src/dash-table/utils/TableClipboardHelper.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export default class TableClipboardHelper {
5252
activeCell: ICellCoordinates,
5353
derived_viewport_indices: number[],
5454
columns: Columns,
55+
visibleColumns: Columns,
5556
data: Data,
5657
overflowColumns: boolean = true,
5758
overflowRows: boolean = true,
@@ -73,6 +74,7 @@ export default class TableClipboardHelper {
7374
activeCell,
7475
derived_viewport_indices,
7576
columns,
77+
visibleColumns,
7678
data,
7779
overflowColumns,
7880
overflowRows

src/dash-table/utils/applyClipboardToData.ts

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ export default (
99
values: any[][],
1010
activeCell: ICellCoordinates,
1111
derived_viewport_indices: number[],
12-
columns: Columns,
12+
columns_: Columns,
13+
visibleColumns: Columns,
1314
data: Data,
1415
overflowColumns: boolean = true,
1516
overflowRows: boolean = true
@@ -23,29 +24,41 @@ export default (
2324
}
2425

2526
// don't modify the data and columns directly -- we may abort the paste
27+
// Individual rows will be modified, needs to be a deep clone
2628
let newData = R.clone(data);
27-
const newColumns = R.clone(columns);
29+
// Might add columns, not modifying the columns themselves, shallow clone is sufficient
30+
let newColumns = columns_.slice(0);
31+
let newVisibleColumns = visibleColumns.slice(0);
2832

29-
if (overflowColumns && values[0].length + (activeCell as any).column >= columns.length) {
33+
if (overflowColumns && values[0].length + (activeCell as any).column >= visibleColumns.length) {
34+
const _newColumns = [];
3035
for (
31-
let i = columns.length;
36+
let i = visibleColumns.length;
3237
i < values[0].length + (activeCell as any).column;
3338
i++
3439
) {
35-
newColumns.push({
40+
_newColumns.push({
3641
id: `Column ${i + 1}`,
3742
name: `Column ${i + 1}`,
3843
type: ColumnType.Any,
3944
sort_as_null: []
4045
} as any);
4146
newData.forEach(row => (row[`Column ${i}`] = ''));
4247
}
48+
49+
newColumns = R.insertAll(
50+
R.indexOf(R.last(visibleColumns), columns_) + 1,
51+
_newColumns,
52+
newColumns
53+
);
54+
55+
newVisibleColumns = R.concat(newVisibleColumns, _newColumns);
4356
}
4457

4558
const realActiveRow = derived_viewport_indices[(activeCell as any).row];
4659
if (overflowRows && values.length + realActiveRow >= data.length) {
4760
const emptyRow: any = {};
48-
columns.forEach(c => (emptyRow[c.id] = ''));
61+
visibleColumns.forEach(c => (emptyRow[c.id] = ''));
4962
newData = R.concat(
5063
newData,
5164
R.repeat(
@@ -73,7 +86,7 @@ export default (
7386
}
7487

7588
const jOffset = (activeCell as any).column + j;
76-
const col = newColumns[jOffset];
89+
const col = newVisibleColumns[jOffset];
7790
if (!col || !col.editable) {
7891
continue;
7992
}

tests/cypress/tests/unit/clipboard_test.ts

Lines changed: 85 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,75 @@ import * as R from 'ramda';
33
import applyClipboardToData from 'dash-table/utils/applyClipboardToData';
44

55
describe('clipboard', () => {
6+
const columns = ['c1'].map(id => ({ id: id, name: id, editable: true, sort_as_null: [] }));
7+
8+
describe('with hidden columns', () => {
9+
const altColumns = [
10+
'c1',
11+
'c2'
12+
].map(id => ({ id: id, name: id, editable: true, sort_as_null: [] }));
13+
14+
describe('with column overflow', () => {
15+
it('returns all columns, 1st column visible only', () => {
16+
const altVisibleColumns = altColumns.slice(0, 1);
17+
18+
const res = applyClipboardToData(
19+
R.range(0, 2).map(value => [`${value}`, `${value + 1}`]),
20+
{ row: 0, column: 0, column_id: '' },
21+
R.range(0, 1),
22+
altColumns,
23+
altVisibleColumns,
24+
R.range(0, 1).map(() => ({ c1: 'c1', c2: 'c2' })),
25+
true,
26+
true
27+
);
28+
29+
expect(res).to.not.equal(undefined);
30+
31+
if (res) {
32+
expect(res.data.length).to.equal(2);
33+
expect(Object.entries(res.data[0]).length).to.equal(3);
34+
expect(res.columns.length).to.equal(3);
35+
expect(res.columns[0].id).to.equal('c1');
36+
expect(res.columns[2].id).to.equal('c2');
37+
}
38+
});
39+
});
40+
41+
it('returns all columns, 2nd column visible only', () => {
42+
const altVisibleColumns = altColumns.slice(-1);
43+
44+
const res = applyClipboardToData(
45+
R.range(0, 2).map(value => [`${value}`, `${value + 1}`]),
46+
{ row: 0, column: 0, column_id: '' },
47+
R.range(0, 1),
48+
altColumns,
49+
altVisibleColumns,
50+
R.range(0, 1).map(() => ({ c1: 'c1', c2: 'c2' })),
51+
true,
52+
true
53+
);
54+
55+
expect(res).to.not.equal(undefined);
56+
57+
if (res) {
58+
expect(res.data.length).to.equal(2);
59+
expect(Object.entries(res.data[0]).length).to.equal(3);
60+
expect(res.columns.length).to.equal(3);
61+
expect(res.columns[0].id).to.equal('c1');
62+
expect(res.columns[1].id).to.equal('c2');
63+
}
64+
});
65+
});
66+
667
describe('with column/row overflow allowed', () => {
768
it('pastes one line at [0, 0] in one line df', () => {
869
const res = applyClipboardToData(
970
R.range(0, 1).map(value => [`${value}`]),
10-
{row: 0, column: 0, column_id: ''},
71+
{ row: 0, column: 0, column_id: '' },
1172
R.range(0, 1),
12-
['c1'].map(id => ({ id: id, name: id, editable: true, sort_as_null: [] })),
73+
columns,
74+
columns,
1375
R.range(0, 1).map(() => ({ c1: 'c1' })),
1476
true,
1577
true
@@ -26,9 +88,10 @@ describe('clipboard', () => {
2688
it('pastes two lines at [0, 0] in one line df', () => {
2789
const res = applyClipboardToData(
2890
R.range(0, 2).map(value => [`${value}`]),
29-
{row: 0, column: 0, column_id: ''},
91+
{ row: 0, column: 0, column_id: '' },
3092
R.range(0, 1),
31-
['c1'].map(id => ({ id: id, name: id, editable: true, sort_as_null: [] })),
93+
columns,
94+
columns,
3295
R.range(0, 1).map(() => ({ c1: 'c1' })),
3396
true,
3497
true
@@ -46,9 +109,10 @@ describe('clipboard', () => {
46109
it('pastes ten lines at [0, 0] in three line df', () => {
47110
const res = applyClipboardToData(
48111
R.range(0, 10).map(value => [`${value}`]),
49-
{row: 0, column: 0, column_id: ''},
112+
{ row: 0, column: 0, column_id: '' },
50113
R.range(0, 3),
51-
['c1'].map(id => ({ id: id, name: id, editable: true, sort_as_null: [] })),
114+
columns,
115+
columns,
52116
R.range(0, 3).map(() => ({ c1: 'c1' })),
53117
true,
54118
true
@@ -67,9 +131,10 @@ describe('clipboard', () => {
67131
it('pastes ten lines at [1, 0] in three line df', () => {
68132
const res = applyClipboardToData(
69133
R.range(0, 10).map(value => [`${value}`]),
70-
{row: 1, column: 0, column_id: ''},
134+
{ row: 1, column: 0, column_id: '' },
71135
R.range(0, 3),
72-
['c1'].map(id => ({ id: id, name: id, editable: true, sort_as_null: [] })),
136+
columns,
137+
columns,
73138
R.range(0, 3).map(() => ({ c1: 'c1' })),
74139
true,
75140
true
@@ -91,9 +156,10 @@ describe('clipboard', () => {
91156
it('pastes one line at [0, 0] in one line df', () => {
92157
const res = applyClipboardToData(
93158
R.range(0, 1).map(value => [`${value}`]),
94-
{row: 0, column: 0, column_id: ''},
159+
{ row: 0, column: 0, column_id: '' },
95160
R.range(0, 1),
96-
['c1'].map(id => ({ id: id, name: id, editable: true, sort_as_null: [] })),
161+
columns,
162+
columns,
97163
R.range(0, 1).map(() => ({ c1: 'c1' })),
98164
true,
99165
false
@@ -110,9 +176,10 @@ describe('clipboard', () => {
110176
it('pastes two lines at [0, 0] in one line df', () => {
111177
const res = applyClipboardToData(
112178
R.range(0, 2).map(value => [`${value}`]),
113-
{row: 0, column: 0, column_id: ''},
179+
{ row: 0, column: 0, column_id: '' },
114180
R.range(0, 1),
115-
['c1'].map(id => ({ id: id, name: id, editable: true, sort_as_null: [] })),
181+
columns,
182+
columns,
116183
R.range(0, 1).map(() => ({ c1: 'c1' })),
117184
true,
118185
false
@@ -129,9 +196,10 @@ describe('clipboard', () => {
129196
it('pastes ten lines at [0, 0] in three line df', () => {
130197
const res = applyClipboardToData(
131198
R.range(0, 10).map(value => [`${value}`]),
132-
{row: 0, column: 0, column_id: ''},
199+
{ row: 0, column: 0, column_id: '' },
133200
R.range(0, 3),
134-
['c1'].map(id => ({ id: id, name: id, editable: true, sort_as_null: [] })),
201+
columns,
202+
columns,
135203
R.range(0, 3).map(() => ({ c1: 'c1' })),
136204
true,
137205
false
@@ -150,9 +218,10 @@ describe('clipboard', () => {
150218
it('pastes ten lines at [1, 0] in three line df', () => {
151219
const res = applyClipboardToData(
152220
R.range(0, 10).map(value => [`${value}`]),
153-
{row: 1, column: 0, column_id: ''},
221+
{ row: 1, column: 0, column_id: '' },
154222
R.range(0, 3),
155-
['c1'].map(id => ({ id: id, name: id, editable: true, sort_as_null: [] })),
223+
columns,
224+
columns,
156225
R.range(0, 3).map(() => ({ c1: 'c1' })),
157226
true,
158227
false

0 commit comments

Comments
 (0)