You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by li...@apache.org on 2024/03/26 18:40:19 UTC
(superset) branch table-time-comparison updated: feat(time-comparison-table): show and hide time comparison columns (#27446)
This is an automated email from the ASF dual-hosted git repository.
lilykuang pushed a commit to branch table-time-comparison
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/table-time-comparison by this push:
new 9f062edb73 feat(time-comparison-table): show and hide time comparison columns (#27446)
9f062edb73 is described below
commit 9f062edb73eb15bc6aee43a9a90aa1662e39949f
Author: Lily Kuang <li...@preset.io>
AuthorDate: Tue Mar 26 11:40:12 2024 -0700
feat(time-comparison-table): show and hide time comparison columns (#27446)
---
.../src/{index.ts => components/Dropdown.tsx} | 20 +--
.../src/{index.ts => components/Menu.tsx} | 20 +--
.../superset-ui-chart-controls/src/index.ts | 4 +-
.../plugins/plugin-chart-table/package.json | 1 +
.../plugin-chart-table/src/DataTable/DataTable.tsx | 20 ++-
.../plugins/plugin-chart-table/src/TableChart.tsx | 172 ++++++++++++++++++++-
6 files changed, 190 insertions(+), 47 deletions(-)
diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/index.ts b/superset-frontend/packages/superset-ui-chart-controls/src/components/Dropdown.tsx
similarity index 56%
copy from superset-frontend/packages/superset-ui-chart-controls/src/index.ts
copy to superset-frontend/packages/superset-ui-chart-controls/src/components/Dropdown.tsx
index 4e00929119..032365ebd5 100644
--- a/superset-frontend/packages/superset-ui-chart-controls/src/index.ts
+++ b/superset-frontend/packages/superset-ui-chart-controls/src/components/Dropdown.tsx
@@ -16,22 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
-import * as sectionsModule from './sections';
-export * from './utils';
-export * from './constants';
-export * from './operators';
-
-// can't do `export * as sections from './sections'`, babel-transformer will fail
-export const sections = sectionsModule;
-
-export * from './components/InfoTooltipWithTrigger';
-export * from './components/ColumnOption';
-export * from './components/ColumnTypeLabel/ColumnTypeLabel';
-export * from './components/MetricOption';
-export * from './components/ControlSubSectionHeader';
-export * from './components/Tooltip';
-
-export * from './shared-controls';
-export * from './types';
-export * from './fixtures';
+export { Dropdown } from 'antd';
+export type { DropDownProps } from 'antd/lib/dropdown';
diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/index.ts b/superset-frontend/packages/superset-ui-chart-controls/src/components/Menu.tsx
similarity index 56%
copy from superset-frontend/packages/superset-ui-chart-controls/src/index.ts
copy to superset-frontend/packages/superset-ui-chart-controls/src/components/Menu.tsx
index 4e00929119..89a7405cde 100644
--- a/superset-frontend/packages/superset-ui-chart-controls/src/index.ts
+++ b/superset-frontend/packages/superset-ui-chart-controls/src/components/Menu.tsx
@@ -16,22 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
-import * as sectionsModule from './sections';
-export * from './utils';
-export * from './constants';
-export * from './operators';
-
-// can't do `export * as sections from './sections'`, babel-transformer will fail
-export const sections = sectionsModule;
-
-export * from './components/InfoTooltipWithTrigger';
-export * from './components/ColumnOption';
-export * from './components/ColumnTypeLabel/ColumnTypeLabel';
-export * from './components/MetricOption';
-export * from './components/ControlSubSectionHeader';
-export * from './components/Tooltip';
-
-export * from './shared-controls';
-export * from './types';
-export * from './fixtures';
+export { Menu } from 'antd';
+export type { MenuProps } from 'antd/lib/menu';
diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/index.ts b/superset-frontend/packages/superset-ui-chart-controls/src/index.ts
index 4e00929119..fed32cae3a 100644
--- a/superset-frontend/packages/superset-ui-chart-controls/src/index.ts
+++ b/superset-frontend/packages/superset-ui-chart-controls/src/index.ts
@@ -28,8 +28,10 @@ export const sections = sectionsModule;
export * from './components/InfoTooltipWithTrigger';
export * from './components/ColumnOption';
export * from './components/ColumnTypeLabel/ColumnTypeLabel';
-export * from './components/MetricOption';
export * from './components/ControlSubSectionHeader';
+export * from './components/Dropdown';
+export * from './components/Menu';
+export * from './components/MetricOption';
export * from './components/Tooltip';
export * from './shared-controls';
diff --git a/superset-frontend/plugins/plugin-chart-table/package.json b/superset-frontend/plugins/plugin-chart-table/package.json
index 6df1ceb33e..d43e33808e 100644
--- a/superset-frontend/plugins/plugin-chart-table/package.json
+++ b/superset-frontend/plugins/plugin-chart-table/package.json
@@ -37,6 +37,7 @@
"xss": "^1.0.14"
},
"peerDependencies": {
+ "@ant-design/icons": "^5.0.1",
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"@testing-library/dom": "^7.29.4",
diff --git a/superset-frontend/plugins/plugin-chart-table/src/DataTable/DataTable.tsx b/superset-frontend/plugins/plugin-chart-table/src/DataTable/DataTable.tsx
index 79ab44981e..242029e163 100644
--- a/superset-frontend/plugins/plugin-chart-table/src/DataTable/DataTable.tsx
+++ b/superset-frontend/plugins/plugin-chart-table/src/DataTable/DataTable.tsx
@@ -68,6 +68,7 @@ export interface DataTableProps<D extends object> extends TableOptions<D> {
wrapperRef?: MutableRefObject<HTMLDivElement>;
onColumnOrderChange: () => void;
renderGroupingHeaders?: () => JSX.Element;
+ renderTimeComparisonDropdown?: () => JSX.Element;
}
export interface RenderHTMLCellProps extends HTMLProps<HTMLTableCellElement> {
@@ -101,6 +102,7 @@ export default typedMemo(function DataTable<D extends object>({
wrapperRef: userWrapperRef,
onColumnOrderChange,
renderGroupingHeaders,
+ renderTimeComparisonDropdown,
...moreUseTableOptions
}: DataTableProps<D>): JSX.Element {
const tableHooks: PluginHook<D>[] = [
@@ -117,7 +119,8 @@ export default typedMemo(function DataTable<D extends object>({
const sortByRef = useRef([]); // cache initial `sortby` so sorting doesn't trigger page reset
const pageSizeRef = useRef([initialPageSize, resultsSize]);
const hasPagination = initialPageSize > 0 && resultsSize > 0; // pageSize == 0 means no pagination
- const hasGlobalControl = hasPagination || !!searchInput;
+ const hasGlobalControl =
+ hasPagination || !!searchInput || renderTimeComparisonDropdown;
const initialState = {
...initialState_,
// zero length means all pages, the `usePagination` plugin does not
@@ -359,7 +362,9 @@ export default typedMemo(function DataTable<D extends object>({
{hasGlobalControl ? (
<div ref={globalControlRef} className="form-inline dt-controls">
<div className="row">
- <div className="col-sm-6">
+ <div
+ className={renderTimeComparisonDropdown ? 'col-sm-5' : 'col-sm-6'}
+ >
{hasPagination ? (
<SelectPageSize
total={resultsSize}
@@ -375,7 +380,11 @@ export default typedMemo(function DataTable<D extends object>({
) : null}
</div>
{searchInput ? (
- <div className="col-sm-6">
+ <div
+ className={
+ renderTimeComparisonDropdown ? 'col-sm-5' : 'col-sm-6'
+ }
+ >
<GlobalFilter<D>
searchInput={
typeof searchInput === 'boolean' ? undefined : searchInput
@@ -386,6 +395,11 @@ export default typedMemo(function DataTable<D extends object>({
/>
</div>
) : null}
+ {renderTimeComparisonDropdown ? (
+ <div className="col-sm-2" style={{ float: 'right' }}>
+ {renderTimeComparisonDropdown()}
+ </div>
+ ) : null}
</div>
</div>
) : null}
diff --git a/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx b/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx
index ab75914c97..c274296ccd 100644
--- a/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx
+++ b/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx
@@ -50,6 +50,13 @@ import {
tn,
useTheme,
} from '@superset-ui/core';
+import { Dropdown, Menu } from '@superset-ui/chart-controls';
+import {
+ CheckOutlined,
+ DownOutlined,
+ MinusCircleOutlined,
+ PlusCircleOutlined,
+} from '@ant-design/icons';
import { isEmpty } from 'lodash';
import { DataColumnMeta, TableChartTransformedProps } from './types';
@@ -242,6 +249,12 @@ export default function TableChart<D extends DataRecord = DataRecord>(
emitCrossFilters,
enableTimeComparison,
} = props;
+ const comparisonColumns = [
+ { key: 'all', label: t('Display all') },
+ { key: '#', label: '#' },
+ { key: '△', label: '△' },
+ { key: '%', label: '%' },
+ ];
const timestampFormatter = useCallback(
value => getTimeFormatterForGranularity(timeGrain)(value),
[timeGrain],
@@ -252,6 +265,11 @@ export default function TableChart<D extends DataRecord = DataRecord>(
});
// keep track of whether column order changed, so that column widths can too
const [columnOrderToggle, setColumnOrderToggle] = useState(false);
+ const [showComparisonDropdown, setShowComparisonDropdown] = useState(false);
+ const [selectedComparisonColumns, setSelectedComparisonColumns] = useState([
+ comparisonColumns[0].key,
+ ]);
+ const [hideComparisonKeys, setHideComparisonKeys] = useState<string[]>([]);
const theme = useTheme();
// only take relevant page size options
@@ -371,6 +389,38 @@ export default function TableChart<D extends DataRecord = DataRecord>(
};
};
+ const comparisonLabels = [t('Main'), '#', '△', '%'];
+ const filteredColumnsMeta = useMemo(() => {
+ if (!enableTimeComparison) {
+ return columnsMeta;
+ }
+ const allColumns = comparisonColumns[0].key;
+ const main = comparisonLabels[0];
+ const showAllColumns = selectedComparisonColumns.includes(allColumns);
+
+ return columnsMeta.filter(({ label, key }) => {
+ // Extract the key portion after the space, assuming the format is always "label key"
+ const keyPortion = key.substring(label.length);
+ const isKeyHidded = hideComparisonKeys.includes(keyPortion);
+ const isLableMain = label === main;
+
+ return (
+ isLableMain ||
+ (!isKeyHidded &&
+ (!comparisonLabels.includes(label) ||
+ showAllColumns ||
+ selectedComparisonColumns.includes(label)))
+ );
+ });
+ }, [
+ columnsMeta,
+ comparisonColumns,
+ comparisonLabels,
+ enableTimeComparison,
+ hideComparisonKeys,
+ selectedComparisonColumns,
+ ]);
+
const handleContextMenu =
onContextMenu && !isRawRecords
? (
@@ -384,7 +434,7 @@ export default function TableChart<D extends DataRecord = DataRecord>(
clientY: number,
) => {
const drillToDetailFilters: BinaryQueryObjectFilterClause[] = [];
- columnsMeta.forEach(col => {
+ filteredColumnsMeta.forEach(col => {
if (!col.isMetric) {
const dataRecordValue = value[col.key];
drillToDetailFilters.push({
@@ -416,8 +466,6 @@ export default function TableChart<D extends DataRecord = DataRecord>(
}
: undefined;
- const comparisonLabels = [t('Main'), '#', '△', '%'];
-
const getHeaderColumns = (
columnsMeta: DataColumnMeta[],
enableTimeComparison?: boolean,
@@ -447,6 +495,89 @@ export default function TableChart<D extends DataRecord = DataRecord>(
return resultMap;
};
+ const renderTimeComparisonDropdown = (): JSX.Element => {
+ const allKey = comparisonColumns[0].key;
+ const handleOnClick = (data: any) => {
+ const { key } = data;
+ // Toggle 'All' key selection
+ if (key === allKey) {
+ setSelectedComparisonColumns([allKey]);
+ } else if (selectedComparisonColumns.includes(allKey)) {
+ setSelectedComparisonColumns([key]);
+ } else {
+ // Toggle selection for other keys
+ setSelectedComparisonColumns(
+ selectedComparisonColumns.includes(key)
+ ? selectedComparisonColumns.filter(k => k !== key) // Deselect if already selected
+ : [...selectedComparisonColumns, key],
+ ); // Select if not already selected
+ }
+ };
+
+ const handleOnBlur = () => {
+ if (selectedComparisonColumns.length === 3) {
+ setSelectedComparisonColumns([comparisonColumns[0].key]);
+ }
+ };
+
+ return (
+ <Dropdown
+ placement="bottomRight"
+ visible={showComparisonDropdown}
+ onVisibleChange={(flag: boolean) => {
+ setShowComparisonDropdown(flag);
+ }}
+ overlay={
+ <Menu
+ multiple
+ onClick={handleOnClick}
+ onBlur={handleOnBlur}
+ selectedKeys={selectedComparisonColumns}
+ >
+ <div
+ css={css`
+ max-width: 242px;
+ padding: 0 ${theme.gridUnit * 2}px;
+ color: ${theme.colors.grayscale.base};
+ font-size: ${theme.typography.sizes.s}px;
+ `}
+ >
+ {t(
+ 'Select columns that will be displayed in the table. You can multiselect columns.',
+ )}
+ </div>
+ {comparisonColumns.map(column => (
+ <Menu.Item key={column.key}>
+ <span
+ css={css`
+ color: ${theme.colors.grayscale.dark2};
+ `}
+ >
+ {column.label}
+ </span>
+ <span
+ css={css`
+ float: right;
+ font-size: ${theme.typography.sizes.s}px;
+ `}
+ >
+ {selectedComparisonColumns.includes(column.key) && (
+ <CheckOutlined />
+ )}
+ </span>
+ </Menu.Item>
+ ))}
+ </Menu>
+ }
+ trigger={['click']}
+ >
+ <span>
+ {t('Display columns')} <DownOutlined />
+ </span>
+ </Dropdown>
+ );
+ };
+
const renderGroupingHeaders = (): JSX.Element => {
// TODO: Make use of ColumnGroup to render the aditional headers
const headers: any = [];
@@ -472,6 +603,30 @@ export default function TableChart<D extends DataRecord = DataRecord>(
headers.push(
<th key={`header-${key}`} colSpan={colSpan} style={{ borderBottom: 0 }}>
{key}
+ <span
+ css={css`
+ float: right;
+ & svg {
+ color: ${theme.colors.grayscale.base} !important;
+ }
+ `}
+ >
+ {hideComparisonKeys.includes(key) ? (
+ <PlusCircleOutlined
+ onClick={() =>
+ setHideComparisonKeys(
+ hideComparisonKeys.filter(k => k !== key),
+ )
+ }
+ />
+ ) : (
+ <MinusCircleOutlined
+ onClick={() =>
+ setHideComparisonKeys([...hideComparisonKeys, key])
+ }
+ />
+ )}
+ </span>
</th>,
);
@@ -499,8 +654,8 @@ export default function TableChart<D extends DataRecord = DataRecord>(
};
const groupHeaderColumns = useMemo(
- () => getHeaderColumns(columnsMeta, enableTimeComparison),
- [columnsMeta, enableTimeComparison],
+ () => getHeaderColumns(filteredColumnsMeta, enableTimeComparison),
+ [filteredColumnsMeta, enableTimeComparison],
);
const getColumnConfigs = useCallback(
@@ -769,8 +924,8 @@ export default function TableChart<D extends DataRecord = DataRecord>(
);
const columns = useMemo(
- () => columnsMeta.map(getColumnConfigs),
- [columnsMeta, getColumnConfigs],
+ () => filteredColumnsMeta.map(getColumnConfigs),
+ [filteredColumnsMeta, getColumnConfigs],
);
const handleServerPaginationChange = useCallback(
@@ -840,6 +995,9 @@ export default function TableChart<D extends DataRecord = DataRecord>(
renderGroupingHeaders={
!isEmpty(groupHeaderColumns) ? renderGroupingHeaders : undefined
}
+ renderTimeComparisonDropdown={
+ enableTimeComparison ? renderTimeComparisonDropdown : undefined
+ }
/>
</Styles>
);