Skip to content

Commit 998ca8a

Browse files
jordangarsideclaude
andcommitted
[feat] add grafana-react OSS package
__Changes__ - Add grafana-react library with JSX components for Grafana dashboards - Include CLI tool for building, validating, and watching dashboard files - Add comprehensive TypeScript types for Grafana panel configurations - Include Astro-based documentation site with custom styling - Add GitHub workflows for CI, docs deployment, and npm publishing - Add unit tests for renderer, CLI, and utilities - Support per-panel datasource override via datasource prop - Remove hardcoded defaults to let Grafana use native defaults - Add hero images and example dashboard for documentation - Add Grafana schema reference notes __Why__ - Provides declarative JSX syntax for Grafana dashboard creation - Enables component composition and reusable dashboard patterns - Compiles to static JSON with no runtime React dependency - Cleaner output JSON by omitting undefined values Co-Authored-By: Claude <noreply@anthropic.com>
0 parents  commit 998ca8a

File tree

86 files changed

+14916
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+14916
-0
lines changed

.github/workflows/ci.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Checkout
14+
uses: actions/checkout@v4
15+
16+
- name: Setup pnpm
17+
uses: pnpm/action-setup@v4
18+
with:
19+
version: 10
20+
21+
- name: Setup Node.js
22+
uses: actions/setup-node@v4
23+
with:
24+
node-version: 22
25+
cache: pnpm
26+
cache-dependency-path: pnpm-lock.yaml
27+
28+
- name: Install dependencies
29+
run: pnpm install --frozen-lockfile
30+
31+
- name: Lint
32+
run: pnpm lint
33+
34+
- name: Type check
35+
run: pnpm typecheck
36+
37+
- name: Build
38+
run: pnpm build
39+
40+
- name: Test
41+
run: pnpm test

.github/workflows/deploy-docs.yml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
name: Deploy docs to GitHub Pages
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
- 'docs/**'
8+
- '.github/workflows/docs.yml'
9+
workflow_dispatch:
10+
11+
permissions:
12+
contents: read
13+
pages: write
14+
id-token: write
15+
16+
concurrency:
17+
group: pages
18+
cancel-in-progress: false
19+
20+
jobs:
21+
build:
22+
runs-on: ubuntu-latest
23+
steps:
24+
- name: Checkout
25+
uses: actions/checkout@v4
26+
27+
- name: Setup pnpm
28+
uses: pnpm/action-setup@v4
29+
with:
30+
version: 9
31+
32+
- name: Setup Node.js
33+
uses: actions/setup-node@v4
34+
with:
35+
node-version: 22
36+
cache: pnpm
37+
cache-dependency-path: docs/pnpm-lock.yaml
38+
39+
- name: Install dependencies
40+
working-directory: docs
41+
run: pnpm install --frozen-lockfile
42+
43+
- name: Build docs
44+
working-directory: docs
45+
run: pnpm build
46+
47+
- name: Upload artifact
48+
uses: actions/upload-pages-artifact@v3
49+
with:
50+
path: docs/dist
51+
52+
deploy:
53+
needs: build
54+
runs-on: ubuntu-latest
55+
environment:
56+
name: github-pages
57+
url: ${{ steps.deployment.outputs.page_url }}
58+
steps:
59+
- name: Deploy to GitHub Pages
60+
id: deployment
61+
uses: actions/deploy-pages@v4

.github/workflows/npm-publish.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Publish to npm
2+
3+
on:
4+
release:
5+
types: [published]
6+
7+
jobs:
8+
publish:
9+
runs-on: ubuntu-latest
10+
permissions:
11+
contents: read
12+
id-token: write
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v4
16+
17+
- name: Setup Node.js
18+
uses: actions/setup-node@v4
19+
with:
20+
node-version: '22'
21+
registry-url: 'https://registry.npmjs.org'
22+
23+
- name: Setup pnpm
24+
uses: pnpm/action-setup@v4
25+
with:
26+
version: 9
27+
28+
- name: Install dependencies
29+
run: pnpm install --frozen-lockfile
30+
31+
- name: Build
32+
run: pnpm run build
33+
34+
- name: Publish
35+
run: npm publish --provenance --access public

.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Build outputs
2+
build/
3+
docs/dist/
4+
5+
# Dependencies
6+
node_modules/
7+
8+
# Astro
9+
docs/.astro/
10+
11+
# Generated docs (from source JSDoc)
12+
docs/src/content/docs/components/_generated/

.prettierignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Prettier respects .gitignore by default
2+
# This file only needs entries for things to ignore from prettier but keep in git
3+
4+
# Lock files (committed for CI, but don't format)
5+
pnpm-lock.yaml

.prettierrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"singleQuote": true,
3+
"trailingComma": "all"
4+
}

CHANGELOG.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [Unreleased]
9+
10+
## [0.0.1] - 2026-01-09
11+
12+
### Added
13+
14+
- Initial release
15+
- Core components: `Dashboard`, `Row`, `Variable`, `Annotation`, `Link`, `Query`, `Override`
16+
- Panel components:
17+
- Core: `Stat`, `Timeseries`, `Table`, `BarGauge`, `Heatmap`, `Gauge`, `Text`
18+
- Charts: `BarChart`, `PieChart`, `Histogram`, `StateTimeline`, `StatusHistory`, `Candlestick`, `Trend`, `XYChart`
19+
- Data display: `Logs`, `Datagrid`
20+
- Specialized: `NodeGraph`, `Traces`, `FlameGraph`, `Canvas`, `Geomap`
21+
- Widgets: `DashboardList`, `AlertList`, `AnnotationsList`, `News`
22+
- Plugins: `PluginPanel`, `BusinessVariablePanel`
23+
- CLI with `build`, `build-all`, `validate`, and `watch` commands
24+
- `render()` and `renderToString()` functions for programmatic use
25+
- Full TypeScript support with comprehensive type exports
26+
- Automatic panel positioning with row wrapping
27+
- Threshold normalization (object syntax: `{ 70: 'yellow', 90: 'red' }`)
28+
- Legend configuration (string shorthand or object)
29+
- Tooltip configuration
30+
- Row padding support
31+
32+
[Unreleased]: https://github.com/kiwi-research/grafana-react/compare/v0.0.1...HEAD
33+
[0.0.1]: https://github.com/kiwi-research/grafana-react/releases/tag/v0.0.1

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Kiwi Research
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# grafana-react
2+
3+
React-based DSL for creating Grafana dashboards. Write dashboards as JSX components and compile them to Grafana JSON.
4+
5+
<p align="center">
6+
<img src="docs/public/img/hero-code.svg" alt="JSX code for Stat panel" height="180" />
7+
&nbsp;&nbsp;&nbsp;
8+
<img src="docs/public/img/hero-grafana-stat-panel.png" alt="Rendered Grafana Stat panel" height="140" />
9+
</p>
10+
11+
## Features
12+
13+
- **Declarative JSX Syntax** - Write dashboards using familiar React patterns
14+
- **Component Composition** - Create reusable dashboard components
15+
- **Type Safety** - Full TypeScript support with comprehensive types
16+
- **CLI Tool** - Build, validate, and watch dashboard files
17+
- **Zero Runtime** - Compiles to static JSON, no React in production
18+
19+
## Installation
20+
21+
```bash
22+
npm install grafana-react react
23+
```
24+
25+
## Quick Start
26+
27+
```tsx
28+
import { Dashboard, Row, Stat, Timeseries, Variable } from 'grafana-react';
29+
30+
export default function MyDashboard() {
31+
return (
32+
<Dashboard uid="my-dashboard" title="My Dashboard" datasource="prometheus">
33+
<Variable name="instance">label_values(up, instance)</Variable>
34+
35+
<Row title="Summary">
36+
<Stat
37+
title="CPU %"
38+
unit="percent"
39+
thresholds={{ 70: 'yellow', 90: 'red' }}
40+
>
41+
100 - avg(rate(cpu_idle[$__rate_interval])) * 100
42+
</Stat>
43+
</Row>
44+
45+
<Row title="Details">
46+
<Timeseries title="CPU Over Time" unit="percent" stack legend="right">
47+
sum(rate(node_cpu_seconds_total[5m])) by (mode) * 100
48+
</Timeseries>
49+
</Row>
50+
</Dashboard>
51+
);
52+
}
53+
```
54+
55+
Build to JSON using the CLI:
56+
57+
```bash
58+
grafana-react build my-dashboard.tsx output/my-dashboard.json
59+
```
60+
61+
Or programmatically with `renderToString`:
62+
63+
```ts
64+
import React from 'react';
65+
import { renderToString } from 'grafana-react';
66+
67+
// Use the JSON string directly, e.g. add as a ConfigMap with Pulumi
68+
const json = renderToString(React.createElement(MyDashboard));
69+
```
70+
71+
## Documentation
72+
73+
Full documentation is available at: **[kiwi-research.github.io/grafana-react](https://kiwi-research.github.io/grafana-react)**
74+
75+
- [Getting Started](https://kiwi-research.github.io/grafana-react/getting-started/installation/)
76+
- [Components Reference](https://kiwi-research.github.io/grafana-react/components/structure/)
77+
- [CLI Usage](https://kiwi-research.github.io/grafana-react/guides/cli-usage/)
78+
- [Reusable Components](https://kiwi-research.github.io/grafana-react/guides/reusable-components/)
79+
80+
## CLI Commands
81+
82+
```bash
83+
grafana-react build <input.tsx> [output.json] # Build single dashboard
84+
grafana-react build-all <dir> [output-dir] # Build all dashboards
85+
grafana-react validate <input.tsx> # Validate without output
86+
grafana-react watch <dir> [output-dir] # Watch and rebuild
87+
```
88+
89+
## License
90+
91+
MIT

docs/astro.config.mjs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { defineConfig } from 'astro/config';
2+
import starlight from '@astrojs/starlight';
3+
4+
export default defineConfig({
5+
site: 'https://kiwi-research.github.io',
6+
base: '/grafana-react',
7+
integrations: [
8+
starlight({
9+
title: 'grafana-react',
10+
customCss: ['./src/styles/custom.css'],
11+
description: 'React DSL for Grafana dashboards',
12+
social: [
13+
{
14+
icon: 'github',
15+
label: 'GitHub',
16+
href: 'https://github.com/kiwi-research/grafana-react',
17+
},
18+
],
19+
editLink: {
20+
baseUrl:
21+
'https://github.com/kiwi-research/grafana-react/edit/main/docs/',
22+
},
23+
sidebar: [
24+
{
25+
label: 'Getting Started',
26+
autogenerate: { directory: 'getting-started' },
27+
},
28+
{
29+
label: 'Guides',
30+
autogenerate: { directory: 'guides' },
31+
},
32+
{
33+
label: 'Components',
34+
items: [
35+
{
36+
label: 'Structure',
37+
autogenerate: { directory: 'components/_generated/structure' },
38+
},
39+
{
40+
label: 'Query',
41+
autogenerate: { directory: 'components/_generated/query' },
42+
},
43+
{
44+
label: 'Panels',
45+
autogenerate: { directory: 'components/_generated/panels' },
46+
},
47+
],
48+
},
49+
{
50+
label: 'API Reference',
51+
autogenerate: { directory: 'api' },
52+
},
53+
],
54+
}),
55+
],
56+
});

0 commit comments

Comments
 (0)