b.peck 83b23431c6 Phase 2: dashboard tabs + popups, chart fixes, shell relocation
Built via parallel Workflow (5 builders + adversarial verifiers), then
live-rendered and fixed in a headless browser against the running gateway.

Tabs (PrimeControls/Tabs/*):
- Overview: priority cards, KPI status row, alarm-rate timeline, insights, top-5
- Analysis: hour x day heatmap, priority donut vs ISA 80/15/5, MTTA/MTTR, floods
- BadActors: chattering/standing/fleeting tables, focus chip, AlarmDetail wiring
- Journal: paginated getJournalPage table, CSV export, EventDetail wiring

Popups (PrimeControls/Popups/*): HealthScore, ShiftReport, AlarmDetail, EventDetail

Chart fixes (verified rendering in-browser):
- Overview timeline: seeded dataSources.rate, switched to static fills, split
  flood bins into their own red stacked series (per-point deriveFieldsFromData
  fill was crashing render with React.cloneElement null).
- BadActors: removed the dual-axis Pareto XY chart (scaling was unusable);
  replaced with a ranked "Top Sources" table (share-of-total progress bar +
  cumulative %). Same insight, no axis scaling to break.

Structural / hygiene:
- Relocated Header + FilterBar from Dashboard/ to Shell/ and updated the two
  embed paths. A Perspective view cannot resolve sub-views nested inside another
  view's folder, so both were rendering as "view does not exist" placeholders.
- Set persistent:false on all view input params. persistent:true caused the
  gateway to bake the live bundle (with sim tag paths) into Tabs/Analysis on
  render; nulled that baked data and reset the session query range to 0.

lint_project.py: 0 failures / 0 warnings.

Verified in-browser: Overview, BadActors. NOT yet live-verified: Analysis,
Journal, and the four popups (schema-verified only). Header content is next
phase (renders now, but a benign cloneElement console warning remains).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 14:45:17 -05:00

Build-a-Thon — Alarm Analysis Dashboard (Ignition 8.3.7 + Perspective)

Local development environment for the Inductive Automation Build-a-Thon. Native Ignition features only — no third-party modules (contest rule).

Quickstart

docker compose up -d
  • Gateway: http://localhost:8088 — login admin / password
  • MariaDB: localhost:3306 — db ignition, user ignition / ignition (root password: password)

First start takes a minute or two while the gateway commissions itself (EULA, edition, and admin credentials are seeded by env vars, so there is no commissioning wizard). Watch with:

docker compose logs -f ignition

The gateway is ready when curl http://localhost:8088/StatusPing returns {"state":"RUNNING"}.

Gateway state lives in this repo (gateway-as-files)

The gateway's durable state is bind-mounted from the repo (primebench/TestingPlatform pattern) — a container recreate can never wipe it, and the gateway never re-commissions:

Repo path In container (data/) What's in it
ignition/gateway/commission/commissioning.json commissioning.json Commissioning marker (committed)
ignition/gateway/config/ config/ All config resources: DB connection, journal, API token, tags, secrets
ignition/gateway/projects/ projects/ Project files: Perspective views, scripts, timers

Everything else (internal db, logs, certs) stays ephemeral in the container. The gateway runs as your host uid/gid (IGNITION_UID/IGNITION_GID, default 1000), so files stay owned by you.

Edit-files workflow: change files under ignition/gateway/, then tell the gateway to reload — python3 tools/provision.py scan-config (config/tags) or scan-projects (project resources). Changes made in the Designer/gateway UI land back in these files, ready to diff.

Automated provisioning (REST API)

Gateway config is provisioned through the Ignition 8.3 HTTP API using tools/provision.py (stdlib only, no pip installs). On a fresh gateway:

python3 tools/provision.py mint-token   # API token file-drops + gateway restart; updates .env
python3 tools/provision.py provision    # secret provider + DB connection + alarm journal + sim tags
  • mint-token writes an api-token config resource under ignition/gateway/config/, patches the Authenticated > API security levels into gateway read/write permissions, restarts the gateway (if running; otherwise the token loads on next boot), and saves IGN_API=Buildathon:<secret> to .env (gitignored). Only the SHA-256 hash of the secret is stored in the config files.
  • provision is idempotent — it skips resources that already exist. It creates:
    • file secret provider local (MariaDB password lives in the gitignored file ignition/gateway/config/secrets/mariadb_password, referenced by the connection — the 8.3 API only accepts encrypted or referenced secrets)
    • database connection Buildathon_DBjdbc:mariadb://db:3306/ignition
    • alarm journal Journal → tables PrimeControls_alarm_events / PrimeControls_alarm_event_data
    • imports test-data/simulation_tags.json into the default tag provider

Ad-hoc API calls use one header: curl -H "X-Ignition-API-Token: $IGN_API" $GATEWAY_URL/openapi.json (source .env first).

Two steps remain manual (Designer-only): creating the Buildathon Perspective project (step 3 below) and installing the simulator timer script (test-data/README.md).

Manual setup reference (what provision.py does, plus the Designer steps)

1. Database connection (MariaDB) — automated

Gateway web UI → Config → Databases → Connections → Create new Database Connection

Setting Value
Name Buildathon_DB
Driver MariaDB
Connect URL jdbc:mariadb://db:3306/ignition
Username ignition
Password ignition

Note the host is db (the compose service name), not localhost — the gateway reaches MariaDB over the compose network. Save and confirm the status shows Valid.

Ignition 8.3 ships the MariaDB JDBC driver, so no driver install is needed.

2. Alarm journal profile — automated

Gateway web UI → Config → Alarming → Journal → Create new Alarm Journal Profile

Setting Value
Name Journal (any name works)
Type Database
Datasource Buildathon_DB
Table prefix PrimeControls_

Leave the event filters at defaults (store everything) so the analytics have full data. The journal auto-creates PrimeControls_alarm_events and PrimeControls_alarm_event_data in MariaDB the first time an alarm event occurs.

3. Perspective project — manual

  1. Gateway web UI → Config → Projects → Create new Project (or Designer → File → New Project)
    • Name: Buildathon
  2. Open it in the Designer (launch from http://localhost:8088 → Designer launcher), then set the project default database: Project → Project Properties → General → Default DatabaseBuildathon_DB. Save the project.

Named queries and bindings that use the "default" database now hit MariaDB.

Test data

See test-data/README.md — imports simulation memory tags with alarm configs and a Jython script that generates realistic alarm activity (baseline alarms across 5 plant areas / 3 priorities, chattering, standing, fleeting, and flood-burst patterns).

Reset to a completely fresh gateway

Gateway state is repo files now, so docker compose down -v alone no longer wipes the gateway — it only removes the containers and the MariaDB volume. To verify the project export imports cleanly on a fresh install (the contest judging scenario), set the gateway files aside and rebuild:

docker compose down -v                    # containers + MariaDB volume
mv ignition/gateway ignition/gateway.bak  # keep your current state for rollback
mkdir -p ignition/gateway/commission ignition/gateway/config ignition/gateway/projects
cp ignition/gateway.bak/commission/commissioning.json ignition/gateway/commission/
docker compose up -d                      # boots factory-fresh, auto-commissions
python3 tools/provision.py mint-token     # old token lived in gateway.bak
python3 tools/provision.py provision

Then import your project export to prove it stands alone. Roll back to your working state with docker compose down && rm -rf ignition/gateway && mv ignition/gateway.bak ignition/gateway && docker compose up -d (MariaDB journal data is gone either way after -v — the sim regenerates it).

A plain docker compose down / up -d restarts with everything intact.

Notes

  • Max JVM heap is 2 GB (-m 2048 runtime arg in the compose command).
  • The 8.3 image's data dir is /usr/local/bin/ignition/data; only commissioning.json, config/, and projects/ are bind-mounted from ignition/gateway/ (see the gateway-as-files section above).
  • ignition waits on the MariaDB healthcheck before starting, so the datasource is reachable as soon as the gateway is up.
Description
No description provided
Readme 823 KiB
Languages
Python 97.6%
CSS 1.3%
Shell 1.1%