mirror of https://github.com/grafana/grafana.git
TablePanel: Improve and align table styles with the rest of Grafana (#60365)
* TablePanel: Improve and align table styles with rest of Grafana * Fixing footer styles
This commit is contained in:
parent
8b5ad5824a
commit
0fb9987d12
|
|
@ -14,11 +14,10 @@ export interface FooterRowProps {
|
|||
footerGroups: HeaderGroup[];
|
||||
footerValues: FooterItem[];
|
||||
isPaginationVisible: boolean;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export const FooterRow = (props: FooterRowProps) => {
|
||||
const { totalColumnsWidth, footerGroups, height, isPaginationVisible } = props;
|
||||
const { totalColumnsWidth, footerGroups, isPaginationVisible } = props;
|
||||
const e2eSelectorsTable = selectors.components.Panels.Visualization.Table;
|
||||
const tableStyles = useStyles2(getTableStyles);
|
||||
|
||||
|
|
@ -33,14 +32,8 @@ export const FooterRow = (props: FooterRowProps) => {
|
|||
{footerGroups.map((footerGroup: HeaderGroup) => {
|
||||
const { key, ...footerGroupProps } = footerGroup.getFooterGroupProps();
|
||||
return (
|
||||
<div
|
||||
className={tableStyles.tfoot}
|
||||
{...footerGroupProps}
|
||||
key={key}
|
||||
data-testid={e2eSelectorsTable.footer}
|
||||
style={height ? { height: `${height}px` } : undefined}
|
||||
>
|
||||
{footerGroup.headers.map((column: ColumnInstance) => renderFooterCell(column, tableStyles, height))}
|
||||
<div className={tableStyles.tfoot} {...footerGroupProps} key={key} data-testid={e2eSelectorsTable.footer}>
|
||||
{footerGroup.headers.map((column: ColumnInstance) => renderFooterCell(column, tableStyles))}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
|
@ -48,7 +41,7 @@ export const FooterRow = (props: FooterRowProps) => {
|
|||
);
|
||||
};
|
||||
|
||||
function renderFooterCell(column: ColumnInstance, tableStyles: TableStyles, height?: number) {
|
||||
function renderFooterCell(column: ColumnInstance, tableStyles: TableStyles) {
|
||||
const footerProps = column.getHeaderProps();
|
||||
|
||||
if (!footerProps) {
|
||||
|
|
@ -58,9 +51,6 @@ function renderFooterCell(column: ColumnInstance, tableStyles: TableStyles, heig
|
|||
footerProps.style = footerProps.style ?? {};
|
||||
footerProps.style.position = 'absolute';
|
||||
footerProps.style.justifyContent = (column as any).justifyContent;
|
||||
if (height) {
|
||||
footerProps.style.height = height;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={tableStyles.headerCell} {...footerProps}>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export const HeaderRow = (props: HeaderRowProps) => {
|
|||
const tableStyles = useStyles2(getTableStyles);
|
||||
|
||||
return (
|
||||
<div role="rowgroup">
|
||||
<div role="rowgroup" className={tableStyles.headerRow}>
|
||||
{headerGroups.map((headerGroup: HeaderGroup) => {
|
||||
const { key, ...headerGroupProps } = headerGroup.getHeaderGroupProps();
|
||||
return (
|
||||
|
|
@ -62,9 +62,12 @@ function renderHeaderCell(column: any, tableStyles: TableStyles, showTypeIcons?:
|
|||
<Icon name={getFieldTypeIcon(field)} title={field?.type} size="sm" className={tableStyles.typeIcon} />
|
||||
)}
|
||||
<div>{column.render('Header')}</div>
|
||||
<div>
|
||||
{column.isSorted && (column.isSortedDesc ? <Icon name="arrow-down" /> : <Icon name="arrow-up" />)}
|
||||
</div>
|
||||
{column.isSorted &&
|
||||
(column.isSortedDesc ? (
|
||||
<Icon size="lg" name="arrow-down" className={tableStyles.sortIcon} />
|
||||
) : (
|
||||
<Icon name="arrow-up" size="lg" className={tableStyles.sortIcon} />
|
||||
))}
|
||||
</button>
|
||||
{column.canFilter && <Filter column={column} tableStyles={tableStyles} field={field} />}
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -150,13 +150,13 @@ export const Table = memo((props: Props) => {
|
|||
const variableSizeListScrollbarRef = useRef<HTMLDivElement>(null);
|
||||
const tableStyles = useStyles2(getTableStyles);
|
||||
const theme = useTheme2();
|
||||
const headerHeight = noHeader ? 0 : tableStyles.cellHeight;
|
||||
const headerHeight = noHeader ? 0 : tableStyles.rowHeight;
|
||||
const [footerItems, setFooterItems] = useState<FooterItem[] | undefined>(footerValues);
|
||||
const [expandedIndexes, setExpandedIndexes] = useState<Set<number>>(new Set());
|
||||
const prevExpandedIndexes = usePrevious(expandedIndexes);
|
||||
|
||||
const footerHeight = useMemo(() => {
|
||||
const EXTENDED_ROW_HEIGHT = 33;
|
||||
const EXTENDED_ROW_HEIGHT = headerHeight;
|
||||
let length = 0;
|
||||
|
||||
if (!footerItems) {
|
||||
|
|
@ -174,7 +174,7 @@ export const Table = memo((props: Props) => {
|
|||
}
|
||||
|
||||
return EXTENDED_ROW_HEIGHT;
|
||||
}, [footerItems]);
|
||||
}, [footerItems, headerHeight]);
|
||||
|
||||
// React table data array. This data acts just like a dummy array to let react-table know how many rows exist
|
||||
// The cells use the field to look up values
|
||||
|
|
@ -288,7 +288,9 @@ export const Table = memo((props: Props) => {
|
|||
if (enablePagination) {
|
||||
listHeight -= tableStyles.cellHeight;
|
||||
}
|
||||
const pageSize = Math.round(listHeight / tableStyles.cellHeight) - 1;
|
||||
|
||||
const pageSize = Math.round(listHeight / tableStyles.rowHeight) - 1;
|
||||
|
||||
useEffect(() => {
|
||||
// Don't update the page size if it is less than 1
|
||||
if (pageSize <= 0) {
|
||||
|
|
@ -473,7 +475,6 @@ export const Table = memo((props: Props) => {
|
|||
)}
|
||||
{footerItems && (
|
||||
<FooterRow
|
||||
height={footerHeight}
|
||||
isPaginationVisible={Boolean(enablePagination)}
|
||||
footerValues={footerItems}
|
||||
footerGroups={footerGroups}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@ import { css, CSSObject } from '@emotion/css';
|
|||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
|
||||
export const getTableStyles = (theme: GrafanaTheme2) => {
|
||||
const { colors } = theme;
|
||||
const headerBg = theme.colors.background.secondary;
|
||||
const borderColor = theme.colors.border.weak;
|
||||
const resizerColor = theme.colors.primary.border;
|
||||
const cellPadding = 6;
|
||||
|
|
@ -107,27 +105,29 @@ export const getTableStyles = (theme: GrafanaTheme2) => {
|
|||
`,
|
||||
thead: css`
|
||||
label: thead;
|
||||
height: ${cellHeight}px;
|
||||
height: ${rowHeight}px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
background: ${headerBg};
|
||||
position: relative;
|
||||
`,
|
||||
tfoot: css`
|
||||
label: tfoot;
|
||||
height: ${cellHeight}px;
|
||||
height: ${rowHeight}px;
|
||||
border-top: 1px solid ${borderColor};
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
background: ${headerBg};
|
||||
position: relative;
|
||||
`,
|
||||
headerRow: css`
|
||||
label: row;
|
||||
border-bottom: 1px solid ${borderColor};
|
||||
`,
|
||||
headerCell: css`
|
||||
padding: ${cellPadding}px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
color: ${colors.primary.text};
|
||||
border-right: 1px solid ${theme.colors.border.weak};
|
||||
display: flex;
|
||||
font-weight: ${theme.typography.fontWeightMedium};
|
||||
|
||||
&:last-child {
|
||||
border-right: none;
|
||||
|
|
@ -141,8 +141,15 @@ export const getTableStyles = (theme: GrafanaTheme2) => {
|
|||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-weight: ${theme.typography.fontWeightMedium};
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: ${theme.spacing(0.5)};
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
color: ${theme.colors.text.link};
|
||||
}
|
||||
`,
|
||||
cellContainer: buildCellContainerStyle(undefined, undefined, true),
|
||||
cellContainerNoOverflow: buildCellContainerStyle(undefined, undefined, false),
|
||||
|
|
@ -152,6 +159,9 @@ export const getTableStyles = (theme: GrafanaTheme2) => {
|
|||
user-select: text;
|
||||
white-space: nowrap;
|
||||
`,
|
||||
sortIcon: css`
|
||||
margin-left: ${theme.spacing(0.5)};
|
||||
`,
|
||||
cellLink: css`
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
|
|
@ -173,12 +183,10 @@ export const getTableStyles = (theme: GrafanaTheme2) => {
|
|||
`,
|
||||
paginationWrapper: css`
|
||||
display: flex;
|
||||
background: ${headerBg};
|
||||
height: ${cellHeight}px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
border-top: 1px solid ${theme.colors.border.weak};
|
||||
li {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ const footerCategory = 'Table footer';
|
|||
export const plugin = new PanelPlugin<PanelOptions, TableFieldOptions>(TablePanel)
|
||||
.setPanelChangeHandler(tablePanelChangedHandler)
|
||||
.setMigrationHandler(tableMigrationHandler)
|
||||
.setNoPadding()
|
||||
.useFieldConfig({
|
||||
useCustomConfig: (builder) => {
|
||||
builder
|
||||
|
|
|
|||
Loading…
Reference in New Issue