Develop a dashboard locally
Ta treść nie jest jeszcze dostępna w Twoim języku.
This guide writes a dashboard’s React module in a pulled workspace and publishes it. What the host expects from the module is in the dashboard host contract. For a board that needs no code, build a value board instead.
Set up the dashboard
Section titled “Set up the dashboard”- Create the dashboard in Setup → Dashboards with the Empty template, in the cloud app or the local app; see Add dashboards and other entities.
- Pull the workspace, or run
pnpm hmi pullin an existing checkout; see Pull a workspace. - Run
pnpm devand open the local host athttp://localhost:8000. It loadssrc/dashboards/<id>/index.tsxand reloads it as you edit. - Open
src/dashboards/<id>/:dashboard.tsxholds the root component,config.tsitsdashboardConfigType,manifest.tsits languages, andindex.tsxre-exports them.
To draw a diagram or build a board of tiles without code, use the Canvas or Value tiles template instead. To show a report, create the dashboard with Create from report.
Write the entry and the configuration
Section titled “Write the entry and the configuration”- Keep
export default function …(props: DashboardRootProps)and thedashboardConfigTypeexport. - Define a strict TypeBox
dashboardConfigTypeinconfig.ts, and describe each key in the schema, so the configuration explains itself in Setup. - Make keys optional with sensible defaults where the dashboard can work without them, so
{}is a valid start. Otherwise show what is missing withDashboardConfigurationRequired. - Narrow the configuration once, at the component boundary, with
parseDashboardConfiguration. The host has already validated it. - Refer to parameters by their UUIDs, not by their names, which are not unique. Bind them as described in Show live values in a dashboard.
- Keep secrets out of the configuration, and do not store
workspaceIdordashboardIdthere; both come in the props. Keep the configuration small enough to edit as JSON in Setup. - Declare
supportedLocalesinmanifest.tsand re-export it from the entry; see Localize a dashboard. - Keep strict TypeScript checking on. Avoid
anyand unnecessary assertions.
Import what the host provides
Section titled “Import what the host provides”The packages a dashboard can import, and which of them the host supplies, are listed in the host contract.
- Import
trpc, live-value hooks, forms, report widgets, and graphics from@overvis/hmi-workspace-ui, and UI primitives from@overvis/hmi-workspace-ui/ui. Do not create a second tRPC client. - Import shared helpers and types from the
@overvis/hmi-sharedsubpaths, such as@overvis/hmi-shared/dashboardforDashboardRootProps. - Import icons directly from
lucide-react. Do not copy SVG paths into the dashboard. - Keep imports inside the dashboard folder. Lazy-load heavy panels with
React.lazyandSuspense.
Design the view
Section titled “Design the view”- Give each view one primary job, such as a status view or a setpoint panel, not both crowded together.
- Prefer the shared primitives to one-off markup, so the dashboard matches the host. Show every
problem or status card with
NoticeCard, and useAlertonly for callouts in printable documents. Draw bars, gauges, and scales withGaugeBarandGauge. - For analyses, proposals, and estimates, use the document components. For
another chart, compose a shadcn chart, and import its Recharts parts from
@overvis/hmi-workspace-ui/ui, not fromrecharts, which would bundle a second copy. - Design mobile-first. Avoid fixed desktop widths, and size grids with container queries on the dashboard panel, because the dashboard often sits in a split pane. Do not trap scrolling without an escape, so the host’s mobile navigation sheet stays usable.
- Give custom controls labels, focus rings, and keyboard operation, and never show a critical alarm by color alone.
- Keep the first paint light: lazy-load charts and panels.
- Do not copy Setup’s parameter or endpoint editors into a dashboard. Catalog changes belong in Setup.
Live values and writes have their own guides: Show live values in a dashboard and Write parameter values from a dashboard.
Style the dashboard
Section titled “Style the dashboard”- Style with Tailwind classes in the dashboard’s
.ts,.tsx,.js, and.jsxfiles. Any class works, including arbitrary values such ash-[80svh]. Do not add.cssfiles or import CSS; the build writesindex.css. - Use host tokens, such as
text-foreground,bg-primary, andborder-border, so light and dark themes match the shell.props.themeis still passed if you need a data attribute. - Do not assume fonts beyond what the host provides.
- On a dialog, sheet, drawer, or menu, spread
DASHBOARD_SCOPE_PROPSfrom@overvis/hmi-shared/dashboardon the content so the dashboard’s classes reach it. - Set each side once instead of a shorthand plus a longhand (
py-4 px-2, notp-4 px-2), and make two variants of the same property exclusive. The styling reference explains why.
Add pages
Section titled “Add pages”-
Declare the fixed pages once, as a
pagesexport ofmanifest.ts, in tab order, with the home page/first:// manifest.ts: literals and type imports only; the build evaluates it on its own.import type { DashboardPage } from "@overvis/hmi-shared/dashboard";export const supportedLocales = ["en", "de"] as const;export const pages = [{ path: "/", name: { en: "Overview", de: "Übersicht" } },{ path: "/settings", name: { en: "Settings", de: "Einstellungen" } },] as const satisfies readonly DashboardPage[]; -
Re-export
pagesfrom the entry, and build the tabs from it withDashboardPageTabs, resolving eachnamewithresolveLocalizedfrom@overvis/hmi-sharedand the dashboard’slocale. -
Match the current path with
dashboardPageAt(paths, location.path), and renderDashboardPageNotFoundfor unknown pages or deleted entities. -
Link with
DashboardLink, or callnavigatefromuseDashboardNavigationfor an action that is not a link. Encode variable path segments withencodeURIComponent, and decode them withdecodeURIComponentbefore you display them. -
Pass
replacefor toggles that should not add history entries, andkeepScrollon both the link that opens a detail overlay at its own path and the link that closes it. -
Keep filter state in the query string, so returning to an overview restores it.
-
When an anchor selects a panel, scroll it into view after its data is ready, for example with
useAnchorScroll. -
Do not mount another router or write browser history directly.
Existing single-page dashboards need no changes.
Show an SVG diagram
Section titled “Show an SVG diagram”Use SvgDiagram when the main view is artwork maintained in a vector drawing tool. For a diagram
that users edit in the browser, use dashboard graphics instead.
- Keep the asset as an ordinary
.svgfile under the dashboard folder, and import it withnew URL("./assets/diagram.svg", import.meta.url).href. - Mark each element that changes with a stable
data-svg-targetvalue. Bind text to the exact<text>or<tspan>, and bind classes, visibility, labels, and actions to container groups. - Read the parameters in the dashboard, derive the display strings and state classes, and pass
them as
bindings. Give every action target anariaLabel. - Optionally define the fallback appearance of live targets in the SVG’s own stylesheet.
- Override the default
min-h-80throughclassNamewhen the artwork has a useful ratio, such asaspect-video min-h-0. - Keep geometry and equipment placement in the SVG. Put only live bindings, labels, and optional links in the configuration, unless operators need to change the layout. Save edits such as renamed labels through the form scaffold.
Show sites on a map
Section titled “Show sites on a map”- When the dashboard watches many similar sites with readings, alarms, and controls, follow
Build a fleet dashboard:
FleetOverviewandFleetMapcombine filters, status, and the map. For a plain map of named sites, start from the Map template. - For another layout, use
DashboardLocationMapwith translated empty and unavailable messages. Give each location atoneand atitlethat names its state, such as “Station 3 – Alarm”, so the map does not rely on color alone. Pass a translatedclusterLabel. - In setup forms, place a position with
DashboardLocationPicker, and keep manual latitude and longitude fields beside it for when Maps cannot load. - Pass a translated
retryLabel, so operators can request the credentials again. - Bundle
@vis.gl/react-google-mapsin the dashboard; do not add it to the host import map. - Load the browser key and map ID with
useMapsBrowserConfig. Never put Maps API keys in the configuration. - Test locally at
http://localhost:8000; the map does not load athttp://127.0.0.1:8000or a LAN address.
The map components are described in maps.
Format dates and times
Section titled “Format dates and times”Show dashboard timestamps with formatAppDateTime, and report data with formatReportDateTime, as
described in Localize a dashboard.
Help the assistant point at your widgets
Section titled “Help the assistant point at your widgets”Put data-context-* attributes on the widgets operators ask about, such as
data-context-widget="pump-start" and data-context-label="Start". Do not reuse
data-overvis-dashboard, which only scopes the CSS.
Build and publish
Section titled “Build and publish”- Run
pnpm buildwhile you work to type-check and build the dashboard, and fix the errors it reports. - Pass settings through the configuration: builds read no environment variables or
.envfiles. - Publish the dashboard as described in Create and publish dashboards.
Check before handing over
Section titled “Check before handing over”- Open the dashboard in the cloud at
/workspace/<workspaceId>/d/<dashboardId>. - Check that values appear progressively, that pause and resume work, and that stale and error states show as expected.
- Try each write path, including a partial failure of a batch.
- Check light and dark themes, and each language the dashboard declares.
- Check a narrow screen.
Keep the dashboard secure
Section titled “Keep the dashboard secure”A dashboard runs with the workspace access of the signed-in user, or of the workspace API key in the local app.
- Never interpolate untrusted strings into markup.
- Do not put API keys in the configuration or in committed source; the local
.envis ignored by git. - Confirm destructive setpoints in the UI, even though the server checks every write.
Update imports after a package upgrade
Section titled “Update imports after a package upgrade”When hmi build fails with has no exported member, the name moved from a package root to a
subpath, for example DashboardRootProps to @overvis/hmi-shared/dashboard.
- Import it from the subpath listed in
@overvis/hmi-sharedor@overvis/hmi-workspace-ui. - Build and push again.
When a published dashboard shows Dashboard needs a rebuild, update the HMI packages, then push; the push rebuilds the dashboard.
Watch the assistant work on a dashboard
Section titled “Watch the assistant work on a dashboard”- While the assistant uses the preview, select the live view above the message box, a browser step in the chat, or the monitor icon in the chat header (Watch assistant preview).
- Check the status line under the preview’s top bar: it says what the assistant is doing and shows Out of date when code changed after the page opened.
- To return to the chat, select the minimize button or press Esc; on a phone, select Back to chat.
- To stop the assistant, select Stop in the chat; the draft is kept for your next message.
- If the preview stays unavailable, ask for a retry, or allow publishing without the visual check in the chat’s confirmation.
- Build preview-friendly dashboards: use the installed packages and workspace assets instead of internet-hosted maps, images, and fonts, which the preview cannot load.
What the preview can and cannot do is in the host contract.