From d16512b7758e36a1263fc63bd7d9d1f93060dc93 Mon Sep 17 00:00:00 2001 From: Kamil Gabryjelski Date: Mon, 6 Mar 2023 13:42:52 +0100 Subject: [PATCH] fix(dashboard): Allow selecting text in cells in Table and PivotTable without triggering cross filters (#23283) --- .../src/utils/getSelectedText.ts | 19 +++++++++++ .../superset-ui-core/src/utils/index.ts | 1 + .../test/utils/getSelectedText.test.ts | 34 +++++++++++++++++++ .../src/PivotTableChart.tsx | 6 ++++ .../plugin-chart-table/src/TableChart.tsx | 8 ++++- 5 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 superset-frontend/packages/superset-ui-core/src/utils/getSelectedText.ts create mode 100644 superset-frontend/packages/superset-ui-core/test/utils/getSelectedText.test.ts diff --git a/superset-frontend/packages/superset-ui-core/src/utils/getSelectedText.ts b/superset-frontend/packages/superset-ui-core/src/utils/getSelectedText.ts new file mode 100644 index 0000000000..d3671d875c --- /dev/null +++ b/superset-frontend/packages/superset-ui-core/src/utils/getSelectedText.ts @@ -0,0 +1,19 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +export const getSelectedText = () => window.getSelection()?.toString(); diff --git a/superset-frontend/packages/superset-ui-core/src/utils/index.ts b/superset-frontend/packages/superset-ui-core/src/utils/index.ts index 19c5ed5861..4efc3dedb6 100644 --- a/superset-frontend/packages/superset-ui-core/src/utils/index.ts +++ b/superset-frontend/packages/superset-ui-core/src/utils/index.ts @@ -27,6 +27,7 @@ export { default as promiseTimeout } from './promiseTimeout'; export { default as logging } from './logging'; export { default as removeDuplicates } from './removeDuplicates'; export { lruCache } from './lruCache'; +export { getSelectedText } from './getSelectedText'; export * from './featureFlags'; export * from './random'; export * from './typedMemo'; diff --git a/superset-frontend/packages/superset-ui-core/test/utils/getSelectedText.test.ts b/superset-frontend/packages/superset-ui-core/test/utils/getSelectedText.test.ts new file mode 100644 index 0000000000..75682e9e74 --- /dev/null +++ b/superset-frontend/packages/superset-ui-core/test/utils/getSelectedText.test.ts @@ -0,0 +1,34 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { getSelectedText } from '@superset-ui/core'; + +test('Returns null if Selection object is null', () => { + jest.spyOn(window, 'getSelection').mockImplementationOnce(() => null); + expect(getSelectedText()).toEqual(undefined); + jest.restoreAllMocks(); +}); + +test('Returns selection text if Selection object is not null', () => { + jest + .spyOn(window, 'getSelection') + // @ts-ignore + .mockImplementationOnce(() => ({ toString: () => 'test string' })); + expect(getSelectedText()).toEqual('test string'); + jest.restoreAllMocks(); +}); diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/src/PivotTableChart.tsx b/superset-frontend/plugins/plugin-chart-pivot-table/src/PivotTableChart.tsx index 84a64adfc7..53e98fd31d 100644 --- a/superset-frontend/plugins/plugin-chart-pivot-table/src/PivotTableChart.tsx +++ b/superset-frontend/plugins/plugin-chart-pivot-table/src/PivotTableChart.tsx @@ -30,6 +30,7 @@ import { isAdhocColumn, BinaryQueryObjectFilterClause, t, + getSelectedText, } from '@superset-ui/core'; import { PivotTable, sortAs, aggregatorTemplates } from './react-pivottable'; import { @@ -356,6 +357,11 @@ export default function PivotTableChart(props: PivotTableProps) { return; } + // allow selecting text in a cell + if (getSelectedText()) { + return; + } + const isActiveFilterValue = (key: string, val: DataRecordValue) => !!selectedFilters && selectedFilters[key]?.includes(val); diff --git a/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx b/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx index 9843a4ae8b..ac02a10137 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx +++ b/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx @@ -41,6 +41,7 @@ import { DTTM_ALIAS, ensureIsArray, GenericDataType, + getSelectedText, getTimeFormatterForGranularity, BinaryQueryObjectFilterClause, styled, @@ -493,7 +494,12 @@ export default function TableChart( title: typeof value === 'number' ? String(value) : undefined, onClick: emitCrossFilters && !valueRange && !isMetric - ? () => toggleFilter(key, value) + ? () => { + // allow selecting text in a cell + if (!getSelectedText()) { + toggleFilter(key, value); + } + } : undefined, onContextMenu: (e: MouseEvent) => { if (handleContextMenu) {