Phase 1 UI foundation: 32 style classes, 9 shared components, tab shell, placeholders

Dashboard shell: bundle expr binding + script transform, onStartup range init,
hand-rolled tab bar (position.display exprs), CONTRACT.md frozen pending G1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-16 12:16:16 -05:00
parent af662f6fd2
commit c82a2fa6df
98 changed files with 3006 additions and 13 deletions

225
CONTRACT.md Normal file
View File

@@ -0,0 +1,225 @@
# CONTRACT.md — PrimeBAT build contract (FROZEN after Gate G1)
Every builder/verifier agent works from this file. Do not deviate; changes require the
integrator to edit this file first. Repo: `/home/bpeck/git/buildathon`. Project root:
`ignition/gateway/projects/PrimeBAT/`. Reload: `python3 tools/provision.py scan-projects`.
Lint: `python3 tools/lint_project.py` (must exit 0). Component prop schemas (ground truth
for every prop name): `/tmp/claude-1000/-home-bpeck-git-buildathon/a7f89b44-360c-4f23-ab63-503f3c25b53b/scratchpad/schemas/components/<component-id>.schema.json`.
Format exemplar (READ IT before writing any view.json):
`/home/bpeck/git/primebench/ignition/gateway/projects/PrimeBench/com.inductiveautomation.perspective/views/ForceRow/view.json`.
## Hard rules (contest + platform)
1. Jython 2.7 everywhere (project scripts, transforms, event scripts): **NO f-strings**
(`%` formatting only), no `typing`, no `statistics`. Scripts in view.json are inline
JSON strings, tab-indented (`\t`), first char of every script/transform line block is a tab.
2. **Java exceptions bypass `except Exception`** in Jython. Gateway-facing defensive code
uses bare `except:` + `sys.exc_info()` (probe-verified).
3. NO tag bindings in PrimeBAT. NO SQL / `system.db.*`. NO `journalName=` literals.
Banned strings (lint-enforced): `[default]`, `BuildathonSim`, `Buildathon_DB`,
`alarmsim`, `SELECT`, f-string prefixes.
4. All views/styles/scripts under `PrimeControls/` namespaces. Single page `/`
`PrimeControls/Dashboard`. `sharedDocks` stays `{}` (docked views prohibited).
5. Every view tolerates `bundle: null` / empty arrays — no binding may throw on empty.
Empty-window UX = `PrimeControls/Components/EmptyState` embed, not a broken chart.
6. resource.json boilerplate for every view:
`{"scope":"G","version":1,"restricted":false,"overridable":true,"files":["view.json"],"attributes":{}}`
(style classes: `files:["style.json"]`; script modules: scope `"A"`, `attributes:{"hintScope":2}`).
7. Numbers/durations/timestamps rendered through `PrimeControls.fmt` helpers (consistency).
## Probe-verified journal API facts (do not re-derive)
- `system.alarm.queryJournal(startDate=<ms|Date>, endDate=<ms|Date>)` — epoch millis
accepted directly; omit `journalName` (uses the single configured journal); nonexistent
name raises java `IllegalArgumentException` (catch with bare except).
- Result `AlarmQueryResultImpl`: iterable, `len()` works. One entry per **transition**;
entries of one alarm instance share `str(evt.getId())` (uuid).
- `str(evt.getState())` is compound: `"Active, Unacknowledged"`, `"Cleared, Acknowledged"`, etc.
Transition kind per row: activation row state starts `"Active"` and row's
`getActiveData()` non-null; clear row starts `"Cleared"` (`getClearedData()` non-null);
ack row has `getAckData()` non-null / state contains `", Acknowledged"`.
Per-instance: `active_ms` = min ts of Active rows; `clear_ms` = min ts of Cleared rows;
`ack_ms` = min ts of rows with ack marker.
- `evt.get("eventTime")` → java Date; `.getTime()` → ms. `evt.get("eventType")` is None (unused).
- `evt.getDisplayPath()` = `""` when unconfigured → fall back to parsing `getSource()`
(`prov:default:/tag:FOLDER/SUB/TAG:/alm:ALARMNAME`).
- `evt.getPriority()` → AlarmPriority enum: `.ordinal()` → 0..4, `str()` → name.
- System rows: `source == "evt:System Startup"` etc., `evt.get("isSystemEvent")` True.
`includeSystem`-style kwargs are ACCEPTED BUT IGNORED — always filter client-side.
- Ack user field: `evt.get("ackUserName")` (unicode, may be `u''`). `ackUser` is None.
- `system.alarm.queryStatus(state=["ActiveUnacked","ActiveAcked"])` works; entries have
`getActiveData()` with eventTime. `system.alarm.getShelvedPaths()` → list.
## Session props (only these exist; NO agent may add any)
`session.custom.PrimeControls`:
```json
{"query": {"startMs": 0, "endMs": 0, "rangePreset": "8h", "priorities": [], "areas": [],
"states": [], "search": "", "refreshToken": 0},
"ui": {"selectedTab": 0, "badActorFocus": ""}}
```
- `rangePreset``4h|8h|24h|7d|custom`. Header preset dropdown writes startMs/endMs/rangePreset.
- Filters (`priorities` = int levels 04, `areas` = strings, `states`
`["active","cleared","acked","unacked"]`, `search` substring) are written by FilterBar;
**Apply button bumps `refreshToken`** (filters do NOT auto-refetch).
- `ui.selectedTab`: 0 Overview · 1 Analysis · 2 Bad Actors · 3 Journal.
- `ui.badActorFocus`: source string; set by Overview top-5 click; BadActors highlights + clears.
## Data layer (script package `PrimeControls`, resource paths `ignition/script-python/PrimeControls/<mod>/code.py`)
Modules: `calc` (pure), `fmt` (pure), `alarms` (gateway adapter). Pure modules run under
CPython 3 for pytest AND Jython 2.7 (`from __future__ import division, print_function`).
### Perspective entry points (exact signatures)
```python
PrimeControls.alarms.getDashboardBundle(startMs, endMs, options=None) # -> bundle dict (below)
PrimeControls.alarms.getJournalPage(startMs, endMs, filters=None, page=0, pageSize=50)
# filters: {"priorities":[int], "areas":[str], "states":[str], "search":str}
# -> {"rows":[{"id","time_ms","time_label","source","label","area","state","state_label",
# "priority","priority_name","ack_user"}], "total":int, "page":int,
# "page_size":int, "truncated":bool, "error":None|str}
PrimeControls.alarms.journalCsv(startMs, endMs, filters=None, maxRows=10000) # -> CSV string
PrimeControls.alarms.getSourceDetail(source, startMs, endMs)
# -> {"label","area","events":[journal-page rows],"daily":[{"t0","count"}],
# "stats":{"count","avg_tta_ms","avg_active_ms","fleeting_count",
# "top_ack_users":[{"user","count"}]},"error":None|str}
PrimeControls.alarms.getEventData(eventId, aroundMs, source) # -> {"props":[{"name","value"}],"error":None|str}
PrimeControls.alarms.getShiftReportText(shiftHours=8, anchorHour=0, options=None)
# -> {"text":str, "start_ms":int, "end_ms":int, "label":str}
PrimeControls.fmt.dur(ms) / num(v, dec=0) / pct(v, dec=0, signed=False) / clock(ms) / day_clock(ms)
PrimeControls.fmt.delta_chip(d) # d = a kpi delta dict -> {"arrow","text","good"}
```
### Bundle schema (`getDashboardBundle` return — every key ALWAYS present)
```
meta: {start_ms, end_ms, prior_start_ms, now_ms, window_hours, event_count,
activation_count, dropped_rows, truncated, correlation_mode,
standing_mode, areas:[str], priorities_seen:[{"value":int,"label":str}],
source_count, error:None|str, opts:{...effective thresholds...}}
kpis: {activations, rate_per_hr, active_now, unacked_now, shelved_now, mtta_ms,
mttr_ms, flood_pct, flood_count, chatter_count, standing_count, fleeting_count}
# each value = {"value", "prior", "delta_pct", "dir": "up|down|flat|new|none", "good": bool|None}
health: {grade:"A".."F"|None, score:float|None,
subs:[{key,label,score:float|None,weight,detail}]} # keys: rate,flood,chatter,standing,priority
insights: [{severity:int(0 crit..3 info), icon:str, text:str, tab:str}]
rate: {bins:[{t0,t1,count,flood:bool}], bin_ms, target_per_bin, flood_threshold, max_count}
floods: {episodes:[{start_ms,end_ms,duration_ms,event_count,peak_bin_count,
top_source_label,top_source_count,top_area}], pct_time_in_flood}
priority: {raw:[{name,level,count}], buckets:{low,medium,high,other},
pct:{low,medium,high}, target:{low:80.0,medium:15.0,high:5.0}, sum_abs_dev}
heatmap: {rows:[[int]*24]*7, row_labels:["Mon".."Sun"], max_count, total}
mtta_mttr: {mtta:{mean_ms,median_ms,count}, mttr:{mean_ms,median_ms,count},
trend:[{t0,mtta_ms|None,mttr_ms|None,ack_n,clear_n}]}
pareto: {total_activations, rows:[{rank,source,label,area,priority_name,count,pct,cum_pct}]}
top_sources: [first 5 pareto rows]
chattering: [{source,label,area,priority_name,count,per_hour,median_gap_s}]
fleeting: {total, sources:[{source,label,area,priority_name,count,median_s}]}
standing: {mode, count, rows:[{source,label,area,priority_name,active_ms,age_ms,age_h,unacked}]}
active_now: [{source,label,area,priority_name,active_ms,age_ms,unacked}] # capped 200
```
Thresholds (surfaced in `meta.opts`): bins 10 min; flood >10/10min (end hysteresis 5);
ISA target 6/hr; chatter >10/hr AND median gap ≤120 s (min 5); fleeting <10 s;
standing >24 h; deltas flat band ±5%; caps: 50 000 events, 5000 bins, lists ≤50 rows.
## Binding patterns (copy these shapes exactly)
**P1 — bundle binding (Dashboard shell ONLY):** `custom.bundle` ← expr binding
```json
{"type": "expr",
"config": {"expression": "{session.custom.PrimeControls.query.refreshToken} + '|' + {session.custom.PrimeControls.query.startMs} + '|' + {session.custom.PrimeControls.query.endMs}"},
"transforms": [{"type": "script", "code": "\tq = self.session.custom.PrimeControls.query\n\treturn PrimeControls.alarms.getDashboardBundle(q.startMs, q.endMs, {'priorities': list(q.priorities), 'areas': list(q.areas), 'states': list(q.states), 'search': q.search})"}]}
```
**P2 — embed a sub-view with bundle + tab visibility:**
```json
{"meta": {"name": "tabOverview"}, "position": {"grow": 1},
"propConfig": {
"props.params.bundle": {"binding": {"type": "property", "config": {"path": "view.custom.bundle"}}},
"position.display": {"binding": {"type": "expr", "config": {"expression": "{session.custom.PrimeControls.ui.selectedTab} = 0"}}}},
"props": {"path": "PrimeControls/Tabs/Overview", "params": {}},
"type": "ia.display.view"}
```
**P3 — bidirectional session binding (FilterBar widgets):**
```json
{"binding": {"bidirectional": true, "type": "property",
"config": {"path": "session.custom.PrimeControls.query.search"}}}
```
**P4 — event scripts:** buttons/dropdowns fire `events.component.onActionPerformed`;
labels/icons/containers fire `events.dom.onClick` (Designer-verified shape). Action object
is identical for both: `{"config": {"script": "\t..."}, "scope": "G", "type": "script"}`.
```json
"events": {"dom": {"onClick": {"config": {"script": "\tsystem.perspective.openPopup('PC_HealthScore', 'PrimeControls/Popups/HealthScore', params = {'health': self.view.params.health}, showCloseIcon = True, draggable = True)"}, "scope": "G", "type": "script"}}}
```
**P5 — flex repeater from bundle slice:**
```json
{"type": "ia.display.flex-repeater",
"propConfig": {"props.instances": {"binding": {"type": "property", "config": {"path": "view.params.bundle.top_sources"}}}},
"props": {"path": "PrimeControls/Components/SourceRow", "direction": "column"}}
```
Repeater instance keys become the child view's params → **bundle array element keys ==
component view param names** (snake_case).
View param declaration: `"params": {"bundle": null}` + propConfig
`"params.bundle": {"paramDirection": "input", "persistent": true}`.
## Popups (IDs are constants)
| ID | View | Params |
|---|---|---|
| `PC_HealthScore` | `PrimeControls/Popups/HealthScore` | `{health: bundle.health}` |
| `PC_AlarmDetail` | `PrimeControls/Popups/AlarmDetail` | `{source, label}` |
| `PC_EventDetail` | `PrimeControls/Popups/EventDetail` | `{event: <journal row dict>}` |
| `PC_ShiftReport` | `PrimeControls/Popups/ShiftReport` | `{}` |
Close: `system.perspective.closePopup('<ID>')`.
## Style classes (foundation-owned; reference as `"style": {"classes": "PrimeControls/Card"}`)
`PrimeControls/Priority/{Diagnostic,Low,Medium,High,Critical}` (solid chip bg+fg) ·
`PrimeControls/PrioritySoft/{...same 5}` (tinted bg) ·
`PrimeControls/Grade/{A,B,C,D,F,NA}` · `PrimeControls/Card` · `PrimeControls/CardTitle` ·
`PrimeControls/Toolbar` · `PrimeControls/PageBg` · `PrimeControls/Chip/{Good,Bad,Flat}` ·
`PrimeControls/Tab/{Active,Inactive}` · `PrimeControls/State/{Active,Acked,Cleared}` ·
`PrimeControls/Text/{Big,Kpi,Muted}` · `PrimeControls/Empty`.
Priority scale: Diagnostic `#8A94A6` · Low `#5B9BD5` · Medium `#E5C453` · High `#E8883A` ·
Critical `#D64550`. Accent: `#3B7DD8`. Agents may ADD classes only under
`style-classes/PrimeControls/<TheirArea>/...`, never modify shared ones.
## Shared components (foundation-owned, under `views/PrimeControls/Components/`)
| View | Params (all input) |
|---|---|
| `Components/TabButton` | `title:str, index:int` (writes `ui.selectedTab` onClick; active style expr) |
| `Components/KpiCard` | `label:str, value:str, unit:str, delta:{...kpi delta}|null` (polarity already encoded in `delta.good`) |
| `Components/PriorityCard` | `priority_name:str, count:int, pct:float` |
| `Components/InsightRow` | `severity:int, icon:str, text:str, tab:str` |
| `Components/SourceRow` | `rank:int, source:str, label:str, count:int, pct:float` (click → focus+tab 2) |
| `Components/HeatmapCell` | `count:int, max:int` (bg alpha-scaled accent) |
| `Components/ScoreBar` | `key:str, label:str, score:float|null, weight:float, detail:str` |
| `Components/EmptyState` | `message:str, icon:str` |
| `Components/HealthGauge` | `health:{grade,score,subs}|null` (own dom.onClick opens PC_HealthScore with `{'health': ...}`) |
## View ownership (Phase 2/3)
A: `Dashboard/Header` + `Dashboard/FilterBar` · B: `Tabs/Overview` · C: `Tabs/Analysis` ·
D: `Tabs/BadActors` · E: `Tabs/Journal` · F: `Popups/HealthScore`+`Popups/ShiftReport` ·
G: `Popups/AlarmDetail`+`Popups/EventDetail` · H: `Components/HealthGauge` upgrade.
Integrator-only: `Dashboard/view.json`, session-props, page-config, shared Components,
root style classes, `script-python/*`, SimHarness.
## Verify loop (every agent, before declaring done)
```bash
python3 tools/lint_project.py
python3 tools/provision.py scan-projects
sleep 5; docker logs buildathon-ignition --since 1m 2>&1 | grep -iE "error|exception|traceback"
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8088/data/perspective/client/PrimeBAT
```
Schema uncertainty → read the harvested schema file; still unsure → minimal probe view in
`SimHarness/views/Scratch/Current` (coordinate via integrator), never guess deep chart JSON.

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,10 @@
{
"base": {
"style": {
"backgroundColor": "var(--neutral-10)",
"borderRadius": "8px",
"boxShadow": "0 1px 3px rgba(0,0,0,0.12)",
"padding": "12px"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,12 @@
{
"base": {
"style": {
"color": "var(--neutral-70)",
"fontSize": "12px",
"fontWeight": "bold",
"letterSpacing": "0.08em",
"marginBottom": "8px",
"textTransform": "uppercase"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,13 @@
{
"base": {
"style": {
"backgroundColor": "#D6455026",
"borderRadius": "10px",
"color": "#D64550",
"fontSize": "11px",
"fontWeight": "bold",
"paddingLeft": "6px",
"paddingRight": "6px"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,13 @@
{
"base": {
"style": {
"backgroundColor": "var(--neutral-30)",
"borderRadius": "10px",
"color": "var(--neutral-70)",
"fontSize": "11px",
"fontWeight": "bold",
"paddingLeft": "6px",
"paddingRight": "6px"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,13 @@
{
"base": {
"style": {
"backgroundColor": "#2E9E5B26",
"borderRadius": "10px",
"color": "#2E9E5B",
"fontSize": "11px",
"fontWeight": "bold",
"paddingLeft": "6px",
"paddingRight": "6px"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,9 @@
{
"base": {
"style": {
"color": "var(--neutral-50)",
"fontStyle": "italic",
"textAlign": "center"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,10 @@
{
"base": {
"style": {
"backgroundColor": "#2E9E5B",
"borderRadius": "8px",
"color": "#FFFFFF",
"fontWeight": "bold"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,10 @@
{
"base": {
"style": {
"backgroundColor": "#7CB342",
"borderRadius": "8px",
"color": "#FFFFFF",
"fontWeight": "bold"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,10 @@
{
"base": {
"style": {
"backgroundColor": "#E5C453",
"borderRadius": "8px",
"color": "#FFFFFF",
"fontWeight": "bold"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,10 @@
{
"base": {
"style": {
"backgroundColor": "#E8883A",
"borderRadius": "8px",
"color": "#FFFFFF",
"fontWeight": "bold"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,10 @@
{
"base": {
"style": {
"backgroundColor": "#D64550",
"borderRadius": "8px",
"color": "#FFFFFF",
"fontWeight": "bold"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,10 @@
{
"base": {
"style": {
"backgroundColor": "#8A94A6",
"borderRadius": "8px",
"color": "#FFFFFF",
"fontWeight": "bold"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,8 @@
{
"base": {
"style": {
"backgroundColor": "var(--neutral-20)",
"padding": "12px"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,15 @@
{
"base": {
"style": {
"backgroundColor": "#D64550",
"borderRadius": "4px",
"color": "#FFFFFF",
"fontSize": "12px",
"fontWeight": "bold",
"paddingBottom": "2px",
"paddingLeft": "8px",
"paddingRight": "8px",
"paddingTop": "2px"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,15 @@
{
"base": {
"style": {
"backgroundColor": "#8A94A6",
"borderRadius": "4px",
"color": "#FFFFFF",
"fontSize": "12px",
"fontWeight": "bold",
"paddingBottom": "2px",
"paddingLeft": "8px",
"paddingRight": "8px",
"paddingTop": "2px"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,15 @@
{
"base": {
"style": {
"backgroundColor": "#E8883A",
"borderRadius": "4px",
"color": "#FFFFFF",
"fontSize": "12px",
"fontWeight": "bold",
"paddingBottom": "2px",
"paddingLeft": "8px",
"paddingRight": "8px",
"paddingTop": "2px"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,15 @@
{
"base": {
"style": {
"backgroundColor": "#5B9BD5",
"borderRadius": "4px",
"color": "#FFFFFF",
"fontSize": "12px",
"fontWeight": "bold",
"paddingBottom": "2px",
"paddingLeft": "8px",
"paddingRight": "8px",
"paddingTop": "2px"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,15 @@
{
"base": {
"style": {
"backgroundColor": "#E5C453",
"borderRadius": "4px",
"color": "#FFFFFF",
"fontSize": "12px",
"fontWeight": "bold",
"paddingBottom": "2px",
"paddingLeft": "8px",
"paddingRight": "8px",
"paddingTop": "2px"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,10 @@
{
"base": {
"style": {
"backgroundColor": "#D6455026",
"borderRadius": "6px",
"color": "#D64550",
"fontWeight": "bold"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,10 @@
{
"base": {
"style": {
"backgroundColor": "#8A94A626",
"borderRadius": "6px",
"color": "#8A94A6",
"fontWeight": "bold"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,10 @@
{
"base": {
"style": {
"backgroundColor": "#E8883A26",
"borderRadius": "6px",
"color": "#E8883A",
"fontWeight": "bold"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,10 @@
{
"base": {
"style": {
"backgroundColor": "#5B9BD526",
"borderRadius": "6px",
"color": "#5B9BD5",
"fontWeight": "bold"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,10 @@
{
"base": {
"style": {
"backgroundColor": "#E5C45326",
"borderRadius": "6px",
"color": "#E5C453",
"fontWeight": "bold"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,8 @@
{
"base": {
"style": {
"backgroundColor": "#3B7DD818",
"color": "#3B7DD8"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,9 @@
{
"base": {
"style": {
"backgroundColor": "#D6455018",
"color": "#D64550",
"fontWeight": "bold"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,8 @@
{
"base": {
"style": {
"backgroundColor": "#2E9E5B18",
"color": "#2E9E5B"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,16 @@
{
"base": {
"style": {
"borderBottomColor": "#3B7DD8",
"borderBottomStyle": "solid",
"borderBottomWidth": "3px",
"color": "var(--neutral-90)",
"cursor": "pointer",
"fontWeight": "bold",
"paddingBottom": "6px",
"paddingLeft": "16px",
"paddingRight": "16px",
"paddingTop": "8px"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,23 @@
{
"base": {
"style": {
"borderBottomColor": "rgba(0,0,0,0)",
"borderBottomStyle": "solid",
"borderBottomWidth": "3px",
"color": "var(--neutral-60)",
"cursor": "pointer",
"paddingBottom": "6px",
"paddingLeft": "16px",
"paddingRight": "16px",
"paddingTop": "8px"
}
},
"variants": [
{
"pseudo": "hover",
"style": {
"color": "var(--neutral-90)"
}
}
]
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,9 @@
{
"base": {
"style": {
"color": "var(--neutral-90)",
"fontSize": "28px",
"fontWeight": "bold"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,9 @@
{
"base": {
"style": {
"color": "var(--neutral-90)",
"fontSize": "22px",
"fontWeight": "bold"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,8 @@
{
"base": {
"style": {
"color": "var(--neutral-60)",
"fontSize": "12px"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"style.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,10 @@
{
"base": {
"style": {
"backgroundColor": "var(--neutral-10)",
"borderRadius": "8px",
"boxShadow": "0 1px 3px rgba(0,0,0,0.12)",
"padding": "8px"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"view.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,93 @@
{
"custom": {},
"params": {
"icon": null,
"message": null
},
"propConfig": {
"params.icon": {
"paramDirection": "input",
"persistent": true
},
"params.message": {
"paramDirection": "input",
"persistent": true
}
},
"props": {},
"root": {
"children": [
{
"meta": {
"name": "icon"
},
"position": {
"basis": "48px",
"shrink": 0
},
"propConfig": {
"props.path": {
"binding": {
"config": {
"path": "view.params.icon"
},
"transforms": [
{
"code": "\treturn 'material/' + (value or 'inbox')",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"color": "var(--neutral-50)",
"path": "material/inbox",
"style": {
"fontSize": "40px"
}
},
"type": "ia.display.icon"
},
{
"meta": {
"name": "msg"
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.message"
},
"transforms": [
{
"code": "\treturn value or 'No alarm events in the selected range'",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"classes": "PrimeControls/Empty"
}
},
"type": "ia.display.label"
}
],
"meta": {
"name": "root"
},
"props": {
"direction": "column",
"style": {
"alignItems": "center",
"justifyContent": "center"
}
},
"type": "ia.container.flex"
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"view.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,137 @@
{
"custom": {},
"params": {
"health": null
},
"propConfig": {
"params.health": {
"paramDirection": "input",
"persistent": true
}
},
"props": {},
"root": {
"children": [
{
"meta": {
"name": "grade"
},
"propConfig": {
"props.style.classes": {
"binding": {
"config": {
"path": "view.params.health"
},
"transforms": [
{
"code": "\ttry:\n\t\tg = value['grade']\n\texcept:\n\t\tg = None\n\treturn 'PrimeControls/Grade/' + (g if g in ['A', 'B', 'C', 'D', 'F'] else 'NA')",
"type": "script"
}
],
"type": "property"
}
},
"props.text": {
"binding": {
"config": {
"path": "view.params.health"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn value['grade'] or 'N/A'\n\texcept:\n\t\treturn 'N/A'",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"fontSize": "30px",
"paddingBottom": "2px",
"paddingLeft": "14px",
"paddingRight": "14px",
"paddingTop": "2px",
"textAlign": "center"
}
},
"type": "ia.display.label"
},
{
"children": [
{
"meta": {
"name": "title"
},
"props": {
"style": {
"fontSize": "13px",
"fontWeight": "bold"
},
"text": "Alarm Health"
},
"type": "ia.display.label"
},
{
"meta": {
"name": "score"
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.health"
},
"transforms": [
{
"code": "\ttry:\n\t\ts = value['score']\n\t\treturn 'Score %d - click for detail' % round(s) if s is not None else 'no data in range'\n\texcept:\n\t\treturn 'no data in range'",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"classes": "PrimeControls/Text/Muted"
}
},
"type": "ia.display.label"
}
],
"meta": {
"name": "scoreCol"
},
"props": {
"direction": "column"
},
"type": "ia.container.flex"
}
],
"events": {
"dom": {
"onClick": {
"config": {
"script": "\tsystem.perspective.openPopup('PC_HealthScore', 'PrimeControls/Popups/HealthScore', params = {'health': self.view.params.health}, showCloseIcon = True, draggable = True)"
},
"scope": "G",
"type": "script"
}
}
},
"meta": {
"name": "root"
},
"props": {
"direction": "row",
"style": {
"alignItems": "center",
"cursor": "pointer",
"gap": "10px"
}
},
"type": "ia.container.flex"
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"view.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,94 @@
{
"custom": {},
"params": {
"count": 0,
"max": 0
},
"propConfig": {
"params.count": {
"paramDirection": "input",
"persistent": true
},
"params.max": {
"paramDirection": "input",
"persistent": true
}
},
"props": {},
"root": {
"children": [
{
"meta": {
"name": "cell"
},
"position": {
"grow": 1
},
"propConfig": {
"props.style.backgroundColor": {
"binding": {
"config": {
"path": "view.params.count"
},
"transforms": [
{
"code": "\ttry:\n\t\tm = self.view.params.max\n\t\tc = value or 0\n\t\tif not m or m <= 0 or c <= 0:\n\t\t\treturn 'rgba(59,125,216,0.06)'\n\t\ta = 0.15 + 0.85 * (float(c) / m)\n\t\treturn 'rgba(59,125,216,%.2f)' % min(a, 1.0)\n\texcept:\n\t\treturn 'rgba(59,125,216,0.06)'",
"type": "script"
}
],
"type": "property"
}
},
"props.style.color": {
"binding": {
"config": {
"path": "view.params.count"
},
"transforms": [
{
"code": "\ttry:\n\t\tm = self.view.params.max\n\t\tif m and value and float(value) / m > 0.55:\n\t\t\treturn '#FFFFFF'\n\texcept:\n\t\tpass\n\treturn 'var(--neutral-90)'",
"type": "script"
}
],
"type": "property"
}
},
"props.text": {
"binding": {
"config": {
"path": "view.params.count"
},
"transforms": [
{
"code": "\treturn '' if not value else value",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"borderRadius": "2px",
"fontSize": "10px",
"marginBottom": "1px",
"marginRight": "1px",
"textAlign": "center"
}
},
"type": "ia.display.label"
}
],
"meta": {
"name": "root"
},
"props": {
"direction": "row",
"style": {
"alignItems": "stretch"
}
},
"type": "ia.container.flex"
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"view.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,121 @@
{
"custom": {},
"params": {
"icon": null,
"severity": 3,
"tab": null,
"text": null
},
"propConfig": {
"params.icon": {
"paramDirection": "input",
"persistent": true
},
"params.severity": {
"paramDirection": "input",
"persistent": true
},
"params.tab": {
"paramDirection": "input",
"persistent": true
},
"params.text": {
"paramDirection": "input",
"persistent": true
}
},
"props": {},
"root": {
"children": [
{
"meta": {
"name": "icon"
},
"position": {
"basis": "24px",
"shrink": 0
},
"propConfig": {
"props.color": {
"binding": {
"config": {
"path": "view.params.severity"
},
"transforms": [
{
"code": "\tcolors = {0: '#D64550', 1: '#E8883A', 2: '#3B7DD8', 3: 'var(--neutral-60)'}\n\treturn colors.get(value, 'var(--neutral-60)')",
"type": "script"
}
],
"type": "property"
}
},
"props.path": {
"binding": {
"config": {
"path": "view.params.icon"
},
"transforms": [
{
"code": "\treturn 'material/' + (value or 'insights')",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"path": "material/insights",
"style": {
"fontSize": "18px"
}
},
"type": "ia.display.icon"
},
{
"meta": {
"name": "text"
},
"position": {
"grow": 1
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.text"
},
"transforms": [
{
"code": "\treturn value or ''",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"fontSize": "13px"
}
},
"type": "ia.display.label"
}
],
"meta": {
"name": "root"
},
"props": {
"direction": "row",
"style": {
"alignItems": "center",
"gap": "8px",
"paddingBottom": "4px",
"paddingTop": "4px"
}
},
"type": "ia.container.flex"
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"view.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,184 @@
{
"custom": {},
"params": {
"delta": null,
"label": "KPI",
"unit": null,
"value": null
},
"propConfig": {
"params.delta": {
"paramDirection": "input",
"persistent": true
},
"params.label": {
"paramDirection": "input",
"persistent": true
},
"params.unit": {
"paramDirection": "input",
"persistent": true
},
"params.value": {
"paramDirection": "input",
"persistent": true
}
},
"props": {},
"root": {
"children": [
{
"meta": {
"name": "lbl"
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.label"
},
"type": "property"
}
}
},
"props": {
"style": {
"classes": "PrimeControls/Text/Muted"
}
},
"type": "ia.display.label"
},
{
"children": [
{
"meta": {
"name": "value"
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.value"
},
"transforms": [
{
"code": "\treturn value if value is not None else '--'",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"classes": "PrimeControls/Text/Kpi"
}
},
"type": "ia.display.label"
},
{
"meta": {
"name": "unit"
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.unit"
},
"transforms": [
{
"code": "\treturn value or ''",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"classes": "PrimeControls/Text/Muted"
}
},
"type": "ia.display.label"
}
],
"meta": {
"name": "valueRow"
},
"props": {
"direction": "row",
"style": {
"alignItems": "baseline",
"gap": "4px"
}
},
"type": "ia.container.flex"
},
{
"meta": {
"name": "chip"
},
"propConfig": {
"position.display": {
"binding": {
"config": {
"path": "view.params.delta"
},
"transforms": [
{
"code": "\treturn value is not None",
"type": "script"
}
],
"type": "property"
}
},
"props.style.classes": {
"binding": {
"config": {
"path": "view.params.delta"
},
"transforms": [
{
"code": "\tbase = 'PrimeControls/Chip/Flat'\n\ttry:\n\t\tif value and value['good'] == True:\n\t\t\tbase = 'PrimeControls/Chip/Good'\n\t\telif value and value['good'] == False:\n\t\t\tbase = 'PrimeControls/Chip/Bad'\n\texcept:\n\t\tpass\n\treturn base",
"type": "script"
}
],
"type": "property"
}
},
"props.text": {
"binding": {
"config": {
"path": "view.params.delta"
},
"transforms": [
{
"code": "\tif not value:\n\t\treturn ''\n\ttry:\n\t\tchip = PrimeControls.fmt.delta_chip(value)\n\t\treturn '%s %s' % (chip['arrow'], chip['text'])\n\texcept:\n\t\treturn ''",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {},
"type": "ia.display.label"
}
],
"meta": {
"name": "root"
},
"props": {
"direction": "column",
"style": {
"classes": "PrimeControls/Card",
"justifyContent": "space-between"
}
},
"type": "ia.container.flex"
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"view.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,137 @@
{
"custom": {},
"params": {
"count": 0,
"pct": null,
"priority_name": null
},
"propConfig": {
"params.count": {
"paramDirection": "input",
"persistent": true
},
"params.pct": {
"paramDirection": "input",
"persistent": true
},
"params.priority_name": {
"paramDirection": "input",
"persistent": true
}
},
"props": {},
"root": {
"children": [
{
"meta": {
"name": "name"
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.priority_name"
},
"transforms": [
{
"code": "\treturn value or 'Unknown'",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"fontSize": "13px",
"fontWeight": "bold"
}
},
"type": "ia.display.label"
},
{
"meta": {
"name": "count"
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.count"
},
"transforms": [
{
"code": "\treturn PrimeControls.fmt.num(value)",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"classes": "PrimeControls/Text/Big"
}
},
"type": "ia.display.label"
},
{
"meta": {
"name": "pct"
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.pct"
},
"transforms": [
{
"code": "\treturn PrimeControls.fmt.pct(value) + ' of events' if value is not None else ''",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"classes": "PrimeControls/Text/Muted"
}
},
"type": "ia.display.label"
}
],
"meta": {
"name": "root"
},
"propConfig": {
"props.style.classes": {
"binding": {
"config": {
"path": "view.params.priority_name"
},
"transforms": [
{
"code": "\tnames = ['Diagnostic', 'Low', 'Medium', 'High', 'Critical']\n\tn = value if value in names else 'Diagnostic'\n\treturn 'PrimeControls/Card PrimeControls/PrioritySoft/' + n",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"direction": "column",
"style": {
"alignItems": "center",
"classes": "PrimeControls/Card",
"gap": "2px"
}
},
"type": "ia.container.flex"
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"view.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,207 @@
{
"custom": {},
"params": {
"detail": null,
"key": null,
"label": null,
"score": null,
"weight": null
},
"propConfig": {
"params.detail": {
"paramDirection": "input",
"persistent": true
},
"params.key": {
"paramDirection": "input",
"persistent": true
},
"params.label": {
"paramDirection": "input",
"persistent": true
},
"params.score": {
"paramDirection": "input",
"persistent": true
},
"params.weight": {
"paramDirection": "input",
"persistent": true
}
},
"props": {},
"root": {
"children": [
{
"children": [
{
"meta": {
"name": "lbl"
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.label"
},
"transforms": [
{
"code": "\treturn value or ''",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"fontSize": "13px",
"fontWeight": "bold"
}
},
"type": "ia.display.label"
},
{
"meta": {
"name": "score"
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.score"
},
"transforms": [
{
"code": "\treturn '%d' % round(value) if value is not None else 'N/A'",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"fontSize": "13px",
"fontWeight": "bold"
}
},
"type": "ia.display.label"
}
],
"meta": {
"name": "topRow"
},
"props": {
"direction": "row",
"style": {
"justifyContent": "space-between"
}
},
"type": "ia.container.flex"
},
{
"children": [
{
"children": [],
"meta": {
"name": "fill"
},
"propConfig": {
"props.style.backgroundColor": {
"binding": {
"config": {
"path": "view.params.score"
},
"transforms": [
{
"code": "\ttry:\n\t\ts = float(value)\n\texcept:\n\t\treturn 'var(--neutral-40)'\n\tif s >= 80:\n\t\treturn '#2E9E5B'\n\tif s >= 60:\n\t\treturn '#E5C453'\n\treturn '#D64550'",
"type": "script"
}
],
"type": "property"
}
},
"props.style.width": {
"binding": {
"config": {
"path": "view.params.score"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn '%d%%' % max(0, min(100, round(value)))\n\texcept:\n\t\treturn '0%'",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"direction": "row",
"style": {
"borderRadius": "4px"
}
},
"type": "ia.container.flex"
}
],
"meta": {
"name": "track"
},
"position": {
"basis": "8px",
"shrink": 0
},
"props": {
"direction": "row",
"style": {
"backgroundColor": "var(--neutral-30)",
"borderRadius": "4px"
}
},
"type": "ia.container.flex"
},
{
"meta": {
"name": "detail"
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.detail"
},
"transforms": [
{
"code": "\treturn value or ''",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"classes": "PrimeControls/Text/Muted"
}
},
"type": "ia.display.label"
}
],
"meta": {
"name": "root"
},
"props": {
"direction": "column",
"style": {
"gap": "2px",
"paddingBottom": "8px"
}
},
"type": "ia.container.flex"
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"view.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,192 @@
{
"custom": {},
"params": {
"count": 0,
"label": null,
"pct": null,
"rank": null,
"source": null
},
"propConfig": {
"params.count": {
"paramDirection": "input",
"persistent": true
},
"params.label": {
"paramDirection": "input",
"persistent": true
},
"params.pct": {
"paramDirection": "input",
"persistent": true
},
"params.rank": {
"paramDirection": "input",
"persistent": true
},
"params.source": {
"paramDirection": "input",
"persistent": true
}
},
"props": {},
"root": {
"children": [
{
"meta": {
"name": "rank"
},
"position": {
"basis": "24px",
"shrink": 0
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.rank"
},
"transforms": [
{
"code": "\treturn '#%s' % value if value is not None else ''",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"classes": "PrimeControls/Text/Muted"
}
},
"type": "ia.display.label"
},
{
"meta": {
"name": "lbl"
},
"position": {
"grow": 1
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.label"
},
"transforms": [
{
"code": "\treturn value or ''",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"fontSize": "13px",
"fontWeight": "bold"
}
},
"type": "ia.display.label"
},
{
"meta": {
"name": "count"
},
"position": {
"basis": "56px",
"shrink": 0
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.count"
},
"transforms": [
{
"code": "\treturn PrimeControls.fmt.num(value)",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"fontSize": "13px",
"fontWeight": "bold",
"textAlign": "right"
}
},
"type": "ia.display.label"
},
{
"meta": {
"name": "pct"
},
"position": {
"basis": "48px",
"shrink": 0
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.pct"
},
"transforms": [
{
"code": "\treturn PrimeControls.fmt.pct(value) if value is not None else ''",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"classes": "PrimeControls/Text/Muted",
"textAlign": "right"
}
},
"type": "ia.display.label"
}
],
"events": {
"dom": {
"onClick": {
"config": {
"script": "\tself.session.custom.PrimeControls.ui.badActorFocus = self.view.params.source\n\tself.session.custom.PrimeControls.ui.selectedTab = 2"
},
"scope": "G",
"type": "script"
}
}
},
"meta": {
"name": "root"
},
"props": {
"direction": "row",
"style": {
"alignItems": "center",
"borderBottomColor": "var(--neutral-30)",
"borderBottomStyle": "solid",
"borderBottomWidth": "1px",
"cursor": "pointer",
"gap": "8px",
"paddingBottom": "4px",
"paddingTop": "4px"
}
},
"type": "ia.container.flex"
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"view.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,69 @@
{
"custom": {},
"params": {
"index": 0,
"title": "Tab"
},
"propConfig": {
"params.index": {
"paramDirection": "input",
"persistent": true
},
"params.title": {
"paramDirection": "input",
"persistent": true
}
},
"props": {},
"root": {
"children": [
{
"events": {
"dom": {
"onClick": {
"config": {
"script": "\tself.session.custom.PrimeControls.ui.selectedTab = self.view.params.index"
},
"scope": "G",
"type": "script"
}
}
},
"meta": {
"name": "btn"
},
"propConfig": {
"props.style.classes": {
"binding": {
"config": {
"expression": "if({view.params.index} = {session.custom.PrimeControls.ui.selectedTab}, 'PrimeControls/Tab/Active', 'PrimeControls/Tab/Inactive')"
},
"type": "expr"
}
},
"props.text": {
"binding": {
"config": {
"path": "view.params.title"
},
"type": "property"
}
}
},
"props": {},
"type": "ia.display.label"
}
],
"meta": {
"name": "root"
},
"props": {
"direction": "row",
"style": {
"alignItems": "center",
"justifyContent": "center"
}
},
"type": "ia.container.flex"
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"view.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,68 @@
{
"custom": {},
"params": {
"bundle": null
},
"propConfig": {
"params.bundle": {
"paramDirection": "input",
"persistent": true
}
},
"props": {},
"root": {
"children": [
{
"meta": {
"name": "ph"
},
"props": {
"style": {
"classes": "PrimeControls/Empty"
},
"text": "Filter bar - built in Phase 2"
},
"type": "ia.display.label"
},
{
"meta": {
"name": "evt"
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn 'bundle: %s events in range' % value['meta']['event_count']\n\texcept:\n\t\treturn 'bundle: not loaded'",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"classes": "PrimeControls/Text/Muted"
}
},
"type": "ia.display.label"
}
],
"meta": {
"name": "root"
},
"props": {
"direction": "column",
"style": {
"alignItems": "center",
"classes": "PrimeControls/Card",
"justifyContent": "center"
}
},
"type": "ia.container.flex"
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"view.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,68 @@
{
"custom": {},
"params": {
"bundle": null
},
"propConfig": {
"params.bundle": {
"paramDirection": "input",
"persistent": true
}
},
"props": {},
"root": {
"children": [
{
"meta": {
"name": "ph"
},
"props": {
"style": {
"classes": "PrimeControls/Empty"
},
"text": "Header - built in Phase 2"
},
"type": "ia.display.label"
},
{
"meta": {
"name": "evt"
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn 'bundle: %s events in range' % value['meta']['event_count']\n\texcept:\n\t\treturn 'bundle: not loaded'",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"classes": "PrimeControls/Text/Muted"
}
},
"type": "ia.display.label"
}
],
"meta": {
"name": "root"
},
"props": {
"direction": "column",
"style": {
"alignItems": "center",
"classes": "PrimeControls/Card",
"justifyContent": "center"
}
},
"type": "ia.container.flex"
}
}

View File

@@ -1,7 +1,35 @@
{ {
"custom": {}, "custom": {
"bundle": null
},
"events": {
"system": {
"onStartup": {
"config": {
"script": "\tq = self.session.custom.PrimeControls.query\n\tif not q.startMs or q.startMs == 0:\n\t\tnow = system.date.toMillis(system.date.now())\n\t\tq.endMs = now\n\t\tq.startMs = now - 8 * 3600 * 1000\n\t\tq.rangePreset = '8h'"
},
"scope": "G",
"type": "script"
}
}
},
"params": {}, "params": {},
"propConfig": {}, "propConfig": {
"custom.bundle": {
"binding": {
"config": {
"expression": "{session.custom.PrimeControls.query.refreshToken} + '|' + {session.custom.PrimeControls.query.startMs} + '|' + {session.custom.PrimeControls.query.endMs}"
},
"transforms": [
{
"code": "\tq = self.session.custom.PrimeControls.query\n\tif not q.startMs or not q.endMs:\n\t\treturn None\n\treturn PrimeControls.alarms.getDashboardBundle(q.startMs, q.endMs, {'priorities': list(q.priorities), 'areas': list(q.areas), 'states': list(q.states), 'search': q.search})",
"type": "script"
}
],
"type": "expr"
}
}
},
"props": { "props": {
"defaultSize": { "defaultSize": {
"height": 900, "height": 900,
@@ -12,28 +40,291 @@
"children": [ "children": [
{ {
"meta": { "meta": {
"name": "lblPlaceholder" "name": "header"
}, },
"position": { "position": {
"grow": 0 "basis": "150px",
"grow": 0,
"shrink": 0
},
"propConfig": {
"props.params.bundle": {
"binding": {
"config": {
"path": "view.custom.bundle"
},
"type": "property"
}
}
}, },
"props": { "props": {
"text": "PrimeControls Dashboard - under construction (Phase 0 placeholder)", "params": {},
"textStyle": { "path": "PrimeControls/Dashboard/Header"
"fontSize": "1.2em" },
"type": "ia.display.view"
},
{
"meta": {
"name": "filterBar"
},
"position": {
"basis": "56px",
"grow": 0,
"shrink": 0
},
"propConfig": {
"props.params.bundle": {
"binding": {
"config": {
"path": "view.custom.bundle"
},
"type": "property"
}
} }
}, },
"type": "ia.display.label" "props": {
"params": {},
"path": "PrimeControls/Dashboard/FilterBar"
},
"type": "ia.display.view"
},
{
"children": [
{
"meta": {
"name": "tabBtn0"
},
"position": {
"basis": "140px",
"shrink": 0
},
"props": {
"params": {
"index": 0,
"title": "Overview"
},
"path": "PrimeControls/Components/TabButton"
},
"type": "ia.display.view"
},
{
"meta": {
"name": "tabBtn1"
},
"position": {
"basis": "140px",
"shrink": 0
},
"props": {
"params": {
"index": 1,
"title": "Analysis"
},
"path": "PrimeControls/Components/TabButton"
},
"type": "ia.display.view"
},
{
"meta": {
"name": "tabBtn2"
},
"position": {
"basis": "140px",
"shrink": 0
},
"props": {
"params": {
"index": 2,
"title": "Bad Actors"
},
"path": "PrimeControls/Components/TabButton"
},
"type": "ia.display.view"
},
{
"meta": {
"name": "tabBtn3"
},
"position": {
"basis": "140px",
"shrink": 0
},
"props": {
"params": {
"index": 3,
"title": "Journal"
},
"path": "PrimeControls/Components/TabButton"
},
"type": "ia.display.view"
}
],
"meta": {
"name": "tabBar"
},
"position": {
"basis": "42px",
"grow": 0,
"shrink": 0
},
"props": {
"direction": "row",
"style": {
"borderBottomColor": "var(--neutral-40)",
"borderBottomStyle": "solid",
"borderBottomWidth": "1px"
}
},
"type": "ia.container.flex"
},
{
"children": [
{
"meta": {
"name": "tabOverview"
},
"position": {
"grow": 1
},
"propConfig": {
"position.display": {
"binding": {
"config": {
"expression": "{session.custom.PrimeControls.ui.selectedTab} = 0"
},
"type": "expr"
}
},
"props.params.bundle": {
"binding": {
"config": {
"path": "view.custom.bundle"
},
"type": "property"
}
}
},
"props": {
"params": {},
"path": "PrimeControls/Tabs/Overview"
},
"type": "ia.display.view"
},
{
"meta": {
"name": "tabAnalysis"
},
"position": {
"grow": 1
},
"propConfig": {
"position.display": {
"binding": {
"config": {
"expression": "{session.custom.PrimeControls.ui.selectedTab} = 1"
},
"type": "expr"
}
},
"props.params.bundle": {
"binding": {
"config": {
"path": "view.custom.bundle"
},
"type": "property"
}
}
},
"props": {
"params": {},
"path": "PrimeControls/Tabs/Analysis"
},
"type": "ia.display.view"
},
{
"meta": {
"name": "tabBadActors"
},
"position": {
"grow": 1
},
"propConfig": {
"position.display": {
"binding": {
"config": {
"expression": "{session.custom.PrimeControls.ui.selectedTab} = 2"
},
"type": "expr"
}
},
"props.params.bundle": {
"binding": {
"config": {
"path": "view.custom.bundle"
},
"type": "property"
}
}
},
"props": {
"params": {},
"path": "PrimeControls/Tabs/BadActors"
},
"type": "ia.display.view"
},
{
"meta": {
"name": "tabJournal"
},
"position": {
"grow": 1
},
"propConfig": {
"position.display": {
"binding": {
"config": {
"expression": "{session.custom.PrimeControls.ui.selectedTab} = 3"
},
"type": "expr"
}
},
"props.params.bundle": {
"binding": {
"config": {
"path": "view.custom.bundle"
},
"type": "property"
}
}
},
"props": {
"params": {},
"path": "PrimeControls/Tabs/Journal"
},
"type": "ia.display.view"
}
],
"meta": {
"name": "tabContent"
},
"position": {
"grow": 1
},
"props": {
"direction": "column"
},
"type": "ia.container.flex"
} }
], ],
"custom": {},
"meta": { "meta": {
"name": "root" "name": "root"
}, },
"props": { "props": {
"alignItems": "center",
"direction": "column", "direction": "column",
"justify": "center" "style": {
"classes": "PrimeControls/PageBg",
"gap": "10px"
}
}, },
"type": "ia.container.flex" "type": "ia.container.flex"
} }

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"view.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,68 @@
{
"custom": {},
"params": {
"bundle": null
},
"propConfig": {
"params.bundle": {
"paramDirection": "input",
"persistent": true
}
},
"props": {},
"root": {
"children": [
{
"meta": {
"name": "ph"
},
"props": {
"style": {
"classes": "PrimeControls/Empty"
},
"text": "Analysis - built in Phase 2"
},
"type": "ia.display.label"
},
{
"meta": {
"name": "evt"
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn 'bundle: %s events in range' % value['meta']['event_count']\n\texcept:\n\t\treturn 'bundle: not loaded'",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"classes": "PrimeControls/Text/Muted"
}
},
"type": "ia.display.label"
}
],
"meta": {
"name": "root"
},
"props": {
"direction": "column",
"style": {
"alignItems": "center",
"classes": "PrimeControls/Card",
"justifyContent": "center"
}
},
"type": "ia.container.flex"
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"view.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,68 @@
{
"custom": {},
"params": {
"bundle": null
},
"propConfig": {
"params.bundle": {
"paramDirection": "input",
"persistent": true
}
},
"props": {},
"root": {
"children": [
{
"meta": {
"name": "ph"
},
"props": {
"style": {
"classes": "PrimeControls/Empty"
},
"text": "Bad Actors - built in Phase 2"
},
"type": "ia.display.label"
},
{
"meta": {
"name": "evt"
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn 'bundle: %s events in range' % value['meta']['event_count']\n\texcept:\n\t\treturn 'bundle: not loaded'",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"classes": "PrimeControls/Text/Muted"
}
},
"type": "ia.display.label"
}
],
"meta": {
"name": "root"
},
"props": {
"direction": "column",
"style": {
"alignItems": "center",
"classes": "PrimeControls/Card",
"justifyContent": "center"
}
},
"type": "ia.container.flex"
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"view.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,68 @@
{
"custom": {},
"params": {
"bundle": null
},
"propConfig": {
"params.bundle": {
"paramDirection": "input",
"persistent": true
}
},
"props": {},
"root": {
"children": [
{
"meta": {
"name": "ph"
},
"props": {
"style": {
"classes": "PrimeControls/Empty"
},
"text": "Journal - built in Phase 2"
},
"type": "ia.display.label"
},
{
"meta": {
"name": "evt"
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn 'bundle: %s events in range' % value['meta']['event_count']\n\texcept:\n\t\treturn 'bundle: not loaded'",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"classes": "PrimeControls/Text/Muted"
}
},
"type": "ia.display.label"
}
],
"meta": {
"name": "root"
},
"props": {
"direction": "column",
"style": {
"alignItems": "center",
"classes": "PrimeControls/Card",
"justifyContent": "center"
}
},
"type": "ia.container.flex"
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"view.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,68 @@
{
"custom": {},
"params": {
"bundle": null
},
"propConfig": {
"params.bundle": {
"paramDirection": "input",
"persistent": true
}
},
"props": {},
"root": {
"children": [
{
"meta": {
"name": "ph"
},
"props": {
"style": {
"classes": "PrimeControls/Empty"
},
"text": "Overview - built in Phase 2"
},
"type": "ia.display.label"
},
{
"meta": {
"name": "evt"
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn 'bundle: %s events in range' % value['meta']['event_count']\n\texcept:\n\t\treturn 'bundle: not loaded'",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"classes": "PrimeControls/Text/Muted"
}
},
"type": "ia.display.label"
}
],
"meta": {
"name": "root"
},
"props": {
"direction": "column",
"style": {
"alignItems": "center",
"classes": "PrimeControls/Card",
"justifyContent": "center"
}
},
"type": "ia.container.flex"
}
}

View File

@@ -42,7 +42,9 @@ STRING_BANS = [
(re.compile(r"journalName\s*="), "hardcoded journalName= (judges' journal name unknown)"), (re.compile(r"journalName\s*="), "hardcoded journalName= (judges' journal name unknown)"),
(re.compile(r"\bsystem\.db\."), "system.db.* SQL access (journal API only)"), (re.compile(r"\bsystem\.db\."), "system.db.* SQL access (journal API only)"),
(re.compile(r"\bSELECT\s+", re.IGNORECASE), "raw SQL SELECT"), (re.compile(r"\bSELECT\s+", re.IGNORECASE), "raw SQL SELECT"),
(re.compile(r"""(^|[^A-Za-z0-9_])[fF]["']"""), "f-string (Jython 2.7 cannot parse)"), # f-string prefix: f/F immediately followed by a quote, not itself preceded by a
# quote (excludes string literals like 'F') or word char (excludes identifiers).
(re.compile(r"""(^|[^A-Za-z0-9_'"])[fF]["']"""), "f-string (Jython 2.7 cannot parse)"),
(re.compile(r"system\.util\.sendRequest\("), "sendRequest dev bridge leftover"), (re.compile(r"system\.util\.sendRequest\("), "sendRequest dev bridge leftover"),
] ]