demo D278
How work flows through the board in React
A cumulative-flow diagram of what sits in each column day by day, with cycle time, lead time and throughput read from the board’s own movements, so a slowdown shows before it becomes a surprise
board.flow · cfd() · cycleTime()
This reads the board's own card movements into a cumulative-flow diagram of what sits in each column day by day, with cycle time, lead time and throughput. It shows where work is piling up before it becomes a surprise, from the movements the board already records.
This is the React version. The grid mounts through the createLatticeGrid adapter, which takes its configuration as ordinary props and hands back the live grid through a ref. The grid below is the same one every other tab runs.
The configuration
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.71.0/lattice-grid.min.css">
<div id="app"></div>
<script type="module">
import React from 'https://esm.sh/react@18';
import { createRoot } from 'https://esm.sh/react-dom@18/client';
import { createHeadlessGrid } from 'https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.71.0/lattice-grid.esm.min.js';
import { createLatticeReact } from 'https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.71.0/modules/react.esm.min.js';
import { createKanban } from 'https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.71.0/modules/kanban.esm.min.js';
import { createChart } from 'https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.71.0/modules/charts.esm.min.js';
const { LatticeKanban, LatticeChart } = createLatticeReact({ React, createKanban, createChart });
const columns = [
{ id: 'backlog', title: 'Backlog' }, { id: 'todo', title: 'To do' },
{ id: 'doing', title: 'In progress' }, { id: 'review', title: 'In review' },
{ id: 'done', title: 'Done', color: '#2e7d32' },
];
const rows = [/* cards in their current column: id, status, points, epic, assignee, title */];
const history = [/* [{ key, from, to, at }, ...] one row per recorded move */];
function App() {
const [board, setBoard] = React.useState(null);
const [cfdGrid, setCfdGrid] = React.useState(null);
React.useEffect(() => {
if (!board) return;
// Wire the flow analytics with the recorded column-to-column moves and
// the roles that bound cycle time (from a start column) and done. This
// reruns the whole board's analytics, so it only fires once.
board.flow.seed();
// Each figure is read from the board's own recorded movements.
const cycle = board.flow.cycleTime(); // { median, p85, ... } in ms
const lead = board.flow.leadTime(); // { median, count, ... }
const perWeek = board.flow.throughput({ bucket: 'week' }); // cards finished per week
// The cumulative-flow diagram, ready as a chart spec over a headless grid.
const cfd = board.flow.chartData('cfd', { bucket: 'day' });
const grid = createHeadlessGrid({
rowKey: 't',
columns: cfd.columns.map((c) => ({ field: c.field, title: c.title, ...(c.field === 't' ? {} : { type: 'number' }) })),
rows: cfd.rows,
});
setCfdGrid({ grid, spec: cfd.spec });
}, [board]);
return (
<>
<LatticeKanban
rowKey="id" rows={rows} columnProperty="status" columns={columns}
pointsProperty="points" showPoints
card={{ title: { field: 'title' }, subtitle: 'assignee', badges: 'epic' }}
doneColumns={['done']}
flow={{ history, doneColumns: ['done'], startColumns: ['doing'] }}
onReady={setBoard}
style={{ height: '520px' }}
/>
{cfdGrid && <LatticeChart grid={cfdGrid.grid} {...cfdGrid.spec} legend style={{ height: '300px', marginTop: '14px' }} />}
</>
);
}
createRoot(document.getElementById('app')).render(<App />);
</script>
Flow metrics read from a board’s own movements
A delivery board already knows more than it shows. Every time a card moves from one column to the next it records when, and that history is enough to answer the questions a team actually asks: how long does a card take, where does work sit, and how fast is it clearing. This screen reads those movements into a cumulative-flow diagram beside the board, with cycle time, lead time and throughput on tiles above it, so the shape of the work is visible rather than felt.
The cumulative-flow diagram stacks how many cards sit in each column day by day. A band that widens is work piling up in that stage, and a top that flattens is delivery slowing down, so a bottleneck reads as a shape before it reads as a missed date. The colour key names each column, so a band on the chart maps straight to a column on the board.
The tiles carry the numbers a stand-up leans on. Cycle time is how long a card takes once work actually starts on it, lead time is the whole wait from the moment it arrived, and throughput counts cards finished per week, the rate the board is really clearing work at. Every figure is derived from the moves the board records, so it stays right as cards are dragged between columns rather than needing a separate report kept in step by hand.
How do I read flow metrics from a kanban board?
Give the board a flow configuration naming the columns that count as started and done, along with the card movement history, then call board.flow.seed() to load it. Read board.flow.cycleTime(), board.flow.leadTime() and board.flow.throughput({ bucket: 'week' }) for the tile figures, and board.flow.chartData('cfd', { bucket: 'day' }) for the cumulative-flow series to draw. Each figure comes from the board’s own recorded moves, so it updates as cards change columns.