Write a document dashboard in code
Цей контент ще не доступний вашою мовою.
A document dashboard presents an answer, such as an energy analysis, a commercial proposal, or an installation estimate. This guide writes one as code in a pulled workspace. The components are described in Document components for code dashboards.
If the document needs only text, figures, tables, charts, live values, tiles and inputs, create it with the Document template instead, as data and without code: see Document specification. The reading orders below apply to both.
Start from the Empty template
Section titled “Start from the Empty template”- Create a dashboard with the Empty template and pull the workspace.
- Replace
dashboard.tsxwith the page. Keepconfig.ts. - In
manifest.ts, setsupportedLocalesto the languages the page’s copy implements, such as["en"].
Choose a reading order
Section titled “Choose a reading order”Start with the conclusion, then supporting figures, comparisons, recommendations, and assumptions. These orders are starting points:
| Task | Suggested composition |
|---|---|
| Energy analysis | Main finding, consumption and cost metrics, supporting chart, recommended actions, estimated benefits, methodology and sources. |
| Commercial proposal | Client need, proposed solution and connection diagram, equipment and scope table, budget, delivery sequence, assumptions and exclusions. |
| Installation estimate | Site conditions and assumptions, quantities and labor, cost breakdown, low/base/high scenarios where justified, uncertainties. |
Lay out the page
Section titled “Lay out the page”- Wrap the page in
DashboardDocument. - Open with
DocumentLead, and use the conclusion as its title. The host already shows the dashboard’s name. - Put each part in a
DocumentSection. InsideDocumentProse, useh3for sub-headings. - Use
DocumentColumnsfor metrics or figures side by side, andDocumentMetricfor headline numbers. Include units or currency in the value. - Keep tables out of prose blocks, so the prose line length does not squeeze numeric columns.
Right-align numeric headers and cells with
className="text-right", and give each table a caption or an accessible label. - Put important caveats in an
Alert, and methodology and sources in aDocumentProsesection. - Add a diagram only when it explains a relationship. Put
SvgDiagramor dashboard graphics in aDocumentFigure, or use ordinary React elements and Lucide icons for simple relationships. Keep diagram text readable on narrow screens.
Add charts
Section titled “Add charts”- Aggregate large datasets before you pass them to
DocumentChart; it draws every row. - Keep the number of series small, and combine only series in comparable units. Draw incompatible units in separate charts.
- Pass
formatValuewith units and a sensible precision, and keep axis labels short. - Validate untrusted input against
DocumentChartDataTypebefore rendering it. - For irregular stored readings, embed a history report widget instead.
Add scenario controls
Section titled “Add scenario controls”- Wrap each control in a
Fieldwith aFieldTitlethat has anid, and label the control with thatid. - Narrow the
Slidervalue withtypeof value === "number". - Derive totals, charts, and dependent prose from the same values, so they agree when an input changes.
Scenario controls change only React state. To save configuration or write to equipment, use the shared form scaffold.
Show evidence
Section titled “Show evidence”- Keep the sources, input assumptions, currency, tax basis, and calculation notes on the page.
- State the time range, time zone, and material gaps of an analysis. Format timestamps with
formatAppDateTime. - Separate verified prices from budgeting allowances, and mark the inputs the user supplied. Keep a missing price unknown or label it as an allowance; do not let it become zero.
- When live components sit beside written findings, label the period each section describes, so a current reading is not taken for the evidence behind an earlier conclusion. Use the standard loading, error, and quality indicators in live sections.
Example: an installation estimate
Section titled “Example: an installation estimate”This dashboard.tsx uses illustrative allowances; replace them with evidence or clearly stated
assumptions. One list feeds the table, chart, and totals, so they agree after the quantity changes.
The copy is English; for several languages, follow Localize a dashboard.
import { useId, useState } from "react";import type { DashboardRootProps } from "@overvis/hmi-shared/dashboard";import { DashboardDocument, DocumentChart, DocumentColumns, DocumentFigure, DocumentLead, DocumentMetric, DocumentProse, DocumentSection, DocumentTable,} from "@overvis/hmi-workspace-ui";import { Alert, AlertDescription, AlertTitle, Field, FieldDescription, FieldTitle, Slider, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow,} from "@overvis/hmi-workspace-ui/ui";
export default function Estimate({ locale }: DashboardRootProps) { const [quantity, setQuantity] = useState(4); const quantityLabel = useId(); const lines = [ { label: "Equipment", detail: `${quantity} meters at €300 each`, cost: quantity * 300 }, { label: "Labor", detail: `${quantity * 2} hours at €60/hour`, cost: quantity * 2 * 60 }, ]; const total = lines.reduce((sum, line) => sum + line.cost, 0); const money = (value: number) => new Intl.NumberFormat(locale, { style: "currency", currency: "EUR", maximumFractionDigits: 0, }).format(value); return ( <DashboardDocument> <DocumentLead title="Budget for equipment and installation together." context="Preliminary estimate · Illustrative allowances" > <p> The base allowance for {quantity} meters is {money(total)}, excluding tax. </p> </DocumentLead> <Alert variant="warning"> <AlertTitle>Allowances, not supplier quotations</AlertTitle> <AlertDescription>Confirm prices and site access before ordering.</AlertDescription> </Alert> <DocumentColumns> <DocumentSection title="Quantity"> <Field> <FieldTitle id={quantityLabel}>Meters: {quantity}</FieldTitle> <Slider aria-labelledby={quantityLabel} min={0} max={12} step={1} value={[quantity]} onValueChange={(value) => setQuantity(typeof value === "number" ? value : (value[0] ?? 0)) } /> <FieldDescription>Reloading restores the initial quantity.</FieldDescription> </Field> </DocumentSection> <DocumentMetric label="Base estimate" value={money(total)} detail="Existing cabinet space and two labor hours per meter assumed." /> </DocumentColumns> <DocumentColumns> <DocumentTable aria-label="Cost breakdown"> <TableHeader> <TableRow> <TableHead>Item</TableHead> <TableHead className="text-right">Cost</TableHead> </TableRow> </TableHeader> <TableBody> {lines.map((line) => ( <TableRow key={line.label}> <TableCell>{line.detail}</TableCell> <TableCell className="text-right">{money(line.cost)}</TableCell> </TableRow> ))} </TableBody> <TableFooter> <TableRow> <TableCell>Total excluding tax</TableCell> <TableCell className="text-right">{money(total)}</TableCell> </TableRow> </TableFooter> </DocumentTable> <DocumentFigure caption="Current equipment and labor allowances, excluding tax."> <DocumentChart kind="bar" label="Cost allocation" formatValue={money} empty="No cost data available." data={{ series: [{ key: "cost", label: "Cost" }], rows: lines.map((line) => ({ label: line.label, values: { cost: line.cost } })), }} /> </DocumentFigure> </DocumentColumns> <DocumentSection title="Basis and exclusions"> <DocumentProse> <p> Allow €300 per meter and two installation hours at €60/hour. These are assumptions, not verified supplier quotations. </p> <p> Travel, cabinet alterations, recurring fees, and tax are excluded. Confirm site access, cable routes, and the shutdown window before ordering. </p> </DocumentProse> </DocumentSection> </DashboardDocument> );}Revise a document
Section titled “Revise a document”- To change a document the assistant made, ask the assistant; follow-up requests normally edit the same dashboard. To keep both versions, ask for a separate dashboard.
- To edit the sources yourself, pull the workspace, edit
dashboard.tsx, and push.