mirror of
https://github.com/grafana/grafana.git
synced 2025-07-28 16:52:12 +08:00
TableNG: Follow-up style fixes (#107274)
* open cell inspect in code mode for JSON panels * increase opacity of TableCellActions background for legibility in overlap cases * fix nested grid width calculation * fix 'jumping' on hover overflow * route transparency through (needs a scenes update) * base row hover color on transparency * update the colors for table * remove console.log * reinstate header toggle for nested row transformation * fix #59474 - graceful handling when subtable has no rows * fix i18n * use TABLE.LINE_HEIGHT * change nestedData back to const
This commit is contained in:
@ -42,7 +42,8 @@ export function TableCellActions(props: TableCellActionsProps) {
|
||||
dataProjection: 'EPSG:4326',
|
||||
});
|
||||
mode = TableCellInspectorMode.code;
|
||||
} else if ('cellType' in cellOptions && cellOptions.cellType === TableCellDisplayMode.JSONView) {
|
||||
}
|
||||
if (cellOptions.type === TableCellDisplayMode.JSONView) {
|
||||
mode = TableCellInspectorMode.code;
|
||||
}
|
||||
|
||||
|
@ -81,13 +81,14 @@ export function TableNG(props: TableNGProps) {
|
||||
onSortByChange,
|
||||
showTypeIcons,
|
||||
structureRev,
|
||||
transparent,
|
||||
width,
|
||||
} = props;
|
||||
|
||||
const theme = useTheme2();
|
||||
const styles = useStyles2(getGridStyles, {
|
||||
enablePagination,
|
||||
noHeader,
|
||||
transparent,
|
||||
});
|
||||
const panelContext = usePanelContext();
|
||||
|
||||
@ -244,21 +245,9 @@ export function TableNG(props: TableNGProps) {
|
||||
},
|
||||
sortColumns,
|
||||
rowHeight,
|
||||
headerRowClass: styles.headerRow,
|
||||
headerRowHeight: headerHeight,
|
||||
bottomSummaryRows: hasFooter ? [{}] : undefined,
|
||||
}) satisfies Partial<DataGridProps<TableRow, TableSummaryRow>>,
|
||||
[
|
||||
enableVirtualization,
|
||||
resizeHandler,
|
||||
sortColumns,
|
||||
headerHeight,
|
||||
styles.headerRow,
|
||||
rowHeight,
|
||||
hasFooter,
|
||||
setSortColumns,
|
||||
onSortByChange,
|
||||
]
|
||||
[enableVirtualization, resizeHandler, sortColumns, rowHeight, hasFooter, setSortColumns, onSortByChange]
|
||||
);
|
||||
|
||||
interface Schema {
|
||||
@ -437,6 +426,7 @@ export function TableNG(props: TableNGProps) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const hasNestedHeaders = firstNestedData.meta?.custom?.noHeader !== true;
|
||||
const renderRow = renderRowFactory(firstNestedData.fields, panelContext, expandedRows, enableSharedCrosshair);
|
||||
const { columns: nestedColumns, cellRootRenderers: nestedCellRootRenderers } = fromFields(
|
||||
firstNestedData.fields,
|
||||
@ -486,11 +476,20 @@ export function TableNG(props: TableNGProps) {
|
||||
}
|
||||
|
||||
const expandedRecords = applySort(frameToRecords(nestedData), nestedData.fields, sortColumns);
|
||||
if (!expandedRecords.length) {
|
||||
return (
|
||||
<div className={styles.noDataNested}>
|
||||
<Trans i18nKey="grafana-ui.table.nested-table.no-data">No data</Trans>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<DataGrid<TableRow, TableSummaryRow>
|
||||
{...commonDataGridProps}
|
||||
className={cx(styles.grid, styles.gridNested)}
|
||||
headerRowClass={cx(styles.headerRow, { [styles.displayNone]: !hasNestedHeaders })}
|
||||
headerRowHeight={hasNestedHeaders ? defaultHeaderHeight : 0}
|
||||
columns={nestedColumns}
|
||||
rows={expandedRecords}
|
||||
renderers={{ renderRow, renderCell: renderCellRoot }}
|
||||
@ -509,6 +508,7 @@ export function TableNG(props: TableNGProps) {
|
||||
crossFilterOrder,
|
||||
crossFilterRows,
|
||||
data,
|
||||
defaultHeaderHeight,
|
||||
defaultRowHeight,
|
||||
enableSharedCrosshair,
|
||||
expandedRows,
|
||||
@ -552,6 +552,8 @@ export function TableNG(props: TableNGProps) {
|
||||
className={styles.grid}
|
||||
columns={structureRevColumns}
|
||||
rows={paginatedRows}
|
||||
headerRowClass={cx(styles.headerRow, { [styles.displayNone]: noHeader })}
|
||||
headerRowHeight={headerHeight}
|
||||
onCellClick={({ column, row }, { clientX, clientY, preventGridDefault }) => {
|
||||
// Note: could be column.field; JS says yes, but TS says no!
|
||||
const field = columns[column.idx].field;
|
||||
@ -693,17 +695,20 @@ const renderRowFactory =
|
||||
|
||||
const getGridStyles = (
|
||||
theme: GrafanaTheme2,
|
||||
{ enablePagination, noHeader }: { enablePagination?: boolean; noHeader?: boolean }
|
||||
{ enablePagination, transparent }: { enablePagination?: boolean; transparent?: boolean }
|
||||
) => ({
|
||||
grid: css({
|
||||
'--rdg-background-color': theme.colors.background.primary,
|
||||
'--rdg-header-background-color': theme.colors.background.primary,
|
||||
'--rdg-border-color': theme.isDark ? '#282b30' : '#ebebec',
|
||||
'--rdg-background-color': transparent ? theme.colors.background.canvas : theme.colors.background.primary,
|
||||
'--rdg-header-background-color': transparent ? theme.colors.background.canvas : theme.colors.background.primary,
|
||||
'--rdg-border-color': theme.colors.border.weak,
|
||||
'--rdg-color': theme.colors.text.primary,
|
||||
|
||||
// note: this cannot have any transparency since default cells that
|
||||
// overlay/overflow on hover inherit this background and need to occlude cells below
|
||||
'--rdg-row-hover-background-color': theme.isDark ? '#212428' : '#f4f5f5',
|
||||
'--rdg-row-background-color': transparent ? theme.colors.background.canvas : theme.colors.background.primary,
|
||||
'--rdg-row-hover-background-color': transparent
|
||||
? theme.colors.background.primary
|
||||
: theme.colors.background.secondary,
|
||||
|
||||
// TODO: magic 32px number is unfortunate. it would be better to have the content
|
||||
// flow using flexbox rather than hard-coding this size via a calc
|
||||
@ -723,15 +728,24 @@ const getGridStyles = (
|
||||
}),
|
||||
gridNested: css({
|
||||
height: '100%',
|
||||
width: `calc(100% - ${COLUMN.EXPANDER_WIDTH - 1}px)`,
|
||||
width: `calc(100% - ${COLUMN.EXPANDER_WIDTH - TABLE.CELL_PADDING * 2 - 1}px)`,
|
||||
overflow: 'visible',
|
||||
marginLeft: COLUMN.EXPANDER_WIDTH - 1,
|
||||
marginLeft: COLUMN.EXPANDER_WIDTH - TABLE.CELL_PADDING - 1,
|
||||
marginBlock: TABLE.CELL_PADDING,
|
||||
}),
|
||||
cellNested: css({
|
||||
'&[aria-selected=true]': {
|
||||
outline: 'none',
|
||||
},
|
||||
}),
|
||||
noDataNested: css({
|
||||
height: TABLE.NESTED_NO_DATA_HEIGHT,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
color: theme.colors.text.secondary,
|
||||
fontSize: theme.typography.h4.fontSize,
|
||||
}),
|
||||
cellActions: css({
|
||||
display: 'none',
|
||||
position: 'absolute',
|
||||
@ -739,7 +753,7 @@ const getGridStyles = (
|
||||
margin: 'auto',
|
||||
height: '100%',
|
||||
color: theme.colors.text.primary,
|
||||
background: theme.isDark ? 'rgba(0, 0, 0, 0.3)' : 'rgba(255, 255, 255, 0.7)',
|
||||
background: theme.isDark ? 'rgba(0, 0, 0, 0.7)' : 'rgba(255, 255, 255, 0.7)',
|
||||
padding: theme.spacing.x0_5,
|
||||
paddingInlineStart: theme.spacing.x1,
|
||||
}),
|
||||
@ -752,12 +766,14 @@ const getGridStyles = (
|
||||
headerRow: css({
|
||||
paddingBlockStart: 0,
|
||||
fontWeight: 'normal',
|
||||
...(noHeader ? { display: 'none' } : {}),
|
||||
'& .rdg-cell': {
|
||||
height: '100%',
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
}),
|
||||
displayNone: css({
|
||||
display: 'none',
|
||||
}),
|
||||
paginationContainer: css({
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
@ -835,6 +851,7 @@ const getCellStyles = (
|
||||
whiteSpace: 'pre-line',
|
||||
height: 'fit-content',
|
||||
minWidth: 'fit-content',
|
||||
paddingBlock: (rowHeight - TABLE.LINE_HEIGHT) / 2 - 1,
|
||||
}),
|
||||
},
|
||||
}),
|
||||
|
@ -14,5 +14,6 @@ export const TABLE = {
|
||||
SCROLL_BAR_WIDTH: 8,
|
||||
SCROLL_BAR_MARGIN: 2,
|
||||
LINE_HEIGHT: 22,
|
||||
NESTED_NO_DATA_HEIGHT: 60,
|
||||
BORDER_RIGHT: 0.666667,
|
||||
};
|
||||
|
@ -503,9 +503,13 @@ export function useRowHeight({
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Ensure we have a minimum height (defaultHeight) for the nested table even if data is empty
|
||||
const rowCount = row.data?.length ?? 0;
|
||||
return Math.max(defaultHeight, defaultHeight * rowCount + headerHeight);
|
||||
if (rowCount === 0) {
|
||||
return TABLE.NESTED_NO_DATA_HEIGHT + TABLE.CELL_PADDING * 2;
|
||||
}
|
||||
|
||||
const nestedHeaderHeight = row.data?.meta?.custom?.noHeader ? 0 : defaultHeight;
|
||||
return Math.max(defaultHeight, defaultHeight * rowCount + nestedHeaderHeight + TABLE.CELL_PADDING * 2);
|
||||
}
|
||||
|
||||
// regular rows
|
||||
@ -519,7 +523,6 @@ export function useRowHeight({
|
||||
fields,
|
||||
hasNestedFrames,
|
||||
hasWrappedCols,
|
||||
headerHeight,
|
||||
maxWrapCellOptions,
|
||||
colWidths,
|
||||
]);
|
||||
|
@ -131,6 +131,7 @@ export interface BaseTableProps {
|
||||
enablePagination?: boolean;
|
||||
cellHeight?: TableCellHeight;
|
||||
structureRev?: number;
|
||||
transparent?: boolean;
|
||||
/** @alpha Used by SparklineCell when provided */
|
||||
timeRange?: TimeRange;
|
||||
enableSharedCrosshair?: boolean;
|
||||
|
@ -26,7 +26,7 @@ import { Options } from './panelcfg.gen';
|
||||
interface Props extends PanelProps<Options> {}
|
||||
|
||||
export function TablePanel(props: Props) {
|
||||
const { data, height, width, options, fieldConfig, id, timeRange, replaceVariables } = props;
|
||||
const { data, height, width, options, fieldConfig, id, timeRange, replaceVariables, transparent } = props;
|
||||
|
||||
useMemo(() => {
|
||||
cacheFieldDisplayNames(data.series);
|
||||
@ -82,6 +82,7 @@ export function TablePanel(props: Props) {
|
||||
fieldConfig={fieldConfig}
|
||||
getActions={_getActions}
|
||||
structureRev={data.structureRev}
|
||||
transparent={transparent}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -8011,6 +8011,9 @@
|
||||
"filter-popup-match-case": "Match case",
|
||||
"inspect-drawer-title": "Inspect value",
|
||||
"inspect-menu-label": "Inspect value",
|
||||
"nested-table": {
|
||||
"no-data": "No data"
|
||||
},
|
||||
"no-values-label": "No values",
|
||||
"pagination-summary": "{{itemsRangeStart}} - {{displayedEnd}} of {{numRows}} rows"
|
||||
},
|
||||
|
Reference in New Issue
Block a user