mirror of
https://github.com/apache/superset.git
synced 2024-09-19 20:19:37 -04:00
feat: align metrics title to the right (#721)
This commit is contained in:
parent
ac1f518c09
commit
835335d3e4
@ -23,7 +23,6 @@ import {
|
||||
useSortBy,
|
||||
useGlobalFilter,
|
||||
PluginHook,
|
||||
TableCellProps,
|
||||
TableOptions,
|
||||
FilterType,
|
||||
IdType,
|
||||
@ -34,7 +33,6 @@ import GlobalFilter, { GlobalFilterProps } from './components/GlobalFilter';
|
||||
import SelectPageSize, { SizeOption } from './components/SelectPageSize';
|
||||
import SimplePagination from './components/Pagination';
|
||||
import useSticky from './hooks/useSticky';
|
||||
import useColumnCellProps from './hooks/useColumnCellProps';
|
||||
|
||||
export interface DataTableProps<D extends object> extends TableOptions<D> {
|
||||
tableClassName?: string;
|
||||
@ -76,7 +74,6 @@ export default function DataTable<D extends object>({
|
||||
useGlobalFilter,
|
||||
useSortBy,
|
||||
usePagination,
|
||||
useColumnCellProps,
|
||||
doSticky ? useSticky : [],
|
||||
hooks || [],
|
||||
].flat();
|
||||
@ -166,19 +163,10 @@ export default function DataTable<D extends object>({
|
||||
return (
|
||||
<tr key={headerGroupKey || headerGroup.id} {...headerGroupProps}>
|
||||
{headerGroup.headers.map(column => {
|
||||
const { key: headerKey, className, ...props } = column.getHeaderProps(
|
||||
column.getSortByToggleProps(),
|
||||
);
|
||||
return (
|
||||
<th
|
||||
key={headerKey || column.id}
|
||||
className={column.isSorted ? `${className || ''} is-sorted` : className}
|
||||
{...props}
|
||||
>
|
||||
{column.render('Header')}
|
||||
{column.render('SortIcon')}
|
||||
</th>
|
||||
);
|
||||
return column.render('Header', {
|
||||
key: column.id,
|
||||
...column.getSortByToggleProps(),
|
||||
});
|
||||
})}
|
||||
</tr>
|
||||
);
|
||||
@ -191,21 +179,7 @@ export default function DataTable<D extends object>({
|
||||
const { key: rowKey, ...rowProps } = row.getRowProps();
|
||||
return (
|
||||
<tr key={rowKey || row.id} {...rowProps}>
|
||||
{row.cells.map(cell => {
|
||||
const cellProps = cell.getCellProps() as TableCellProps & RenderHTMLCellProps;
|
||||
const { key: cellKey, cellContent, ...restProps } = cellProps;
|
||||
const key = cellKey || cell.column.id;
|
||||
if (cellProps.dangerouslySetInnerHTML) {
|
||||
return <td key={key} {...restProps} />;
|
||||
}
|
||||
// If cellProps renderes textContent already, then we don't have to
|
||||
// render `Cell`. This saves some time for large tables.
|
||||
return (
|
||||
<td key={key} {...restProps}>
|
||||
{cellContent || cell.render('Cell')}
|
||||
</td>
|
||||
);
|
||||
})}
|
||||
{row.cells.map(cell => cell.render('Cell', { key: cell.column.id }))}
|
||||
</tr>
|
||||
);
|
||||
})
|
||||
|
@ -1,38 +0,0 @@
|
||||
/**
|
||||
* 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 { HTMLProps } from 'react';
|
||||
import { Hooks, Cell, TableCellProps, ColumnInstance } from 'react-table';
|
||||
|
||||
export interface UseColumnCellPropsColumnOption<D extends object, V = unknown> {
|
||||
cellProps?: (
|
||||
cell: Cell<D, V>,
|
||||
props: Partial<TableCellProps>,
|
||||
) => Partial<HTMLProps<HTMLTableDataCellElement>> | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure cell props in column options.
|
||||
*/
|
||||
export default function useColumnCellProps<D extends object>(hooks: Hooks<D>) {
|
||||
hooks.getCellProps.push((props, { cell }) => {
|
||||
const column = cell.column as ColumnInstance<D>;
|
||||
return (column.cellProps && column.cellProps(cell, props)) || [];
|
||||
});
|
||||
}
|
||||
useColumnCellProps.pluginName = 'useColumnCellProps';
|
@ -16,7 +16,6 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
export * from './hooks/useColumnCellProps';
|
||||
export * from './hooks/useSticky';
|
||||
export * from './components/GlobalFilter';
|
||||
export * from './components/Pagination';
|
||||
|
@ -19,10 +19,10 @@ import {
|
||||
UseSortByHooks,
|
||||
TableInstance,
|
||||
ColumnInstance,
|
||||
Column,
|
||||
Renderer,
|
||||
HeaderProps,
|
||||
} from 'react-table';
|
||||
|
||||
import { UseColumnCellPropsColumnOption } from '../hooks/useColumnCellProps';
|
||||
import { UseStickyState, UseStickyTableOptions, UseStickyInstanceProps } from '../hooks/useSticky';
|
||||
|
||||
declare module 'react-table' {
|
||||
@ -53,13 +53,6 @@ declare module 'react-table' {
|
||||
UseSortByState<D>,
|
||||
UseStickyState {}
|
||||
|
||||
export interface ColumnInterface<D extends object>
|
||||
extends UseGlobalFiltersColumnOptions<D>,
|
||||
UseSortByColumnOptions<D>,
|
||||
UseColumnCellPropsColumnOption<D> {
|
||||
SortIcon: Column['Header'];
|
||||
}
|
||||
|
||||
// Typing from @types/react-table is incomplete
|
||||
interface TableSortByToggleProps {
|
||||
style?: React.CSSProperties;
|
||||
@ -67,10 +60,17 @@ declare module 'react-table' {
|
||||
onClick?: React.MouseEventHandler;
|
||||
}
|
||||
|
||||
export interface ColumnInterface<D extends object>
|
||||
extends UseGlobalFiltersColumnOptions<D>,
|
||||
UseSortByColumnOptions<D> {
|
||||
// must define as a new property because it's not possible to override
|
||||
// the existing `Header` renderer option
|
||||
Header?: Renderer<TableSortByToggleProps & HeaderProps<D>>;
|
||||
}
|
||||
|
||||
export interface ColumnInstance<D extends object>
|
||||
extends UseGlobalFiltersColumnOptions<D>,
|
||||
UseSortByColumnProps<D>,
|
||||
UseColumnCellPropsColumnOption<D> {
|
||||
UseSortByColumnProps<D> {
|
||||
getSortByToggleProps: (props?: Partial<TableSortByToggleProps>) => TableSortByToggleProps;
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* under the License.
|
||||
*/
|
||||
import React, { useState, useMemo, useCallback } from 'react';
|
||||
import { ColumnInstance, Column, DefaultSortTypes } from 'react-table';
|
||||
import { ColumnInstance, DefaultSortTypes, ColumnWithLooseAccessor } from 'react-table';
|
||||
import { extent as d3Extent, max as d3Max } from 'd3-array';
|
||||
import { FaSort, FaSortUp as FaSortAsc, FaSortDown as FaSortDesc } from 'react-icons/fa';
|
||||
import { t } from '@superset-ui/translation';
|
||||
@ -83,7 +83,7 @@ function cellBar({
|
||||
);
|
||||
}
|
||||
|
||||
function SortIcon({ column }: { column: ColumnInstance }) {
|
||||
function SortIcon<D extends object>({ column }: { column: ColumnInstance<D> }) {
|
||||
const { isSorted, isSortedDesc } = column;
|
||||
let sortIcon = <FaSort />;
|
||||
if (isSorted) {
|
||||
@ -173,53 +173,66 @@ export default function TableChart<D extends DataRecord = DataRecord>(
|
||||
);
|
||||
|
||||
const getColumnConfigs = useCallback(
|
||||
(column: DataColumnMeta, i: number): Column<D> => {
|
||||
(column: DataColumnMeta, i: number): ColumnWithLooseAccessor<D> => {
|
||||
const { key, label, dataType } = column;
|
||||
let className = '';
|
||||
if (dataType === DataType.Number) {
|
||||
className += ' dt-metric';
|
||||
} else if (emitFilter) {
|
||||
className += ' dt-is-filter';
|
||||
}
|
||||
const valueRange = showCellBars && getValueRange(key);
|
||||
const cellProps: Column<D>['cellProps'] = ({ value: value_ }, sharedCellProps) => {
|
||||
let className = '';
|
||||
const value = value_ as DataRecordValue;
|
||||
if (dataType === DataType.Number) {
|
||||
className += ' dt-metric';
|
||||
} else if (emitFilter) {
|
||||
className += ' dt-is-filter';
|
||||
if (isActiveFilterValue(key, value)) {
|
||||
className += ' dt-is-active-filter';
|
||||
}
|
||||
}
|
||||
const [isHtml, text] = formatValue(column, value);
|
||||
const style = {
|
||||
...sharedCellProps.style,
|
||||
background: valueRange
|
||||
? cellBar({
|
||||
value: value as number,
|
||||
valueRange,
|
||||
alignPositiveNegative,
|
||||
colorPositiveNegative,
|
||||
})
|
||||
: undefined,
|
||||
};
|
||||
return {
|
||||
// show raw number in title in case of numeric values
|
||||
title: typeof value === 'number' ? String(value) : undefined,
|
||||
dangerouslySetInnerHTML: isHtml ? { __html: text } : undefined,
|
||||
cellContent: text,
|
||||
onClick: emitFilter && !valueRange ? () => toggleFilter(key, value) : undefined,
|
||||
className,
|
||||
style,
|
||||
};
|
||||
};
|
||||
return {
|
||||
id: String(i), // to allow duplicate column keys
|
||||
// must use custom accessor to allow `.` in column names
|
||||
// typing is incorrect in current version of `@types/react-table`
|
||||
// so we ask TS not to check.
|
||||
accessor: ((datum: D) => datum[key]) as never,
|
||||
Header: label,
|
||||
SortIcon,
|
||||
Cell: ({ column: col, value }: { column: ColumnInstance<D>; value: DataRecordValue }) => {
|
||||
const [isHtml, text] = formatValue(column, value);
|
||||
const style = {
|
||||
background: valueRange
|
||||
? cellBar({
|
||||
value: value as number,
|
||||
valueRange,
|
||||
alignPositiveNegative,
|
||||
colorPositiveNegative,
|
||||
})
|
||||
: undefined,
|
||||
};
|
||||
const html = isHtml ? { __html: text } : undefined;
|
||||
const cellProps = {
|
||||
// show raw number in title in case of numeric values
|
||||
title: typeof value === 'number' ? String(value) : undefined,
|
||||
onClick: emitFilter && !valueRange ? () => toggleFilter(key, value) : undefined,
|
||||
className: `${className}${
|
||||
isActiveFilterValue(key, value) ? ' dt-is-active-filter' : ''
|
||||
}`,
|
||||
style,
|
||||
};
|
||||
if (html) {
|
||||
// eslint-disable-next-line react/no-danger
|
||||
return <td {...cellProps} dangerouslySetInnerHTML={html} />;
|
||||
}
|
||||
// If cellProps renderes textContent already, then we don't have to
|
||||
// render `Cell`. This saves some time for large tables.
|
||||
return <td {...cellProps}>{text}</td>;
|
||||
},
|
||||
Header: ({ column: col, title, onClick, style }) => {
|
||||
return (
|
||||
<th
|
||||
title={title}
|
||||
className={col.isSorted ? `${className || ''} is-sorted` : className}
|
||||
style={style}
|
||||
onClick={onClick}
|
||||
>
|
||||
{label}
|
||||
<SortIcon column={col} />
|
||||
</th>
|
||||
);
|
||||
},
|
||||
sortDescFirst: sortDesc,
|
||||
sortType: getSortTypeByDataType(dataType),
|
||||
cellProps,
|
||||
};
|
||||
},
|
||||
[
|
||||
|
Loading…
Reference in New Issue
Block a user