@forge-glance/react
React component library for Forge Glance — pre-themed MR dashboards, CI badges, and base primitives powered by the GDS design system.
Install
npm install @forge-glance/react @forge-glance/sdk
bun add @forge-glance/react @forge-glance/sdk
Quick Start
import '@forge-glance/react/styles.css';
import { MRCard, Button, Badge } from '@forge-glance/react';
The CSS import brings in all tokens, utilities, and component styles — no Tailwind required on your end.
Dashboard Integration
The dashboard API provides real-time MR data and pre-bound mutation actions. There are three integration patterns depending on your architecture:
1. React Hook — useDashboard
The simplest approach for standard React apps. Handles the subscription lifecycle and state internally.
import '@forge-glance/react/styles.css';
import { useDashboard, MRCard, MRRow } from '@forge-glance/react';
function MergeRequestDashboard({ provider, projectPath, mrIid, userId }) {
const { mr, actions, status } = useDashboard({
provider, projectPath, mrIid, userId
});
if (status === 'connecting' || !mr) return <p>Loading…</p>;
return <MRCard mr={mr} actions={actions} />;
}
useDashboard returns:
mr | MRDashboardProps | null | Render-ready props. null until first update. |
actions | MRDashboardActions | Pre-bound mutations (merge, rebase, approve, etc.) |
status | 'connecting' | 'watching' | Subscription state |
2. SDK + State Manager (Zustand, Redux, etc.)
Use createDashboard from the SDK directly when you manage state outside React (e.g., Zustand stores).
import { createDashboard } from '@forge-glance/sdk';
import { create } from 'zustand';
import type { MRDashboardProps, MRDashboardActions } from '@forge-glance/sdk';
const useMRStore = create<{
mr: MRDashboardProps | null;
actions: MRDashboardActions | null;
}>(() => ({
mr: null,
actions: null,
}));
const { actions, subscribe, dispose } = createDashboard({
provider, projectPath: 'group/project', mrIid: 42, userId
});
useMRStore.setState({ actions });
subscribe((mr) => useMRStore.setState({ mr }));
dispose();
Then in your React component:
import '@forge-glance/react/styles.css';
import { MRCard } from '@forge-glance/react';
function Dashboard() {
const mr = useMRStore((s) => s.mr);
const actions = useMRStore((s) => s.actions);
if (!mr) return <p>Loading…</p>;
return <MRCard mr={mr} actions={actions} />;
}
3. Read-Only (no actions)
For displaying MR data without mutation buttons, simply omit the actions prop:
import { useDashboard, MRCard } from '@forge-glance/react';
function ReadOnlyCard({ provider, projectPath, mrIid, userId }) {
const { mr } = useDashboard({ provider, projectPath, mrIid, userId });
if (!mr) return <p>Loading…</p>;
return <MRCard mr={mr} />;
}
4. Multi-MR Dashboard (shared WebSocket)
Watch multiple MRs over a single connection:
import { createDashboard } from '@forge-glance/sdk';
import { MRRow } from '@forge-glance/react';
const { actionsFor, subscribe, dispose } = createDashboard({
provider, projectPath: 'group/project',
mrIid: [42, 43, 44, 45],
userId
});
subscribe((mrs) => {
for (const [iid, mr] of mrs) {
renderRow(mr, actionsFor(iid));
}
});
createDashboard Return Shape
const { actions, subscribe, dispose } = createDashboard(provider, path, iid, userId);
actions | MRDashboardActions | Pre-bound mutations — available immediately |
subscribe(cb) | (listener: (mr: MRDashboardProps) => void) => void | Register a listener for real-time MR updates |
dispose() | () => void | Stop the subscription and clean up |
MRDashboardActions
Actions are pre-bound to the specific MR — no need to pass project path or IID:
merge(input?) | Merge the MR (optional merge options) |
rebase() | Rebase onto target branch |
approve() | Approve the MR |
unapprove() | Remove your approval |
setAutoMerge() | Enable auto-merge when pipeline passes |
cancelAutoMerge() | Cancel auto-merge |
retryPipeline(id) | Retry a specific pipeline |
requestReReview(usernames?) | Request re-review |
can | Provider capability flags |
Components
Forge Components
Built for GitLab/GitHub merge request dashboards. Feed them MRDashboardProps from @forge-glance/sdk.
MRCard | Full MR card — status, pipeline, reviewers, merge/rebase actions, forge icon link |
MRRow | Compact MR row for list views |
MRRowList | Renders a list of MRRow items |
MRStatusBadge | Status badge — mergeable, blocked, draft, merged, closed |
PipelineBadge | CI pipeline badge — passing, failing, running, warnings |
ReviewerList | Reviewer avatars with approval state badges |
ReviewerRow | Single reviewer row (used by ReviewerList) |
Both MRCard and MRRow accept an optional actions prop. When provided, the SDK actions
take precedence over individual onMerge/onRebase callbacks (which still work for backward compatibility).
Brand Icons
import { GitLabIcon, GitHubIcon, IconButton } from '@forge-glance/react';
<IconButton variant="ghost" aria-label="Open in GitLab">
<GitLabIcon className="size-4" />
</IconButton>
GitLabIcon | GitLab tanuki logo (official brand colors) |
GitHubIcon | GitHub octocat logo (uses currentColor) |
IconButton | Square icon-only button wrapper — supports all Button variants and colors |
Base Primitives
Themed variants of common UI elements. Built on Radix UI + CVA.
Button | filled outline subtle ghost link | emphasis action positive negative caution merge neutral |
IconButton | filled outline subtle ghost | emphasis action positive negative caution merge neutral |
Badge | filled outline subtle | emphasis action positive negative caution merge neutral |
Switch | — | — |
Tooltip | — | — |
Theming
Light / Dark Mode
Toggle by adding .dark to your <html> element:
document.documentElement.classList.toggle('dark');
Using Tokens in Your Own Tailwind Setup
If you want to use the GDS tokens as Tailwind utilities in your own code, import tokens.css instead of styles.css:
@import 'tailwindcss';
@import '@forge-glance/react/tokens.css';
@theme inline {
--color-positive: var(--positive);
--color-negative: var(--negative);
--color-caution: var(--caution);
}
Overriding Tokens
All component colors are CSS custom properties — override any token to retheme:
:root {
--positive: oklch(0.72 0.22 145);
--btn-merge: oklch(0.55 0.20 280);
}
SDK Types
Common types are re-exported so you don't need to install @forge-glance/sdk separately for types:
import type {
MRDashboardProps,
MRDashboardActions,
Dashboard,
MRStatus,
Reviewer,
} from '@forge-glance/react';
Development
bun install
bun run dev:app
bun storybook
bun run build
Releasing
This package uses @changesets/cli for independent versioning:
bun changeset
bun run version
bun run release
License
MIT