refactor(ui): prioritize permitted operational views and touch topology

This commit is contained in:
Joseph Doherty
2026-11-13 19:24:12 -05:00
parent 0c41b613ac
commit 9dbfe7bcaf
70 changed files with 13050 additions and 96 deletions
@@ -115,3 +115,19 @@ The broad presentation fixture initially used a hyphenated value that could wrap
The reduced-motion matrix alone did not cover two existing opacity paths: pending pills faded to0.6 mid-animation, and predicted ghost groups faded all labels to0.45. Focused actual before proof is pending-motion-before.json and ghost-opacity-before.json (the fixture now supplies a real PredictedFlow overlay). The decorative pending fade is removed; ghost text stays opaque while its existing dashed shape/tinted fill still conveys prediction. No state mapping, edge math, poll or callback change. The reduced-motion matrix alone did not cover two existing opacity paths: pending pills faded to0.6 mid-animation, and predicted ghost groups faded all labels to0.45. Focused actual before proof is pending-motion-before.json and ghost-opacity-before.json (the fixture now supplies a real PredictedFlow overlay). The decorative pending fade is removed; ghost text stays opaque while its existing dashed shape/tinted fill still conveys prediction. No state mapping, edge math, poll or callback change.
Focused after proof covers light/dark × normal/reduced motion, four cases: pending opacity1/no animation, ghost group opacity1, and actual title/caption/pill text contrast at least4.5:1. The SVG ghost-background calculation composites its actual fill opacity over the actual alternate lane and wrap surfaces, rather than ignoring ancestor opacity. Existing FlowGraph/FlowDebugger/FlowTrace semantics118/118 tests pass (flow-opacity-focused.log). This is a narrow readability correction after the reduced-motion matrix, not a third broad screenshot review. Last full functional baseline remains1582/1582 with only these CSS opacity changes following it. Focused after proof covers light/dark × normal/reduced motion, four cases: pending opacity1/no animation, ghost group opacity1, and actual title/caption/pill text contrast at least4.5:1. The SVG ghost-background calculation composites its actual fill opacity over the actual alternate lane and wrap surfaces, rather than ignoring ancestor opacity. Existing FlowGraph/FlowDebugger/FlowTrace semantics118/118 tests pass (flow-opacity-focused.log). This is a narrow readability correction after the reduced-motion matrix, not a third broad screenshot review. Last full functional baseline remains1582/1582 with only these CSS opacity changes following it.
## SB10–12: policy shortcuts, observation summaries and topology composition
SB07–09 reviewed source/evidence was committed as `0c41b613`. This next batch is isolated to Dashboard/Health/Topology, TreeView scoped CSS, site.css, and DashboardStateTests/HealthPageTests, plus read-only fixture tooling and evidence.
- **SB10:** Dashboard shortcuts evaluate the exact `RequireDesign` and `OperationalAudit` policies used by the destination routes and rail. Health stays authenticated-only. Real-policy tests distinguish Viewer, Designer, Deployer, Administrator-only, unmapped and expanded multi-role principals. Administrator-only does not satisfy current RequireDesign; no role mapping or route policy was broadened. The initial test premise that it did was corrected transparently; raw failing logs remain. Six actual synthetic principal checks across the suite and four browser rail/shortcut comparisons cover these distinctions.
- **SB11:** Dashboard's four independent configured facts use shared aggregate geometry in a compact four/two/one-column composition; count-loading/failure/retry/single-flight behavior is unchanged. Health exposes online/offline/latest-interval-errors/unknown-metrics facts before its existing KPI groups. Site cards prioritize known offline observations, existing stale/backlog/reconciler/mirror/rejected-row/latest-interval conditions, missing reports, then remaining observations, with display-name and ordinal-id tie-breakers. This is presentation ordering, not a new fleet health aggregation or guarantee of healthy state. Heartbeat-only sites keep known Online liveness and explicitly say Metrics unknown. Script/alarm/dead-letter counters are atomically reset by SiteHealthCollector, so the former active-errors caption now says errors in last report interval; cumulative event-log failure badges and all existing failover/KPI/polling semantics remain unchanged. Native narrow inspection found the existing trend-window group extending to452px at390px; wrapping its existing header containers corrected it without changing query handlers.
- **SB12:** Topology no longer subtracts a guessed240px from viewport height. On narrow/short screens its tree follows document flow; roomy desktop uses actual flex available space and dvh-compatible height with a usable minimum tree region. Coarse pointers receive44px expand/content/button regions and always-visible existing row menus, while fine-pointer density and all lazy-loading, selection, search qualification, paging and poll/concurrency handlers remain unchanged. Its scope remains loaded sites/areas/instances. Checkbox-mode input semantics are unchanged; this batch does not claim a44px checkbox-input target across every TreeView consumer.
Validation: red-policy-health.log retains six intended preimplementation failures. Additional retained logs show the missing Razor using, real-auth fixture correction (bUnit's preexisting test cascade had masked the registered provider), and mistaken Administrator-only expectation; none was hidden or resolved by weakening authorization. The final focused behavior run passed101/101; full suite passed1591/1591, zero skipped/failed, in sb10-12-final.trx. Only the subsequent Health wrapping classes changed after that full run; final-wrap-focused.log passed101/101. No package dependency or backend model changed in this batch.
Browser acceptance is summarized explicitly in evidence/sb10-12/acceptance.json:22 accepted cases combine actual light/dark topology+Health at1440/768-short/390/real200% (720 CSS pixels/DPR2), four real-policy rail/shortcut fixtures, and two verified coarse contexts. Loaded topology includes12 synthetic sites ×6 areas, deliberately long names, actual lazy Load instances→Page1, existing loaded-search wording and native keyboard navigation. Health shows offline→warning→unknown→healthy ordering with unknown separated from known liveness. All accepted document widths fit; focus remains reachable after native smooth scrolling settles; coarse expand regions measure44×44px and rows≥44px. Mobile dark Health and touch screenshots were visually inspected.
The first pass stopped at missing fixture-only AuthorizedManualFailoverService DI before Health could render. After adding the real authorization wrapper over a rejecting synthetic backend, the retained initial22-case JSON recorded19 passes, including requested dark cases that actually stayed light and a false coarse context; those do not establish dark/touch acceptance. Final broad progress20 contains actual light/dark measurements but stopped awaiting coarse initialization. Its six immediate End-key geometry failures were measured before Bootstrap's existing smooth document scroll settled (timing proof retained). Focused confirmation waits for the actual last treeitem and viewport geometry, passing6/6 without keyboard source changes; two additional contexts explicitly verify CDP native touch emulation (maxTouchPoints1, pointer:coarse) and pass2/2. Raw failures, progress, scripts and corrected measurements remain separate; no all-first-pass-success claim is made.
The disposable localhost5201 host renders actual components/real policies with synthetic roles and rejecting read-only adapters. It has no database, fleet/actor system, LDAP or COM connection and is not complete application authorization/route acceptance. G1 historical evidence is unchanged. SB00 remains pending the published shared Secrets.Ui1.0.1 contrast patch and complete consumer baseline; no local undefined-token alias or caption override was introduced. No deployment or production name inventory was performed.
@@ -0,0 +1,259 @@
{
"cases": 22,
"passed": 22,
"records": [
{
"kind": "topology",
"scheme": "light",
"role": null,
"requested": [
1440,
900
],
"zoom": 1,
"passed": true,
"source": "browser-final/progress.json"
},
{
"kind": "topology",
"scheme": "light",
"requested": [
768,
480
],
"zoom": 1,
"passed": true,
"source": "browser-final/progress.json + focused-keyboard-touch-confirmation.json",
"supersedes": "immediate pre-scroll focus geometry"
},
{
"kind": "topology",
"scheme": "light",
"requested": [
390,
844
],
"zoom": 1,
"passed": true,
"source": "browser-final/progress.json + focused-keyboard-touch-confirmation.json",
"supersedes": "immediate pre-scroll focus geometry"
},
{
"kind": "topology",
"scheme": "light",
"requested": [
1440,
900
],
"zoom": 2,
"passed": true,
"source": "browser-final/progress.json + focused-keyboard-touch-confirmation.json",
"supersedes": "immediate pre-scroll focus geometry"
},
{
"kind": "topology",
"scheme": "dark",
"role": null,
"requested": [
1440,
900
],
"zoom": 1,
"passed": true,
"source": "browser-final/progress.json"
},
{
"kind": "topology",
"scheme": "dark",
"requested": [
768,
480
],
"zoom": 1,
"passed": true,
"source": "browser-final/progress.json + focused-keyboard-touch-confirmation.json",
"supersedes": "immediate pre-scroll focus geometry"
},
{
"kind": "topology",
"scheme": "dark",
"requested": [
390,
844
],
"zoom": 1,
"passed": true,
"source": "browser-final/progress.json + focused-keyboard-touch-confirmation.json",
"supersedes": "immediate pre-scroll focus geometry"
},
{
"kind": "topology",
"scheme": "dark",
"requested": [
1440,
900
],
"zoom": 2,
"passed": true,
"source": "browser-final/progress.json + focused-keyboard-touch-confirmation.json",
"supersedes": "immediate pre-scroll focus geometry"
},
{
"kind": "health",
"scheme": "light",
"role": null,
"requested": [
1440,
900
],
"zoom": 1,
"passed": true,
"source": "browser-final/progress.json"
},
{
"kind": "health",
"scheme": "light",
"role": null,
"requested": [
768,
480
],
"zoom": 1,
"passed": true,
"source": "browser-final/progress.json"
},
{
"kind": "health",
"scheme": "light",
"role": null,
"requested": [
390,
844
],
"zoom": 1,
"passed": true,
"source": "browser-final/progress.json"
},
{
"kind": "health",
"scheme": "light",
"role": null,
"requested": [
1440,
900
],
"zoom": 2,
"passed": true,
"source": "browser-final/progress.json"
},
{
"kind": "health",
"scheme": "dark",
"role": null,
"requested": [
1440,
900
],
"zoom": 1,
"passed": true,
"source": "browser-final/progress.json"
},
{
"kind": "health",
"scheme": "dark",
"role": null,
"requested": [
768,
480
],
"zoom": 1,
"passed": true,
"source": "browser-final/progress.json"
},
{
"kind": "health",
"scheme": "dark",
"role": null,
"requested": [
390,
844
],
"zoom": 1,
"passed": true,
"source": "browser-final/progress.json"
},
{
"kind": "health",
"scheme": "dark",
"role": null,
"requested": [
1440,
900
],
"zoom": 2,
"passed": true,
"source": "browser-final/progress.json"
},
{
"kind": "policy",
"scheme": null,
"role": "Viewer",
"requested": null,
"zoom": null,
"passed": true,
"source": "browser-final/progress.json"
},
{
"kind": "policy",
"scheme": null,
"role": "Designer",
"requested": null,
"zoom": null,
"passed": true,
"source": "browser-final/progress.json"
},
{
"kind": "policy",
"scheme": null,
"role": "Deployer",
"requested": null,
"zoom": null,
"passed": true,
"source": "browser-final/progress.json"
},
{
"kind": "policy",
"scheme": null,
"role": "Administrator,Designer,Deployer",
"requested": null,
"zoom": null,
"passed": true,
"source": "browser-final/progress.json"
},
{
"kind": "touch",
"requested": [
390,
844
],
"passed": true,
"source": "focused-keyboard-touch-confirmation.json"
},
{
"kind": "touch",
"requested": [
768,
480
],
"passed": true,
"source": "focused-keyboard-touch-confirmation.json"
}
],
"limitations": [
"Synthetic actual-component host; not complete application auth/route baseline",
"First interrupted run failed missing fixture DI; initial22-case JSON19passes includes actual-light dark requests and unverified touch, not accepted dark/touch proof",
"Final broad pass interrupted waiting for falsely requested touch; raw progress20 records retained",
"Six immediate keyboard geometry failures superseded by focused settled native-scroll measurements; no source keyboard behavior changed",
"No production scan, fleet queries, deployments, LDAP, COM or database writes"
]
}
@@ -0,0 +1,17 @@
[
{
"path": "src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Dashboard.razor",
"eventAndBindingExpressionsPreserved": true,
"routeAuthorizeAttributesPreserved": true
},
{
"path": "src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Deployment/Topology.razor",
"eventAndBindingExpressionsPreserved": true,
"routeAuthorizeAttributesPreserved": true
},
{
"path": "src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Monitoring/Health.razor",
"eventAndBindingExpressionsPreserved": true,
"routeAuthorizeAttributesPreserved": true
}
]
@@ -0,0 +1,116 @@
{
"cases": 22,
"passed": 19,
"failures": [
{
"width": 390,
"dpr": 1,
"document": 452,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 1,
"requested": [
390,
844
],
"errors": [],
"passed": false
},
{
"width": 390,
"dpr": 1,
"document": 452,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 1,
"requested": [
390,
844
],
"errors": [],
"passed": false
},
{
"width": 390,
"document": 390,
"coarse": false,
"rows": [
51.21875,
51.21875,
51.21875,
51.21875,
51.21875,
51.21875,
51.21875,
51.21875
],
"toggles": [
{
"width": 20,
"height": 21.609375
},
{
"width": 20,
"height": 21.609375
},
{
"width": 20,
"height": 21.609375
},
{
"width": 20,
"height": 21.609375
},
{
"width": 20,
"height": 21.609375
},
{
"width": 20,
"height": 21.609375
},
{
"width": 20,
"height": 21.609375
},
{
"width": 20,
"height": 21.609375
}
],
"overflow": "visible",
"kind": "touch",
"requested": [
390,
844
],
"passed": false
}
]
}
@@ -0,0 +1,34 @@
Traceback (most recent call last):
File "/Users/dohertj2/Desktop/ScadaBridge/infra/tools/inspect_operations.py", line 54, in <module>
main()
~~~~^^
File "/Users/dohertj2/Desktop/ScadaBridge/infra/tools/inspect_operations.py", line 48, in main
page=touch.new_page();page.goto('http://127.0.0.1:5201/topology-canary?role=Deployer');page.locator('.tv-root').wait_for();page.wait_for_function("matchMedia('(pointer:coarse)').matches")
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/lib/python3.14/site-packages/playwright/sync_api/_generated.py", line 11599, in wait_for_function
self._sync(
~~~~~~~~~~^
self._impl_obj.wait_for_function(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...<4 lines>...
)
^
)
^
File "/opt/homebrew/lib/python3.14/site-packages/playwright/_impl/_sync_base.py", line 115, in _sync
return task.result()
~~~~~~~~~~~^^
File "/opt/homebrew/lib/python3.14/site-packages/playwright/_impl/_page.py", line 1110, in wait_for_function
return await self._main_frame.wait_for_function(**locals_to_params(locals()))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/lib/python3.14/site-packages/playwright/_impl/_frame.py", line 878, in wait_for_function
await self._channel.send("waitForFunction", self._timeout, params)
File "/opt/homebrew/lib/python3.14/site-packages/playwright/_impl/_connection.py", line 69, in send
return await self._connection.wrap_api_call(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...<3 lines>...
)
^
File "/opt/homebrew/lib/python3.14/site-packages/playwright/_impl/_connection.py", line 559, in wrap_api_call
raise rewrite_error(error, f"{parsed_st['apiName']}: {error}") from None
playwright._impl._errors.TimeoutError: Page.wait_for_function: Timeout 30000ms exceeded.
Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

@@ -0,0 +1,574 @@
[
{
"width": 1440,
"dpr": 1,
"document": 1440,
"scheme": "light",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 631,
"scroll": 2921,
"overflow": "auto"
},
"rows": [
29.609375,
29.609375,
29.609375,
29.609375,
29.609375
],
"endFocus": {
"role": "treeitem",
"bottom": 859.5,
"viewport": 900
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 1,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"width": 768,
"dpr": 1,
"document": 768,
"scheme": "light",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 2921,
"scroll": 2921,
"overflow": "visible"
},
"rows": [
29.609375,
29.609375,
29.609375,
29.609375,
29.609375
],
"endFocus": {
"role": "treeitem",
"bottom": 3227.578125,
"viewport": 480
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 1,
"requested": [
768,
480
],
"errors": [],
"passed": false
},
{
"width": 390,
"dpr": 1,
"document": 390,
"scheme": "light",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 4736,
"scroll": 4736,
"overflow": "visible"
},
"rows": [
51.21875,
51.21875,
51.21875,
51.21875,
51.21875
],
"endFocus": {
"role": "treeitem",
"bottom": 5140.625,
"viewport": 844
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 1,
"requested": [
390,
844
],
"errors": [],
"passed": false
},
{
"width": 720,
"dpr": 2,
"document": 720,
"scheme": "light",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 2919,
"scroll": 2919,
"overflow": "visible"
},
"rows": [
29.59375,
29.59375,
29.59375,
29.59375,
29.59375
],
"endFocus": {
"role": "treeitem",
"bottom": 3246.5390625,
"viewport": 450
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 2,
"requested": [
1440,
900
],
"errors": [],
"passed": false
},
{
"width": 1440,
"dpr": 1,
"document": 1440,
"scheme": "dark",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 631,
"scroll": 2921,
"overflow": "auto"
},
"rows": [
29.609375,
29.609375,
29.609375,
29.609375,
29.609375
],
"endFocus": {
"role": "treeitem",
"bottom": 859.5,
"viewport": 900
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 1,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"width": 768,
"dpr": 1,
"document": 768,
"scheme": "dark",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 2921,
"scroll": 2921,
"overflow": "visible"
},
"rows": [
29.609375,
29.609375,
29.609375,
29.609375,
29.609375
],
"endFocus": {
"role": "treeitem",
"bottom": 3222.578125,
"viewport": 480
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 1,
"requested": [
768,
480
],
"errors": [],
"passed": false
},
{
"width": 390,
"dpr": 1,
"document": 390,
"scheme": "dark",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 4736,
"scroll": 4736,
"overflow": "visible"
},
"rows": [
51.21875,
51.21875,
51.21875,
51.21875,
51.21875
],
"endFocus": {
"role": "treeitem",
"bottom": 5140.625,
"viewport": 844
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 1,
"requested": [
390,
844
],
"errors": [],
"passed": false
},
{
"width": 720,
"dpr": 2,
"document": 720,
"scheme": "dark",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 2919,
"scroll": 2919,
"overflow": "visible"
},
"rows": [
29.59375,
29.59375,
29.59375,
29.59375,
29.59375
],
"endFocus": {
"role": "treeitem",
"bottom": 3247.5390625,
"viewport": 450
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 2,
"requested": [
1440,
900
],
"errors": [],
"passed": false
},
{
"width": 1440,
"dpr": 1,
"document": 1440,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 1,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"width": 768,
"dpr": 1,
"document": 768,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 1,
"requested": [
768,
480
],
"errors": [],
"passed": true
},
{
"width": 390,
"dpr": 1,
"document": 390,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 1,
"requested": [
390,
844
],
"errors": [],
"passed": true
},
{
"width": 720,
"dpr": 2,
"document": 720,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 2,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"width": 1440,
"dpr": 1,
"document": 1440,
"scheme": "dark",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 1,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"width": 768,
"dpr": 1,
"document": 768,
"scheme": "dark",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 1,
"requested": [
768,
480
],
"errors": [],
"passed": true
},
{
"width": 390,
"dpr": 1,
"document": 390,
"scheme": "dark",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 1,
"requested": [
390,
844
],
"errors": [],
"passed": true
},
{
"width": 720,
"dpr": 2,
"document": 720,
"scheme": "dark",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 2,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"kind": "policy",
"role": "Viewer",
"shortcuts": {
"/design/templates": 0,
"/audit/configuration": 1
},
"rail": {
"/design/templates": 0,
"/audit/configuration": 1
},
"passed": true
},
{
"kind": "policy",
"role": "Designer",
"shortcuts": {
"/design/templates": 1,
"/audit/configuration": 0
},
"rail": {
"/design/templates": 1,
"/audit/configuration": 0
},
"passed": true
},
{
"kind": "policy",
"role": "Deployer",
"shortcuts": {
"/design/templates": 0,
"/audit/configuration": 0
},
"rail": {
"/design/templates": 0,
"/audit/configuration": 0
},
"passed": true
},
{
"kind": "policy",
"role": "Administrator,Designer,Deployer",
"shortcuts": {
"/design/templates": 1,
"/audit/configuration": 1
},
"rail": {
"/design/templates": 1,
"/audit/configuration": 1
},
"passed": true
}
]
Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

@@ -0,0 +1,17 @@
Traceback (most recent call last):
File "/Users/dohertj2/Desktop/ScadaBridge/infra/tools/inspect_operations.py", line 47, in <module>
asyncio.run(main())
~~~~~~~~~~~^^^^^^^^
File "/opt/homebrew/Cellar/python@3.14/3.14.3_1/Frameworks/Python.framework/Versions/3.14/lib/python3.14/asyncio/runners.py", line 204, in run
return runner.run(main)
~~~~~~~~~~^^^^^^
File "/opt/homebrew/Cellar/python@3.14/3.14.3_1/Frameworks/Python.framework/Versions/3.14/lib/python3.14/asyncio/runners.py", line 127, in run
return self._loop.run_until_complete(task)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/opt/homebrew/Cellar/python@3.14/3.14.3_1/Frameworks/Python.framework/Versions/3.14/lib/python3.14/asyncio/base_events.py", line 719, in run_until_complete
return future.result()
~~~~~~~~~~~~~^^
File "/Users/dohertj2/Desktop/ScadaBridge/infra/tools/inspect_operations.py", line 11, in main
context,worker=await zoom_browser(p)
^^^^^^^^^^^^^^^^^^^^^
TypeError: '_GeneratorContextManager' object can't be awaited
@@ -0,0 +1,40 @@
Traceback (most recent call last):
File "/Users/dohertj2/Desktop/ScadaBridge/infra/tools/inspect_operations.py", line 46, in <module>
main()
~~~~^^
File "/Users/dohertj2/Desktop/ScadaBridge/infra/tools/inspect_operations.py", line 19, in main
page.goto('http://127.0.0.1:5201/'+route)
~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/lib/python3.14/site-packages/playwright/sync_api/_generated.py", line 9054, in goto
self._sync(
~~~~~~~~~~^
self._impl_obj.goto(
^^^^^^^^^^^^^^^^^^^^
url=url, timeout=timeout, waitUntil=wait_until, referer=referer
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
)
^
File "/opt/homebrew/lib/python3.14/site-packages/playwright/_impl/_sync_base.py", line 115, in _sync
return task.result()
~~~~~~~~~~~^^
File "/opt/homebrew/lib/python3.14/site-packages/playwright/_impl/_page.py", line 552, in goto
return await self._main_frame.goto(**locals_to_params(locals()))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/lib/python3.14/site-packages/playwright/_impl/_frame.py", line 153, in goto
await self._channel.send(
"goto", self._navigation_timeout, locals_to_params(locals())
)
File "/opt/homebrew/lib/python3.14/site-packages/playwright/_impl/_connection.py", line 69, in send
return await self._connection.wrap_api_call(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...<3 lines>...
)
^
File "/opt/homebrew/lib/python3.14/site-packages/playwright/_impl/_connection.py", line 559, in wrap_api_call
raise rewrite_error(error, f"{parsed_st['apiName']}: {error}") from None
playwright._impl._errors.Error: Page.goto: net::ERR_HTTP_RESPONSE_CODE_FAILURE at http://127.0.0.1:5201/operations-canary?role=Viewer
Call log:
- navigating to "http://127.0.0.1:5201/operations-canary?role=Viewer", waiting until "load"
Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

@@ -0,0 +1,574 @@
[
{
"width": 1440,
"dpr": 1,
"document": 1440,
"scheme": "light",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 631,
"scroll": 2921,
"overflow": "auto"
},
"rows": [
29.609375,
29.609375,
29.609375,
29.609375,
29.609375
],
"endFocus": {
"role": "treeitem",
"bottom": 859.5,
"viewport": 900
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 1,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"width": 768,
"dpr": 1,
"document": 768,
"scheme": "light",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 2921,
"scroll": 2921,
"overflow": "visible"
},
"rows": [
29.609375,
29.609375,
29.609375,
29.609375,
29.609375
],
"endFocus": {
"role": "treeitem",
"bottom": 3148.578125,
"viewport": 480
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 1,
"requested": [
768,
480
],
"errors": [],
"passed": true
},
{
"width": 390,
"dpr": 1,
"document": 390,
"scheme": "light",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 4736,
"scroll": 4736,
"overflow": "visible"
},
"rows": [
51.21875,
51.21875,
51.21875,
51.21875,
51.21875
],
"endFocus": {
"role": "treeitem",
"bottom": 5075.625,
"viewport": 844
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 1,
"requested": [
390,
844
],
"errors": [],
"passed": true
},
{
"width": 720,
"dpr": 2,
"document": 720,
"scheme": "light",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 2919,
"scroll": 2919,
"overflow": "visible"
},
"rows": [
29.59375,
29.59375,
29.59375,
29.59375,
29.59375
],
"endFocus": {
"role": "treeitem",
"bottom": 3228.5390625,
"viewport": 450
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 2,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"width": 1440,
"dpr": 1,
"document": 1440,
"scheme": "light",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 631,
"scroll": 2921,
"overflow": "auto"
},
"rows": [
29.609375,
29.609375,
29.609375,
29.609375,
29.609375
],
"endFocus": {
"role": "treeitem",
"bottom": 859.5,
"viewport": 900
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 1,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"width": 768,
"dpr": 1,
"document": 768,
"scheme": "light",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 2921,
"scroll": 2921,
"overflow": "visible"
},
"rows": [
29.609375,
29.609375,
29.609375,
29.609375,
29.609375
],
"endFocus": {
"role": "treeitem",
"bottom": 3150.578125,
"viewport": 480
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 1,
"requested": [
768,
480
],
"errors": [],
"passed": true
},
{
"width": 390,
"dpr": 1,
"document": 390,
"scheme": "light",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 4736,
"scroll": 4736,
"overflow": "visible"
},
"rows": [
51.21875,
51.21875,
51.21875,
51.21875,
51.21875
],
"endFocus": {
"role": "treeitem",
"bottom": 5075.625,
"viewport": 844
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 1,
"requested": [
390,
844
],
"errors": [],
"passed": true
},
{
"width": 720,
"dpr": 2,
"document": 720,
"scheme": "light",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 2919,
"scroll": 2919,
"overflow": "visible"
},
"rows": [
29.59375,
29.59375,
29.59375,
29.59375,
29.59375
],
"endFocus": {
"role": "treeitem",
"bottom": 3207.0390625,
"viewport": 450
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 2,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"width": 1440,
"dpr": 1,
"document": 1440,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 1,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"width": 768,
"dpr": 1,
"document": 768,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 1,
"requested": [
768,
480
],
"errors": [],
"passed": true
},
{
"width": 390,
"dpr": 1,
"document": 452,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 1,
"requested": [
390,
844
],
"errors": [],
"passed": false
},
{
"width": 720,
"dpr": 2,
"document": 720,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 2,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"width": 1440,
"dpr": 1,
"document": 1440,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 1,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"width": 768,
"dpr": 1,
"document": 768,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 1,
"requested": [
768,
480
],
"errors": [],
"passed": true
},
{
"width": 390,
"dpr": 1,
"document": 452,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 1,
"requested": [
390,
844
],
"errors": [],
"passed": false
},
{
"width": 720,
"dpr": 2,
"document": 720,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 2,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"kind": "policy",
"role": "Viewer",
"shortcuts": {
"/design/templates": 0,
"/audit/configuration": 1
},
"rail": {
"/design/templates": 0,
"/audit/configuration": 1
},
"passed": true
},
{
"kind": "policy",
"role": "Designer",
"shortcuts": {
"/design/templates": 1,
"/audit/configuration": 0
},
"rail": {
"/design/templates": 1,
"/audit/configuration": 0
},
"passed": true
},
{
"kind": "policy",
"role": "Deployer",
"shortcuts": {
"/design/templates": 0,
"/audit/configuration": 0
},
"rail": {
"/design/templates": 0,
"/audit/configuration": 0
},
"passed": true
},
{
"kind": "policy",
"role": "Administrator,Designer,Deployer",
"shortcuts": {
"/design/templates": 1,
"/audit/configuration": 1
},
"rail": {
"/design/templates": 1,
"/audit/configuration": 1
},
"passed": true
}
]
@@ -0,0 +1,686 @@
[
{
"width": 1440,
"dpr": 1,
"document": 1440,
"scheme": "light",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 631,
"scroll": 2921,
"overflow": "auto"
},
"rows": [
29.609375,
29.609375,
29.609375,
29.609375,
29.609375
],
"endFocus": {
"role": "treeitem",
"bottom": 859.5,
"viewport": 900
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 1,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"width": 768,
"dpr": 1,
"document": 768,
"scheme": "light",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 2921,
"scroll": 2921,
"overflow": "visible"
},
"rows": [
29.609375,
29.609375,
29.609375,
29.609375,
29.609375
],
"endFocus": {
"role": "treeitem",
"bottom": 3148.578125,
"viewport": 480
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 1,
"requested": [
768,
480
],
"errors": [],
"passed": true
},
{
"width": 390,
"dpr": 1,
"document": 390,
"scheme": "light",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 4736,
"scroll": 4736,
"overflow": "visible"
},
"rows": [
51.21875,
51.21875,
51.21875,
51.21875,
51.21875
],
"endFocus": {
"role": "treeitem",
"bottom": 5075.625,
"viewport": 844
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 1,
"requested": [
390,
844
],
"errors": [],
"passed": true
},
{
"width": 720,
"dpr": 2,
"document": 720,
"scheme": "light",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 2919,
"scroll": 2919,
"overflow": "visible"
},
"rows": [
29.59375,
29.59375,
29.59375,
29.59375,
29.59375
],
"endFocus": {
"role": "treeitem",
"bottom": 3228.5390625,
"viewport": 450
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 2,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"width": 1440,
"dpr": 1,
"document": 1440,
"scheme": "light",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 631,
"scroll": 2921,
"overflow": "auto"
},
"rows": [
29.609375,
29.609375,
29.609375,
29.609375,
29.609375
],
"endFocus": {
"role": "treeitem",
"bottom": 859.5,
"viewport": 900
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 1,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"width": 768,
"dpr": 1,
"document": 768,
"scheme": "light",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 2921,
"scroll": 2921,
"overflow": "visible"
},
"rows": [
29.609375,
29.609375,
29.609375,
29.609375,
29.609375
],
"endFocus": {
"role": "treeitem",
"bottom": 3150.578125,
"viewport": 480
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 1,
"requested": [
768,
480
],
"errors": [],
"passed": true
},
{
"width": 390,
"dpr": 1,
"document": 390,
"scheme": "light",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 4736,
"scroll": 4736,
"overflow": "visible"
},
"rows": [
51.21875,
51.21875,
51.21875,
51.21875,
51.21875
],
"endFocus": {
"role": "treeitem",
"bottom": 5075.625,
"viewport": 844
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 1,
"requested": [
390,
844
],
"errors": [],
"passed": true
},
{
"width": 720,
"dpr": 2,
"document": 720,
"scheme": "light",
"headings": [
"Topology"
],
"sites": [],
"summary": null,
"tree": {
"height": 2919,
"scroll": 2919,
"overflow": "visible"
},
"rows": [
29.59375,
29.59375,
29.59375,
29.59375,
29.59375
],
"endFocus": {
"role": "treeitem",
"bottom": 3207.0390625,
"viewport": 450
},
"lazyLoad": true,
"loadedSearchQualifier": "Search loaded sites, areas, instances...",
"kind": "topology",
"zoom": 2,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"width": 1440,
"dpr": 1,
"document": 1440,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 1,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"width": 768,
"dpr": 1,
"document": 768,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 1,
"requested": [
768,
480
],
"errors": [],
"passed": true
},
{
"width": 390,
"dpr": 1,
"document": 452,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 1,
"requested": [
390,
844
],
"errors": [],
"passed": false
},
{
"width": 720,
"dpr": 2,
"document": 720,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 2,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"width": 1440,
"dpr": 1,
"document": 1440,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 1,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"width": 768,
"dpr": 1,
"document": 768,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 1,
"requested": [
768,
480
],
"errors": [],
"passed": true
},
{
"width": 390,
"dpr": 1,
"document": 452,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 1,
"requested": [
390,
844
],
"errors": [],
"passed": false
},
{
"width": 720,
"dpr": 2,
"document": 720,
"scheme": "light",
"headings": [
"Health Dashboard"
],
"sites": [
"offline",
"warning",
"unknown",
"healthy"
],
"summary": "SITES ONLINE\n3\nSITES OFFLINE\n1\nSITES WITH ERRORS IN LAST REPORT INTERVAL\n0\nSITES WITH UNKNOWN METRICS\n1",
"tree": null,
"rows": [],
"orderPass": true,
"kind": "health",
"zoom": 2,
"requested": [
1440,
900
],
"errors": [],
"passed": true
},
{
"kind": "policy",
"role": "Viewer",
"shortcuts": {
"/design/templates": 0,
"/audit/configuration": 1
},
"rail": {
"/design/templates": 0,
"/audit/configuration": 1
},
"passed": true
},
{
"kind": "policy",
"role": "Designer",
"shortcuts": {
"/design/templates": 1,
"/audit/configuration": 0
},
"rail": {
"/design/templates": 1,
"/audit/configuration": 0
},
"passed": true
},
{
"kind": "policy",
"role": "Deployer",
"shortcuts": {
"/design/templates": 0,
"/audit/configuration": 0
},
"rail": {
"/design/templates": 0,
"/audit/configuration": 0
},
"passed": true
},
{
"kind": "policy",
"role": "Administrator,Designer,Deployer",
"shortcuts": {
"/design/templates": 1,
"/audit/configuration": 1
},
"rail": {
"/design/templates": 1,
"/audit/configuration": 1
},
"passed": true
},
{
"width": 390,
"document": 390,
"coarse": false,
"rows": [
51.21875,
51.21875,
51.21875,
51.21875,
51.21875,
51.21875,
51.21875,
51.21875
],
"toggles": [
{
"width": 20,
"height": 21.609375
},
{
"width": 20,
"height": 21.609375
},
{
"width": 20,
"height": 21.609375
},
{
"width": 20,
"height": 21.609375
},
{
"width": 20,
"height": 21.609375
},
{
"width": 20,
"height": 21.609375
},
{
"width": 20,
"height": 21.609375
},
{
"width": 20,
"height": 21.609375
}
],
"overflow": "visible",
"kind": "touch",
"requested": [
390,
844
],
"passed": false
},
{
"width": 768,
"document": 768,
"coarse": true,
"rows": [
52,
52,
52,
52,
52,
52,
52,
52
],
"toggles": [
{
"width": 44,
"height": 44
},
{
"width": 44,
"height": 44
},
{
"width": 44,
"height": 44
},
{
"width": 44,
"height": 44
},
{
"width": 44,
"height": 44
},
{
"width": 44,
"height": 44
},
{
"width": 44,
"height": 44
},
{
"width": 44,
"height": 44
}
],
"overflow": "visible",
"kind": "touch",
"requested": [
768,
480
],
"passed": true
}
]
Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

@@ -0,0 +1,25 @@
ZB.MOM.WW.ScadaBridge.Commons -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Commons/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Commons.dll
ZB.MOM.WW.ScadaBridge.KpiHistory -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.KpiHistory/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.KpiHistory.dll
ZB.MOM.WW.ScadaBridge.Security -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Security/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Security.dll
ZB.MOM.WW.ScadaBridge.Communication -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Communication/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Communication.dll
ZB.MOM.WW.ScadaBridge.ConfigurationDatabase -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.dll
ZB.MOM.WW.ScadaBridge.ScriptAnalysis -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ScriptAnalysis/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ScriptAnalysis.dll
ZB.MOM.WW.ScadaBridge.SiteEventLogging -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.SiteEventLogging/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.SiteEventLogging.dll
ZB.MOM.WW.ScadaBridge.StoreAndForward -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.StoreAndForward/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.StoreAndForward.dll
ZB.MOM.WW.ScadaBridge.TemplateEngine -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.TemplateEngine.dll
ZB.MOM.WW.ScadaBridge.AuditLog -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.AuditLog/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.AuditLog.dll
ZB.MOM.WW.ScadaBridge.Transport -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Transport/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Transport.dll
ZB.MOM.WW.ScadaBridge.DeploymentManager -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.DeploymentManager/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.DeploymentManager.dll
ZB.MOM.WW.ScadaBridge.HealthMonitoring -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.HealthMonitoring/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.HealthMonitoring.dll
ZB.MOM.WW.ScadaBridge.NotificationService -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.NotificationService/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.NotificationService.dll
ZB.MOM.WW.ScadaBridge.ExternalSystemGateway -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ExternalSystemGateway/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ExternalSystemGateway.dll
ZB.MOM.WW.ScadaBridge.InboundAPI -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.InboundAPI/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.InboundAPI.dll
ZB.MOM.WW.ScadaBridge.NotificationOutbox -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.NotificationOutbox/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.NotificationOutbox.dll
ZB.MOM.WW.ScadaBridge.ManagementService -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ManagementService/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ManagementService.dll
ZB.MOM.WW.ScadaBridge.CentralUI -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.dll
ZB.MOM.WW.ScadaBridge.CentralUI.SandboxWorker -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI.SandboxWorker/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.SandboxWorker.dll
ZB.MOM.WW.ScadaBridge.CentralUI.Tests -> /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.Tests.dll
Test run for /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.Tests.dll (.NETCoreApp,Version=v10.0)
A total of 1 test files matched the specified pattern.
Passed! - Failed: 0, Passed: 101, Skipped: 0, Total: 101, Duration: 544 ms - ZB.MOM.WW.ScadaBridge.CentralUI.Tests.dll (net10.0)
@@ -0,0 +1,226 @@
[
{
"width": 768,
"document": 768,
"dpr": 1,
"scheme": "light",
"top": 443.109375,
"bottom": 478.578125,
"height": 480,
"focused": "treeitem",
"requested": [
768,
480
],
"zoom": 1,
"kind": "keyboard",
"passed": true
},
{
"width": 390,
"document": 390,
"dpr": 1,
"scheme": "light",
"top": 809.15625,
"bottom": 844.625,
"height": 844,
"focused": "treeitem",
"requested": [
390,
844
],
"zoom": 1,
"kind": "keyboard",
"passed": true
},
{
"width": 720,
"document": 720,
"dpr": 2,
"scheme": "light",
"top": 414.078125,
"bottom": 449.5390625,
"height": 450,
"focused": "treeitem",
"requested": [
1440,
900
],
"zoom": 2,
"kind": "keyboard",
"passed": true
},
{
"width": 768,
"document": 768,
"dpr": 1,
"scheme": "dark",
"top": 442.109375,
"bottom": 477.578125,
"height": 480,
"focused": "treeitem",
"requested": [
768,
480
],
"zoom": 1,
"kind": "keyboard",
"passed": true
},
{
"width": 390,
"document": 390,
"dpr": 1,
"scheme": "dark",
"top": 809.15625,
"bottom": 844.625,
"height": 844,
"focused": "treeitem",
"requested": [
390,
844
],
"zoom": 1,
"kind": "keyboard",
"passed": true
},
{
"width": 720,
"document": 720,
"dpr": 2,
"scheme": "dark",
"top": 413.578125,
"bottom": 449.0390625,
"height": 450,
"focused": "treeitem",
"requested": [
1440,
900
],
"zoom": 2,
"kind": "keyboard",
"passed": true
},
{
"width": 390,
"document": 390,
"coarse": true,
"touch": 1,
"overflow": "visible",
"rows": [
52,
52,
52,
52,
52,
52,
52,
52
],
"toggles": [
{
"width": 44,
"height": 44
},
{
"width": 44,
"height": 44
},
{
"width": 44,
"height": 44
},
{
"width": 44,
"height": 44
},
{
"width": 44,
"height": 44
},
{
"width": 44,
"height": 44
},
{
"width": 44,
"height": 44
},
{
"width": 44,
"height": 44
}
],
"requested": [
390,
844
],
"initialRequestedContext": {
"coarse": true,
"touch": 1
},
"kind": "touch",
"passed": true
},
{
"width": 768,
"document": 768,
"coarse": true,
"touch": 1,
"overflow": "visible",
"rows": [
52,
52,
52,
52,
52,
52,
52,
52
],
"toggles": [
{
"width": 44,
"height": 44
},
{
"width": 44,
"height": 44
},
{
"width": 44,
"height": 44
},
{
"width": 44,
"height": 44
},
{
"width": 44,
"height": 44
},
{
"width": 44,
"height": 44
},
{
"width": 44,
"height": 44
},
{
"width": 44,
"height": 44
}
],
"requested": [
768,
480
],
"initialRequestedContext": {
"coarse": true,
"touch": 1
},
"kind": "touch",
"passed": true
}
]
@@ -0,0 +1,4 @@
{
"cases": 8,
"passed": 8
}
@@ -0,0 +1,26 @@
ZB.MOM.WW.ScadaBridge.Commons -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Commons/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Commons.dll
ZB.MOM.WW.ScadaBridge.KpiHistory -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.KpiHistory/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.KpiHistory.dll
ZB.MOM.WW.ScadaBridge.ConfigurationDatabase -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.dll
ZB.MOM.WW.ScadaBridge.Security -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Security/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Security.dll
ZB.MOM.WW.ScadaBridge.Communication -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Communication/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Communication.dll
ZB.MOM.WW.ScadaBridge.ScriptAnalysis -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ScriptAnalysis/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ScriptAnalysis.dll
ZB.MOM.WW.ScadaBridge.SiteEventLogging -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.SiteEventLogging/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.SiteEventLogging.dll
ZB.MOM.WW.ScadaBridge.AuditLog -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.AuditLog/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.AuditLog.dll
ZB.MOM.WW.ScadaBridge.StoreAndForward -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.StoreAndForward/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.StoreAndForward.dll
ZB.MOM.WW.ScadaBridge.TemplateEngine -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.TemplateEngine.dll
ZB.MOM.WW.ScadaBridge.Transport -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Transport/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Transport.dll
ZB.MOM.WW.ScadaBridge.InboundAPI -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.InboundAPI/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.InboundAPI.dll
ZB.MOM.WW.ScadaBridge.DeploymentManager -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.DeploymentManager/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.DeploymentManager.dll
ZB.MOM.WW.ScadaBridge.HealthMonitoring -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.HealthMonitoring/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.HealthMonitoring.dll
ZB.MOM.WW.ScadaBridge.ExternalSystemGateway -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ExternalSystemGateway/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ExternalSystemGateway.dll
ZB.MOM.WW.ScadaBridge.NotificationService -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.NotificationService/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.NotificationService.dll
ZB.MOM.WW.ScadaBridge.NotificationOutbox -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.NotificationOutbox/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.NotificationOutbox.dll
ZB.MOM.WW.ScadaBridge.ManagementService -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ManagementService/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ManagementService.dll
ZB.MOM.WW.ScadaBridge.CentralUI -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.dll
ZB.MOM.WW.ScadaBridge.CentralUI.SandboxWorker -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI.SandboxWorker/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.SandboxWorker.dll
ZB.MOM.WW.ScadaBridge.CentralUI.Tests -> /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.Tests.dll
Test run for /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.Tests.dll (.NETCoreApp,Version=v10.0)
A total of 1 test files matched the specified pattern.
Results File: /Users/dohertj2/Desktop/ScadaBridge/docs/ui-consistency/evidence/sb10-12/sb10-12-final.trx
Passed! - Failed: 0, Passed: 1591, Skipped: 0, Total: 1591, Duration: 35 s - ZB.MOM.WW.ScadaBridge.CentralUI.Tests.dll (net10.0)
@@ -0,0 +1,25 @@
ZB.MOM.WW.ScadaBridge.Commons -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Commons/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Commons.dll
ZB.MOM.WW.ScadaBridge.KpiHistory -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.KpiHistory/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.KpiHistory.dll
ZB.MOM.WW.ScadaBridge.ConfigurationDatabase -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.dll
ZB.MOM.WW.ScadaBridge.Communication -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Communication/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Communication.dll
ZB.MOM.WW.ScadaBridge.SiteEventLogging -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.SiteEventLogging/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.SiteEventLogging.dll
ZB.MOM.WW.ScadaBridge.ScriptAnalysis -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ScriptAnalysis/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ScriptAnalysis.dll
ZB.MOM.WW.ScadaBridge.Security -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Security/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Security.dll
ZB.MOM.WW.ScadaBridge.TemplateEngine -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.TemplateEngine.dll
ZB.MOM.WW.ScadaBridge.AuditLog -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.AuditLog/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.AuditLog.dll
ZB.MOM.WW.ScadaBridge.StoreAndForward -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.StoreAndForward/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.StoreAndForward.dll
ZB.MOM.WW.ScadaBridge.Transport -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Transport/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Transport.dll
ZB.MOM.WW.ScadaBridge.DeploymentManager -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.DeploymentManager/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.DeploymentManager.dll
ZB.MOM.WW.ScadaBridge.InboundAPI -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.InboundAPI/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.InboundAPI.dll
ZB.MOM.WW.ScadaBridge.HealthMonitoring -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.HealthMonitoring/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.HealthMonitoring.dll
ZB.MOM.WW.ScadaBridge.NotificationService -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.NotificationService/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.NotificationService.dll
ZB.MOM.WW.ScadaBridge.ExternalSystemGateway -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ExternalSystemGateway/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ExternalSystemGateway.dll
ZB.MOM.WW.ScadaBridge.NotificationOutbox -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.NotificationOutbox/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.NotificationOutbox.dll
ZB.MOM.WW.ScadaBridge.ManagementService -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ManagementService/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ManagementService.dll
ZB.MOM.WW.ScadaBridge.CentralUI -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.dll
ZB.MOM.WW.ScadaBridge.CentralUI.SandboxWorker -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI.SandboxWorker/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.SandboxWorker.dll
ZB.MOM.WW.ScadaBridge.CentralUI.Tests -> /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.Tests.dll
Test run for /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.Tests.dll (.NETCoreApp,Version=v10.0)
A total of 1 test files matched the specified pattern.
Passed! - Failed: 0, Passed: 101, Skipped: 0, Total: 101, Duration: 504 ms - ZB.MOM.WW.ScadaBridge.CentralUI.Tests.dll (net10.0)
@@ -0,0 +1,25 @@
ZB.MOM.WW.ScadaBridge.Commons -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Commons/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Commons.dll
ZB.MOM.WW.ScadaBridge.KpiHistory -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.KpiHistory/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.KpiHistory.dll
ZB.MOM.WW.ScadaBridge.Security -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Security/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Security.dll
ZB.MOM.WW.ScadaBridge.ConfigurationDatabase -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.dll
ZB.MOM.WW.ScadaBridge.Communication -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Communication/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Communication.dll
ZB.MOM.WW.ScadaBridge.ScriptAnalysis -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ScriptAnalysis/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ScriptAnalysis.dll
ZB.MOM.WW.ScadaBridge.SiteEventLogging -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.SiteEventLogging/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.SiteEventLogging.dll
ZB.MOM.WW.ScadaBridge.StoreAndForward -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.StoreAndForward/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.StoreAndForward.dll
ZB.MOM.WW.ScadaBridge.TemplateEngine -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.TemplateEngine.dll
ZB.MOM.WW.ScadaBridge.AuditLog -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.AuditLog/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.AuditLog.dll
ZB.MOM.WW.ScadaBridge.Transport -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Transport/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Transport.dll
ZB.MOM.WW.ScadaBridge.DeploymentManager -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.DeploymentManager/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.DeploymentManager.dll
ZB.MOM.WW.ScadaBridge.HealthMonitoring -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.HealthMonitoring/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.HealthMonitoring.dll
ZB.MOM.WW.ScadaBridge.NotificationService -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.NotificationService/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.NotificationService.dll
ZB.MOM.WW.ScadaBridge.InboundAPI -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.InboundAPI/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.InboundAPI.dll
ZB.MOM.WW.ScadaBridge.ExternalSystemGateway -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ExternalSystemGateway/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ExternalSystemGateway.dll
ZB.MOM.WW.ScadaBridge.NotificationOutbox -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.NotificationOutbox/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.NotificationOutbox.dll
ZB.MOM.WW.ScadaBridge.ManagementService -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ManagementService/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ManagementService.dll
ZB.MOM.WW.ScadaBridge.CentralUI -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.dll
ZB.MOM.WW.ScadaBridge.CentralUI.SandboxWorker -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI.SandboxWorker/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.SandboxWorker.dll
ZB.MOM.WW.ScadaBridge.CentralUI.Tests -> /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.Tests.dll
Test run for /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.Tests.dll (.NETCoreApp,Version=v10.0)
A total of 1 test files matched the specified pattern.
Passed! - Failed: 0, Passed: 59, Skipped: 0, Total: 59, Duration: 465 ms - ZB.MOM.WW.ScadaBridge.CentralUI.Tests.dll (net10.0)
@@ -0,0 +1,55 @@
ZB.MOM.WW.ScadaBridge.Commons -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Commons/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Commons.dll
ZB.MOM.WW.ScadaBridge.KpiHistory -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.KpiHistory/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.KpiHistory.dll
ZB.MOM.WW.ScadaBridge.ConfigurationDatabase -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.dll
ZB.MOM.WW.ScadaBridge.Communication -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Communication/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Communication.dll
ZB.MOM.WW.ScadaBridge.Security -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Security/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Security.dll
ZB.MOM.WW.ScadaBridge.ScriptAnalysis -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ScriptAnalysis/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ScriptAnalysis.dll
ZB.MOM.WW.ScadaBridge.SiteEventLogging -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.SiteEventLogging/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.SiteEventLogging.dll
ZB.MOM.WW.ScadaBridge.StoreAndForward -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.StoreAndForward/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.StoreAndForward.dll
ZB.MOM.WW.ScadaBridge.TemplateEngine -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.TemplateEngine.dll
ZB.MOM.WW.ScadaBridge.AuditLog -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.AuditLog/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.AuditLog.dll
ZB.MOM.WW.ScadaBridge.Transport -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Transport/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Transport.dll
ZB.MOM.WW.ScadaBridge.DeploymentManager -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.DeploymentManager/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.DeploymentManager.dll
ZB.MOM.WW.ScadaBridge.HealthMonitoring -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.HealthMonitoring/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.HealthMonitoring.dll
ZB.MOM.WW.ScadaBridge.NotificationService -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.NotificationService/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.NotificationService.dll
ZB.MOM.WW.ScadaBridge.ExternalSystemGateway -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ExternalSystemGateway/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ExternalSystemGateway.dll
ZB.MOM.WW.ScadaBridge.InboundAPI -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.InboundAPI/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.InboundAPI.dll
ZB.MOM.WW.ScadaBridge.NotificationOutbox -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.NotificationOutbox/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.NotificationOutbox.dll
ZB.MOM.WW.ScadaBridge.ManagementService -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ManagementService/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ManagementService.dll
ZB.MOM.WW.ScadaBridge.CentralUI -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.dll
ZB.MOM.WW.ScadaBridge.CentralUI.SandboxWorker -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI.SandboxWorker/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.SandboxWorker.dll
ZB.MOM.WW.ScadaBridge.CentralUI.Tests -> /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.Tests.dll
Test run for /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.Tests.dll (.NETCoreApp,Version=v10.0)
A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:00.42] ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(role: "Viewer", templates: False, audit: True) [FAIL]
[xUnit.net 00:00:00.42] ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(role: "Designer", templates: True, audit: False) [FAIL]
Failed ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(role: "Viewer", templates: False, audit: True) [2 ms]
Error Message:
Assert.Equal() Failure: Values differ
Expected: 1
Actual: 0
Stack Trace:
at ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(String role, Boolean templates, Boolean audit) in /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Pages/DashboardStateTests.cs:line 57
at InvokeStub_DashboardStateTests.Shortcuts_RespectDestinationPolicies(Object, Span`1)
at System.Reflection.MethodBaseInvoker.InvokeWithFewArgs(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
Failed ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(role: "Designer", templates: True, audit: False) [1 ms]
Error Message:
Assert.Equal() Failure: Values differ
Expected: 1
Actual: 0
Stack Trace:
at ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(String role, Boolean templates, Boolean audit) in /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Pages/DashboardStateTests.cs:line 56
at InvokeStub_DashboardStateTests.Shortcuts_RespectDestinationPolicies(Object, Span`1)
at System.Reflection.MethodBaseInvoker.InvokeWithFewArgs(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
[xUnit.net 00:00:00.42] ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(role: "Administrator", templates: True, audit: True) [FAIL]
Failed ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(role: "Administrator", templates: True, audit: True) [1 ms]
Error Message:
Assert.Equal() Failure: Values differ
Expected: 1
Actual: 0
Stack Trace:
at ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(String role, Boolean templates, Boolean audit) in /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Pages/DashboardStateTests.cs:line 56
at InvokeStub_DashboardStateTests.Shortcuts_RespectDestinationPolicies(Object, Span`1)
at System.Reflection.MethodBaseInvoker.InvokeWithFewArgs(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
Failed! - Failed: 3, Passed: 55, Skipped: 0, Total: 58, Duration: 451 ms - ZB.MOM.WW.ScadaBridge.CentralUI.Tests.dll (net10.0)
@@ -0,0 +1,20 @@
ZB.MOM.WW.ScadaBridge.Commons -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Commons/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Commons.dll
ZB.MOM.WW.ScadaBridge.KpiHistory -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.KpiHistory/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.KpiHistory.dll
ZB.MOM.WW.ScadaBridge.Communication -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Communication/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Communication.dll
ZB.MOM.WW.ScadaBridge.ConfigurationDatabase -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.dll
ZB.MOM.WW.ScadaBridge.Security -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Security/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Security.dll
ZB.MOM.WW.ScadaBridge.ScriptAnalysis -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ScriptAnalysis/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ScriptAnalysis.dll
ZB.MOM.WW.ScadaBridge.SiteEventLogging -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.SiteEventLogging/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.SiteEventLogging.dll
ZB.MOM.WW.ScadaBridge.StoreAndForward -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.StoreAndForward/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.StoreAndForward.dll
ZB.MOM.WW.ScadaBridge.TemplateEngine -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.TemplateEngine.dll
ZB.MOM.WW.ScadaBridge.AuditLog -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.AuditLog/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.AuditLog.dll
ZB.MOM.WW.ScadaBridge.Transport -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Transport/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Transport.dll
ZB.MOM.WW.ScadaBridge.DeploymentManager -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.DeploymentManager/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.DeploymentManager.dll
ZB.MOM.WW.ScadaBridge.NotificationService -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.NotificationService/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.NotificationService.dll
ZB.MOM.WW.ScadaBridge.HealthMonitoring -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.HealthMonitoring/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.HealthMonitoring.dll
ZB.MOM.WW.ScadaBridge.ExternalSystemGateway -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ExternalSystemGateway/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ExternalSystemGateway.dll
ZB.MOM.WW.ScadaBridge.InboundAPI -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.InboundAPI/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.InboundAPI.dll
ZB.MOM.WW.ScadaBridge.NotificationOutbox -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.NotificationOutbox/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.NotificationOutbox.dll
ZB.MOM.WW.ScadaBridge.ManagementService -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ManagementService/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ManagementService.dll
/Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Dashboard.razor(71,33): error CS0103: The name 'AuthorizationPolicies' does not exist in the current context [/Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI/ZB.MOM.WW.ScadaBridge.CentralUI.csproj]
/Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Dashboard.razor(84,33): error CS0103: The name 'AuthorizationPolicies' does not exist in the current context [/Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI/ZB.MOM.WW.ScadaBridge.CentralUI.csproj]
@@ -0,0 +1,35 @@
ZB.MOM.WW.ScadaBridge.Commons -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Commons/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Commons.dll
ZB.MOM.WW.ScadaBridge.KpiHistory -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.KpiHistory/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.KpiHistory.dll
ZB.MOM.WW.ScadaBridge.ConfigurationDatabase -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.dll
ZB.MOM.WW.ScadaBridge.Communication -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Communication/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Communication.dll
ZB.MOM.WW.ScadaBridge.Security -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Security/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Security.dll
ZB.MOM.WW.ScadaBridge.ScriptAnalysis -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ScriptAnalysis/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ScriptAnalysis.dll
ZB.MOM.WW.ScadaBridge.SiteEventLogging -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.SiteEventLogging/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.SiteEventLogging.dll
ZB.MOM.WW.ScadaBridge.StoreAndForward -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.StoreAndForward/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.StoreAndForward.dll
ZB.MOM.WW.ScadaBridge.TemplateEngine -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.TemplateEngine.dll
ZB.MOM.WW.ScadaBridge.AuditLog -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.AuditLog/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.AuditLog.dll
ZB.MOM.WW.ScadaBridge.NotificationService -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.NotificationService/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.NotificationService.dll
ZB.MOM.WW.ScadaBridge.ExternalSystemGateway -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ExternalSystemGateway/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ExternalSystemGateway.dll
ZB.MOM.WW.ScadaBridge.HealthMonitoring -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.HealthMonitoring/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.HealthMonitoring.dll
ZB.MOM.WW.ScadaBridge.DeploymentManager -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.DeploymentManager/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.DeploymentManager.dll
ZB.MOM.WW.ScadaBridge.InboundAPI -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.InboundAPI/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.InboundAPI.dll
ZB.MOM.WW.ScadaBridge.Transport -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Transport/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Transport.dll
ZB.MOM.WW.ScadaBridge.NotificationOutbox -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.NotificationOutbox/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.NotificationOutbox.dll
ZB.MOM.WW.ScadaBridge.ManagementService -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ManagementService/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ManagementService.dll
ZB.MOM.WW.ScadaBridge.CentralUI -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.dll
ZB.MOM.WW.ScadaBridge.CentralUI.SandboxWorker -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI.SandboxWorker/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.SandboxWorker.dll
ZB.MOM.WW.ScadaBridge.CentralUI.Tests -> /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.Tests.dll
Test run for /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.Tests.dll (.NETCoreApp,Version=v10.0)
A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:00.41] ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(role: "Administrator", templates: True, audit: True) [FAIL]
Failed ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(role: "Administrator", templates: True, audit: True) [1 ms]
Error Message:
Assert.Equal() Failure: Values differ
Expected: 1
Actual: 0
Stack Trace:
at ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(String role, Boolean templates, Boolean audit) in /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Pages/DashboardStateTests.cs:line 64
at InvokeStub_DashboardStateTests.Shortcuts_RespectDestinationPolicies(Object, Span`1)
at System.Reflection.MethodBaseInvoker.InvokeWithFewArgs(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
Failed! - Failed: 1, Passed: 57, Skipped: 0, Total: 58, Duration: 445 ms - ZB.MOM.WW.ScadaBridge.CentralUI.Tests.dll (net10.0)
@@ -0,0 +1,23 @@
[
{
"tag": "DIV",
"cls": "btn-group btn-group-sm",
"text": "24h\n 7d\n 30d\n 90d",
"right": 452.15625,
"width": 163
},
{
"tag": "BUTTON",
"cls": "btn btn-outline-secondary",
"text": "30d",
"right": 409.75,
"width": 43.40625
},
{
"tag": "BUTTON",
"cls": "btn btn-outline-secondary",
"text": "90d",
"right": 452.15625,
"width": 43.40625
}
]
@@ -0,0 +1,46 @@
[
{
"active": "Synthetic facility 01 with a deliberately long local display nameSynthetic area ",
"role": "treeitem",
"tab": 0,
"scroll": 0,
"bodyHeight": 5165,
"scrollElement": "HTML",
"top": 412.625,
"style": "smooth",
"bodyStyle": "visible"
},
{
"active": "Load instances",
"role": "treeitem",
"tab": 0,
"scroll": 0,
"bodyHeight": 5165,
"scrollElement": "HTML",
"top": 5105.15625,
"style": "smooth",
"bodyStyle": "visible"
},
{
"active": "Load instances",
"role": "treeitem",
"tab": 0,
"scroll": 0,
"bodyHeight": 5165,
"scrollElement": "HTML",
"top": 5105.15625,
"style": "smooth",
"bodyStyle": "visible"
},
{
"active": "Load instances",
"role": "treeitem",
"tab": 0,
"scroll": 4321,
"bodyHeight": 5165,
"scrollElement": "HTML",
"top": 784.15625,
"style": "smooth",
"bodyStyle": "visible"
}
]
@@ -0,0 +1,128 @@
ZB.MOM.WW.ScadaBridge.Commons -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Commons/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Commons.dll
ZB.MOM.WW.ScadaBridge.KpiHistory -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.KpiHistory/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.KpiHistory.dll
ZB.MOM.WW.ScadaBridge.Security -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Security/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Security.dll
ZB.MOM.WW.ScadaBridge.ScriptAnalysis -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ScriptAnalysis/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ScriptAnalysis.dll
ZB.MOM.WW.ScadaBridge.SiteEventLogging -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.SiteEventLogging/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.SiteEventLogging.dll
ZB.MOM.WW.ScadaBridge.ConfigurationDatabase -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.dll
ZB.MOM.WW.ScadaBridge.Communication -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Communication/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Communication.dll
ZB.MOM.WW.ScadaBridge.StoreAndForward -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.StoreAndForward/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.StoreAndForward.dll
ZB.MOM.WW.ScadaBridge.TemplateEngine -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.TemplateEngine.dll
ZB.MOM.WW.ScadaBridge.AuditLog -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.AuditLog/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.AuditLog.dll
ZB.MOM.WW.ScadaBridge.DeploymentManager -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.DeploymentManager/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.DeploymentManager.dll
ZB.MOM.WW.ScadaBridge.Transport -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Transport/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.Transport.dll
ZB.MOM.WW.ScadaBridge.NotificationService -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.NotificationService/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.NotificationService.dll
ZB.MOM.WW.ScadaBridge.HealthMonitoring -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.HealthMonitoring/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.HealthMonitoring.dll
ZB.MOM.WW.ScadaBridge.InboundAPI -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.InboundAPI/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.InboundAPI.dll
ZB.MOM.WW.ScadaBridge.ExternalSystemGateway -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ExternalSystemGateway/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ExternalSystemGateway.dll
ZB.MOM.WW.ScadaBridge.NotificationOutbox -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.NotificationOutbox/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.NotificationOutbox.dll
ZB.MOM.WW.ScadaBridge.ManagementService -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ManagementService/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.ManagementService.dll
ZB.MOM.WW.ScadaBridge.CentralUI -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.dll
ZB.MOM.WW.ScadaBridge.CentralUI.SandboxWorker -> /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI.SandboxWorker/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.SandboxWorker.dll
ZB.MOM.WW.ScadaBridge.CentralUI.Tests -> /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.Tests.dll
Test run for /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/bin/Release/net10.0/ZB.MOM.WW.ScadaBridge.CentralUI.Tests.dll (.NETCoreApp,Version=v10.0)
A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:00.42] ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(role: "Unmapped", templates: False, audit: False) [FAIL]
[xUnit.net 00:00:00.42] ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(role: "Viewer", templates: False, audit: True) [FAIL]
[xUnit.net 00:00:00.42] ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(role: "Designer", templates: True, audit: False) [FAIL]
[xUnit.net 00:00:00.43] ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(role: "Deployer", templates: False, audit: False) [FAIL]
Failed ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(role: "Unmapped", templates: False, audit: False) [5 ms]
Error Message:
Assert.Equal() Failure: Values differ
Expected: 0
Actual: 1
Stack Trace:
at ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(String role, Boolean templates, Boolean audit) in /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Pages/DashboardStateTests.cs:line 56
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
Failed ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(role: "Viewer", templates: False, audit: True) [5 ms]
Error Message:
Assert.Equal() Failure: Values differ
Expected: 0
Actual: 1
Stack Trace:
at ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(String role, Boolean templates, Boolean audit) in /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Pages/DashboardStateTests.cs:line 56
at InvokeStub_DashboardStateTests.Shortcuts_RespectDestinationPolicies(Object, Span`1)
at System.Reflection.MethodBaseInvoker.InvokeWithFewArgs(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
Failed ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(role: "Designer", templates: True, audit: False) [1 ms]
Error Message:
Assert.Equal() Failure: Values differ
Expected: 0
Actual: 1
Stack Trace:
at ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(String role, Boolean templates, Boolean audit) in /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Pages/DashboardStateTests.cs:line 57
at InvokeStub_DashboardStateTests.Shortcuts_RespectDestinationPolicies(Object, Span`1)
at System.Reflection.MethodBaseInvoker.InvokeWithFewArgs(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
Failed ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(role: "Deployer", templates: False, audit: False) [1 ms]
Error Message:
Assert.Equal() Failure: Values differ
Expected: 0
Actual: 1
Stack Trace:
at ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.DashboardStateTests.Shortcuts_RespectDestinationPolicies(String role, Boolean templates, Boolean audit) in /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Pages/DashboardStateTests.cs:line 56
at InvokeStub_DashboardStateTests.Shortcuts_RespectDestinationPolicies(Object, Span`1)
at System.Reflection.MethodBaseInvoker.InvokeWithFewArgs(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
[xUnit.net 00:00:01.55] ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.HealthPageTests.MissingReport_IsUnknownAndIntervalErrorsAreNamedHonestly [FAIL]
Failed ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.HealthPageTests.MissingReport_IsUnknownAndIntervalErrorsAreNamedHonestly [1 s]
Error Message:
Bunit.Extensions.WaitForHelpers.WaitForFailedException : The assertion did not pass within the timeout period.
If this test does not fail consistently, the reason may be that
the wait timeout is too short, and the runtime did not have enough
time to complete the necessary number of renders of the component under test.
This can happen on highly utilized or slower hardware, for example.
To determine if this is the cause, compare the check and render count(s) below
and see if they match what is expected. If they do not,
consider increasing the timeout, either at the individual
method call level, e.g. WaitForElement("div", TimeSpan.FromSeconds(15)),
or via the static TestContext.DefaultWaitTimeout property.
Check count: 1.
Component render count: 2.
Total render count across all components: 0.
---- Bunit.ElementNotFoundException : No elements were found that matches the selector '[data-site-id='heartbeat-only']'
Stack Trace:
at Bunit.RenderedComponentWaitForHelperExtensions.WaitForAssertion[TComponent](IRenderedComponent`1 renderedComponent, Action assertion, Nullable`1 timeout) in /_/src/bunit/Extensions/WaitForHelpers/RenderedComponentWaitForHelperExtensions.WaitForState.cs:line 77
at ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.HealthPageTests.MissingReport_IsUnknownAndIntervalErrorsAreNamedHonestly() in /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Pages/HealthPageTests.cs:line 785
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
----- Inner Stack Trace -----
at Bunit.RenderedComponentExtensions.Find[TComponent,TElement](IRenderedComponent`1 renderedComponent, String cssSelector) in /_/src/bunit/Extensions/RenderedComponentExtensions.cs:line 42
at Bunit.RenderedComponentExtensions.Find[TComponent](IRenderedComponent`1 renderedComponent, String cssSelector) in /_/src/bunit/Extensions/RenderedComponentExtensions.cs:line 21
at ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.HealthPageTests.<>c__DisplayClass34_0.<MissingReport_IsUnknownAndIntervalErrorsAreNamedHonestly>b__0() in /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Pages/HealthPageTests.cs:line 787
at Bunit.Extensions.WaitForHelpers.WaitForAssertionHelper`1.<>c__DisplayClass6_0.<.ctor>b__0() in /_/src/bunit/Extensions/WaitForHelpers/WaitForAssertionHelper.cs:line 35
at Bunit.Extensions.WaitForHelpers.WaitForHelper`2.OnAfterRender(Object sender, EventArgs args) in /_/src/bunit/Extensions/WaitForHelpers/WaitForHelper.cs:line 173
[xUnit.net 00:00:02.60] ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.HealthPageTests.SiteCards_PrioritizeOfflineThenWarningsAndMissingReports [FAIL]
Failed ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.HealthPageTests.SiteCards_PrioritizeOfflineThenWarningsAndMissingReports [1 s]
Error Message:
Bunit.Extensions.WaitForHelpers.WaitForFailedException : The assertion did not pass within the timeout period.
If this test does not fail consistently, the reason may be that
the wait timeout is too short, and the runtime did not have enough
time to complete the necessary number of renders of the component under test.
This can happen on highly utilized or slower hardware, for example.
To determine if this is the cause, compare the check and render count(s) below
and see if they match what is expected. If they do not,
consider increasing the timeout, either at the individual
method call level, e.g. WaitForElement("div", TimeSpan.FromSeconds(15)),
or via the static TestContext.DefaultWaitTimeout property.
Check count: 1.
Component render count: 2.
Total render count across all components: 0.
---- Assert.Equal() Failure: Collections differ
↓ (pos 0)
Expected: ["offline-a", "offline-z", "warning-b", "unknown", "healthy-a"]
Actual: []
Stack Trace:
at Bunit.RenderedComponentWaitForHelperExtensions.WaitForAssertion[TComponent](IRenderedComponent`1 renderedComponent, Action assertion, Nullable`1 timeout) in /_/src/bunit/Extensions/WaitForHelpers/RenderedComponentWaitForHelperExtensions.WaitForState.cs:line 77
at ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.HealthPageTests.SiteCards_PrioritizeOfflineThenWarningsAndMissingReports() in /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Pages/HealthPageTests.cs:line 772
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
----- Inner Stack Trace -----
at ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.HealthPageTests.<>c__DisplayClass33_0.<SiteCards_PrioritizeOfflineThenWarningsAndMissingReports>b__1() in /Users/dohertj2/Desktop/ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Pages/HealthPageTests.cs:line 772
at Bunit.Extensions.WaitForHelpers.WaitForAssertionHelper`1.<>c__DisplayClass6_0.<.ctor>b__0() in /_/src/bunit/Extensions/WaitForHelpers/WaitForAssertionHelper.cs:line 35
at Bunit.Extensions.WaitForHelpers.WaitForHelper`2.OnAfterRender(Object sender, EventArgs args) in /_/src/bunit/Extensions/WaitForHelpers/WaitForHelper.cs:line 173
Failed! - Failed: 6, Passed: 41, Skipped: 0, Total: 47, Duration: 2 s - ZB.MOM.WW.ScadaBridge.CentralUI.Tests.dll (net10.0)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,30 @@
[
{
"path": "src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Dashboard.razor",
"sha256": "b3bb2c73802cfe88230e3d58dc8cd9a4d700c19be37cedef3932a12cfaf8d28d"
},
{
"path": "src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Deployment/Topology.razor",
"sha256": "c30cd66b8fe1244442b5b98a91e4c067ccb263eff1beaac4e2b5d364236c0f71"
},
{
"path": "src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Monitoring/Health.razor",
"sha256": "c67b39abc0ea879387d2354c595bfbd6aa2ec60ba459ee5cd8b1c8136146c85d"
},
{
"path": "src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Shared/TreeView.razor.css",
"sha256": "f1bcb918867f06b954eb4c89fca77ff0209ad5bfd09480cccc8cf5b279f39f20"
},
{
"path": "src/ZB.MOM.WW.ScadaBridge.CentralUI/wwwroot/css/site.css",
"sha256": "535bd58d69a7060e48c3e20259788e46b0fc4911619a269c13f4e1ce27a0a1e3"
},
{
"path": "tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Pages/DashboardStateTests.cs",
"sha256": "18252c79c81485e0c9b7d28b87df14053a45cba5a68cabc02965acb6c30769ea"
},
{
"path": "tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Pages/HealthPageTests.cs",
"sha256": "172cea51beb00f096c585ca3989f70c0bf8a6f838392c01f5a712f2f2957120c"
}
]
@@ -0,0 +1,58 @@
[
{
"width": 390,
"height": 844,
"document": 390,
"title": "Topology",
"tree": {
"x": 32,
"y": 408.625,
"width": 326,
"height": 604,
"top": 408.625,
"right": 358,
"bottom": 1012.625,
"left": 32
},
"rowHeights": [
51.21875,
51.21875,
51.21875,
51.21875,
51.21875,
51.21875,
51.21875,
35.46875
],
"body": "\nSynthetic area 02 with a long inspection label\nSynthetic area 03 with a long inspection label\nSynthetic area 04 with a long inspection label\nSynthetic area 05 with a long inspection label\nSynthetic area 06 with a long inspection label\nLoad instances",
"errors": []
},
{
"width": 768,
"height": 480,
"document": 768,
"title": "Topology",
"tree": {
"x": 32,
"y": 313.765625,
"width": 704,
"height": 240,
"top": 313.765625,
"right": 736,
"bottom": 553.765625,
"left": 32
},
"rowHeights": [
29.609375,
29.609375,
29.609375,
29.609375,
29.609375,
29.609375,
29.609375,
35.46875
],
"body": "\nSynthetic area 02 with a long inspection label\nSynthetic area 03 with a long inspection label\nSynthetic area 04 with a long inspection label\nSynthetic area 05 with a long inspection label\nSynthetic area 06 with a long inspection label\nLoad instances",
"errors": []
}
]
+27
View File
@@ -0,0 +1,27 @@
"""Focused technical confirmation: await native smooth scrolling and verify real touch emulation."""
import json,sys
from pathlib import Path
from playwright.sync_api import sync_playwright
sys.path.insert(0,'/Users/dohertj2/.codex/worktrees/scada-ui-consistency/scadaproj/components/ui-theme/validation/theme-1.0.0/canary')
from browser_zoom import zoom_browser,set_browser_zoom
out=[]
with sync_playwright() as p:
with zoom_browser(p) as (context,worker):
for scheme in ['light','dark']:
for w,h,z in [(768,480,1),(390,844,1),(1440,900,2)]:
page=context.new_page();page.set_viewport_size({'width':w,'height':h});page.goto('http://127.0.0.1:5201/topology-canary?role=Deployer',wait_until='networkidle');page.evaluate('s=>window.sbTheme.set(s)',scheme);set_browser_zoom(worker,page,z)
page.locator('[role=treeitem][tabindex="0"]').first.focus();page.keyboard.press('End')
page.wait_for_function("document.activeElement === [...document.querySelectorAll('[role=treeitem]')].at(-1)")
page.wait_for_function("document.activeElement.querySelector('.tv-row').getBoundingClientRect().bottom <= innerHeight + 1")
record=page.evaluate("""() => ({width:innerWidth,document:document.documentElement.scrollWidth,dpr:devicePixelRatio,scheme:document.documentElement.dataset.bsTheme,top:document.activeElement.querySelector('.tv-row').getBoundingClientRect().top,bottom:document.activeElement.querySelector('.tv-row').getBoundingClientRect().bottom,height:innerHeight,focused:document.activeElement.getAttribute('role')})""")
record.update(requested=[w,h],zoom=z,kind='keyboard');record['passed']=record['top']>=0 and record['bottom']<=record['height']+1 and record['document']<=record['width'];out.append(record);page.close()
b=p.chromium.launch(channel='chromium')
for w,h in [(390,844),(768,480)]:
context=b.new_context(viewport={'width':w,'height':h},is_mobile=True,has_touch=True);page=context.new_page();page.goto('http://127.0.0.1:5201/topology-canary?role=Deployer',wait_until='networkidle')
requested=page.evaluate('({coarse:matchMedia("(pointer:coarse)").matches,touch:navigator.maxTouchPoints})')
cdp=context.new_cdp_session(page);cdp.send('Emulation.setTouchEmulationEnabled',{'enabled':True,'maxTouchPoints':1});page.wait_for_function('matchMedia("(pointer:coarse)").matches')
record=page.evaluate("""() => ({width:innerWidth,document:document.documentElement.scrollWidth,coarse:matchMedia('(pointer:coarse)').matches,touch:navigator.maxTouchPoints,overflow:getComputedStyle(document.querySelector('.topology-tree')).overflowY,rows:[...document.querySelectorAll('.tv-row')].slice(0,8).map(e=>e.getBoundingClientRect().height),toggles:[...document.querySelectorAll('.tv-toggle')].slice(0,8).map(e=>({width:e.getBoundingClientRect().width,height:e.getBoundingClientRect().height}))})""")
record.update(requested=[w,h],initialRequestedContext=requested,kind='touch');record['passed']=record['coarse'] and record['touch']==1 and record['document']<=record['width'] and min(record['rows'])>=44 and all(x['width']>=44 and x['height']>=44 for x in record['toggles']) and record['overflow']=='visible';out.append(record)
page.screenshot(path=f'docs/ui-consistency/evidence/sb10-12/browser-final/topology-verified-touch-{w}-{h}.png');context.close()
b.close()
Path('docs/ui-consistency/evidence/sb10-12/focused-keyboard-touch-confirmation.json').write_text(json.dumps(out,indent=2));print(json.dumps({'cases':len(out),'passed':sum(r['passed'] for r in out)},indent=2))
+54
View File
@@ -0,0 +1,54 @@
"""Bounded synthetic actual-component SB10–12 check; no live/fleet operations."""
import asyncio,json,sys
from pathlib import Path
from playwright.sync_api import sync_playwright
sys.path.insert(0,'/Users/dohertj2/.codex/worktrees/scada-ui-consistency/scadaproj/components/ui-theme/validation/theme-1.0.0/canary')
from browser_zoom import zoom_browser,set_browser_zoom
OUT=Path('docs/ui-consistency/evidence/sb10-12/browser-final');OUT.mkdir(parents=True,exist_ok=True)
def main():
results=[]
with sync_playwright() as p:
with zoom_browser(p) as (context,worker):
for kind in ['topology','health']:
for scheme in ['light','dark']:
for w,h,zoom in [(1440,900,1),(768,480,1),(390,844,1),(1440,900,2)]:
page=context.new_page();page.set_viewport_size({'width':w,'height':h})
errors=[];page.on('pageerror',lambda e:errors.append(str(e)))
page.add_init_script("localStorage.setItem('sb-theme', '"+scheme+"')")
route='topology-canary?role=Deployer' if kind=='topology' else 'operations-canary?role=Viewer'
page.goto('http://127.0.0.1:5201/'+route,wait_until='networkidle');page.evaluate('s => window.sbTheme.set(s)',scheme)
page.locator('.tv-root' if kind=='topology' else '[data-site-id]').first.wait_for()
page.wait_for_timeout(500)
set_browser_zoom(worker,page,zoom)
data=page.evaluate('''() => ({width:innerWidth,dpr:devicePixelRatio,document:document.documentElement.scrollWidth,scheme:document.documentElement.dataset.bsTheme,headings:[...document.querySelectorAll('h1')].map(e=>e.textContent),sites:[...document.querySelectorAll('[data-site-id]')].map(e=>e.dataset.siteId),summary:document.querySelector('[aria-label="Site observations"]')?.innerText,tree:document.querySelector('.topology-tree')&&{height:document.querySelector('.topology-tree').clientHeight,scroll:document.querySelector('.topology-tree').scrollHeight,overflow:getComputedStyle(document.querySelector('.topology-tree')).overflowY},rows:[...document.querySelectorAll('.tv-row')].slice(0,5).map(e=>e.getBoundingClientRect().height)})''')
if kind=='topology':
item=page.locator('[role=treeitem][tabindex="0"]').first;item.focus();page.keyboard.press('End');page.wait_for_function("document.activeElement === [...document.querySelectorAll('[role=treeitem]')].at(-1)")
data['endFocus']=page.evaluate('''() => ({role:document.activeElement.getAttribute('role'),bottom:document.activeElement.querySelector('.tv-row')?.getBoundingClientRect().bottom,viewport:innerHeight})''')
page.keyboard.press('Home');page.wait_for_function("document.activeElement === document.querySelector('[role=treeitem]')")
page.get_by_role('button',name='Load instances',exact=True).first.click()
page.get_by_text('Page 1',exact=True).first.wait_for();data['lazyLoad']=True
page.get_by_role('textbox',name='Search loaded sites, areas and instances').fill('facility 01');data['loadedSearchQualifier']=page.get_by_role('textbox',name='Search loaded sites, areas and instances').get_attribute('placeholder')
else: data['orderPass']=data['sites']==['offline','warning','unknown','healthy']
data.update(kind=kind,zoom=zoom,requested=[w,h],errors=errors)
data['passed']=data['document']<=data['width'] and data['scheme']==scheme and not errors and len(data['headings'])==1 and (data.get('orderPass',True)) and (kind!='topology' or data['endFocus']['bottom']<=data['endFocus']['viewport'])
if zoom==2: page.screenshot(path=str(OUT/f'{kind}-{scheme}-{w}-{h}-zoom{zoom}.png'),full_page=False)
else: page.screenshot(path=str(OUT/f'{kind}-{scheme}-{w}-{h}-zoom{zoom}.png'),full_page=False)
results.append(data);(OUT/'progress.json').write_text(json.dumps(results,indent=2));page.close()
for role,templates,audit in [('Viewer',False,True),('Designer',True,False),('Deployer',False,False),('Administrator,Designer,Deployer',True,True)]:
page=context.new_page();page.goto('http://127.0.0.1:5201/batch-two?Sample=dashboard&role='+role)
page.get_by_role('region',name='Sites configured',exact=True).wait_for();page.wait_for_timeout(300)
data={target:page.locator('main a[href="'+target+'"]').count() for target in ['/design/templates','/audit/configuration']}
# Rail uses the same real policies; hidden native navigation remains in DOM for comparison.
nav={target:page.locator('nav a[href="'+target+'"]').count() for target in data}
results.append(dict(kind='policy',role=role,shortcuts=data,rail=nav,passed=data['/design/templates']==int(templates) and data['/audit/configuration']==int(audit) and data==nav));(OUT/'progress.json').write_text(json.dumps(results,indent=2))
page.close()
touch_browser=p.chromium.launch(channel='chromium',args=['--touch-events=enabled'])
for w,h in [(390,844),(768,480)]:
touch=touch_browser.new_context(viewport={'width':w,'height':h},is_mobile=True,has_touch=True)
page=touch.new_page();page.goto('http://127.0.0.1:5201/topology-canary?role=Deployer');page.locator('.tv-root').wait_for();page.wait_for_function("matchMedia('(pointer:coarse)').matches")
record=page.evaluate("""() => ({width:innerWidth,document:document.documentElement.scrollWidth,coarse:matchMedia('(pointer:coarse)').matches,rows:[...document.querySelectorAll('.tv-row')].slice(0,8).map(e=>e.getBoundingClientRect().height),toggles:[...document.querySelectorAll('.tv-toggle')].slice(0,8).map(e=>({width:e.getBoundingClientRect().width,height:e.getBoundingClientRect().height})),overflow:getComputedStyle(document.querySelector('.topology-tree')).overflowY})""")
record.update(kind='touch',requested=[w,h]);record['passed']=record['coarse'] and min(record['rows'])>=44 and all(t['width']>=44 and t['height']>=44 for t in record['toggles']) and record['document']<=record['width'] and record['overflow']=='visible'
results.append(record);page.screenshot(path=str(OUT/f'topology-touch-{w}-{h}.png'));touch.close()
touch_browser.close()
(OUT/'results.json').write_text(json.dumps(results,indent=2));print(json.dumps({'cases':len(results),'passed':sum(x['passed'] for x in results),'failures':[r for r in results if not r['passed']]},indent=2))
main()
@@ -1,5 +1,6 @@
@page "/" @page "/"
@attribute [Authorize] @attribute [Authorize]
@using ZB.MOM.WW.ScadaBridge.Security
@using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories @using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories
@using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Security @using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Security
@inject ISiteRepository SiteRepository @inject ISiteRepository SiteRepository
@@ -19,55 +20,38 @@
</AuthorizeView> </AuthorizeView>
</div> </div>
@* KPI row *@ <div class="agg-grid dashboard-facts" aria-label="Configuration facts">
<div class="row g-3 mb-4"> <div class="agg-card" role="region" aria-label="Sites configured">
<div class="col-lg-3 col-md-6 col-12"> <div class="agg-label">Sites configured</div>
<div class="card h-100" role="region" aria-label="Sites configured"> <div class="agg-value" role="status" aria-live="polite">@CountText(_sites)</div>
<div class="card-body text-center"> @if (_sites.Failed)
<div class="fs-2 fw-bold" role="status" aria-live="polite">@CountText(_sites)</div> {
@if (_sites.Failed) <button type="button" class="btn btn-sm btn-outline-secondary mt-2" disabled="@_sites.Loading" @onclick="LoadSites">Retry Sites configured</button>
{ }
<button type="button" class="btn btn-sm btn-outline-secondary" disabled="@_sites.Loading" @onclick="LoadSites">Retry Sites configured</button>
}
<div class="text-muted small">Sites configured</div>
</div>
</div>
</div> </div>
<div class="col-lg-3 col-md-6 col-12"> <div class="agg-card" role="region" aria-label="Data connections configured">
<div class="card h-100" role="region" aria-label="Data connections configured"> <div class="agg-label">Data connections configured</div>
<div class="card-body text-center"> <div class="agg-value" role="status" aria-live="polite">@CountText(_connections)</div>
<div class="fs-2 fw-bold" role="status" aria-live="polite">@CountText(_connections)</div> @if (_connections.Failed)
@if (_connections.Failed) {
{ <button type="button" class="btn btn-sm btn-outline-secondary mt-2" disabled="@_connections.Loading" @onclick="LoadConnections">Retry Data connections configured</button>
<button type="button" class="btn btn-sm btn-outline-secondary" disabled="@_connections.Loading" @onclick="LoadConnections">Retry Data connections configured</button> }
}
<div class="text-muted small">Data connections configured</div>
</div>
</div>
</div> </div>
<div class="col-lg-3 col-md-6 col-12"> <div class="agg-card" role="region" aria-label="Templates">
<div class="card h-100" role="region" aria-label="Templates"> <div class="agg-label">Templates</div>
<div class="card-body text-center"> <div class="agg-value" role="status" aria-live="polite">@CountText(_templates)</div>
<div class="fs-2 fw-bold" role="status" aria-live="polite">@CountText(_templates)</div> @if (_templates.Failed)
@if (_templates.Failed) {
{ <button type="button" class="btn btn-sm btn-outline-secondary mt-2" disabled="@_templates.Loading" @onclick="LoadTemplates">Retry Templates</button>
<button type="button" class="btn btn-sm btn-outline-secondary" disabled="@_templates.Loading" @onclick="LoadTemplates">Retry Templates</button> }
}
<div class="text-muted small">Templates</div>
</div>
</div>
</div> </div>
<div class="col-lg-3 col-md-6 col-12"> <div class="agg-card" role="region" aria-label="API keys">
<div class="card h-100" role="region" aria-label="API keys"> <div class="agg-label">API keys</div>
<div class="card-body text-center"> <div class="agg-value" role="status" aria-live="polite">@CountText(_apiKeys)</div>
<div class="fs-2 fw-bold" role="status" aria-live="polite">@CountText(_apiKeys)</div> @if (_apiKeys.Failed)
@if (_apiKeys.Failed) {
{ <button type="button" class="btn btn-sm btn-outline-secondary mt-2" disabled="@_apiKeys.Loading" @onclick="LoadApiKeys">Retry API keys</button>
<button type="button" class="btn btn-sm btn-outline-secondary" disabled="@_apiKeys.Loading" @onclick="LoadApiKeys">Retry API keys</button> }
}
<div class="text-muted small">API keys</div>
</div>
</div>
</div> </div>
</div> </div>
@@ -85,6 +69,7 @@
</div> </div>
</a> </a>
</div> </div>
<AuthorizeView Policy="@AuthorizationPolicies.OperationalAudit" Context="shortcutContext">
<div class="col-lg-4 col-md-6 col-12"> <div class="col-lg-4 col-md-6 col-12">
<a class="card h-100 text-decoration-none text-reset" href="/audit/configuration"> <a class="card h-100 text-decoration-none text-reset" href="/audit/configuration">
<div class="card-body"> <div class="card-body">
@@ -96,6 +81,8 @@
</div> </div>
</a> </a>
</div> </div>
</AuthorizeView>
<AuthorizeView Policy="@AuthorizationPolicies.RequireDesign" Context="shortcutContext">
<div class="col-lg-4 col-md-6 col-12"> <div class="col-lg-4 col-md-6 col-12">
<a class="card h-100 text-decoration-none text-reset" href="/design/templates"> <a class="card h-100 text-decoration-none text-reset" href="/design/templates">
<div class="card-body"> <div class="card-body">
@@ -107,6 +94,7 @@
</div> </div>
</a> </a>
</div> </div>
</AuthorizeView>
</div> </div>
</div> </div>
@@ -29,7 +29,7 @@
@inject IServiceScopeFactory ScopeFactory @inject IServiceScopeFactory ScopeFactory
@implements IDisposable @implements IDisposable
<div class="container-fluid mt-3"> <div class="container-fluid mt-3 topology-page">
<ToastNotification @ref="_toast" /> <ToastNotification @ref="_toast" />
<CreateAreaDialog @bind-IsVisible="_showCreateAreaDialog" <CreateAreaDialog @bind-IsVisible="_showCreateAreaDialog"
@@ -111,7 +111,7 @@
@_allAreas.Count loaded area(s) · @_allInstances.Count loaded instance(s) across @_sites.Count site(s). Expand a branch and load its instances (50 per page). @_allAreas.Count loaded area(s) · @_allInstances.Count loaded instance(s) across @_sites.Count site(s). Expand a branch and load its instances (50 per page).
</div> </div>
<div style="max-height: calc(100vh - 240px); overflow-y: auto; padding: 4px;"> <div class="topology-tree" role="region" aria-label="Loaded topology">
<TreeView @ref="_tree" TItem="TopoNode" Items="_treeRoots" <TreeView @ref="_tree" TItem="TopoNode" Items="_treeRoots"
ChildrenSelector="n => n.Children" ChildrenSelector="n => n.Children"
HasChildrenSelector="n => n.Children.Count > 0" HasChildrenSelector="n => n.Children.Count > 0"
@@ -30,6 +30,16 @@
</div> </div>
</div> </div>
@if (_siteStates.Count > 0)
{
<section aria-label="Site observations" class="agg-grid health-facts">
<div class="agg-card"><div class="agg-label">Sites online</div><div class="agg-value">@_siteStates.Values.Count(s => s.IsOnline)</div></div>
<div class="agg-card @(_siteStates.Values.Any(s => !s.IsOnline) ? "alert" : "")"><div class="agg-label">Sites offline</div><div class="agg-value">@_siteStates.Values.Count(s => !s.IsOnline)</div></div>
<div class="agg-card @(_siteStates.Values.Any(SiteHasReportIntervalErrors) ? "caution" : "")"><div class="agg-label">Sites with errors in last report interval</div><div class="agg-value">@_siteStates.Values.Count(SiteHasReportIntervalErrors)</div></div>
<div class="agg-card"><div class="agg-label">Sites with unknown metrics</div><div class="agg-value">@_siteStates.Values.Count(s => s.LatestReport is null)</div></div>
</section>
}
@* Headline KPI groups. Each is a self-contained panel, so each gets its own card @* Headline KPI groups. Each is a self-contained panel, so each gets its own card
boundary — the same treatment the Site Health Trends group below already uses, boundary — the same treatment the Site Health Trends group below already uses,
including tiles-that-are-cards nested in a card body (Trends does exactly that including tiles-that-are-cards nested in a card body (Trends does exactly that
@@ -112,8 +122,8 @@
reuses the site keys already loaded into _siteStates; the window toggle reuses the site keys already loaded into _siteStates; the window toggle
drives the time range. Both re-query independently. *@ drives the time range. Both re-query independently. *@
<div class="card mb-3" data-test="site-health-trends"> <div class="card mb-3" data-test="site-health-trends">
<div class="card-header d-flex justify-content-between align-items-center py-2"> <div class="card-header d-flex flex-wrap gap-2 justify-content-between align-items-center py-2">
<div class="d-flex align-items-center"> <div class="d-flex flex-wrap gap-2 align-items-center">
<h6 class="text-muted mb-0 me-3">Site Health Trends</h6> <h6 class="text-muted mb-0 me-3">Site Health Trends</h6>
@if (_trendSiteKeys.Count > 0) @if (_trendSiteKeys.Count > 0)
{ {
@@ -198,50 +208,13 @@
} }
else else
{ {
@* Overview cards — the fourth headline tile row, so it takes the same card @* Actionable observations first; display name and site id provide stable tie-breakers. *@
boundary as the three above it. It was also the only tile row on the page @foreach (var (siteId, state) in _siteStates.OrderBy(s => SiteAttentionOrder(s.Value)).ThenBy(s => GetSiteName(s.Key), StringComparer.OrdinalIgnoreCase).ThenBy(s => s.Key, StringComparer.Ordinal))
with no heading at all; it now carries one for the same reason. *@
<div class="card mb-3">
<div class="card-body pb-0">
<div class="d-flex justify-content-between align-items-center mb-2">
<h6 class="text-muted mb-0">Sites</h6>
</div>
<div class="row g-3 mb-3">
<div class="col-lg-4 col-md-6 col-12">
<div class="card border-success h-100">
<div class="card-body text-center">
<h3 class="mb-0 text-success">@_siteStates.Values.Count(s => s.IsOnline)</h3>
<small class="text-muted">Sites Online</small>
</div>
</div>
</div>
<div class="col-lg-4 col-md-6 col-12">
<div class="card border-danger h-100">
<div class="card-body text-center">
<h3 class="mb-0 text-danger">@_siteStates.Values.Count(s => !s.IsOnline)</h3>
<small class="text-muted">Sites Offline</small>
</div>
</div>
</div>
<div class="col-lg-4 col-md-6 col-12">
<div class="card border-warning h-100">
<div class="card-body text-center">
<h3 class="mb-0 text-warning">@_siteStates.Values.Count(SiteHasActiveErrors)</h3>
<small class="text-muted">Sites with active errors</small>
</div>
</div>
</div>
</div>
</div>
</div>
@* Per-site detail cards — central cluster pinned to the top, then sites alphabetically *@
@foreach (var (siteId, state) in _siteStates.OrderBy(s => s.Key == CentralHealthReportLoop.CentralSiteId ? 0 : 1).ThenBy(s => s.Key))
{ {
var isCentral = siteId == CentralHealthReportLoop.CentralSiteId; var isCentral = siteId == CentralHealthReportLoop.CentralSiteId;
var siteName = isCentral ? "Central Cluster" : GetSiteName(siteId); var siteName = isCentral ? "Central Cluster" : GetSiteName(siteId);
var detailsCollapseId = $"site-details-{siteId}"; var detailsCollapseId = $"site-details-{siteId}";
<div class="card mb-3"> <div class="card mb-3" data-site-id="@siteId">
<div class="card-header d-flex justify-content-between align-items-center py-2"> <div class="card-header d-flex justify-content-between align-items-center py-2">
@* Display name and machine id are two different things and are read @* Display name and machine id are two different things and are read
for two different reasons, so they get two lines: chips + name on for two different reasons, so they get two lines: chips + name on
@@ -258,6 +231,10 @@
<span class="badge bg-danger" aria-label="State: Offline">@OfflineGlyph Offline</span> <span class="badge bg-danger" aria-label="State: Offline">@OfflineGlyph Offline</span>
} }
<strong class="fs-5">@siteName</strong> <strong class="fs-5">@siteName</strong>
@if (state.LatestReport is null)
{
<span class="badge bg-secondary">Metrics unknown</span>
}
@if (state.IsOnline && state.IsMetricsStale) @if (state.IsOnline && state.IsMetricsStale)
{ {
<span class="badge bg-warning text-dark" <span class="badge bg-warning text-dark"
@@ -751,7 +728,7 @@
private bool _localDbBacklogAvailable = true; private bool _localDbBacklogAvailable = true;
private string? _localDbBacklogError; private string? _localDbBacklogError;
private static bool SiteHasActiveErrors(SiteHealthState state) private static bool SiteHasReportIntervalErrors(SiteHealthState state)
{ {
var report = state.LatestReport; var report = state.LatestReport;
if (report == null) return false; if (report == null) return false;
@@ -760,6 +737,13 @@
|| report.DeadLetterCount > 0; || report.DeadLetterCount > 0;
} }
// Liveness remains the aggregator's observation. Missing metrics are not a healthy reading;
// report counters describe one collection interval, not an ongoing or cumulative fault.
private int SiteAttentionOrder(SiteHealthState state) => !state.IsOnline ? 0
: state.IsMetricsStale || IsLocalDbBacklogSustained(state) || IsStartupReconcilerMissing(state)
|| HasSecretMirrorFailures(state) || HasAuditRejectedRows(state) || SiteHasReportIntervalErrors(state) ? 1
: state.LatestReport is null ? 2 : 3;
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
// Load site names for display // Load site names for display
@@ -160,3 +160,13 @@ li[role="treeitem"]:focus-visible > .tv-row {
.tv-row .tv-kebab .show { .tv-row .tv-kebab .show {
opacity: 1; opacity: 1;
} }
/* Touch retains the same tree callbacks/roving focus with practical hit regions.
Fine pointers retain the existing compact rows. */
@media (pointer: coarse) {
.tv-row { min-height: 44px; }
.tv-row .tv-toggle { min-width: 44px; min-height: 44px; }
.tv-row .tv-content { min-height: 44px; }
.tv-row .tv-content button { min-width: 44px; min-height: 44px; }
.tv-row .tv-kebab { opacity: 1; }
}
@@ -214,3 +214,30 @@
.text-primary { color: var(--accent-deep) !important; } .text-primary { color: var(--accent-deep) !important; }
.text-secondary { color: var(--ink-soft) !important; } .text-secondary { color: var(--ink-soft) !important; }
.text-muted, .text-body-secondary, .text-body-tertiary { color: var(--ink-faint) !important; } .text-muted, .text-body-secondary, .text-body-tertiary { color: var(--ink-faint) !important; }
/* Host-specific four-fact composition; shared aggregate tokens and geometry own each fact. */
.dashboard-facts, .health-facts { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 1000px) { .dashboard-facts, .health-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 420px) { .dashboard-facts, .health-facts { grid-template-columns: minmax(0, 1fr); } }
/* Topology follows document flow on small/short screens; no guessed header subtraction.
On roomy desktop screens the page/toolbar/tree share the actual available height. */
.topology-page { display: flex; flex-direction: column; min-width: 0; }
.topology-tree { min-width: 0; padding: 4px; }
@media (min-width: 992px) and (min-height: 640px) {
.app-shell > main.page:has(.topology-page) {
display: flex;
flex-direction: column;
height: 100vh;
height: 100dvh;
min-height: 0;
}
.topology-page { flex: 1; min-height: 0; padding-bottom: 1rem; }
.topology-tree { flex: 1; min-height: 12rem; overflow-y: auto; }
}
@media (pointer: coarse) {
.topology-page button, .topology-page summary, .topology-page input[type="text"] {
min-height: 44px;
}
.topology-page input[type="checkbox"] { min-width: 24px; min-height: 24px; }
}
@@ -1,4 +1,9 @@
using Bunit; using Bunit;
using Microsoft.AspNetCore.Components;
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization;
using ZB.MOM.WW.ScadaBridge.Security;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using NSubstitute; using NSubstitute;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Sites; using ZB.MOM.WW.ScadaBridge.Commons.Entities.Sites;
@@ -18,7 +23,7 @@ public class DashboardStateTests : BunitContext
/// <summary>Registers deterministic read-only dependencies and a signed-in fixture.</summary> /// <summary>Registers deterministic read-only dependencies and a signed-in fixture.</summary>
public DashboardStateTests() public DashboardStateTests()
{ {
this.AddAuthorization().SetAuthorized("fixture"); SetRoles("Viewer");
_sites.GetAllSitesAsync().Returns(Task.FromResult<IReadOnlyList<Site>>([new("A", "a"), new("B", "b")])); _sites.GetAllSitesAsync().Returns(Task.FromResult<IReadOnlyList<Site>>([new("A", "a"), new("B", "b")]));
_sites.GetAllDataConnectionsAsync().Returns(Task.FromResult<IReadOnlyList<DataConnection>>([new("Link", "OpcUa", 1)])); _sites.GetAllDataConnectionsAsync().Returns(Task.FromResult<IReadOnlyList<DataConnection>>([new("Link", "OpcUa", 1)]));
_templates.GetTemplateStubsAsync().Returns(Task.FromResult<IReadOnlyList<TemplateStub>>([ _templates.GetTemplateStubsAsync().Returns(Task.FromResult<IReadOnlyList<TemplateStub>>([
@@ -26,6 +31,41 @@ public class DashboardStateTests : BunitContext
_keys.ListAsync().Returns(Task.FromResult<IReadOnlyList<InboundApiKeyInfo>>([])); _keys.ListAsync().Returns(Task.FromResult<IReadOnlyList<InboundApiKeyInfo>>([]));
Services.AddSingleton(_sites); Services.AddSingleton(_templates); Services.AddSingleton(_keys); Services.AddSingleton(_sites); Services.AddSingleton(_templates); Services.AddSingleton(_keys);
} }
private void SetRoles(params string[] roles)
{
var claims = new List<Claim> { new(JwtTokenService.UsernameClaimType, "fixture") };
claims.AddRange(roles.Select(role => new Claim(JwtTokenService.RoleClaimType, role)));
Services.AddSingleton<AuthenticationStateProvider>(new TestAuthStateProvider(
new ClaimsPrincipal(new ClaimsIdentity(claims, "TestAuth"))));
Services.AddAuthorizationCore();
AuthorizationPolicies.AddScadaBridgeAuthorization(Services);
Services.AddSingleton<IAuthorizationService, DefaultAuthorizationService>();
}
private IRenderedComponent<DashboardPage> RenderDashboard() => Render<CascadingAuthenticationState>(parameters =>
parameters.Add(p => p.ChildContent, (RenderFragment)(builder =>
{
builder.OpenComponent<DashboardPage>(0);
builder.CloseComponent();
}))).FindComponent<DashboardPage>();
/// <summary>Shortcut visibility evaluates the same real policies as navigation and destination routes.</summary>
[Theory]
[InlineData("Viewer", false, true)]
[InlineData("Designer", true, false)]
[InlineData("Deployer", false, false)]
[InlineData("Administrator", false, true)]
[InlineData("Administrator,Designer,Deployer", true, true)]
[InlineData("Unmapped", false, false)]
public void Shortcuts_RespectDestinationPolicies(string role, bool templates, bool audit)
{
SetRoles(role.Split(','));
var cut = RenderDashboard();
Assert.Single(cut.FindAll("a[href='/monitoring/health']"));
Assert.Equal(templates ? 1 : 0, cut.FindAll("a[href='/design/templates']").Count);
Assert.Equal(audit ? 1 : 0, cut.FindAll("a[href='/audit/configuration']").Count);
}
/// <summary>Each read failure leaves the other facts intact and is never a false zero.</summary> /// <summary>Each read failure leaves the other facts intact and is never a false zero.</summary>
[Theory] [Theory]
[InlineData("Sites configured")] [InlineData("Sites configured")]
@@ -38,7 +78,7 @@ public class DashboardStateTests : BunitContext
if(label=="Data connections configured")_sites.GetAllDataConnectionsAsync().Returns(Task.FromException<IReadOnlyList<DataConnection>>(new Exception("local failure"))); if(label=="Data connections configured")_sites.GetAllDataConnectionsAsync().Returns(Task.FromException<IReadOnlyList<DataConnection>>(new Exception("local failure")));
if(label=="Templates")_templates.GetTemplateStubsAsync().Returns(Task.FromException<IReadOnlyList<TemplateStub>>(new Exception("local failure"))); if(label=="Templates")_templates.GetTemplateStubsAsync().Returns(Task.FromException<IReadOnlyList<TemplateStub>>(new Exception("local failure")));
if(label=="API keys")_keys.ListAsync().Returns(Task.FromException<IReadOnlyList<InboundApiKeyInfo>>(new Exception("local failure"))); if(label=="API keys")_keys.ListAsync().Returns(Task.FromException<IReadOnlyList<InboundApiKeyInfo>>(new Exception("local failure")));
var cut=Render<DashboardPage>(); var cut=RenderDashboard();
var facts=new Dictionary<string,string>{{"Sites configured","2"},{"Data connections configured","1"},{"Templates","3"},{"API keys","0"}}; var facts=new Dictionary<string,string>{{"Sites configured","2"},{"Data connections configured","1"},{"Templates","3"},{"API keys","0"}};
foreach(var (name,count) in facts) foreach(var (name,count) in facts)
{ {
@@ -56,7 +96,7 @@ public class DashboardStateTests : BunitContext
public void RetryFailure_PreservesSuccessfulFactsAndCanRecoverToZero() public void RetryFailure_PreservesSuccessfulFactsAndCanRecoverToZero()
{ {
_keys.ListAsync().Returns(Task.FromException<IReadOnlyList<InboundApiKeyInfo>>(new Exception("local failure"))); _keys.ListAsync().Returns(Task.FromException<IReadOnlyList<InboundApiKeyInfo>>(new Exception("local failure")));
var cut=Render<DashboardPage>(); var cut=RenderDashboard();
Assert.Contains("Unavailable",cut.Find("[aria-label='API keys']").TextContent); Assert.Contains("Unavailable",cut.Find("[aria-label='API keys']").TextContent);
_keys.ListAsync().Returns(Task.FromResult<IReadOnlyList<InboundApiKeyInfo>>([])); _keys.ListAsync().Returns(Task.FromResult<IReadOnlyList<InboundApiKeyInfo>>([]));
cut.Find("[aria-label='API keys'] button").Click(); cut.Find("[aria-label='API keys'] button").Click();
@@ -72,7 +112,7 @@ public class DashboardStateTests : BunitContext
_sites.GetAllSitesAsync().Returns(Task.FromException<IReadOnlyList<Site>>(new Exception("local failure")), _sites.GetAllSitesAsync().Returns(Task.FromException<IReadOnlyList<Site>>(new Exception("local failure")),
Task.FromResult<IReadOnlyList<Site>>([new("Recovered", "recovered")])); Task.FromResult<IReadOnlyList<Site>>([new("Recovered", "recovered")]));
_sites.GetAllDataConnectionsAsync().Returns(connectionRead.Task); _sites.GetAllDataConnectionsAsync().Returns(connectionRead.Task);
var cut = Render<DashboardPage>(); var cut = RenderDashboard();
Assert.Contains("Unavailable", cut.Find("[aria-label='Sites configured']").TextContent); Assert.Contains("Unavailable", cut.Find("[aria-label='Sites configured']").TextContent);
Assert.Contains("Loading", cut.Find("[aria-label='Data connections configured']").TextContent); Assert.Contains("Loading", cut.Find("[aria-label='Data connections configured']").TextContent);
// Model two already-dispatched retries without relying on a stale DOM node. // Model two already-dispatched retries without relying on a stale DOM node.
@@ -98,7 +138,7 @@ public class DashboardStateTests : BunitContext
{ {
var pending=new TaskCompletionSource<IReadOnlyList<InboundApiKeyInfo>>(TaskCreationOptions.RunContinuationsAsynchronously); var pending=new TaskCompletionSource<IReadOnlyList<InboundApiKeyInfo>>(TaskCreationOptions.RunContinuationsAsynchronously);
_keys.ListAsync().Returns(pending.Task); _keys.ListAsync().Returns(pending.Task);
var cut=Render<DashboardPage>(); var cut=RenderDashboard();
Assert.Contains("Loading",cut.Find("[aria-label='API keys']").TextContent); Assert.Contains("Loading",cut.Find("[aria-label='API keys']").TextContent);
Assert.Contains("2",cut.Find("[aria-label='Sites configured']").TextContent); Assert.Contains("2",cut.Find("[aria-label='Sites configured']").TextContent);
await cut.InvokeAsync(()=>pending.SetResult([])); await cut.InvokeAsync(()=>pending.SetResult([]));
@@ -755,6 +755,60 @@ public class HealthPageTests : BunitContext
}); });
} }
/// <summary>Actionable observations precede healthy entries and use stable display-name ordering.</summary>
[Fact]
public void SiteCards_PrioritizeOfflineThenWarningsAndMissingReports()
{
var now = DateTimeOffset.UtcNow;
SiteHealthState Observed(string id, bool online = true, bool stale = false) => new()
{
SiteId = id, IsOnline = online, IsMetricsStale = stale,
LastHeartbeatAt = now, LastReportReceivedAt = now,
LatestReport = ReportWithReconciler(id, true)
};
SeedStates(Observed("healthy-a"), Observed("offline-z", false), Observed("warning-b", stale: true),
Observed("offline-a", false), new SiteHealthState { SiteId = "unknown", IsOnline = true, LastHeartbeatAt = now });
var cut = RenderHealthPage();
cut.WaitForAssertion(() => Assert.Equal(
new[] { "offline-a", "offline-z", "warning-b", "unknown", "healthy-a" },
cut.FindAll("[data-site-id]").Select(e => e.GetAttribute("data-site-id")).ToArray()));
}
/// <summary>Within a priority group, display name wins over machine-id order.</summary>
[Fact]
public void SiteCards_UseDisplayNameThenStableIdentifierWithinPriority()
{
var repo = Substitute.For<ISiteRepository>();
repo.GetAllSitesAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult<IReadOnlyList<Site>>([
new("Zulu", "a-id"), new("Alpha", "z-id"), new("Alpha", "b-id")]));
Services.AddSingleton(repo);
SeedStates(new SiteHealthState { SiteId = "a-id", IsOnline = false },
new SiteHealthState { SiteId = "z-id", IsOnline = false },
new SiteHealthState { SiteId = "b-id", IsOnline = false });
var cut = RenderHealthPage();
cut.WaitForAssertion(() => Assert.Equal(new[] { "b-id", "z-id", "a-id" },
cut.FindAll("[data-site-id]").Select(e => e.GetAttribute("data-site-id")).ToArray()));
}
/// <summary>Heartbeat-only sites retain known liveness but never claim observed healthy metrics.</summary>
[Fact]
public void MissingReport_IsUnknownAndIntervalErrorsAreNamedHonestly()
{
SeedStates(new SiteHealthState { SiteId = "heartbeat-only", IsOnline = true, LastHeartbeatAt = DateTimeOffset.UtcNow },
new SiteHealthState { SiteId = "observed", IsOnline = true, LastHeartbeatAt = DateTimeOffset.UtcNow,
LatestReport = ReportWithReconciler("observed", true) with { ScriptErrorCount = 2 } });
var cut = RenderHealthPage();
cut.WaitForAssertion(() =>
{
var unknown = cut.Find("[data-site-id='heartbeat-only']");
Assert.Contains("Metrics unknown", unknown.TextContent);
Assert.Contains("Online", unknown.TextContent);
Assert.DoesNotContain("Offline", unknown.TextContent);
Assert.Contains("Sites with errors in last report interval", cut.Markup);
Assert.DoesNotContain("Sites with active errors", cut.Markup);
});
}
// Re-seeds the aggregator substitute with fully-specified states (as opposed // Re-seeds the aggregator substitute with fully-specified states (as opposed
// to SeedSites' minimal online placeholders). // to SeedSites' minimal online placeholders).
private void SeedStates(params SiteHealthState[] states) private void SeedStates(params SiteHealthState[] states)