Change Log
All changes noted here.
v2.2.0 (2026-04-21)
Bug Fixes (Rendering and Migration)
- Fix
for...initerating array indices instead of values inrenderMajorTickLabels, causing incorrectmaxLabelLengthcalculation for font scaling - Fix falsy-zero bug where
displayValueof0skipped threshold coloring inrenderCircleGroup,valueColor, andtitleColor(use strict!== nullcheck matching thenumber | nulltype) - Add React
keyprops to threshold band elements to fix missing key warnings and prevent incorrect reconciliation - Fix
migrateTickMapsmissingenabledfield in return value - Fix marker shape migration assigning
MarkerTypeobject tostringfield (now correctly extracts.name) - Fix browser hang when gauge max value is very large (e.g., 6 billion) by lowering tick cap from 500 to 100, adding an iteration guard to prevent runaway loops, and auto-calculating tick spacing when the user changes min/max values (fixes #63)
- Fix threshold band angular misalignment with gauge ticks when using
non-default
zeroTickAngle/maxTickAnglevalues; thedrawBandrotation is now computed as2 * zeroTickAngle + 180instead of being hardcoded tomaxTickAngle(fixes #109) - Fix Needle Length Stem ignoring decimal values by changing
integer: truetointeger: false(fixes #110)
Type Safety
- Replace
anytype ondToRparameter withnumber - Replace
anytypes onpanelHeight/panelWidthwithnumber - Add
AngularPanelPropertiesinterface andAngularPaneltype for migration code, eliminating all 38@ts-ignoresuppressions - Add
AngularFieldConfiginterface for angular fieldConfig migration - Type
migrateValueAndRangeMapsparameter (wasany) - Replace
return {} as anywithreturn {}inPanelMigrationHandler
Code Quality
- Remove all
eslint-disablecomments fromsrc/by inlininggetValuesintouseMemoand narrowing dependency arrays - Increase tick label gap from 1.0x to 1.3x font size for better spacing with unit-formatted labels
Cleanup
- Remove unused
GaugeModelinterface - Remove commented-out
MarkerStartShapes/MarkerEndShapesarrays - Remove unused
GaugePresetOptionsimports and commented-out preset block - Remove unused
PanelChangedHandlerexport - Remove unused
Reactimport inneedle_utils.tsx - Remove unexposed
needleLengthNegCalcfromuseGaugeDimensionsreturn
Testing
- Add 34 migration tests covering
convertOperators,migrateTickMaps,migrateFieldConfig,migrateValueAndRangeMaps,migrateDefaults, and fullPanelMigrationHandlerintegration (threshold migration with custom/default colors, format migration, angular property cleanup) - Migration tests: 4 → 38, total suite: 200 → 234
Build & Config
- Update
.config/scaffolding from latest@grafana/create-plugin - Move shared bundler utilities (
constants.ts,utils.ts) to.config/bundler/ - Centralize webpack copy patterns into
.config/bundler/copyFiles.ts - Add
react/jsx-runtimeandreact/jsx-dev-runtimeto externals for React 19 compatibility - Add
eslint.config.mjsscaffolding header and update README with flat config example - Add
mise.tomlfor Node.js version pinning (24.14.1) - Add AGENTS instructions, e2e testing guide, and build/validate skills
- Change
grafanaDependencyto>=10.0.0with no upper limit
CI
- Replace reusable
grafana/plugin-ci-workflows@v7with inline workflow (build, lint, typecheck, unit tests, Playwright e2e with Grafana version matrix) - Enable Playwright report artifact uploading
- Bump
grafana/plugin-actions/build-pluginv1.0.2 → v1.2.0 - Bump
grafana/plugin-actions/e2e-versionv1.1.2 → v1.2.1 - Bump
magefile/mage-actionv3.1.0 → v4.0.0 - Bump
actions/upload-artifactv6 → v7,actions/download-artifactv7 → v8 - Bump
actions/github-scriptv8.0.0 → v9.0.0 - Bump
tj-actions/changed-filesv47 → v47.0.6 inpr-files.yml - Include
grafana-devimage in the e2e version matrix (skip-grafana-dev-image: falseinci.yml) - Remove
masterbranch references, pin actions to version tags - Clean up scaffolding comments in release.yml
- Replace Dependabot with Renovate: add
renovate.jsonwith weekly Monday schedule, grouped non-major dev/prod bumps, vulnerability alerts,lockFileMaintenance, a rule blocking@grafana/**@13.x(pendinggrafanaDependencyupper-bound bump), and a rule pinning@types/nodebelow v25 to matchengines.node >= 24 - Remove
.github/dependabot.yml(superseded by Renovate) - Add
.github/workflows/lint-actions.yml— runsactionlintandzizmoron PRs and pushes tomainthat touch.github/workflows/** - Grant
security-events: writeandactions: readto thezizmorjob inlint-actions.ymlsozizmorcore/zizmor-actioncan upload its SARIF report viagithub/codeql-action/upload-sarif(previously failed onmainwith "Resource not accessible by integration") - Fix actionlint findings surfaced by the new workflow:
- Quote
$GITHUB_OUTPUT,$PWD, and metadata vars inci.yml(SC2086); drop uselesscatand consolidate>>redirects in theGet plugin metadatastep (SC2002, SC2129, SC2155) - Quote
$GITHUB_OUTPUTinis-compatible.ymland collapse the folded-scalarrun:into a plain block - Replace
ubuntu-x64-smallrunner label withubuntu-latestinversion-bump-changelog.yml(scaffolding leftover; this repo is not on Grafana Labs self-hosted runners)
- Quote
- Pin all third-party GitHub Actions to full-length commit SHAs with a
trailing version comment (required by
zizmor). Covers everyuses:acrossci.yml,bundle-stats.yml,coverage.yml,cp-update.yml,is-compatible.yml,pr-files.yml,release-please.yml,release.yml, andversion-bump-changelog.yml
Docs
- Update
AGENTS.mdAction Pinning rule: require full-length commit SHAs with a trailing version comment (was: version tags). Reflects thezizmor-enforced policy. - Restructure
AGENTS.mdaround the TheRealSeanDonahoe/agents-md template. Sections 0–9 (non-negotiables, simplicity, surgical changes, goal-driven execution, tool use, session hygiene, communication style, ask-vs-proceed, self-improvement) and sections 11–12 follow upstream; all prior project-specific content (stack, commands, layout, conventions, forbidden) now lives under Section 10. Every line now wraps at 120 chars, so the repo's.markdownlint.yamlrule applies cleanly (no per-fileMD013disable needed). cspell.config.json: add proper names and tool names referenced in the new template (Andrej,Cherny,Donahoe,IJFW,Karpathy,cking,importme,negotiables,zizmor).- Add an E2E targeting subsection to
AGENTS.md§10 Testing:- Ours →
data-testid. - Grafana option builder ≥ 11.0.0 →
selectors.components.PanelEditor.OptionsPane.fieldInput(<label>)via@grafana/plugin-e2e. - Grafana option builder ≥ 12.0.0 → also
label[for="<plugin-id>-<option-path>"]with.first(). Do not use this below Grafana 12 — confirmed failing on 10.0.13 / 10.2.9 / 11.1.13 / 11.5.10 in PR #173 CI. - Always gate edit-mode interaction tests on a
grafanaVersionfloor viatest.skipin a describe-levelbeforeEach— panel-editor chrome diverges across majors. This repo's current floor is 12.0.0. - Always verify on the matrix floor (not just
pnpm server's default image) before declaring a locator stable.
- Ours →
New Features
- Add
computeTickSpacingutility that calculates human-friendly ("nice number") tick intervals for any value range - Auto-fill tick spacing when min/max values change in the panel editor, only when the new range would exceed the 100-tick limit (preserves user-configured spacing otherwise)
- Show warning icon with tooltip when tick count is clamped, including suggested spacing values
- Use
@grafana/uiInputcomponent inRangeEditorfor theme consistency - Sync
RangeEditorlocal state when external value prop changes (undo/reset) - Add "Show Value on Gauge" toggle to hide/show the numeric value display (fixes #101)
- Add "Show Tick Labels" toggle to hide/show the tick mark labels (fixes #101)
- Add "Wrap Values to Range" option under Limits for compass-style gauges; normalizes out-of-range values using modulo arithmetic (e.g., -90 becomes 270 for a 0-360 range) (related to #13)
- Remove hardcoded decimals default of 2; now uses Grafana's auto
- Add provisioned compass dashboard for testing
- Add "Format Tick Labels with Unit" option under Gauge Readings; formats tick labels using the configured unit and decimals (e.g., 100000000 displays as "100 MB/s") (related to #57)
Panel Editor UX
- Rename "Show title" to "Show Display Name on Gauge" and move above Stat in Standard options
- Rename "Title Font/Size" to "Display Name Font/Size"
- Rename "Title Y-Offset" to "Display Name Y-Offset (Vertical)"
- Rename "Value Y-Offset" to "Value Y-Offset (Vertical)"
- Reorder font settings: Display Name, Value, Tick Label
- Add inline description to Tick Maps editor section
- Fix
needleCrossLimitDegreesdefault (10 → 5) to match description - Increase vertical spacing between display name and value labels
Testing Infrastructure
- Suppress jsdom SVG tag warnings (
<path>,<marker>,<defs>) in test output viajest-setup.jsconsole filter - Suppress i18next promotional banner in test output
E2E Fixes
- Rewrite
tests/grafana-version.spec.tsto read the Grafana version from thegrafanaVersionfixture in@grafana/plugin-e2e(which readswindow.grafanaBootData.settings.buildInfo.version) instead of clicking the Help toolbar button. Avoids the Grafana 13.x / React 19 preview portal overlay that intercepted the click and timed out the test (fixes #164). - Add plugin-level smoke test
tests/gauge-smoke.spec.tsplus a provisioned dashboardprovisioning/dashboards/dashboards/D3Gauge-Smoke.json. The test navigates to the provisionedSmoke Gaugepanel (uidbriangann-gauge-smoke), waits for the gauge SVG to become visible, and asserts the render output (multiple<path>elements and at least one<text>label). The panel is located viagetPanelById(1)and the gauge SVG is disambiguated from the panel-header icon by itsviewBox="0,0,…"attribute. - Add panel-level interaction test
tests/gauge-interactions.spec.tscovering three edit-mode flows:Show Value on Gaugetoggle — text-element count drops when the value label is hidden and returns when toggled back on.Show Threshold Band On Gaugetoggle — path-element count drops when the three bands are hidden and returns when toggled back on.- Tick maps — clicking
Add Tick Map, entering value50+ textHALF, and asserting the gauge renders a<text>withHALFin place of the50tick label. Tests skip on Grafana<12.0.0— the panel-editor chrome (options group aria-labels, option-idlabel[for]attributes) only stabilizes around Grafana 12. Thegauge-smoke.spec.tsrender check keeps coverage for 10.x / 11.x.
Testing (interaction coverage)
- Add
data-testid="tickmap-add-button"on theAdd Tick Mapbutton inTickMapEditoranddata-testid="tickmap-value-input-<order>"/data-testid="tickmap-text-input-<order>"on the Value and Text inputs inTickMapItem, so the tick-maps interaction test can target them without relying on Grafana-generated class names.
E2E Testing
- Add Playwright config with
@grafana/plugin-e2eauth and Chromium project - Add
tests/grafana-version.spec.tssmoke test - Replace Cypress e2e scripts with
playwright test - Add
@playwright/testand@grafana/plugin-e2edev dependencies
Docker & Provisioning
- Rewrite
docker-compose.yamlwith healthcheck, port mapping, volume mounts - Add provisioning dashboards, datasource, and provider configs
Plugin Compatibility
- Bump
grafanaDependencyfrom>=9.3.16to>=10 <=13.0 - Remove deprecated
grafanaVersionfield
Dependencies
@testing-library/react14.0.0 → 15.0.7 (fixesReactDOMTestUtils.actwarnings)@grafana/eslint-config8.2.0 → 9.0.0@stylistic/eslint-plugin-ts2.13.0 → 4.4.1@types/node20.19.37 → 24.x (pinned to matchengines.node >= 24; do not drift to 25 while the engine floor is 24)cspell7.3.8 → 10.0.0eslint-config-prettier8.10.2 → 10.1.8eslint-plugin-jsdoc51.4.1 → 62.9.0eslint-plugin-react-hooks5.2.0 → 7.0.1 (held at 7.0.1 via~range; 7.1.x addsreact-hooks/immutabilityrule that requires code changes inGaugePanel.tsx, tracked separately)glob10.5.0 → 13.0.6@grafana/plugin-e2e3.4.12 → 3.5.1@swc/core1.15.24 → 1.15.30@typescript-eslint/eslint-plugin8.58.1 → 8.59.0@typescript-eslint/parser8.58.1 → 8.59.0webpack5.106.0 → 5.106.2uuid13.0.0 → 14.0.0 (drops Node 18 support, expects globalcrypto; safe underengines.node >= 24)- Remove deprecated
@types/glob(glob 13 ships own types)
Refactor
- Replace needle
useRefwithuseId()+ DOM id lookup (fixesreact-hooks/refslint error fromeslint-plugin-react-hooks@7, gives each gauge instance a unique needle id for multi-panel dashboards)
v2.0.4 (unreleased)
Bug Fixes
- Fixed needle animation jumping instead of smoothly transitioning between values
- Replaced two-effect state-based animation with single-effect ref-based pattern
- Clamped values now animate to the limit instead of snapping instantly
- Needle stays buried when consecutive values exceed limits, animates back when value returns in range
- Removed deprecated
collapsibleandheadingprops from TickMaps editor - Fixed
getNeedleAngleMaximumto usemaxNeedleAngleinstead ofmaxTickAnglefor non-buried needle clamping - Fixed
renderThresholdBandscrash when thresholds are undefined - Fixed browser hard-lock when using fractional or zero tick spacing values (#114)
- Added safety cap of 500 maximum ticks to prevent runaway computation
- Fixed floating-point comparison for minor/major tick overlap detection
Performance
- Share a single memoized
valueScale(d3scaleLinear) across hooks instead of creating three independent instances - Reuse d3
line()generator instead of recreating per tick - Pre-compute tick path strings in
useTickComputations(skip recomputation on value-only updates) - Memoize metrics computation, SVG dimensions, and font size calculations in GaugePanel
- Memoize all SVG creation functions (circles, ticks, labels, needle, thresholds) in Gauge
- Add stable React keys for tick mark elements
- Narrow
useEffectdependency arrays to prevent unnecessary re-renders - Memoize
createNeedleMarkersin Gauge to avoid recreating SVG defs on every render - Memoize
gaugeRadiusCalcand inline dimension styles in GaugePanel
Features
- Allow fractional tick spacing (e.g., 0.1 Hz) in panel editor for minor and major ticks (#114)
Refactoring
- Extract render functions to
gauge_render.tsx, styles togauge_styles.ts - Extract custom hooks:
useNeedleAnimation,useTickComputations,useGaugeDimensions - Remove all
eslint-disable react-hooks/exhaustive-depscomments from Gauge component - Simplify GaugePanel: remove dead code, use prop spread, extract styles
- Organize Gauge files into dedicated
src/components/Gauge/folder - Remove unused
marginstate variable - Consolidate
useGaugeDimensionsfrom useState+useEffect to single useMemo - Type all
TickMapItemPropscallbacks (removeanytypes) and remove unusedenabled/contextprops - Rewrite
TickMapItemas a controlled component (remove duplicate local state) - Consolidate
TickMapEditorstate: merge parallelisOpenarray intoTickMapItemTracker - Replace in-place
arrayMovemutation with immutableswapItems/reorderhelpers - Wrap all
TickMapEditorcallbacks inuseCallback
Tests
- Added unit tests for
utils.tsx,gauge_render.tsx,useGaugeDimensions,useNeedleAnimation,useTickComputations,GaugePanel,Gauge,TickMapItem, andTickMapEditor - Restructured
renderThresholdBandstests with nested describes for early returns, 2-step, 3+ step, and Infinity threshold scenarios - Added edge case tests for
needle_utilscross-limit clamping branches - 181 tests across 12 suites
v2.0.3 - 2026-04-01
- Updated pnpm/action-setup from v4 to v5
- Updated magefile/mage-action from v3.1.0 to v4.0.0
- Aligned release workflow Node version to 24
- Changed release workflow Go version to use go.mod instead of hardcoded v1.21
- Upgraded @grafana/data, i18n, runtime, schema, ui from 12.4.1 to 12.4.2
- Upgraded minor/patch dependencies (@babel/core, @swc/core, @swc/helpers, @swc/jest, swc-loader, @types/lodash, @typescript-eslint/eslint-plugin, @typescript-eslint/parser, css-loader, eslint-config-prettier, eslint-webpack-plugin, glob, semver, terser-webpack-plugin, webpack)
- Upgraded sass from 1.63.2 to 1.98.0
- Upgraded sass-loader from 13.3.1 to 13.3.3
- Upgraded typescript from 5.5.4 to 5.9.3
- Upgraded uuid from 9.x to 13.0.0, removed @types/uuid (types now bundled)
v2.0.2 - 2026-03-16
- Removed suggestions supplier
- Upgraded GitHub Actions to latest versions across all workflows
- Renamed CLAUDE.md to AGENTS.md
- Upgraded minor/patch dependencies (@emotion/css, tslib, d3, @testing-library/jest-dom, @types/d3-scale, @grafana packages)
v2.0.1 - 2023-11-13
- Fix font sizing during migrations
- Autoscales font according to gauge size
v2.0.0 - 2023-10-20
- Rewritten from Angular to React
- NEW: Needle Width can now be specified
- NEW: Thresholds now use the standard Grafana threshold mechanics
- NEW: Needle can optionally exceed the tick mark (min and max) to show values that are outside of limits
- NEW: Needle Center can use all marker types, with arrow-inverse added to options
- Switched to
pnpm
v0.0.9 - 2021-04-21
- Add option to display needle arrow
- Update packages
v0.0.8 - 2020-10-26
- Signed Plugin!
- Updated build process
v0.0.7 - 2020-04-18
- Fixes
- Update to typescript and using standardized build process.
- Simplified value display
v0.0.1
- Initial commit