grafana/packages/grafana-ui/src/components/Table/Cells/SparklineCell.tsx

159 lines
4.4 KiB
TypeScript
Raw Normal View History

import * as React from 'react';
import {
FieldType,
FieldConfig,
getMinMaxAndDelta,
FieldSparkline,
isDataFrame,
Field,
isDataFrameWithValue,
formattedValueToString,
} from '@grafana/data';
import {
BarAlignment,
GraphDrawStyle,
GraphFieldConfig,
GraphGradientMode,
LineInterpolation,
TableSparklineCellOptions,
TableCellDisplayMode,
VisibilityMode,
} from '@grafana/schema';
import { useTheme2 } from '../../../themes/ThemeContext';
import { measureText } from '../../../utils/measureText';
Table: Move library to react-data-grid (#102482) * Changes galore * Freedom 🗽 * Add feature flag * Latest changes * Basic auto cell type * Partially working bar-gauge * Brokenish but whatevs * Include the toggle doc * TableNG: Context menu (#94094) * feat(table-ng): context menu init commit * betterer * feat(table-ng): re-use contextmenu component * fix(table-ng): close context menu issue * TableNG: Sorting columns (#94200) feat(table-ng): sorting column * fix feature toggle conflict * TableNG: Sorting with custom table header (#95351) * TableNG: Header Toggle (#95310) * TableNG: Multi-column sorting (#95395) feat(table-ng): multi-sorting * TableNG: Column width options (#95426) * feat(table-ng): column width * mouse handle drag event * move resizing task * TableNG: Fix icon sorting direction (#95653) fix(table-ng): sorting icon direction * TableNG: Show table footer (#95313) * TableNG: Show table footer * Revert betterer * Update betterer * Incorporate reducer calculations into footer * Update imports in FooterRow * Use getFooterValue for summary cell render * TableNG: Min column width (#95657) * feat(table-ng): min column width * feat(table-ng): set a min width constant * TableNG: Column alignment (#95679) * feat(table-ng): column alignment * cleaning * feat(table-ng): header cell alignment * optimizations * feat(table-ng): footer cell alignment * calc counter * TableNG: use compiled fn for columns -> records conversion (#95914) * use compiled fn for columns -> records conversion * TableNG: Move key rev and fix width overrides (#95921) * meh * add index to records --------- Co-authored-by: Drew Slobodnjak <60050885+drew08t@users.noreply.github.com> * TableNG: Sparkline Cell Parity (#95690) * sparkline value * todo * Remove unsued shallowField * Pass justifyContent to sparkline --------- Co-authored-by: drew08t <drew08@gmail.com> * TableNG: BarGauge cell updates (#95521) * fix bargauge cell * merge and fix props * cleanup imports * TableNG: Text wrapping (#96041) * feat(table-ng): fix long text cell width * feat(table-ng): fix long text cell width 2 * comment out column rowHeight * fix long text column width * fix types * fix types * naming * Check current header cell ref is defined for key * cleaning * make table re-render when data changed * eslint --------- Co-authored-by: drew08t <drew08@gmail.com> * TableNG: Text overflow (#96641) * feat(table-ng): text overflow * cleaning * TableNG: Fix footer for count (#96802) * TableNG: Table column filter (#96767) * feat(table-ng): add filter form --------- Co-authored-by: drew08t <drew08@gmail.com> Co-authored-by: Leon Sorokin <leeoniya@gmail.com> * TableNG: On column resize trigger (#97004) chore(table-ng): trigger on resize on text wrap only * TableNG: Improve sort performance (#97767) * TableNG: Improve sort performance * clean a bit * a bit more * Remove const that was breaking sort --------- Co-authored-by: Leon Sorokin <leeoniya@gmail.com> * TableNG: Fix sorting (#98141) fix(table-ng): sorting * TableNG: fix multi sorting (#98668) fix(table-ng): multi sorting * TableNG: Column re-size handler (#98901) * feat(table-ng): column re-size handler * TableNG: Fix footer calcs with no reducer (#99347) * TableNG: Update renderHeaderCell with filter dep (#99483) * TableNG: Updated styles for demo (#99530) * style proposal: table ng * chore: revert gauge cell custom stuff * TableNG: Cross-filter (#99459) * feat(table-ng): cross-filter * fix filter update issue * fix filter reset issue * Fix spacebar for filter input --------- Co-authored-by: drew08t <drew08@gmail.com> * TableNG: Filter perfomance optimization (#99620) fix(table-ng): filter performance optimization * TableNG: Refine styling closer to original table (#99625) * TableNG: Support groupToNestedTableTransform (#97134) * TableNG: Support groupToNestedTableTransform * Fix merge issues * Force refresh for now * Remove log * Fix some conflicts * Fix more conflicts * Help avoid clash with compiled frameToRecords keys * Make subtable height unconstrained * Support show field names in nested tables toggle * TableNG: Fix footer + some other misc updates (#99846) fix: footer fixes huzzah * TableNG: Styling - Update styling for cells (#99851) * fix(table-ng): bargauge inner width issue * TableNG: Move header cell component (#99844) * fix(table-ng): move header cell into separate file * Fix sub table --------- Co-authored-by: drew08t <drew08@gmail.com> * TableNG: Auto cell feature parity (#100095) * feat(table-ng): auto cell feature parity * TableNG: JSON cell implementation + hover fixes (#100152) * feat: tableNG json cell + auto fixes * chore: add comment * add justify content to json cell --------- Co-authored-by: Ihor Yeromin <yeryomin.igor@gmail.com> * TableNG: Fix cell hover issue (#100207) * fix(table-ng): cell hover issue * better commenting * TableNG: Text color cell (#100120) feat(table-ng): text color cell feature parity * TableNG: Image cell implementation (#100132) * feat: tableNG image cell * fix: incorporate justify-content correctly * chore: pass down cell options from fieldConfig --------- Co-authored-by: Ihor Yeromin <yeryomin.igor@gmail.com> * TableNG: Cell height performance improvement (#100544) * chore: perf improvement * chore: minor fix * Update packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx Co-authored-by: Leon Sorokin <leeoniya@gmail.com> * chore: fix betterer --------- Co-authored-by: Leon Sorokin <leeoniya@gmail.com> * TableNG: Add pagination (#100165) * TableNG: Add pagination * TableNG: Get collapsed icon state correct + update `rowHeight` (#100556) * fix: get collapsed icon state correct + update condition for calculating row height * chore: some cleanup! * chore: naming to avoid confusion with local state name * TableNG: Add support for `DataLinksCell` (#100459) * TableNG: Improve sub table styling (#100772) * Move files temporarily to fix conflicts * Fix feature flag conflicts * Move files back to cell dir * TableNG: Update inner height of bar gauge cell (#100996) * fix: change inner height of bar gauge cell * chore: move function to utils, cleanup * Remove testing line * TableNG: Add bottom border to column headers + fix footer styling (#101016) * feat: add bottom border to column headers for table parity * feat: summary row style fix * chore: remove redundant style --------- Co-authored-by: drew08t <drew08@gmail.com> * TableNG: Add support for `ActionsCell` (#101024) * TableNG: Cell hover styles + header resize handler indicator (#100770) * fix: tableNG styles * chore: clean up comments * chore: remove column header stuffz for now * fix: refactor to transform/translate + resize handler hover styling * chore: re-think approach - change a lot of things * chore: most recent iteration * chore: wait i like this better * chore: hoist into colors function + clean it up! * moar better * chore: define constants for clarity * chore: calculate rbga to rgb values given background color --------- Co-authored-by: drew08t <drew08@gmail.com> * TableNG: Fix scoll hover jumpy behavior (#101085) * fix(table-ng): hover scroll jumping * Account for panel padding during pagination --------- Co-authored-by: Drew Slobodnjak <60050885+drew08t@users.noreply.github.com> Co-authored-by: drew08t <drew08@gmail.com> * TableNG: Fix imports (#101059) * fix(table-ng): clean imports Co-authored-by: Drew Slobodnjak <60050885+drew08t@users.noreply.github.com> * TableNG: Sorted rows dependent upon filtered rows (#100985) TableNG: Improve multi-sort performance * TableNG: Fix sparkline width (#101164) fix(table-ng): sparkline width * TableNG: Type TableNG (#101257) * feat: type tableNG * chore: push betterer * chore: fix linter + why can't I have inline if statements... GRR! * fix: linter - props name got changed at some point... * feedback: data links prop consistency + json cell robustness * chore: remove unused rowIndex prop --------- Co-authored-by: drew08t <drew08@gmail.com> * TableNG: Add support for datalinks (#100769) Co-authored-by: drew08t <drew08@gmail.com> * Chore: Remove unused import (#102064) remove unused import * Update betterer * BarGauge: Remove z-index (#102220) fix(bargauge): remove z-index * TableNG: Refactor + testing (#102045) * feat: type tableNG * chore: push betterer * chore: fix linter + why can't I have inline if statements... GRR! * fix: linter - props name got changed at some point... * feedback: data links prop consistency + json cell robustness * feat: refactor + tests * chore: fix import lint errors * betterer * chore: fix image cell * chore: revert width function * add test * betterer * chore: fix sorting + add tests * chore: pr feedback --------- Co-authored-by: Ihor Yeromin <yeryomin.igor@gmail.com> Co-authored-by: drew08t <drew08@gmail.com> * TableNG: Fix table suggestion (#102497) fix: defensively guard against missing cellOptions * TableNG: Footer fields calc fix (#102487) * fix: respect footer fields calc selection * chore: add test * TableNG: Image cell hover fix (#102489) fix: image cell hover * TableNG: Persist scrollbars during re render (#102559) * TableNG: Persist scrollbars during re render * Update improved betterer * TableNG: Fix column width override (#102474) * fix(table): column width override * TableNG: Add support for crosshair share (#102410) * TableNG: Add support for crosshair share * Add tests * TableNG: Fix table ng tests (#102645) fix: cellType causing tests to fail * Remove empty file * TableNG: Update util tests (#102646) * TableNG: Add column type icon (#102686) * chore(table-ng): add column type icon * chore(table-ng): clean styling * Use core internationalization outside grafana ui * Import popover directly * Add count to grafana-ui locales * TableNG: Change feature flag to tableNextGen (#102814) Change feature flag to tableNextGen * TableNG: Add row colors (#102706) * chore(table-ng): add row colors * clean up * fix params * fix(table-ng): cell color background indexing --------- Co-authored-by: Kyle Cunningham <kyle@codeincarnate.com> Co-authored-by: Ihor Yeromin <yeryomin.igor@gmail.com> Co-authored-by: Adela Almasan <adela.almasan@grafana.com> Co-authored-by: Leon Sorokin <leeoniya@gmail.com> Co-authored-by: Adela Almasan <88068998+adela-almasan@users.noreply.github.com> Co-authored-by: Alex Spencer <52186778+alexjonspencer1@users.noreply.github.com>
2025-03-26 11:57:57 +08:00
import { FormattedValueDisplay } from '../../FormattedValueDisplay/FormattedValueDisplay';
import { Sparkline } from '../../Sparkline/Sparkline';
import { TableCellProps } from '../types';
import { getAlignmentFactor, getCellOptions } from '../utils';
export const defaultSparklineCellConfig: TableSparklineCellOptions = {
type: TableCellDisplayMode.Sparkline,
drawStyle: GraphDrawStyle.Line,
lineInterpolation: LineInterpolation.Smooth,
lineWidth: 1,
fillOpacity: 17,
gradientMode: GraphGradientMode.Hue,
pointSize: 2,
barAlignment: BarAlignment.Center,
showPoints: VisibilityMode.Never,
hideValue: false,
};
export const SparklineCell = (props: TableCellProps) => {
const { field, innerWidth, tableStyles, cell, cellProps, timeRange } = props;
const sparkline = getSparkline(cell.value);
const theme = useTheme2();
if (!sparkline) {
return (
<div {...cellProps} className={tableStyles.cellContainer}>
{field.config.noValue || 'no data'}
</div>
);
}
// Get the step from the first two values to null-fill the x-axis based on timerange
if (sparkline.x && !sparkline.x.config.interval && sparkline.x.values.length > 1) {
sparkline.x.config.interval = sparkline.x.values[1] - sparkline.x.values[0];
}
// Remove non-finite values, e.g: NaN, +/-Infinity
sparkline.y.values = sparkline.y.values.map((v) => {
if (!Number.isFinite(v)) {
return null;
} else {
return v;
}
});
const range = getMinMaxAndDelta(sparkline.y);
sparkline.y.config.min = range.min;
sparkline.y.config.max = range.max;
sparkline.y.state = { range };
sparkline.timeRange = timeRange;
const cellOptions = getTableSparklineCellOptions(field);
const config: FieldConfig<GraphFieldConfig> = {
color: field.config.color,
custom: {
...defaultSparklineCellConfig,
...cellOptions,
},
};
const hideValue = field.config.custom?.cellOptions?.hideValue;
let valueWidth = 0;
let valueElement: React.ReactNode = null;
if (!hideValue) {
const value = isDataFrameWithValue(cell.value) ? cell.value.value : null;
const displayValue = field.display!(value);
const alignmentFactor = getAlignmentFactor(field, displayValue, cell.row.index);
valueWidth = measureText(formattedValueToString(alignmentFactor), 16).width + theme.spacing.gridSize;
valueElement = (
<FormattedValueDisplay
style={{
width: `${valueWidth - theme.spacing.gridSize}px`,
textAlign: 'right',
marginRight: theme.spacing(1),
}}
value={displayValue}
/>
);
}
return (
<div {...cellProps} className={tableStyles.cellContainer}>
{valueElement}
<div>
<Sparkline
width={innerWidth - valueWidth}
height={tableStyles.cellHeightInner}
sparkline={sparkline}
config={config}
theme={tableStyles.theme}
/>
</div>
</div>
);
};
function getSparkline(value: unknown): FieldSparkline | undefined {
if (Array.isArray(value)) {
return {
y: {
name: 'test',
type: FieldType.number,
values: value,
config: {},
},
};
}
if (isDataFrame(value)) {
const timeField = value.fields.find((x) => x.type === FieldType.time);
const numberField = value.fields.find((x) => x.type === FieldType.number);
if (timeField && numberField) {
return { x: timeField, y: numberField };
}
}
return;
}
function getTableSparklineCellOptions(field: Field): TableSparklineCellOptions {
let options = getCellOptions(field);
if (options.type === TableCellDisplayMode.Auto) {
options = { ...options, type: TableCellDisplayMode.Sparkline };
}
if (options.type === TableCellDisplayMode.Sparkline) {
return options;
}
throw new Error(`Expected options type ${TableCellDisplayMode.Sparkline} but got ${options.type}`);
}