Learn / Kits: dashboards, ER & UML

Kits: dashboards, ER & UML

A kit turns plain data into a finished interactive diagram — entities in, an ER diagram with column-level ports out. Kits are functions returning specs, so they compose with everything else on this site.

The pattern

import { render, erDiagram } from '@grafloria/element';

const spec = erDiagram({ entities, relationships });
const api = render(spec, host);      // render() runs the kit's finalize for you

In Vue: <GrafloriaDiagram :spec="spec" />. A kit spec is { nodes, edges, finalize } — regular nodes and edges plus a wiring step, so everything else (layout, export, undo, collaboration) works on kit diagrams unchanged.

ER — tables with real columns

const spec = erDiagram({
  entities: [
    { id: 'CUSTOMER', name: 'Customer', position: { x: 60, y: 76 }, columns: [
      { name: 'id', type: 'int', pk: true },
      { name: 'email', type: 'varchar' },
    ]},
    { id: 'ORDER', name: 'Order', position: { x: 400, y: 64 }, columns: [
      { name: 'id', type: 'int', pk: true },
      { name: 'customer_id', type: 'int', fk: true },
    ]},
  ],
  relationships: [
    { from: 'CUSTOMER', to: 'ORDER', label: 'places', cardinality: 'one-to-many' },
    // attach at a COLUMN with ENTITY.column:
    { from: 'ORDER.customer_id', to: 'CUSTOMER.id' },
  ],
});

Rows are selectable (listen for axk:row-select), a fixed entity height makes the column list scroll, and editable: true adds rename/add/delete chrome where every edit is one undoable step.

Live: ER diagram →

UML — classes, stereotypes, markers

const spec = umlDiagram({
  classes: [
    { id: 'Animal', abstract: true, position: { x: 380, y: 40 },
      attributes: ['# name: String'], methods: ['+ speak(): void'] },
    { id: 'Dog', position: { x: 150, y: 320 }, methods: ['+ fetch(): void'] },
  ],
  relationships: [
    { from: 'Dog', to: 'Animal', kind: 'inheritance' },
    { from: 'Owner', to: 'Dog', kind: 'aggregation', label: 'owns', multiplicity: ['1', '0..*'] },
  ],
});

Relationship kinds draw the correct UML markers: inheritance, realization, association, directed-association, aggregation, composition, dependency.

Both card kits also expose a typed handle façade for programmatic editing that rides the undo stack:

import { umlClass } from '@grafloria/element';

const animal = umlClass(api, 'Animal');
await animal.methods.add('+ move(): void');
await animal.setAbstract(true);
await animal.undo();

Live: UML class diagram →

Dashboards — a drag-and-pack grid

import { render, dashboard } from '@grafloria/element';

const spec = dashboard({
  columns: 12,
  widgets: [
    { id: 'kpi-revenue', kind: 'kpi', span: 3,
      data: { label: 'Total revenue', value: '$6.81M', delta: 12.4,
              spark: [42, 45, 51, 55, 61, 71, 76] } },
    { id: 'trend', kind: 'line', span: 6, rows: 2, title: 'Revenue trend',
      data: { series: [{ name: 'Revenue', values: [1.2, 1.4, 1.9, 2.3] }],
              labels: ['Q1', 'Q2', 'Q3', 'Q4'] } },
    { id: 'mix', kind: 'donut', span: 3, rows: 2, title: 'By region',
      data: { slices: [{ label: 'EMEA', value: 2.9, color: '#3B52D9' }] } },
  ],
});
render(spec, host);
spec.handle.addWidget({ id: 'later', kind: 'bar', span: 3, data: { bars: [] } });

Containers — widgets that hold widgets. A widget carrying widgets mounts as a section: a locked slab in the board with its own pack grid inside (own columns, default: its span). Tiles drag across the boundary in both directions — the other grid adopts them live — and one undo restores the whole gesture. A child resized past the section's designed rows escalates: the section grows a row in the board. toJSON() reports the nesting from live membership, so a dragged-in tile serialises under its new parent. Tested to two levels of nesting.

{ id: 'kpis', title: 'KPI section', span: 12, rows: 1, columns: 4,
  widgets: [
    { id: 'k-rev',  kind: 'kpi', span: 1, data: { label: 'Revenue', value: '$6.8M' } },
    { id: 'k-cust', kind: 'kpi', span: 1, data: { label: 'Customers', value: '1,284' } },
  ] }

Live: dashboard containers →

Six built-in widget kinds render with zero code — kpi, line, bar, donut, funnel, table — and renderWidget (or React's widgetTypes, Vue's #widget-<kind> slots, Angular's ng-template grafloriaWidget) takes over for your own. Widgets drag and pack live, gridstack-style; multiple views give you tabs; and handle.toJSON() returns exactly what dashboard() accepts — the layout round-trips by construction.

Live: dashboard builder →

Where next