From 118b187d65d6dce096215f0202ed0e7cb0c25107 Mon Sep 17 00:00:00 2001 From: Ville Brofeldt Date: Tue, 18 Apr 2023 11:25:36 +0300 Subject: [PATCH 1/4] feat(sqllab): add headers when copying results to clipboard --- superset-frontend/src/utils/common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/superset-frontend/src/utils/common.js b/superset-frontend/src/utils/common.js index 4bc702d447584..30a356a57589e 100644 --- a/superset-frontend/src/utils/common.js +++ b/superset-frontend/src/utils/common.js @@ -79,7 +79,7 @@ export function optionFromValue(opt) { } export function prepareCopyToClipboardTabularData(data, columns) { - let result = ''; + let result = `${columns.map(column => column.name).join('\t')}\n`; for (let i = 0; i < data.length; i += 1) { const row = {}; for (let j = 0; j < columns.length; j += 1) { From 327bace7ad59b8699d1a79b83d8cf93579a43f19 Mon Sep 17 00:00:00 2001 From: Ville Brofeldt Date: Tue, 18 Apr 2023 11:48:26 +0300 Subject: [PATCH 2/4] fix tests --- superset-frontend/src/utils/common.js | 2 +- superset-frontend/src/utils/common.test.jsx | 24 ++++++++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/superset-frontend/src/utils/common.js b/superset-frontend/src/utils/common.js index 30a356a57589e..c7b95dfafafc5 100644 --- a/superset-frontend/src/utils/common.js +++ b/superset-frontend/src/utils/common.js @@ -79,7 +79,7 @@ export function optionFromValue(opt) { } export function prepareCopyToClipboardTabularData(data, columns) { - let result = `${columns.map(column => column.name).join('\t')}\n`; + let result = `${columns.map(column => column.name || column).join('\t')}\n`; for (let i = 0; i < data.length; i += 1) { const row = {}; for (let j = 0; j < columns.length; j += 1) { diff --git a/superset-frontend/src/utils/common.test.jsx b/superset-frontend/src/utils/common.test.jsx index 59cba6e7b2d0c..1e4dfcb8218b9 100644 --- a/superset-frontend/src/utils/common.test.jsx +++ b/superset-frontend/src/utils/common.test.jsx @@ -50,28 +50,28 @@ describe('utils/common', () => { }); describe('prepareCopyToClipboardTabularData', () => { it('converts empty array', () => { - const array = []; - const column = []; - expect(prepareCopyToClipboardTabularData(array, column)).toEqual(''); + const data = []; + const columns = []; + expect(prepareCopyToClipboardTabularData(data, columns)).toEqual('\n'); }); it('converts non empty array', () => { - const array = [ + const data = [ { column1: 'lorem', column2: 'ipsum' }, { column1: 'dolor', column2: 'sit', column3: 'amet' }, ]; - const column = ['column1', 'column2', 'column3']; - expect(prepareCopyToClipboardTabularData(array, column)).toEqual( - 'lorem\tipsum\t\ndolor\tsit\tamet\n', + const columns = ['column1', 'column2', 'column3']; + expect(prepareCopyToClipboardTabularData(data, columns)).toEqual( + 'column1\tcolumn2\tcolumn3\nlorem\tipsum\t\ndolor\tsit\tamet\n', ); }); - it('includes 0 values', () => { - const array = [ + it('includes 0 values and handle column objects', () => { + const data = [ { column1: 0, column2: 0 }, { column1: 1, column2: -1, 0: 0 }, ]; - const column = ['column1', 'column2', '0']; - expect(prepareCopyToClipboardTabularData(array, column)).toEqual( - '0\t0\t\n1\t-1\t0\n', + const columns = [{ name: 'column1' }, { name: 'column2' }, { name: '0' }]; + expect(prepareCopyToClipboardTabularData(data, columns)).toEqual( + 'column1\tcolumn2\t0\n0\t0\t\n1\t-1\t0\n', ); }); }); From 458edf785bb1ff5f5652b36b05d03242fe45b8a3 Mon Sep 17 00:00:00 2001 From: Ville Brofeldt Date: Tue, 18 Apr 2023 13:12:55 +0300 Subject: [PATCH 3/4] DRY --- superset-frontend/src/utils/common.js | 10 ++++++++-- superset-frontend/src/utils/common.test.jsx | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/superset-frontend/src/utils/common.js b/superset-frontend/src/utils/common.js index c7b95dfafafc5..e9418f9d31d2d 100644 --- a/superset-frontend/src/utils/common.js +++ b/superset-frontend/src/utils/common.js @@ -78,14 +78,20 @@ export function optionFromValue(opt) { return { value: optionValue(opt), label: optionLabel(opt) }; } +function getColumnName(column) { + return column.name || column; +} + export function prepareCopyToClipboardTabularData(data, columns) { - let result = `${columns.map(column => column.name || column).join('\t')}\n`; + let result = columns.length + ? `${columns.map(getColumnName).join('\t')}\n` + : ''; for (let i = 0; i < data.length; i += 1) { const row = {}; for (let j = 0; j < columns.length; j += 1) { // JavaScript does not maintain the order of a mixed set of keys (i.e integers and strings) // the below function orders the keys based on the column names. - const key = columns[j].name || columns[j]; + const key = getColumnName(columns[j]); if (key in data[i]) { row[j] = data[i][key]; } else { diff --git a/superset-frontend/src/utils/common.test.jsx b/superset-frontend/src/utils/common.test.jsx index 1e4dfcb8218b9..a334b342c296d 100644 --- a/superset-frontend/src/utils/common.test.jsx +++ b/superset-frontend/src/utils/common.test.jsx @@ -52,7 +52,7 @@ describe('utils/common', () => { it('converts empty array', () => { const data = []; const columns = []; - expect(prepareCopyToClipboardTabularData(data, columns)).toEqual('\n'); + expect(prepareCopyToClipboardTabularData(data, columns)).toEqual(''); }); it('converts non empty array', () => { const data = [ From d431f6a0301d3511fc792ce90d1b39e11cc3afc2 Mon Sep 17 00:00:00 2001 From: Ville Brofeldt Date: Tue, 18 Apr 2023 17:38:21 +0300 Subject: [PATCH 4/4] fix yet another test --- .../components/DataTablesPane/test/DataTablesPane.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/superset-frontend/src/explore/components/DataTablesPane/test/DataTablesPane.test.tsx b/superset-frontend/src/explore/components/DataTablesPane/test/DataTablesPane.test.tsx index 4a4a5203f5af9..34dcf01bca7d1 100644 --- a/superset-frontend/src/explore/components/DataTablesPane/test/DataTablesPane.test.tsx +++ b/superset-frontend/src/explore/components/DataTablesPane/test/DataTablesPane.test.tsx @@ -108,7 +108,7 @@ describe('DataTablesPane', () => { userEvent.click(screen.getByLabelText('Copy')); expect(copyToClipboardSpy).toHaveBeenCalledTimes(1); const value = await copyToClipboardSpy.mock.calls[0][0](); - expect(value).toBe('2009-01-01 00:00:00\tAction\n'); + expect(value).toBe('__timestamp\tgenre\n2009-01-01 00:00:00\tAction\n'); copyToClipboardSpy.mockRestore(); fetchMock.restore(); });