Przejdź do głównej zawartości

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.

  1. Create the dashboard in Setup → Dashboards with the Empty template, in the cloud app or the local app; see Add dashboards and other entities.
  2. Pull the workspace, or run pnpm hmi pull in an existing checkout; see Pull a workspace.
  3. Run pnpm dev and open the local host at http://localhost:8000. It loads src/dashboards/<id>/index.tsx and reloads it as you edit.
  4. Open src/dashboards/<id>/: dashboard.tsx holds the root component, config.ts its dashboardConfigType, manifest.ts its languages, and index.tsx re-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.

  1. Keep export default function …(props: DashboardRootProps) and the dashboardConfigType export.
  2. Define a strict TypeBox dashboardConfigType in config.ts, and describe each key in the schema, so the configuration explains itself in Setup.
  3. Make keys optional with sensible defaults where the dashboard can work without them, so {} is a valid start. Otherwise show what is missing with DashboardConfigurationRequired.
  4. Narrow the configuration once, at the component boundary, with parseDashboardConfiguration. The host has already validated it.
  5. 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.
  6. Keep secrets out of the configuration, and do not store workspaceId or dashboardId there; both come in the props. Keep the configuration small enough to edit as JSON in Setup.
  7. Declare supportedLocales in manifest.ts and re-export it from the entry; see Localize a dashboard.
  8. Keep strict TypeScript checking on. Avoid any and unnecessary assertions.

The packages a dashboard can import, and which of them the host supplies, are listed in the host contract.

  1. 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.
  2. Import shared helpers and types from the @overvis/hmi-shared subpaths, such as @overvis/hmi-shared/dashboard for DashboardRootProps.
  3. Import icons directly from lucide-react. Do not copy SVG paths into the dashboard.
  4. Keep imports inside the dashboard folder. Lazy-load heavy panels with React.lazy and Suspense.
  1. Give each view one primary job, such as a status view or a setpoint panel, not both crowded together.
  2. Prefer the shared primitives to one-off markup, so the dashboard matches the host. Show every problem or status card with NoticeCard, and use Alert only for callouts in printable documents. Draw bars, gauges, and scales with GaugeBar and Gauge.
  3. 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 from recharts, which would bundle a second copy.
  4. 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.
  5. Give custom controls labels, focus rings, and keyboard operation, and never show a critical alarm by color alone.
  6. Keep the first paint light: lazy-load charts and panels.
  7. 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.

  1. Style with Tailwind classes in the dashboard’s .ts, .tsx, .js, and .jsx files. Any class works, including arbitrary values such as h-[80svh]. Do not add .css files or import CSS; the build writes index.css.
  2. Use host tokens, such as text-foreground, bg-primary, and border-border, so light and dark themes match the shell. props.theme is still passed if you need a data attribute.
  3. Do not assume fonts beyond what the host provides.
  4. On a dialog, sheet, drawer, or menu, spread DASHBOARD_SCOPE_PROPS from @overvis/hmi-shared/dashboard on the content so the dashboard’s classes reach it.
  5. Set each side once instead of a shorthand plus a longhand (py-4 px-2, not p-4 px-2), and make two variants of the same property exclusive. The styling reference explains why.
  1. Declare the fixed pages once, as a pages export of manifest.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[];
  2. Re-export pages from the entry, and build the tabs from it with DashboardPageTabs, resolving each name with resolveLocalized from @overvis/hmi-shared and the dashboard’s locale.

  3. Match the current path with dashboardPageAt(paths, location.path), and render DashboardPageNotFound for unknown pages or deleted entities.

  4. Link with DashboardLink, or call navigate from useDashboardNavigation for an action that is not a link. Encode variable path segments with encodeURIComponent, and decode them with decodeURIComponent before you display them.

  5. Pass replace for toggles that should not add history entries, and keepScroll on both the link that opens a detail overlay at its own path and the link that closes it.

  6. Keep filter state in the query string, so returning to an overview restores it.

  7. When an anchor selects a panel, scroll it into view after its data is ready, for example with useAnchorScroll.

  8. Do not mount another router or write browser history directly.

Existing single-page dashboards need no changes.

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.

  1. Keep the asset as an ordinary .svg file under the dashboard folder, and import it with new URL("./assets/diagram.svg", import.meta.url).href.
  2. Mark each element that changes with a stable data-svg-target value. Bind text to the exact <text> or <tspan>, and bind classes, visibility, labels, and actions to container groups.
  3. Read the parameters in the dashboard, derive the display strings and state classes, and pass them as bindings. Give every action target an ariaLabel.
  4. Optionally define the fallback appearance of live targets in the SVG’s own stylesheet.
  5. Override the default min-h-80 through className when the artwork has a useful ratio, such as aspect-video min-h-0.
  6. 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.
  1. When the dashboard watches many similar sites with readings, alarms, and controls, follow Build a fleet dashboard: FleetOverview and FleetMap combine filters, status, and the map. For a plain map of named sites, start from the Map template.
  2. For another layout, use DashboardLocationMap with translated empty and unavailable messages. Give each location a tone and a title that names its state, such as “Station 3 – Alarm”, so the map does not rely on color alone. Pass a translated clusterLabel.
  3. In setup forms, place a position with DashboardLocationPicker, and keep manual latitude and longitude fields beside it for when Maps cannot load.
  4. Pass a translated retryLabel, so operators can request the credentials again.
  5. Bundle @vis.gl/react-google-maps in the dashboard; do not add it to the host import map.
  6. Load the browser key and map ID with useMapsBrowserConfig. Never put Maps API keys in the configuration.
  7. Test locally at http://localhost:8000; the map does not load at http://127.0.0.1:8000 or a LAN address.

The map components are described in maps.

Show dashboard timestamps with formatAppDateTime, and report data with formatReportDateTime, as described in Localize a dashboard.

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.

  1. Run pnpm build while you work to type-check and build the dashboard, and fix the errors it reports.
  2. Pass settings through the configuration: builds read no environment variables or .env files.
  3. Publish the dashboard as described in Create and publish dashboards.
  1. Open the dashboard in the cloud at /workspace/<workspaceId>/d/<dashboardId>.
  2. Check that values appear progressively, that pause and resume work, and that stale and error states show as expected.
  3. Try each write path, including a partial failure of a batch.
  4. Check light and dark themes, and each language the dashboard declares.
  5. Check a narrow screen.

A dashboard runs with the workspace access of the signed-in user, or of the workspace API key in the local app.

  1. Never interpolate untrusted strings into markup.
  2. Do not put API keys in the configuration or in committed source; the local .env is ignored by git.
  3. Confirm destructive setpoints in the UI, even though the server checks every write.

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.

  1. Import it from the subpath listed in @overvis/hmi-shared or @overvis/hmi-workspace-ui.
  2. Build and push again.

When a published dashboard shows Dashboard needs a rebuild, update the HMI packages, then push; the push rebuilds the dashboard.

  1. 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).
  2. 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.
  3. To return to the chat, select the minimize button or press Esc; on a phone, select Back to chat.
  4. To stop the assistant, select Stop in the chat; the draft is kept for your next message.
  5. If the preview stays unavailable, ask for a retry, or allow publishing without the visual check in the chat’s confirmation.
  6. 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.