Table: Support DataLinks and Actions in SparklineCell (#112244)
* Table: Support DataLinks in SparklineCell * add data links to sparkline gdev * fix migrator test * Clean up single action use case
This commit is contained in:
+22
-2
@@ -208,7 +208,27 @@
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"fetch": {
|
||||
"body": "{}",
|
||||
"headers": [["Content-Type", "application/json"]],
|
||||
"method": "GET",
|
||||
"queryParams": [],
|
||||
"url": "/api/health"
|
||||
},
|
||||
"title": "Get instance health",
|
||||
"type": "fetch"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"targetBlank": true,
|
||||
"title": "Google Grafana",
|
||||
"url": "https://google.com/search?q=grafana"
|
||||
}
|
||||
]
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
@@ -592,4 +612,4 @@
|
||||
"title": "Panel Tests - Table - Sparklines",
|
||||
"uid": "d6373b49-1957-4f00-9218-ee2120d3ecd9",
|
||||
"weekStart": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +204,27 @@
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"fetch": {
|
||||
"body": "{}",
|
||||
"headers": [["Content-Type", "application/json"]],
|
||||
"method": "GET",
|
||||
"queryParams": [],
|
||||
"url": "/api/health"
|
||||
},
|
||||
"title": "Get instance health",
|
||||
"type": "fetch"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"targetBlank": true,
|
||||
"title": "Google Grafana",
|
||||
"url": "https://google.com/search?q=grafana"
|
||||
}
|
||||
]
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
import { measureText } from '../../../../utils/measureText';
|
||||
import { FormattedValueDisplay } from '../../../FormattedValueDisplay/FormattedValueDisplay';
|
||||
import { Sparkline } from '../../../Sparkline/Sparkline';
|
||||
import { MaybeWrapWithLink } from '../components/MaybeWrapWithLink';
|
||||
import { SparklineCellProps, TableCellStyles } from '../types';
|
||||
import { getAlignmentFactor, getCellOptions, prepareSparklineValue } from '../utils';
|
||||
|
||||
@@ -38,7 +39,11 @@ export const SparklineCell = (props: SparklineCellProps) => {
|
||||
const sparkline = prepareSparklineValue(value, field);
|
||||
|
||||
if (!sparkline) {
|
||||
return <>{field.config.noValue || t('grafana-ui.table.sparkline.no-data', 'no data')}</>;
|
||||
return (
|
||||
<MaybeWrapWithLink field={field} rowIdx={rowIdx}>
|
||||
{field.config.noValue || t('grafana-ui.table.sparkline.no-data', 'no data')}
|
||||
</MaybeWrapWithLink>
|
||||
);
|
||||
}
|
||||
|
||||
// Get the step from the first two values to null-fill the x-axis based on timerange
|
||||
@@ -87,10 +92,10 @@ export const SparklineCell = (props: SparklineCellProps) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<MaybeWrapWithLink field={field} rowIdx={rowIdx}>
|
||||
{valueElement}
|
||||
<Sparkline width={width - valueWidth} height={25} sparkline={sparkline} config={config} theme={theme} />
|
||||
</>
|
||||
</MaybeWrapWithLink>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -107,8 +112,12 @@ function getTableSparklineCellOptions(field: Field): TableSparklineCellOptions {
|
||||
|
||||
export const getStyles: TableCellStyles = (theme, { textAlign }) =>
|
||||
css({
|
||||
width: '100%',
|
||||
gap: theme.spacing(1),
|
||||
justifyContent: 'space-between',
|
||||
...(textAlign === 'right' && { flexDirection: 'row-reverse' }),
|
||||
'&, & > a': {
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
gap: theme.spacing(1),
|
||||
...(textAlign === 'right' && { flexDirection: 'row-reverse' }),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -94,7 +94,6 @@ import {
|
||||
predicateByName,
|
||||
shouldTextOverflow,
|
||||
shouldTextWrap,
|
||||
withDataLinksActionsTooltip,
|
||||
getSummaryCellTextAlign,
|
||||
parseStyleJson,
|
||||
IS_SAFARI_26,
|
||||
@@ -406,7 +405,6 @@ export function TableNG(props: TableNGProps) {
|
||||
const result: FromFieldsResult = {
|
||||
columns: [],
|
||||
cellRootRenderers: {},
|
||||
colsWithTooltip: {},
|
||||
};
|
||||
|
||||
let lastRowIdx = -1;
|
||||
@@ -464,7 +462,6 @@ export function TableNG(props: TableNGProps) {
|
||||
const shouldOverflow =
|
||||
!IS_SAFARI_26 && rowHeight !== 'auto' && (shouldTextOverflow(field) || Boolean(maxRowHeight));
|
||||
const textWrap = rowHeight === 'auto' || shouldTextWrap(field);
|
||||
const withTooltip = withDataLinksActionsTooltip(field, cellType);
|
||||
const canBeColorized = canFieldBeColorized(cellType, applyToRowBgFn);
|
||||
const cellStyleOptions: TableCellStyleOptions = {
|
||||
textAlign,
|
||||
@@ -473,8 +470,6 @@ export function TableNG(props: TableNGProps) {
|
||||
maxHeight: maxRowHeight,
|
||||
};
|
||||
|
||||
result.colsWithTooltip[displayName] = withTooltip;
|
||||
|
||||
const defaultCellStyles = getDefaultCellStyles(theme, cellStyleOptions);
|
||||
const cellSpecificStyles = getCellSpecificStyles(cellType, field, theme, cellStyleOptions);
|
||||
const linkStyles = getLinkStyles(theme, canBeColorized);
|
||||
@@ -737,7 +732,7 @@ export function TableNG(props: TableNGProps) {
|
||||
);
|
||||
const [nestedFieldWidths] = useColWidths(firstRowNestedData?.fields ?? [], availableWidth);
|
||||
|
||||
const { columns, cellRootRenderers, colsWithTooltip } = useMemo(() => {
|
||||
const { columns, cellRootRenderers } = useMemo(() => {
|
||||
const result = fromFields(visibleFields, widths);
|
||||
|
||||
// if nested frames are present, augment the columns to include the nested table expander column.
|
||||
@@ -805,7 +800,6 @@ export function TableNG(props: TableNGProps) {
|
||||
const field = columns[column.idx].field;
|
||||
|
||||
if (
|
||||
colsWithTooltip[getDisplayName(field)] &&
|
||||
target instanceof HTMLElement &&
|
||||
// this walks up the tree to find either a faux link wrapper or the cell root
|
||||
// it then only proceeds if we matched the faux link wrapper
|
||||
|
||||
@@ -34,4 +34,5 @@ export const MaybeWrapWithLink = memo(({ field, rowIdx, children }: MaybeWrapWit
|
||||
// raw value
|
||||
return children;
|
||||
});
|
||||
|
||||
MaybeWrapWithLink.displayName = 'MaybeWrapWithLink';
|
||||
|
||||
@@ -308,7 +308,6 @@ export type CellRootRenderer = (key: React.Key, props: CellRendererProps<TableRo
|
||||
export interface FromFieldsResult {
|
||||
columns: TableColumn[];
|
||||
cellRootRenderers: Record<string, CellRootRenderer>;
|
||||
colsWithTooltip: Record<string, boolean>;
|
||||
}
|
||||
|
||||
export interface FooterFieldState extends FieldState {
|
||||
|
||||
@@ -955,15 +955,6 @@ export function getApplyToRowBgFn(
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function withDataLinksActionsTooltip(field: Field, cellType: TableCellDisplayMode) {
|
||||
return (
|
||||
cellType !== TableCellDisplayMode.DataLinks &&
|
||||
cellType !== TableCellDisplayMode.Actions &&
|
||||
(field.config.links?.length ?? 0) + (field.config.actions?.length ?? 0) > 1
|
||||
);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function canFieldBeColorized(
|
||||
cellType: TableCellDisplayMode,
|
||||
|
||||
Reference in New Issue
Block a user