grafana/public/app/core/components/TimeSeries/utils.ts

744 lines
22 KiB
TypeScript
Raw Normal View History

2021-05-05 16:44:31 +08:00
import { isNumber } from 'lodash';
import uPlot from 'uplot';
2021-05-05 16:44:31 +08:00
import {
DataFrame,
FieldConfig,
FieldType,
formattedValueToString,
getFieldColorModeForField,
getFieldSeriesColor,
getFieldDisplayName,
getDisplayProcessor,
FieldColorModeId,
DecimalCount,
2021-05-05 16:44:31 +08:00
} from '@grafana/data';
// eslint-disable-next-line import/order
2021-05-05 16:44:31 +08:00
import {
AxisPlacement,
GraphDrawStyle,
2021-05-05 16:44:31 +08:00
GraphFieldConfig,
GraphThresholdsStyleMode,
VisibilityMode,
2021-05-05 16:44:31 +08:00
ScaleDirection,
ScaleOrientation,
StackingMode,
GraphTransform,
AxisColorMode,
GraphGradientMode,
VizOrientation,
ScaleDistributionConfig,
} from '@grafana/schema';
// unit lookup needed to determine if we want power-of-2 or power-of-10 axis ticks
// see categories.ts is @grafana/data
const IEC_UNITS = new Set([
'bytes',
'bits',
'kbytes',
'mbytes',
'gbytes',
'tbytes',
'pbytes',
'binBps',
'binbps',
'KiBs',
'Kibits',
'MiBs',
'Mibits',
'GiBs',
'Gibits',
'TiBs',
'Tibits',
'PiBs',
'Pibits',
]);
const BIN_INCRS = Array(53);
for (let i = 0; i < BIN_INCRS.length; i++) {
BIN_INCRS[i] = 2 ** i;
}
import * as common from '@grafana/schema/dist/esm/index';
import { DrawStyle } from '@grafana/ui';
import {
UPlotConfigBuilder,
UPlotConfigPrepFn,
getScaleGradientFn,
buildScaleKey,
getStackingGroups,
preparePlotData2,
2025-09-25 01:48:22 +08:00
AxisProps,
} from '@grafana/ui/internal';
2021-05-05 16:44:31 +08:00
2025-09-24 22:21:16 +08:00
import { ANNOTATION_LANE_SIZE } from '../../../plugins/panel/timeseries/plugins/utils';
2025-09-25 01:48:22 +08:00
// See UPlotAxisBuilder.ts::calculateAxisSize for default axis size calculation
export const UPLOT_DEFAULT_AXIS_SIZE = 17;
export const UPLOT_DEFAULT_AXIS_GAP = 5;
2025-09-24 22:21:16 +08:00
const defaultFormatter = (v: any, decimals: DecimalCount = 1) => (v == null ? '-' : v.toFixed(decimals));
2021-05-05 16:44:31 +08:00
const defaultConfig: GraphFieldConfig = {
drawStyle: GraphDrawStyle.Line,
showPoints: VisibilityMode.Auto,
2021-05-05 16:44:31 +08:00
axisPlacement: AxisPlacement.Auto,
showValues: false,
2021-05-05 16:44:31 +08:00
};
export const preparePlotConfigBuilder: UPlotConfigPrepFn = ({
frame,
theme,
timeZones,
getTimeRange,
allFrames,
renderers,
tweakScale = (opts) => opts,
tweakAxis = (opts) => opts,
hoverProximity,
orientation = VizOrientation.Horizontal,
xAxisConfig,
}) => {
// we want the Auto and Horizontal orientation to default to Horizontal
const isHorizontal = orientation !== VizOrientation.Vertical;
const builder = new UPlotConfigBuilder(timeZones[0]);
2021-05-05 16:44:31 +08:00
let alignedFrame: DataFrame;
builder.setPrepData((frames) => {
// cache alignedFrame
alignedFrame = frames[0];
return preparePlotData2(frames[0], builder.getStackingGroups());
});
2021-07-29 09:31:07 +08:00
2021-05-05 16:44:31 +08:00
// X is the first field in the aligned frame
const xField = frame.fields[0];
if (!xField) {
return builder; // empty frame with no options
}
const xScaleKey = 'x';
GraphNG - shared cursor (#33433) * Initial work * WIP add cursor in debug panel * shared cursor.sync filter * explicit uplot events * explicit uplot events * uplot events * uplot events * depend on master uplot * sync sync sync * Fix merge * Get rid of PlotSyncContext and sync tooltip positions * make sync optional * Improve shared tooltip positioning * Plugins: add level and signature badges to plugin details page (#33553) * feat(grafana-ui): badge can accept react node for text, add shield-exclamation to icons * feat(plugins): add PluginSignatureType type * feat(pluginpage): introduce PluginSignatureDetailsBadge. Fix sidebar icon margin * feat(pluginlistpage): update filterinput placeholder, introduce filter by plugin type * Variables: Removes the never refresh option (#33533) * Variables: Removes the never refresh option * Tests: fixes DashboardModel repeat tests * Tests: fixs snapshots * Tests: fixes processVariable test * Tests: fixes DashboardModel tests * PageLayout: Fixes max-width breakpoint so that it triggers only when there is room for margin+ (#33558) * Alerting: Remove datasource (name) from migration (#33544) no longer needed as of https://github.com/grafana/grafana/pull/33416 for https://github.com/grafana/alerting-squad/issues/126 * Library panels: Adds description to library panels tab (#33428) * CodeOwners: Set owners of unified alerting migration (#33571) * ButtonSelect: updates component with the new theme model (#33565) * EmptySearchResult: updates component with the new theme model (#33573) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design (#33575) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design * Fixed font weight * Removed comment * Update * gitignore: Ignore files for accesscontrol provisioning (#33577) * Alerting/metrics (#33547) * moves alerting metrics to their own pkg * adds grafana_alerting_alerts (by state) metric * alerts_received_{total,invalid} * embed alertmanager alerting struct in ng metrics & remove duplicated notification metrics (already embed alertmanager notifier metrics) * use silence metrics from alertmanager lib * fix - manager has metrics * updates ngalert tests * comment lint Signed-off-by: Owen Diehl <ow.diehl@gmail.com> * cleaner prom registry code * removes ngalert global metrics * new registry use in all tests * ngalert metrics impl service, hack testinfra code to prevent duplicate metric registrations * nilmetrics unexported * Add note to Snapshot API doc to specify that user has to provide the entire dashboard model (#33572) * Added note as suggested by Macus E. * Update docs/sources/http_api/snapshot.md Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> * Alerting: backend "ng" code cleanup (#33578) * AlertMigration: remove alert_rule UID db check (#33568) do not believe this is needed due to uniqueness promised by shortid lib since there is no provisioning yet. https://github.com/teris-io/shortid * Live: persisting last message in cache for broadcast scope (#32938) * Alerting: Load annotations from rule into State cache (#33542) for https://github.com/grafana/alerting-squad/issues/127 * add template for dashboard url parameters (#33549) * Update dashboard-links.md parameters with plain text like `var-something=value` can make confusion. template it to clarify . * describe way for template link. * AlertingMigration: Create alert_rule_version entry (#33585) Create the alert rule version entry during the migration so it is consistent with rules created via api. for https://github.com/grafana/alerting-squad/issues/123 * Build: Fix with cleanup call maybe? (#33590) * add selector for code editor (#33554) * broadcast over eventBus * broadcasting to eventbus (but not useing it yet) * merge master * moved to context * fix yarn.lock * update snapshot * Fix direct state mutation * Persist location state on partial updates * GraphNG- use getStream rather than subscribe * Sync LegacyGraphHoverEvent with GraphNG * Chenge plotRef signature * use subscription * subscription * one fewer file * Update types * Remove unnecessary filtering * Disable cursor sync when in edit mode * GraphNG - bring back logging Co-authored-by: Ryan McKinley <ryantxu@gmail.com> Co-authored-by: Leon Sorokin <leeoniya@gmail.com> Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com> Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.org> Co-authored-by: Kyle Brandt <kyle@grafana.com> Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> Co-authored-by: Uchechukwu Obasi <obasiuche62@gmail.com> Co-authored-by: gamab <gamab@users.noreply.github.com> Co-authored-by: Owen Diehl <ow.diehl@gmail.com> Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Alexander Emelin <frvzmb@gmail.com> Co-authored-by: Nagle Zhang <nagle.zhang@sap.com> Co-authored-by: Erik Sundell <erik.sundell@grafana.com>
2021-05-10 20:24:23 +08:00
let yScaleKey = '';
const xFieldAxisPlacement =
xField.config.custom?.axisPlacement === AxisPlacement.Hidden
? AxisPlacement.Hidden
: isHorizontal
? AxisPlacement.Bottom
: AxisPlacement.Left;
const xFieldAxisShow = xField.config.custom?.axisPlacement !== AxisPlacement.Hidden;
2021-05-05 16:44:31 +08:00
if (xField.type === FieldType.time) {
builder.addScale({
GraphNG - shared cursor (#33433) * Initial work * WIP add cursor in debug panel * shared cursor.sync filter * explicit uplot events * explicit uplot events * uplot events * uplot events * depend on master uplot * sync sync sync * Fix merge * Get rid of PlotSyncContext and sync tooltip positions * make sync optional * Improve shared tooltip positioning * Plugins: add level and signature badges to plugin details page (#33553) * feat(grafana-ui): badge can accept react node for text, add shield-exclamation to icons * feat(plugins): add PluginSignatureType type * feat(pluginpage): introduce PluginSignatureDetailsBadge. Fix sidebar icon margin * feat(pluginlistpage): update filterinput placeholder, introduce filter by plugin type * Variables: Removes the never refresh option (#33533) * Variables: Removes the never refresh option * Tests: fixes DashboardModel repeat tests * Tests: fixs snapshots * Tests: fixes processVariable test * Tests: fixes DashboardModel tests * PageLayout: Fixes max-width breakpoint so that it triggers only when there is room for margin+ (#33558) * Alerting: Remove datasource (name) from migration (#33544) no longer needed as of https://github.com/grafana/grafana/pull/33416 for https://github.com/grafana/alerting-squad/issues/126 * Library panels: Adds description to library panels tab (#33428) * CodeOwners: Set owners of unified alerting migration (#33571) * ButtonSelect: updates component with the new theme model (#33565) * EmptySearchResult: updates component with the new theme model (#33573) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design (#33575) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design * Fixed font weight * Removed comment * Update * gitignore: Ignore files for accesscontrol provisioning (#33577) * Alerting/metrics (#33547) * moves alerting metrics to their own pkg * adds grafana_alerting_alerts (by state) metric * alerts_received_{total,invalid} * embed alertmanager alerting struct in ng metrics & remove duplicated notification metrics (already embed alertmanager notifier metrics) * use silence metrics from alertmanager lib * fix - manager has metrics * updates ngalert tests * comment lint Signed-off-by: Owen Diehl <ow.diehl@gmail.com> * cleaner prom registry code * removes ngalert global metrics * new registry use in all tests * ngalert metrics impl service, hack testinfra code to prevent duplicate metric registrations * nilmetrics unexported * Add note to Snapshot API doc to specify that user has to provide the entire dashboard model (#33572) * Added note as suggested by Macus E. * Update docs/sources/http_api/snapshot.md Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> * Alerting: backend "ng" code cleanup (#33578) * AlertMigration: remove alert_rule UID db check (#33568) do not believe this is needed due to uniqueness promised by shortid lib since there is no provisioning yet. https://github.com/teris-io/shortid * Live: persisting last message in cache for broadcast scope (#32938) * Alerting: Load annotations from rule into State cache (#33542) for https://github.com/grafana/alerting-squad/issues/127 * add template for dashboard url parameters (#33549) * Update dashboard-links.md parameters with plain text like `var-something=value` can make confusion. template it to clarify . * describe way for template link. * AlertingMigration: Create alert_rule_version entry (#33585) Create the alert rule version entry during the migration so it is consistent with rules created via api. for https://github.com/grafana/alerting-squad/issues/123 * Build: Fix with cleanup call maybe? (#33590) * add selector for code editor (#33554) * broadcast over eventBus * broadcasting to eventbus (but not useing it yet) * merge master * moved to context * fix yarn.lock * update snapshot * Fix direct state mutation * Persist location state on partial updates * GraphNG- use getStream rather than subscribe * Sync LegacyGraphHoverEvent with GraphNG * Chenge plotRef signature * use subscription * subscription * one fewer file * Update types * Remove unnecessary filtering * Disable cursor sync when in edit mode * GraphNG - bring back logging Co-authored-by: Ryan McKinley <ryantxu@gmail.com> Co-authored-by: Leon Sorokin <leeoniya@gmail.com> Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com> Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.org> Co-authored-by: Kyle Brandt <kyle@grafana.com> Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> Co-authored-by: Uchechukwu Obasi <obasiuche62@gmail.com> Co-authored-by: gamab <gamab@users.noreply.github.com> Co-authored-by: Owen Diehl <ow.diehl@gmail.com> Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Alexander Emelin <frvzmb@gmail.com> Co-authored-by: Nagle Zhang <nagle.zhang@sap.com> Co-authored-by: Erik Sundell <erik.sundell@grafana.com>
2021-05-10 20:24:23 +08:00
scaleKey: xScaleKey,
orientation: isHorizontal ? ScaleOrientation.Horizontal : ScaleOrientation.Vertical,
direction: isHorizontal ? ScaleDirection.Right : ScaleDirection.Up,
2021-05-05 16:44:31 +08:00
isTime: true,
range: () => {
GraphNG - shared cursor (#33433) * Initial work * WIP add cursor in debug panel * shared cursor.sync filter * explicit uplot events * explicit uplot events * uplot events * uplot events * depend on master uplot * sync sync sync * Fix merge * Get rid of PlotSyncContext and sync tooltip positions * make sync optional * Improve shared tooltip positioning * Plugins: add level and signature badges to plugin details page (#33553) * feat(grafana-ui): badge can accept react node for text, add shield-exclamation to icons * feat(plugins): add PluginSignatureType type * feat(pluginpage): introduce PluginSignatureDetailsBadge. Fix sidebar icon margin * feat(pluginlistpage): update filterinput placeholder, introduce filter by plugin type * Variables: Removes the never refresh option (#33533) * Variables: Removes the never refresh option * Tests: fixes DashboardModel repeat tests * Tests: fixs snapshots * Tests: fixes processVariable test * Tests: fixes DashboardModel tests * PageLayout: Fixes max-width breakpoint so that it triggers only when there is room for margin+ (#33558) * Alerting: Remove datasource (name) from migration (#33544) no longer needed as of https://github.com/grafana/grafana/pull/33416 for https://github.com/grafana/alerting-squad/issues/126 * Library panels: Adds description to library panels tab (#33428) * CodeOwners: Set owners of unified alerting migration (#33571) * ButtonSelect: updates component with the new theme model (#33565) * EmptySearchResult: updates component with the new theme model (#33573) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design (#33575) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design * Fixed font weight * Removed comment * Update * gitignore: Ignore files for accesscontrol provisioning (#33577) * Alerting/metrics (#33547) * moves alerting metrics to their own pkg * adds grafana_alerting_alerts (by state) metric * alerts_received_{total,invalid} * embed alertmanager alerting struct in ng metrics & remove duplicated notification metrics (already embed alertmanager notifier metrics) * use silence metrics from alertmanager lib * fix - manager has metrics * updates ngalert tests * comment lint Signed-off-by: Owen Diehl <ow.diehl@gmail.com> * cleaner prom registry code * removes ngalert global metrics * new registry use in all tests * ngalert metrics impl service, hack testinfra code to prevent duplicate metric registrations * nilmetrics unexported * Add note to Snapshot API doc to specify that user has to provide the entire dashboard model (#33572) * Added note as suggested by Macus E. * Update docs/sources/http_api/snapshot.md Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> * Alerting: backend "ng" code cleanup (#33578) * AlertMigration: remove alert_rule UID db check (#33568) do not believe this is needed due to uniqueness promised by shortid lib since there is no provisioning yet. https://github.com/teris-io/shortid * Live: persisting last message in cache for broadcast scope (#32938) * Alerting: Load annotations from rule into State cache (#33542) for https://github.com/grafana/alerting-squad/issues/127 * add template for dashboard url parameters (#33549) * Update dashboard-links.md parameters with plain text like `var-something=value` can make confusion. template it to clarify . * describe way for template link. * AlertingMigration: Create alert_rule_version entry (#33585) Create the alert rule version entry during the migration so it is consistent with rules created via api. for https://github.com/grafana/alerting-squad/issues/123 * Build: Fix with cleanup call maybe? (#33590) * add selector for code editor (#33554) * broadcast over eventBus * broadcasting to eventbus (but not useing it yet) * merge master * moved to context * fix yarn.lock * update snapshot * Fix direct state mutation * Persist location state on partial updates * GraphNG- use getStream rather than subscribe * Sync LegacyGraphHoverEvent with GraphNG * Chenge plotRef signature * use subscription * subscription * one fewer file * Update types * Remove unnecessary filtering * Disable cursor sync when in edit mode * GraphNG - bring back logging Co-authored-by: Ryan McKinley <ryantxu@gmail.com> Co-authored-by: Leon Sorokin <leeoniya@gmail.com> Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com> Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.org> Co-authored-by: Kyle Brandt <kyle@grafana.com> Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> Co-authored-by: Uchechukwu Obasi <obasiuche62@gmail.com> Co-authored-by: gamab <gamab@users.noreply.github.com> Co-authored-by: Owen Diehl <ow.diehl@gmail.com> Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Alexander Emelin <frvzmb@gmail.com> Co-authored-by: Nagle Zhang <nagle.zhang@sap.com> Co-authored-by: Erik Sundell <erik.sundell@grafana.com>
2021-05-10 20:24:23 +08:00
const r = getTimeRange();
return [r.from.valueOf(), r.to.valueOf()];
2021-05-05 16:44:31 +08:00
},
});
// filters first 2 ticks to make space for timezone labels
const filterTicks: uPlot.Axis.Filter | undefined =
timeZones.length > 1
? (u, splits) => {
if (isHorizontal) {
return splits.map((v, i) => (i < 2 ? null : v));
}
return splits;
}
: undefined;
for (let i = 0; i < timeZones.length; i++) {
const timeZone = timeZones[i];
builder.addAxis({
scaleKey: xScaleKey,
isTime: true,
placement: xFieldAxisPlacement,
show: xFieldAxisShow,
label: xField.config.custom?.axisLabel,
timeZone,
theme,
grid: { show: i === 0 && xField.config.custom?.axisGridShow },
filter: filterTicks,
...xAxisConfig,
});
}
// render timezone labels
if (timeZones.length > 1) {
builder.addHook('drawAxes', (u: uPlot) => {
u.ctx.save();
let i = 0;
u.axes.forEach((a) => {
if (isHorizontal && a.side === 2) {
u.ctx.fillStyle = theme.colors.text.primary;
u.ctx.textAlign = 'left';
u.ctx.textBaseline = 'bottom';
//@ts-ignore
let cssBaseline: number = a._pos + a._size;
u.ctx.fillText(timeZones[i], u.bbox.left, cssBaseline * uPlot.pxRatio);
i++;
}
});
u.ctx.restore();
});
}
2021-05-05 16:44:31 +08:00
} else {
let custom = xField.config.custom;
let scaleDistr: ScaleDistributionConfig = { ...custom?.scaleDistribution };
2021-05-05 16:44:31 +08:00
builder.addScale({
GraphNG - shared cursor (#33433) * Initial work * WIP add cursor in debug panel * shared cursor.sync filter * explicit uplot events * explicit uplot events * uplot events * uplot events * depend on master uplot * sync sync sync * Fix merge * Get rid of PlotSyncContext and sync tooltip positions * make sync optional * Improve shared tooltip positioning * Plugins: add level and signature badges to plugin details page (#33553) * feat(grafana-ui): badge can accept react node for text, add shield-exclamation to icons * feat(plugins): add PluginSignatureType type * feat(pluginpage): introduce PluginSignatureDetailsBadge. Fix sidebar icon margin * feat(pluginlistpage): update filterinput placeholder, introduce filter by plugin type * Variables: Removes the never refresh option (#33533) * Variables: Removes the never refresh option * Tests: fixes DashboardModel repeat tests * Tests: fixs snapshots * Tests: fixes processVariable test * Tests: fixes DashboardModel tests * PageLayout: Fixes max-width breakpoint so that it triggers only when there is room for margin+ (#33558) * Alerting: Remove datasource (name) from migration (#33544) no longer needed as of https://github.com/grafana/grafana/pull/33416 for https://github.com/grafana/alerting-squad/issues/126 * Library panels: Adds description to library panels tab (#33428) * CodeOwners: Set owners of unified alerting migration (#33571) * ButtonSelect: updates component with the new theme model (#33565) * EmptySearchResult: updates component with the new theme model (#33573) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design (#33575) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design * Fixed font weight * Removed comment * Update * gitignore: Ignore files for accesscontrol provisioning (#33577) * Alerting/metrics (#33547) * moves alerting metrics to their own pkg * adds grafana_alerting_alerts (by state) metric * alerts_received_{total,invalid} * embed alertmanager alerting struct in ng metrics & remove duplicated notification metrics (already embed alertmanager notifier metrics) * use silence metrics from alertmanager lib * fix - manager has metrics * updates ngalert tests * comment lint Signed-off-by: Owen Diehl <ow.diehl@gmail.com> * cleaner prom registry code * removes ngalert global metrics * new registry use in all tests * ngalert metrics impl service, hack testinfra code to prevent duplicate metric registrations * nilmetrics unexported * Add note to Snapshot API doc to specify that user has to provide the entire dashboard model (#33572) * Added note as suggested by Macus E. * Update docs/sources/http_api/snapshot.md Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> * Alerting: backend "ng" code cleanup (#33578) * AlertMigration: remove alert_rule UID db check (#33568) do not believe this is needed due to uniqueness promised by shortid lib since there is no provisioning yet. https://github.com/teris-io/shortid * Live: persisting last message in cache for broadcast scope (#32938) * Alerting: Load annotations from rule into State cache (#33542) for https://github.com/grafana/alerting-squad/issues/127 * add template for dashboard url parameters (#33549) * Update dashboard-links.md parameters with plain text like `var-something=value` can make confusion. template it to clarify . * describe way for template link. * AlertingMigration: Create alert_rule_version entry (#33585) Create the alert rule version entry during the migration so it is consistent with rules created via api. for https://github.com/grafana/alerting-squad/issues/123 * Build: Fix with cleanup call maybe? (#33590) * add selector for code editor (#33554) * broadcast over eventBus * broadcasting to eventbus (but not useing it yet) * merge master * moved to context * fix yarn.lock * update snapshot * Fix direct state mutation * Persist location state on partial updates * GraphNG- use getStream rather than subscribe * Sync LegacyGraphHoverEvent with GraphNG * Chenge plotRef signature * use subscription * subscription * one fewer file * Update types * Remove unnecessary filtering * Disable cursor sync when in edit mode * GraphNG - bring back logging Co-authored-by: Ryan McKinley <ryantxu@gmail.com> Co-authored-by: Leon Sorokin <leeoniya@gmail.com> Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com> Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.org> Co-authored-by: Kyle Brandt <kyle@grafana.com> Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> Co-authored-by: Uchechukwu Obasi <obasiuche62@gmail.com> Co-authored-by: gamab <gamab@users.noreply.github.com> Co-authored-by: Owen Diehl <ow.diehl@gmail.com> Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Alexander Emelin <frvzmb@gmail.com> Co-authored-by: Nagle Zhang <nagle.zhang@sap.com> Co-authored-by: Erik Sundell <erik.sundell@grafana.com>
2021-05-10 20:24:23 +08:00
scaleKey: xScaleKey,
orientation: isHorizontal ? ScaleOrientation.Horizontal : ScaleOrientation.Vertical,
direction: isHorizontal ? ScaleDirection.Right : ScaleDirection.Up,
distribution: scaleDistr?.type,
log: scaleDistr?.log,
linearThreshold: scaleDistr?.linearThreshold,
min: xField.config.min,
max: xField.config.max,
softMin: custom?.axisSoftMin,
softMax: custom?.axisSoftMax,
centeredZero: custom?.axisCenteredZero,
decimals: xField.config.decimals,
padMinBy: 0,
padMaxBy: 0,
2021-05-05 16:44:31 +08:00
});
builder.addAxis({
GraphNG - shared cursor (#33433) * Initial work * WIP add cursor in debug panel * shared cursor.sync filter * explicit uplot events * explicit uplot events * uplot events * uplot events * depend on master uplot * sync sync sync * Fix merge * Get rid of PlotSyncContext and sync tooltip positions * make sync optional * Improve shared tooltip positioning * Plugins: add level and signature badges to plugin details page (#33553) * feat(grafana-ui): badge can accept react node for text, add shield-exclamation to icons * feat(plugins): add PluginSignatureType type * feat(pluginpage): introduce PluginSignatureDetailsBadge. Fix sidebar icon margin * feat(pluginlistpage): update filterinput placeholder, introduce filter by plugin type * Variables: Removes the never refresh option (#33533) * Variables: Removes the never refresh option * Tests: fixes DashboardModel repeat tests * Tests: fixs snapshots * Tests: fixes processVariable test * Tests: fixes DashboardModel tests * PageLayout: Fixes max-width breakpoint so that it triggers only when there is room for margin+ (#33558) * Alerting: Remove datasource (name) from migration (#33544) no longer needed as of https://github.com/grafana/grafana/pull/33416 for https://github.com/grafana/alerting-squad/issues/126 * Library panels: Adds description to library panels tab (#33428) * CodeOwners: Set owners of unified alerting migration (#33571) * ButtonSelect: updates component with the new theme model (#33565) * EmptySearchResult: updates component with the new theme model (#33573) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design (#33575) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design * Fixed font weight * Removed comment * Update * gitignore: Ignore files for accesscontrol provisioning (#33577) * Alerting/metrics (#33547) * moves alerting metrics to their own pkg * adds grafana_alerting_alerts (by state) metric * alerts_received_{total,invalid} * embed alertmanager alerting struct in ng metrics & remove duplicated notification metrics (already embed alertmanager notifier metrics) * use silence metrics from alertmanager lib * fix - manager has metrics * updates ngalert tests * comment lint Signed-off-by: Owen Diehl <ow.diehl@gmail.com> * cleaner prom registry code * removes ngalert global metrics * new registry use in all tests * ngalert metrics impl service, hack testinfra code to prevent duplicate metric registrations * nilmetrics unexported * Add note to Snapshot API doc to specify that user has to provide the entire dashboard model (#33572) * Added note as suggested by Macus E. * Update docs/sources/http_api/snapshot.md Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> * Alerting: backend "ng" code cleanup (#33578) * AlertMigration: remove alert_rule UID db check (#33568) do not believe this is needed due to uniqueness promised by shortid lib since there is no provisioning yet. https://github.com/teris-io/shortid * Live: persisting last message in cache for broadcast scope (#32938) * Alerting: Load annotations from rule into State cache (#33542) for https://github.com/grafana/alerting-squad/issues/127 * add template for dashboard url parameters (#33549) * Update dashboard-links.md parameters with plain text like `var-something=value` can make confusion. template it to clarify . * describe way for template link. * AlertingMigration: Create alert_rule_version entry (#33585) Create the alert rule version entry during the migration so it is consistent with rules created via api. for https://github.com/grafana/alerting-squad/issues/123 * Build: Fix with cleanup call maybe? (#33590) * add selector for code editor (#33554) * broadcast over eventBus * broadcasting to eventbus (but not useing it yet) * merge master * moved to context * fix yarn.lock * update snapshot * Fix direct state mutation * Persist location state on partial updates * GraphNG- use getStream rather than subscribe * Sync LegacyGraphHoverEvent with GraphNG * Chenge plotRef signature * use subscription * subscription * one fewer file * Update types * Remove unnecessary filtering * Disable cursor sync when in edit mode * GraphNG - bring back logging Co-authored-by: Ryan McKinley <ryantxu@gmail.com> Co-authored-by: Leon Sorokin <leeoniya@gmail.com> Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com> Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.org> Co-authored-by: Kyle Brandt <kyle@grafana.com> Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> Co-authored-by: Uchechukwu Obasi <obasiuche62@gmail.com> Co-authored-by: gamab <gamab@users.noreply.github.com> Co-authored-by: Owen Diehl <ow.diehl@gmail.com> Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Alexander Emelin <frvzmb@gmail.com> Co-authored-by: Nagle Zhang <nagle.zhang@sap.com> Co-authored-by: Erik Sundell <erik.sundell@grafana.com>
2021-05-10 20:24:23 +08:00
scaleKey: xScaleKey,
placement: xFieldAxisPlacement,
show: xFieldAxisShow,
label: custom?.axisLabel,
2021-05-05 16:44:31 +08:00
theme,
grid: { show: custom?.axisGridShow },
formatValue: (v, decimals) => formattedValueToString(xField.display!(v, decimals)),
2021-05-05 16:44:31 +08:00
});
}
let customRenderedFields =
renderers?.flatMap((r) => Object.values(r.fieldMap).filter((name) => r.indicesOnly.indexOf(name) === -1)) ?? [];
let indexByName: Map<string, number> | undefined;
2021-05-05 16:44:31 +08:00
GraphNG - shared cursor (#33433) * Initial work * WIP add cursor in debug panel * shared cursor.sync filter * explicit uplot events * explicit uplot events * uplot events * uplot events * depend on master uplot * sync sync sync * Fix merge * Get rid of PlotSyncContext and sync tooltip positions * make sync optional * Improve shared tooltip positioning * Plugins: add level and signature badges to plugin details page (#33553) * feat(grafana-ui): badge can accept react node for text, add shield-exclamation to icons * feat(plugins): add PluginSignatureType type * feat(pluginpage): introduce PluginSignatureDetailsBadge. Fix sidebar icon margin * feat(pluginlistpage): update filterinput placeholder, introduce filter by plugin type * Variables: Removes the never refresh option (#33533) * Variables: Removes the never refresh option * Tests: fixes DashboardModel repeat tests * Tests: fixs snapshots * Tests: fixes processVariable test * Tests: fixes DashboardModel tests * PageLayout: Fixes max-width breakpoint so that it triggers only when there is room for margin+ (#33558) * Alerting: Remove datasource (name) from migration (#33544) no longer needed as of https://github.com/grafana/grafana/pull/33416 for https://github.com/grafana/alerting-squad/issues/126 * Library panels: Adds description to library panels tab (#33428) * CodeOwners: Set owners of unified alerting migration (#33571) * ButtonSelect: updates component with the new theme model (#33565) * EmptySearchResult: updates component with the new theme model (#33573) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design (#33575) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design * Fixed font weight * Removed comment * Update * gitignore: Ignore files for accesscontrol provisioning (#33577) * Alerting/metrics (#33547) * moves alerting metrics to their own pkg * adds grafana_alerting_alerts (by state) metric * alerts_received_{total,invalid} * embed alertmanager alerting struct in ng metrics & remove duplicated notification metrics (already embed alertmanager notifier metrics) * use silence metrics from alertmanager lib * fix - manager has metrics * updates ngalert tests * comment lint Signed-off-by: Owen Diehl <ow.diehl@gmail.com> * cleaner prom registry code * removes ngalert global metrics * new registry use in all tests * ngalert metrics impl service, hack testinfra code to prevent duplicate metric registrations * nilmetrics unexported * Add note to Snapshot API doc to specify that user has to provide the entire dashboard model (#33572) * Added note as suggested by Macus E. * Update docs/sources/http_api/snapshot.md Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> * Alerting: backend "ng" code cleanup (#33578) * AlertMigration: remove alert_rule UID db check (#33568) do not believe this is needed due to uniqueness promised by shortid lib since there is no provisioning yet. https://github.com/teris-io/shortid * Live: persisting last message in cache for broadcast scope (#32938) * Alerting: Load annotations from rule into State cache (#33542) for https://github.com/grafana/alerting-squad/issues/127 * add template for dashboard url parameters (#33549) * Update dashboard-links.md parameters with plain text like `var-something=value` can make confusion. template it to clarify . * describe way for template link. * AlertingMigration: Create alert_rule_version entry (#33585) Create the alert rule version entry during the migration so it is consistent with rules created via api. for https://github.com/grafana/alerting-squad/issues/123 * Build: Fix with cleanup call maybe? (#33590) * add selector for code editor (#33554) * broadcast over eventBus * broadcasting to eventbus (but not useing it yet) * merge master * moved to context * fix yarn.lock * update snapshot * Fix direct state mutation * Persist location state on partial updates * GraphNG- use getStream rather than subscribe * Sync LegacyGraphHoverEvent with GraphNG * Chenge plotRef signature * use subscription * subscription * one fewer file * Update types * Remove unnecessary filtering * Disable cursor sync when in edit mode * GraphNG - bring back logging Co-authored-by: Ryan McKinley <ryantxu@gmail.com> Co-authored-by: Leon Sorokin <leeoniya@gmail.com> Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com> Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.org> Co-authored-by: Kyle Brandt <kyle@grafana.com> Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> Co-authored-by: Uchechukwu Obasi <obasiuche62@gmail.com> Co-authored-by: gamab <gamab@users.noreply.github.com> Co-authored-by: Owen Diehl <ow.diehl@gmail.com> Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Alexander Emelin <frvzmb@gmail.com> Co-authored-by: Nagle Zhang <nagle.zhang@sap.com> Co-authored-by: Erik Sundell <erik.sundell@grafana.com>
2021-05-10 20:24:23 +08:00
for (let i = 1; i < frame.fields.length; i++) {
2021-05-05 16:44:31 +08:00
const field = frame.fields[i];
const config: FieldConfig<GraphFieldConfig> = {
...field.config,
custom: {
...defaultConfig,
...field.config.custom,
},
};
const customConfig: GraphFieldConfig = config.custom!;
2021-05-05 16:44:31 +08:00
if (field === xField || (field.type !== FieldType.number && field.type !== FieldType.enum)) {
2021-05-05 16:44:31 +08:00
continue;
}
let fmt = field.display ?? defaultFormatter;
if (field.config.custom?.stacking?.mode === StackingMode.Percent) {
fmt = getDisplayProcessor({
field: {
...field,
config: {
...field.config,
unit: 'percentunit',
},
},
theme,
});
}
const scaleKey = buildScaleKey(config, field.type);
2021-05-05 16:44:31 +08:00
const colorMode = getFieldColorModeForField(field);
const scaleColor = getFieldSeriesColor(field, theme);
const seriesColor = scaleColor.color;
// The builder will manage unique scaleKeys and combine where appropriate
builder.addScale(
tweakScale(
{
scaleKey,
orientation: isHorizontal ? ScaleOrientation.Vertical : ScaleOrientation.Horizontal,
direction: isHorizontal ? ScaleDirection.Up : ScaleDirection.Right,
distribution: customConfig.scaleDistribution?.type,
log: customConfig.scaleDistribution?.log,
linearThreshold: customConfig.scaleDistribution?.linearThreshold,
min: field.config.min,
max: field.config.max,
softMin: customConfig.axisSoftMin,
softMax: customConfig.axisSoftMax,
centeredZero: customConfig.axisCenteredZero,
stackingMode: customConfig.stacking?.mode,
range:
field.type === FieldType.enum
? (u: uPlot, dataMin: number, dataMax: number) => {
// this is the exhaustive enum (stable)
let len = field.config.type!.enum!.text!.length;
return [-1, len];
// these are only values that are present
// return [dataMin - 1, dataMax + 1]
}
: undefined,
decimals: field.config.decimals,
},
field
)
);
2021-05-05 16:44:31 +08:00
GraphNG - shared cursor (#33433) * Initial work * WIP add cursor in debug panel * shared cursor.sync filter * explicit uplot events * explicit uplot events * uplot events * uplot events * depend on master uplot * sync sync sync * Fix merge * Get rid of PlotSyncContext and sync tooltip positions * make sync optional * Improve shared tooltip positioning * Plugins: add level and signature badges to plugin details page (#33553) * feat(grafana-ui): badge can accept react node for text, add shield-exclamation to icons * feat(plugins): add PluginSignatureType type * feat(pluginpage): introduce PluginSignatureDetailsBadge. Fix sidebar icon margin * feat(pluginlistpage): update filterinput placeholder, introduce filter by plugin type * Variables: Removes the never refresh option (#33533) * Variables: Removes the never refresh option * Tests: fixes DashboardModel repeat tests * Tests: fixs snapshots * Tests: fixes processVariable test * Tests: fixes DashboardModel tests * PageLayout: Fixes max-width breakpoint so that it triggers only when there is room for margin+ (#33558) * Alerting: Remove datasource (name) from migration (#33544) no longer needed as of https://github.com/grafana/grafana/pull/33416 for https://github.com/grafana/alerting-squad/issues/126 * Library panels: Adds description to library panels tab (#33428) * CodeOwners: Set owners of unified alerting migration (#33571) * ButtonSelect: updates component with the new theme model (#33565) * EmptySearchResult: updates component with the new theme model (#33573) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design (#33575) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design * Fixed font weight * Removed comment * Update * gitignore: Ignore files for accesscontrol provisioning (#33577) * Alerting/metrics (#33547) * moves alerting metrics to their own pkg * adds grafana_alerting_alerts (by state) metric * alerts_received_{total,invalid} * embed alertmanager alerting struct in ng metrics & remove duplicated notification metrics (already embed alertmanager notifier metrics) * use silence metrics from alertmanager lib * fix - manager has metrics * updates ngalert tests * comment lint Signed-off-by: Owen Diehl <ow.diehl@gmail.com> * cleaner prom registry code * removes ngalert global metrics * new registry use in all tests * ngalert metrics impl service, hack testinfra code to prevent duplicate metric registrations * nilmetrics unexported * Add note to Snapshot API doc to specify that user has to provide the entire dashboard model (#33572) * Added note as suggested by Macus E. * Update docs/sources/http_api/snapshot.md Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> * Alerting: backend "ng" code cleanup (#33578) * AlertMigration: remove alert_rule UID db check (#33568) do not believe this is needed due to uniqueness promised by shortid lib since there is no provisioning yet. https://github.com/teris-io/shortid * Live: persisting last message in cache for broadcast scope (#32938) * Alerting: Load annotations from rule into State cache (#33542) for https://github.com/grafana/alerting-squad/issues/127 * add template for dashboard url parameters (#33549) * Update dashboard-links.md parameters with plain text like `var-something=value` can make confusion. template it to clarify . * describe way for template link. * AlertingMigration: Create alert_rule_version entry (#33585) Create the alert rule version entry during the migration so it is consistent with rules created via api. for https://github.com/grafana/alerting-squad/issues/123 * Build: Fix with cleanup call maybe? (#33590) * add selector for code editor (#33554) * broadcast over eventBus * broadcasting to eventbus (but not useing it yet) * merge master * moved to context * fix yarn.lock * update snapshot * Fix direct state mutation * Persist location state on partial updates * GraphNG- use getStream rather than subscribe * Sync LegacyGraphHoverEvent with GraphNG * Chenge plotRef signature * use subscription * subscription * one fewer file * Update types * Remove unnecessary filtering * Disable cursor sync when in edit mode * GraphNG - bring back logging Co-authored-by: Ryan McKinley <ryantxu@gmail.com> Co-authored-by: Leon Sorokin <leeoniya@gmail.com> Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com> Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.org> Co-authored-by: Kyle Brandt <kyle@grafana.com> Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> Co-authored-by: Uchechukwu Obasi <obasiuche62@gmail.com> Co-authored-by: gamab <gamab@users.noreply.github.com> Co-authored-by: Owen Diehl <ow.diehl@gmail.com> Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Alexander Emelin <frvzmb@gmail.com> Co-authored-by: Nagle Zhang <nagle.zhang@sap.com> Co-authored-by: Erik Sundell <erik.sundell@grafana.com>
2021-05-10 20:24:23 +08:00
if (!yScaleKey) {
yScaleKey = scaleKey;
}
2021-05-05 16:44:31 +08:00
if (customConfig.axisPlacement !== AxisPlacement.Hidden) {
let axisColor: uPlot.Axis.Stroke | undefined;
if (customConfig.axisColorMode === AxisColorMode.Series) {
if (
colorMode.isByValue &&
field.config.custom?.gradientMode === GraphGradientMode.Scheme &&
colorMode.id === FieldColorModeId.Thresholds
) {
axisColor = getScaleGradientFn(1, theme, colorMode, field.config.thresholds);
} else {
axisColor = seriesColor;
}
}
const axisDisplayOptions = {
border: {
show: customConfig.axisBorderShow || false,
width: 1 / devicePixelRatio,
stroke: axisColor || theme.colors.text.primary,
},
ticks: {
show: customConfig.axisBorderShow || false,
stroke: axisColor || theme.colors.text.primary,
},
color: axisColor || theme.colors.text.primary,
};
let incrs: uPlot.Axis.Incrs | undefined;
// TODO: these will be dynamic with frame updates, so need to accept getYTickLabels()
let values: uPlot.Axis.Values | undefined;
let splits: uPlot.Axis.Splits | undefined;
if (IEC_UNITS.has(config.unit!)) {
incrs = BIN_INCRS;
} else if (field.type === FieldType.enum) {
let text = field.config.type!.enum!.text!;
splits = text.map((v: string, i: number) => i);
values = text;
}
builder.addAxis(
tweakAxis(
{
scaleKey,
label: customConfig.axisLabel,
size: customConfig.axisWidth,
2024-07-23 20:56:57 +08:00
placement: isHorizontal ? (customConfig.axisPlacement ?? AxisPlacement.Auto) : AxisPlacement.Bottom,
formatValue: (v, decimals) => formattedValueToString(fmt(v, decimals)),
theme,
grid: { show: customConfig.axisGridShow },
decimals: field.config.decimals,
distr: customConfig.scaleDistribution?.type,
splits,
values,
incrs,
...axisDisplayOptions,
},
field
)
);
2021-05-05 16:44:31 +08:00
}
const showPoints =
customConfig.drawStyle === GraphDrawStyle.Points ? VisibilityMode.Always : customConfig.showPoints;
2021-05-05 16:44:31 +08:00
let pointsFilter: uPlot.Series.Points.Filter = () => null;
if (customConfig.spanNulls !== true && showPoints === VisibilityMode.Auto) {
pointsFilter = (u, seriesIdx, show, gaps) => {
let filtered = [];
if (!show) {
const yData = u.data[seriesIdx];
if (gaps && gaps.length) {
const firstIdx = u.posToIdx(gaps[0][0], true);
if (yData[firstIdx - 1] == null) {
filtered.push(firstIdx);
}
// show single points between consecutive gaps that share end/start
for (let i = 0; i < gaps.length; i++) {
let thisGap = gaps[i];
let nextGap = gaps[i + 1];
if (nextGap && thisGap[1] === nextGap[0]) {
// approx when data density is > 1pt/px, since gap start/end pixels are rounded
let approxIdx = u.posToIdx(thisGap[1], true);
if (yData[approxIdx] == null) {
// scan left/right alternating to find closest index with non-null value
for (let j = 1; j < 100; j++) {
if (yData[approxIdx + j] != null) {
approxIdx += j;
break;
}
if (yData[approxIdx - j] != null) {
approxIdx -= j;
break;
}
}
}
filtered.push(approxIdx);
}
}
const lastIdx = u.posToIdx(gaps[gaps.length - 1][1], true);
if (yData[lastIdx + 1] == null) {
filtered.push(lastIdx);
}
}
// single point
else {
// scan right
let leftIdx = 0;
while (yData[leftIdx] === null) {
leftIdx++;
}
// scan left
let rightIdx = yData.length - 1;
while (rightIdx >= leftIdx && yData[rightIdx] === null) {
rightIdx--;
}
// render if same
if (leftIdx === rightIdx) {
filtered.push(leftIdx);
}
}
}
return filtered.length ? filtered : null;
};
}
2021-05-05 16:44:31 +08:00
let { fillOpacity } = customConfig;
let pathBuilder: uPlot.Series.PathBuilder | null = null;
let pointsBuilder: uPlot.Series.Points.Show | null = null;
if (field.state?.origin) {
2021-05-05 16:44:31 +08:00
if (!indexByName) {
indexByName = getNamesToFieldIndex(frame, allFrames);
2021-05-05 16:44:31 +08:00
}
const originFrame = allFrames[field.state.origin.frameIndex];
const originField = originFrame?.fields[field.state.origin.fieldIndex];
const dispName = getFieldDisplayName(originField ?? field, originFrame, allFrames);
// disable default renderers
if (customRenderedFields.indexOf(dispName) >= 0) {
pathBuilder = () => null;
pointsBuilder = () => undefined;
} else if (customConfig.transform === GraphTransform.Constant) {
// patch some monkeys!
const defaultBuilder = uPlot.paths!.linear!();
pathBuilder = (u, seriesIdx) => {
//eslint-disable-next-line
const _data: any[] = (u as any)._data; // uplot.AlignedData not exposed in types
// the data we want the line renderer to pull is x at each plot edge with paired flat y values
const r = getTimeRange();
let xData = [r.from.valueOf(), r.to.valueOf()];
let firstY = _data[seriesIdx].find((v: number | null | undefined) => v != null);
let yData = [firstY, firstY];
let fauxData = _data.slice();
fauxData[0] = xData;
fauxData[seriesIdx] = yData;
//eslint-disable-next-line
return defaultBuilder(
{
...u,
_data: fauxData,
} as any,
seriesIdx,
0,
1
);
};
2021-05-05 16:44:31 +08:00
}
if (customConfig.fillBelowTo) {
const fillBelowToField = frame.fields.find(
(f) =>
customConfig.fillBelowTo === f.name ||
customConfig.fillBelowTo === f.config?.displayNameFromDS ||
customConfig.fillBelowTo === getFieldDisplayName(f, frame, allFrames)
);
const fillBelowDispName = fillBelowToField
? getFieldDisplayName(fillBelowToField, frame, allFrames)
: customConfig.fillBelowTo;
const t = indexByName.get(dispName);
const b = indexByName.get(fillBelowDispName);
if (isNumber(b) && isNumber(t)) {
builder.addBand({
series: [t, b],
fill: undefined, // using null will have the band use fill options from `t`
});
if (!fillOpacity) {
fillOpacity = 35; // default from flot
}
} else {
fillOpacity = 0;
}
2021-05-05 16:44:31 +08:00
}
}
let dynamicSeriesColor: ((seriesIdx: number) => string | undefined) | undefined = undefined;
if (colorMode.id === FieldColorModeId.Thresholds) {
dynamicSeriesColor = (seriesIdx) => getFieldSeriesColor(alignedFrame.fields[seriesIdx], theme).color;
}
2021-05-05 16:44:31 +08:00
builder.addSeries({
pathBuilder,
pointsBuilder,
2021-05-05 16:44:31 +08:00
scaleKey,
showPoints,
pointsFilter,
2021-05-05 16:44:31 +08:00
colorMode,
fillOpacity,
theme,
dynamicSeriesColor,
2021-05-05 16:44:31 +08:00
drawStyle: customConfig.drawStyle!,
lineColor: customConfig.lineColor ?? seriesColor,
lineWidth: customConfig.lineWidth,
lineInterpolation: customConfig.lineInterpolation,
lineStyle: customConfig.lineStyle,
barAlignment: customConfig.barAlignment,
barWidthFactor: customConfig.barWidthFactor,
barMaxWidth: customConfig.barMaxWidth,
2021-05-05 16:44:31 +08:00
pointSize: customConfig.pointSize,
spanNulls: customConfig.spanNulls || false,
show: !customConfig.hideFrom?.viz,
2021-05-05 16:44:31 +08:00
gradientMode: customConfig.gradientMode,
thresholds: config.thresholds,
hardMin: field.config.min,
hardMax: field.config.max,
softMin: customConfig.axisSoftMin,
softMax: customConfig.axisSoftMax,
2021-05-05 16:44:31 +08:00
// The following properties are not used in the uPlot config, but are utilized as transport for legend config
dataFrameFieldIndex: field.state?.origin,
showValues: customConfig.showValues,
2021-05-05 16:44:31 +08:00
});
// Render thresholds in graph
if (customConfig.thresholdsStyle && config.thresholds) {
const thresholdDisplay = customConfig.thresholdsStyle.mode ?? GraphThresholdsStyleMode.Off;
if (thresholdDisplay !== GraphThresholdsStyleMode.Off) {
2021-05-05 16:44:31 +08:00
builder.addThresholds({
config: customConfig.thresholdsStyle,
thresholds: config.thresholds,
scaleKey,
theme,
hardMin: field.config.min,
hardMax: field.config.max,
softMin: customConfig.axisSoftMin,
softMax: customConfig.axisSoftMax,
2021-05-05 16:44:31 +08:00
});
}
}
}
let stackingGroups = getStackingGroups(frame);
builder.setStackingGroups(stackingGroups);
GraphNG - shared cursor (#33433) * Initial work * WIP add cursor in debug panel * shared cursor.sync filter * explicit uplot events * explicit uplot events * uplot events * uplot events * depend on master uplot * sync sync sync * Fix merge * Get rid of PlotSyncContext and sync tooltip positions * make sync optional * Improve shared tooltip positioning * Plugins: add level and signature badges to plugin details page (#33553) * feat(grafana-ui): badge can accept react node for text, add shield-exclamation to icons * feat(plugins): add PluginSignatureType type * feat(pluginpage): introduce PluginSignatureDetailsBadge. Fix sidebar icon margin * feat(pluginlistpage): update filterinput placeholder, introduce filter by plugin type * Variables: Removes the never refresh option (#33533) * Variables: Removes the never refresh option * Tests: fixes DashboardModel repeat tests * Tests: fixs snapshots * Tests: fixes processVariable test * Tests: fixes DashboardModel tests * PageLayout: Fixes max-width breakpoint so that it triggers only when there is room for margin+ (#33558) * Alerting: Remove datasource (name) from migration (#33544) no longer needed as of https://github.com/grafana/grafana/pull/33416 for https://github.com/grafana/alerting-squad/issues/126 * Library panels: Adds description to library panels tab (#33428) * CodeOwners: Set owners of unified alerting migration (#33571) * ButtonSelect: updates component with the new theme model (#33565) * EmptySearchResult: updates component with the new theme model (#33573) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design (#33575) * DashboardSettings: Slight design tweak to fix page toolbar padding and align design * Fixed font weight * Removed comment * Update * gitignore: Ignore files for accesscontrol provisioning (#33577) * Alerting/metrics (#33547) * moves alerting metrics to their own pkg * adds grafana_alerting_alerts (by state) metric * alerts_received_{total,invalid} * embed alertmanager alerting struct in ng metrics & remove duplicated notification metrics (already embed alertmanager notifier metrics) * use silence metrics from alertmanager lib * fix - manager has metrics * updates ngalert tests * comment lint Signed-off-by: Owen Diehl <ow.diehl@gmail.com> * cleaner prom registry code * removes ngalert global metrics * new registry use in all tests * ngalert metrics impl service, hack testinfra code to prevent duplicate metric registrations * nilmetrics unexported * Add note to Snapshot API doc to specify that user has to provide the entire dashboard model (#33572) * Added note as suggested by Macus E. * Update docs/sources/http_api/snapshot.md Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> * Alerting: backend "ng" code cleanup (#33578) * AlertMigration: remove alert_rule UID db check (#33568) do not believe this is needed due to uniqueness promised by shortid lib since there is no provisioning yet. https://github.com/teris-io/shortid * Live: persisting last message in cache for broadcast scope (#32938) * Alerting: Load annotations from rule into State cache (#33542) for https://github.com/grafana/alerting-squad/issues/127 * add template for dashboard url parameters (#33549) * Update dashboard-links.md parameters with plain text like `var-something=value` can make confusion. template it to clarify . * describe way for template link. * AlertingMigration: Create alert_rule_version entry (#33585) Create the alert rule version entry during the migration so it is consistent with rules created via api. for https://github.com/grafana/alerting-squad/issues/123 * Build: Fix with cleanup call maybe? (#33590) * add selector for code editor (#33554) * broadcast over eventBus * broadcasting to eventbus (but not useing it yet) * merge master * moved to context * fix yarn.lock * update snapshot * Fix direct state mutation * Persist location state on partial updates * GraphNG- use getStream rather than subscribe * Sync LegacyGraphHoverEvent with GraphNG * Chenge plotRef signature * use subscription * subscription * one fewer file * Update types * Remove unnecessary filtering * Disable cursor sync when in edit mode * GraphNG - bring back logging Co-authored-by: Ryan McKinley <ryantxu@gmail.com> Co-authored-by: Leon Sorokin <leeoniya@gmail.com> Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com> Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.org> Co-authored-by: Kyle Brandt <kyle@grafana.com> Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com> Co-authored-by: Uchechukwu Obasi <obasiuche62@gmail.com> Co-authored-by: gamab <gamab@users.noreply.github.com> Co-authored-by: Owen Diehl <ow.diehl@gmail.com> Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com> Co-authored-by: Alexander Emelin <frvzmb@gmail.com> Co-authored-by: Nagle Zhang <nagle.zhang@sap.com> Co-authored-by: Erik Sundell <erik.sundell@grafana.com>
2021-05-10 20:24:23 +08:00
const mightShowValues = frame.fields.some((field, i) => {
if (i === 0) {
return false;
}
const customConfig = field.config.custom ?? {};
return (
customConfig.showValues &&
(customConfig.drawStyle === GraphDrawStyle.Points || customConfig.showPoints !== VisibilityMode.Never)
);
});
if (mightShowValues) {
// since bars style doesnt show points in Auto mode, we can't piggyback on series.points.show()
// so we make a simple density-based callback to use here
const barsShowValues = (u: uPlot) => {
let width = u.bbox.width / uPlot.pxRatio;
let count = u.data[0].length;
// render values when each has at least 30px of width available
return width / count >= 30;
};
builder.addHook('draw', (u: uPlot) => {
const baseFontSize = 12;
const font = `${baseFontSize * uPlot.pxRatio}px ${theme.typography.fontFamily}`;
const { ctx } = u;
ctx.save();
ctx.fillStyle = theme.colors.text.primary;
ctx.font = font;
ctx.textAlign = 'center';
for (let seriesIdx = 1; seriesIdx < u.data.length; seriesIdx++) {
const series = u.series[seriesIdx];
const field = frame.fields[seriesIdx];
if (
field.config.custom?.showValues &&
// @ts-ignore points.show() is always callable on the instance (but may be boolean when passed to uPlot as init option)
(series.points?.show?.(u, seriesIdx) ||
(field.config.custom?.drawStyle === DrawStyle.Bars && barsShowValues(u)))
) {
const xData = u.data[0];
const yData = u.data[seriesIdx];
const yScale = series.scale!;
for (let dataIdx = 0; dataIdx < yData.length; dataIdx++) {
const yVal = yData[dataIdx];
if (yVal != null) {
const text = formattedValueToString(field.display!(yVal));
const isNegative = yVal < 0;
const textOffset = isNegative ? 15 : -5;
ctx.textBaseline = isNegative ? 'top' : 'bottom';
const xVal = xData[dataIdx];
const x = u.valToPos(xVal, 'x', true);
const y = u.valToPos(yVal, yScale, true);
ctx.fillText(text, x, y + textOffset);
}
}
}
}
ctx.restore();
});
}
// hook up custom/composite renderers
renderers?.forEach((r) => {
if (!indexByName) {
indexByName = getNamesToFieldIndex(frame, allFrames);
}
let fieldIndices: Record<string, number> = {};
for (let key in r.fieldMap) {
let dispName = r.fieldMap[key];
fieldIndices[key] = indexByName.get(dispName)!;
}
r.init(builder, fieldIndices);
});
// if hovered value is null, how far we may scan left/right to hover nearest non-null
const DEFAULT_HOVER_NULL_PROXIMITY = 15;
const DEFAULT_FOCUS_PROXIMITY = 30;
let cursor: Partial<uPlot.Cursor> = {
// horizontal proximity / point hover behavior
hover: {
prox: (self, seriesIdx, hoveredIdx) => {
if (hoverProximity != null) {
return hoverProximity;
}
// when hovering null values, scan data left/right up to 15px
const yVal = self.data[seriesIdx][hoveredIdx];
if (yVal === null) {
return DEFAULT_HOVER_NULL_PROXIMITY;
}
// no proximity limit
return null;
},
skip: [null],
},
// vertical proximity / series focus behavior
focus: {
prox: hoverProximity ?? DEFAULT_FOCUS_PROXIMITY,
},
points: { one: true },
};
builder.setCursor(cursor);
2021-05-05 16:44:31 +08:00
return builder;
};
function getNamesToFieldIndex(frame: DataFrame, allFrames: DataFrame[]): Map<string, number> {
const originNames = new Map<string, number>();
frame.fields.forEach((field, i) => {
const origin = field.state?.origin;
if (origin) {
const origField = allFrames[origin.frameIndex]?.fields[origin.fieldIndex];
if (origField) {
originNames.set(getFieldDisplayName(origField, allFrames[origin.frameIndex], allFrames), i);
}
}
});
return originNames;
2021-05-05 16:44:31 +08:00
}
2025-09-25 01:48:22 +08:00
export function calculateAnnotationLaneSizes(
annotationLanes = 0,
annotationConfig?: common.VizAnnotations
): Pick<AxisProps, 'size' | 'gap' | 'ticks'> {
if (annotationConfig?.multiLane && annotationLanes > 1) {
const annotationLanesSize = annotationLanes * ANNOTATION_LANE_SIZE;
// Add an extra lane's worth of height below the annotation lanes in order to show the gridlines through the annotation lanes
const axisSize = annotationLanes > 0 ? annotationLanesSize + UPLOT_DEFAULT_AXIS_GAP : 0;
// Consistent gap between gridlines and x-axis labels
const gap = UPLOT_DEFAULT_AXIS_GAP;
// Axis size is: default size + gap size + annotationLaneSize
const size = annotationLanes > 0 ? UPLOT_DEFAULT_AXIS_SIZE + gap + annotationLanesSize : UPLOT_DEFAULT_AXIS_SIZE;
return {
size,
gap,
ticks: {
size: axisSize,
},
};
}
return {};
2025-09-25 01:48:22 +08:00
}