plugin-ui
Shared React components and utilities for building Grafana data source and app plugins.
Repository Health
Technical Analysis
@grafana/plugin-ui is Grafana Labs’ shared component library for plugin authors, providing the config editors, query editors, SQL editor, data source picker, and secret-scanning utilities that Grafana’s own core data source plugins are built from. Rather than reimplementing connection settings, auth toggles, or a SQL query builder for every plugin, authors import these pieces directly and get consistent behavior and styling that matches Grafana’s own UI.
Beyond visual components, the package ships an async-query-data layer for backends that stream results progressively, an abstract SqlDatasource base class wiring RxJS-based backend requests into Grafana’s query pipeline, and a Monaco-integrated secret scanner that detects credentials typed into query/config editors and offers to migrate them into Grafana’s secure secrets store.
What You Get
- ConfigEditor building blocks — Auth, Connection, AdvancedSettings, and DatasourceConfigWizard components for a plugin’s data source settings page
- QueryEditor scaffolding — EditorRow/EditorField/EditorList primitives plus a full raw/visual SQL query editor pair
- A dedicated SQLEditor package with Monaco-based syntax highlighting, autocomplete, and a standard-SQL dialect layer
- An abstract SqlDatasource class and async-query-data hooks (request looper, run-query buttons) for backends returning results progressively
- A Monaco- and React-integrated secret scanner (rules derived from Gitleaks) that flags hardcoded credentials and offers one-click migration to Grafana secrets
Common Use Cases
- A new SQL-based data source plugin reuses SQLEditor and SqlDatasource instead of writing a query editor and backend wiring from scratch
- A plugin author builds a settings page with Connection/Auth/AdvancedSettings sections that match Grafana’s other core data sources
- A plugin adds secret detection to its config or query editor so users don’t accidentally commit API keys into dashboard JSON
- A backend plugin with long-running queries wires up the async-query-data request looper to stream partial results into the query editor
Under The Hood
Architecture The package is organized as a flat feature-oriented module tree under src/ — components/, async-query-data/, datasource/, schema/, secret-scanner/, hooks/ — each exported through barrel index.ts files and re-exported from a single top-level src/index.ts, with secret-scanner further split into rules/core/react/monaco/panel layers that isolate detection logic (scanCode/scanText) from its Monaco and React bindings so it can run outside a browser. The abstract SqlDatasource in datasource/SqlDatasource.ts is the load-bearing abstraction: it wires RxJS-based backend fetches, Grafana’s TemplateSrv, and an injected getDB() into DataSourceWithBackend, and every SQL-plugin-facing component (QueryEditor, SQLEditor, VisualQueryBuilder) depends on the DB/SqlQueryModel interfaces it defines, so changing that contract ripples through the whole SQL-editing surface. Separation of concerns is otherwise solid — presentational editor components are decoupled from query-building logic — though the components directory is large and flat with some cross-imports between QueryEditor and ConfigEditor utilities.
Tech Stack TypeScript targeting es2022, built as dual ESM/CJS output via tsc plus Rollup (rollup-plugin-esbuild, rollup-plugin-dts, rollup-plugin-node-externals) with react and react-dom deliberately pinned to peerDependencies — documented at length in the README — to avoid a duplicate-React-instance bug in host Grafana plugins. It targets the React 18/19 peer range, styles with @emotion/css, highlights SQL via Monaco (optional peer) and prismjs, formats SQL via sql-formatter, handles drag-and-drop via @hello-pangea/dnd, and parses expressions with acorn/acorn-typescript and a CEL-adjacent helper. Storybook is configured but the README calls it “pretty broken” since most components depend on Grafana runtime globals unavailable in isolation. Jest with @swc/jest runs tests, ESLint extends @grafana/eslint-config, and Yarn Berry manages the workspace with lefthook for git hooks.
Code Quality Dozens of test files sit alongside their source (query editor components, the datasource-with-async-backend layer, secret-scanner detection logic), run via jest —ci with jest-environment-jsdom and @testing-library/react, giving reasonable coverage of both UI components and pure logic. Error handling favors optional chaining and typed guards over thrown exceptions in UI code, while backend calls in SqlDatasource go through RxJS’s catchError. Naming is consistent PascalCase-components / camelCase-utilities, types are used extensively with verbatimModuleSyntax and consistent-type-imports enforced by ESLint, and CI runs lint, typecheck, spellcheck, and tests on every push.
API Design The public API is intentionally narrow: a single barrel export re-exports components, async-query-data, SqlDatasource, and schema, plus two deep-import subpaths (test utilities and the secret scanner) kept separate so consumers don’t pay for Monaco/secret-scanner code they don’t need. Component props are typed and exported alongside each component, and the secret-scanner docs show complete “with Monaco” and “without an editor” usage pairs, lowering the boilerplate needed to adopt just one piece. The tradeoff is that most components assume a Grafana runtime host is present, so the API is ergonomic for its target audience — Grafana plugin authors — but not usable standalone outside that runtime, an intentional and well-documented scope rather than an accidental limitation.