Skip to content
This repository was archived by the owner on Aug 29, 2025. It is now read-only.

fix regression + basic test#70

Merged
Marc-Andre-Rivet merged 10 commits intomasterfrom
3.0-copy-paste-regression
Sep 11, 2018
Merged

fix regression + basic test#70
Marc-Andre-Rivet merged 10 commits intomasterfrom
3.0-copy-paste-regression

Conversation

@Marc-Andre-Rivet
Copy link
Copy Markdown
Contributor

@Marc-Andre-Rivet Marc-Andre-Rivet commented Sep 11, 2018

This review is pretty big and divided in two parts

  1. the actual fix for the copy/paste issue + the delete cell issue + save on click out/blur issue (not much here -- mostly adding transforms between the real dataframe and the virtualized one and offsets)
  2. making it possible to test the copy/paste scenario in CI tests -- this requires overriding some behavior so that the copy/paste behaves in a way compatible with cypress -- this means creating a custom test configuration / special test code that overrides the normal behavior of the copy/paste while staying as close as possible to the original code so the test is still significant. ......... This is of course a bit hacky but well worth the price IMO.. this is the 2nd regression on this feature in 2 weeks, I'll take whatever flavor of coverage I can get!
  3. adding tests for the regressions

So, the special test version will handle the paste event through the onKeyDown event and call the onPaste handler. Copy will keep the copied value cached as it will be required -- there's no onPaste event -- and that's the only place where the clipboard data is made available.

"preprivate::opentests": "run-s private::wait*",
"preprivate::runtests": "run-s private::wait*",
"private::build": "webpack --display-reasons --bail",
"private::build_test": "webpack --display-reasons --bail --config webpack.test.config.js",
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A special 'test' build with a slightly different configuration for webpack

export default class Clipboard {
/*#if TEST_COPY_PASTE*/
private static value: string;
/*#endif*/
Copy link
Copy Markdown
Contributor Author

@Marc-Andre-Rivet Marc-Andre-Rivet Sep 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Webpack-preprocessor allows for conditional/build based code. This sometimes makes for pretty involved code.. but is a lot more flexible than, say, having an alias to some folder in dev vs test vs prod.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have to be careful though.. for the editor there is no if..else.. so all the code co-exists

let value;

/*#if TEST_COPY_PASTE*/
value = Clipboard.value;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep the copy value in a variable.. there's no event clipboard value in the test environment.. return the stored value instead!

// if paste event onPaste handler registered in Table jsx handles it
if (ctrlDown && e.keyCode === KEY_CODES.V) {
/*#if TEST_COPY_PASTE*/
this.onPaste({} as any);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normally the paste event is handled on its own, but here we need to call it from onkeydown instead

(row_deletable ? 1 : 0) +
(row_selectable ? 1 : 0);

const noOffsetSelectedCells: [number, number][] = R.map(
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actual offset fix. These offsets are creeping up everywhere.. once we have coverage we should refactor them out, they are useless and complicate everything.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, this is kind of confusing and perhaps a culprit for regressions. Not especially a fan of this const columnIndexOffset being repeated in switchCell, deleteCell, getNextCell, onCopy, onPaste etc..

module.exports = (on) => {
const options = {
webpackOptions: require('../../../../webpack.config'),
webpackOptions: require('../../../../webpack.test.config.js'),
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cypress uses the test configuration

{
definitions: ['TEST_COPY_PASTE']
},
'development'
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

preprocessor and mode overrides

- run:
name: Run build:js
command: npm run build:js
command: npm run build:js-test
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Build the test version..

});

// Commenting this test as Cypress team is having issues with the copy/paste scenario
// https://github.com/cypress-io/cypress/issues/2386
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Marc-Andre-Rivet maybe we want to add a TODO and keep a link to this issue in the code so we can rework this test if/when the above issue is resolved.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cldougl Good point. I'll add it back.

@cldougl
Copy link
Copy Markdown
Member

cldougl commented Sep 11, 2018

@Marc-Andre-Rivet copy and pasting works well for me initially, but it does not work if I sort a column:

cp

lmk if I can provide more information

@Marc-Andre-Rivet
Copy link
Copy Markdown
Contributor Author

Marc-Andre-Rivet commented Sep 11, 2018

@cldougl Thanks, will test it out.. guessing that if you remove the sorting, the data has been copied at the beginning of the dataframe -- behavior confirmed

@Marc-Andre-Rivet
Copy link
Copy Markdown
Contributor Author

@cldougl This problem sort/filter issue will also apply to delete cell #67 but should not affect actual cell editing

Marc-André Rivet added 2 commits September 11, 2018 10:29
- delete cell with and w/o sorting
- additional tests for copy/paste
## RC11 - Fix copy/paste regression, fix delete regression

Issue: https://github.com/plotly/dash-table/issues/64
Issue: https://github.com/plotly/dash-table/issues/67 No newline at end of file
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ended up working on both celle delete and copy/paste as it's the same issue

selected_cell
);

realCells.forEach(cell => {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we need to work on the real dataframe and the viewport is showing a virtualized subsection of the whole df, we need to map between the virtualized df and the real one to modify the correct indices.

}

const realActiveRow = virtual_dataframe_indices[activeCell[0]];
if (overflowRows && values.length + realActiveRow >= dataframe.length) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We normally add rows if the copy/paste requires more entries, but with sorting or filtering on, it's not obvious what the behavior should be. Preventing this from happening for now.

// let newDataframe = dataframe;
const col = newColumns[jOffset];
if (colIsEditable(true, col)) {
if (col && colIsEditable(true, col)) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's possible now that the column was not created, checking for it

row.forEach((cell: string, j: number) => {
const iOffset = activeCell[0] + i;
if (virtual_dataframe_indices.length <= activeCell[0] + i) {
return;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

row may not exist bc of the overflow toggle

.within(() => cy.get('.cell-value').should('have.value', 'MODIFIED'));
});

it('BE rountrip with sorted, unfiltered data', () => {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new test case for sorted data + copy/paste

@cldougl
Copy link
Copy Markdown
Member

cldougl commented Sep 11, 2018

💃 this looks a lot better to me!
As this is bug/regression fixes and test additions (great job adding tests @Marc-Andre-Rivet 🎉 🎉 )
I'm happy if we can merge this now to generate a bundle asap as this fixes a lot of issues.
@wbrgss feel free to continue to reviewing post merge if you have some comments or any questions about this 'workaround' testing structure!

Copy link
Copy Markdown
Contributor

@wbrgss wbrgss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests look good to me. Too bad about having to hack around the Cypress issue but I agree better there than not! 💃

(row_deletable ? 1 : 0) +
(row_selectable ? 1 : 0);

const realCells: [number, number][] = R.map(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Performance consideration: might be worth checking alternatives to R.map for mapping between many virtual => real cells if this is executing a lot. Same goes for noOffsetSelectedCells. Benchmark (higher is better):
https://www.measurethat.net/Benchmarks/ShowResult/32960

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know Ramda use is encouraged, but if you're looking to squeeze out some better UX responsiveness..

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wbrgss Agreed. Just being consistent. All this needs to be reworked. I have a placeholder issue #71 -- it feels like the virtualization layer will be the right place to put this in, make consistent, and optimize.

(row_deletable ? 1 : 0) +
(row_selectable ? 1 : 0);

const noOffsetSelectedCells: [number, number][] = R.map(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, this is kind of confusing and perhaps a culprit for regressions. Not especially a fan of this const columnIndexOffset being repeated in switchCell, deleteCell, getNextCell, onCopy, onPaste etc..

@Marc-Andre-Rivet Marc-Andre-Rivet merged commit 05ced2e into master Sep 11, 2018
@Marc-Andre-Rivet Marc-Andre-Rivet deleted the 3.0-copy-paste-regression branch September 12, 2018 11:31
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants