Tables: optionally show field type icon in tables (#38855)

This commit is contained in:
Ryan McKinley
2021-09-08 00:44:41 -07:00
committed by GitHub
parent ecf40f0331
commit 10ffc9a754
9 changed files with 42 additions and 17 deletions

View File

@@ -1,6 +1,6 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { DataFrame, Field, FieldType, getFieldDisplayName, SelectableValue } from '@grafana/data'; import { DataFrame, Field, getFieldDisplayName, SelectableValue } from '@grafana/data';
import { IconName } from '../..'; import { getFieldTypeIcon } from '../../types';
/** /**
* @internal * @internal
@@ -62,15 +62,6 @@ export function useFieldDisplayNames(data: DataFrame[], filter?: (field: Field)
}, [data, filter]); }, [data, filter]);
} }
const fieldTypeIcons: { [key in FieldType]: IconName } = {
time: 'clock-nine',
string: 'font',
number: 'calculator-alt',
boolean: 'toggle-on',
trace: 'info-circle',
other: 'brackets-curly',
};
/** /**
* @internal * @internal
*/ */
@@ -93,7 +84,7 @@ export function useSelectOptions(
options.push({ options.push({
value: name, value: name,
label: name, label: name,
icon: field ? fieldTypeIcons[field.type] : undefined, icon: field ? getFieldTypeIcon(field) : undefined,
}); });
} }
for (const name of displayNames.raw) { for (const name of displayNames.raw) {

View File

@@ -6,14 +6,16 @@ import { getTableStyles, TableStyles } from './styles';
import { useStyles2 } from '../../themes'; import { useStyles2 } from '../../themes';
import { Filter } from './Filter'; import { Filter } from './Filter';
import { Icon } from '../Icon/Icon'; import { Icon } from '../Icon/Icon';
import { getFieldTypeIcon } from '../../types';
export interface HeaderRowProps { export interface HeaderRowProps {
headerGroups: HeaderGroup[]; headerGroups: HeaderGroup[];
data: DataFrame; data: DataFrame;
showTypeIcons?: boolean;
} }
export const HeaderRow = (props: HeaderRowProps) => { export const HeaderRow = (props: HeaderRowProps) => {
const { headerGroups, data } = props; const { headerGroups, data, showTypeIcons } = props;
const e2eSelectorsTable = selectors.components.Panels.Visualization.Table; const e2eSelectorsTable = selectors.components.Panels.Visualization.Table;
const tableStyles = useStyles2(getTableStyles); const tableStyles = useStyles2(getTableStyles);
@@ -30,7 +32,7 @@ export const HeaderRow = (props: HeaderRowProps) => {
role="row" role="row"
> >
{headerGroup.headers.map((column: Column, index: number) => {headerGroup.headers.map((column: Column, index: number) =>
renderHeaderCell(column, tableStyles, data.fields[index]) renderHeaderCell(column, tableStyles, data.fields[index], showTypeIcons)
)} )}
</div> </div>
); );
@@ -39,7 +41,7 @@ export const HeaderRow = (props: HeaderRowProps) => {
); );
}; };
function renderHeaderCell(column: any, tableStyles: TableStyles, field?: Field) { function renderHeaderCell(column: any, tableStyles: TableStyles, field?: Field, showTypeIcons?: boolean) {
const headerProps = column.getHeaderProps(); const headerProps = column.getHeaderProps();
if (column.canResize) { if (column.canResize) {
@@ -58,6 +60,9 @@ function renderHeaderCell(column: any, tableStyles: TableStyles, field?: Field)
className={tableStyles.headerCellLabel} className={tableStyles.headerCellLabel}
title={column.render('Header')} title={column.render('Header')}
> >
{showTypeIcons && (
<Icon name={getFieldTypeIcon(field)} title={field?.type} size="sm" style={{ marginRight: '8px' }} />
)}
<div>{column.render('Header')}</div> <div>{column.render('Header')}</div>
<div> <div>
{column.isSorted && (column.isSortedDesc ? <Icon name="arrow-down" /> : <Icon name="arrow-up" />)} {column.isSorted && (column.isSortedDesc ? <Icon name="arrow-down" /> : <Icon name="arrow-up" />)}

View File

@@ -38,6 +38,7 @@ export interface Props {
/** Minimal column width specified in pixels */ /** Minimal column width specified in pixels */
columnMinWidth?: number; columnMinWidth?: number;
noHeader?: boolean; noHeader?: boolean;
showTypeIcons?: boolean;
resizable?: boolean; resizable?: boolean;
initialSortBy?: TableSortByFieldState[]; initialSortBy?: TableSortByFieldState[];
onColumnResize?: TableColumnResizeActionCallback; onColumnResize?: TableColumnResizeActionCallback;
@@ -124,6 +125,7 @@ export const Table: FC<Props> = memo((props: Props) => {
resizable = true, resizable = true,
initialSortBy, initialSortBy,
footerValues, footerValues,
showTypeIcons,
} = props; } = props;
const tableStyles = useStyles2(getTableStyles); const tableStyles = useStyles2(getTableStyles);
@@ -204,7 +206,7 @@ export const Table: FC<Props> = memo((props: Props) => {
<div {...getTableProps()} className={tableStyles.table} aria-label={ariaLabel} role="table"> <div {...getTableProps()} className={tableStyles.table} aria-label={ariaLabel} role="table">
<CustomScrollbar hideVerticalTrack={true}> <CustomScrollbar hideVerticalTrack={true}>
<div style={{ width: totalColumnsWidth ? `${totalColumnsWidth}px` : '100%' }}> <div style={{ width: totalColumnsWidth ? `${totalColumnsWidth}px` : '100%' }}>
{!noHeader && <HeaderRow data={data} headerGroups={headerGroups} />} {!noHeader && <HeaderRow data={data} headerGroups={headerGroups} showTypeIcons={showTypeIcons} />}
{rows.length > 0 ? ( {rows.length > 0 ? (
<FixedSizeList <FixedSizeList
height={height - headerHeight} height={height - headerHeight}

View File

@@ -1,3 +1,4 @@
import { Field, FieldType } from '@grafana/data';
import { ComponentSize } from './size'; import { ComponentSize } from './size';
export type IconType = 'mono' | 'default'; export type IconType = 'mono' | 'default';
export type IconSize = ComponentSize | 'xl' | 'xxl' | 'xxxl'; export type IconSize = ComponentSize | 'xl' | 'xxl' | 'xxxl';
@@ -154,3 +155,24 @@ export const getAvailableIcons = () =>
type BrandIconNames = 'google' | 'microsoft' | 'github' | 'gitlab' | 'okta'; type BrandIconNames = 'google' | 'microsoft' | 'github' | 'gitlab' | 'okta';
export type IconName = ReturnType<typeof getAvailableIcons>[number] | BrandIconNames; export type IconName = ReturnType<typeof getAvailableIcons>[number] | BrandIconNames;
/** Get the icon for a given field type */
export function getFieldTypeIcon(field?: Field): IconName {
if (field) {
switch (field.type) {
case FieldType.time:
return 'clock-nine';
case FieldType.string:
return 'font';
case FieldType.number:
return 'calculator-alt';
case FieldType.boolean:
return 'toggle-on';
case FieldType.trace:
return 'info-circle';
case FieldType.other:
return 'brackets-curly';
}
}
return 'question-circle';
}

View File

@@ -19,6 +19,7 @@ export function PanelEditorTableView({ width, height, panel, dashboard }: Props)
const [options, setOptions] = useState<PanelOptions>({ const [options, setOptions] = useState<PanelOptions>({
frameIndex: 0, frameIndex: 0,
showHeader: true, showHeader: true,
showTypeIcons: true,
}); });
// Subscribe to panel event // Subscribe to panel event

View File

@@ -228,7 +228,7 @@ export class InspectDataTab extends PureComponent<Props, State> {
return ( return (
<div style={{ width, height }}> <div style={{ width, height }}>
<Table width={width} height={height} data={dataFrame} /> <Table width={width} height={height} data={dataFrame} showTypeIcons={true} />
</div> </div>
); );
}} }}

View File

@@ -86,6 +86,7 @@ export class TablePanel extends Component<Props> {
width={width} width={width}
data={frame} data={frame}
noHeader={!options.showHeader} noHeader={!options.showHeader}
showTypeIcons={options.showTypeIcons}
resizable={true} resizable={true}
initialSortBy={options.sortBy} initialSortBy={options.sortBy}
onSortByChange={this.onSortByChange} onSortByChange={this.onSortByChange}

View File

@@ -25,6 +25,7 @@ Family: {
PanelOptions: { PanelOptions: {
frameIndex: number | *0 frameIndex: number | *0
showHeader: bool | *true showHeader: bool | *true
showTypeIcons: bool | *false
sortBy?: [...ui.TableSortByFieldState] sortBy?: [...ui.TableSortByFieldState]
} }
PanelFieldConfig: { PanelFieldConfig: {

View File

@@ -14,12 +14,14 @@ export const modelVersion = Object.freeze([1, 0]);
export interface PanelOptions { export interface PanelOptions {
frameIndex: number; frameIndex: number;
showHeader: boolean; showHeader: boolean;
showTypeIcons?: boolean;
sortBy?: TableSortByFieldState[]; sortBy?: TableSortByFieldState[];
} }
export const defaultPanelOptions: PanelOptions = { export const defaultPanelOptions: PanelOptions = {
frameIndex: 0, frameIndex: 0,
showHeader: true, showHeader: true,
showTypeIcons: false,
}; };
export interface PanelFieldConfig { export interface PanelFieldConfig {