Phase 0: wipe PrimeBAT template, SimHarness (sim+probe), lint + schema harvest tools
Gate G0 green: scan clean, lint 0 failures, clients 200, probe P0 facts captured, simulator journaling. Probe locked: uuid row grouping, compound AlarmState strings, java-exception bare-except gotcha, millis dates OK, ackUserName field. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@@ -1,53 +1,9 @@
|
|||||||
{
|
{
|
||||||
"pages": {
|
"pages": {
|
||||||
"/": {
|
"/": {
|
||||||
"viewPath": "Page/Home"
|
"title": "Alarm Analysis",
|
||||||
},
|
"viewPath": "PrimeControls/Dashboard"
|
||||||
"/alarms": {
|
|
||||||
"viewPath": "Page/Alarms"
|
|
||||||
},
|
|
||||||
"/charts": {
|
|
||||||
"viewPath": "Page/Charts"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sharedDocks": {
|
"sharedDocks": {}
|
||||||
"cornerPriority": "top-bottom",
|
}
|
||||||
"left": [
|
|
||||||
{
|
|
||||||
"anchor": "fixed",
|
|
||||||
"autoBreakpoint": 768,
|
|
||||||
"content": "push",
|
|
||||||
"handle": "hide",
|
|
||||||
"iconUrl": "",
|
|
||||||
"id": "menu",
|
|
||||||
"modal": false,
|
|
||||||
"resizable": false,
|
|
||||||
"show": "auto",
|
|
||||||
"size": 210,
|
|
||||||
"viewParams": {},
|
|
||||||
"viewPath": "Docks/Menu"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"top": [
|
|
||||||
{
|
|
||||||
"anchor": "fixed",
|
|
||||||
"autoBreakpoint": 480,
|
|
||||||
"content": "push",
|
|
||||||
"handle": "hide",
|
|
||||||
"iconUrl": "",
|
|
||||||
"id": "",
|
|
||||||
"modal": false,
|
|
||||||
"resizable": false,
|
|
||||||
"show": "visible",
|
|
||||||
"size": 58,
|
|
||||||
"viewParams": {
|
|
||||||
"breakpointLarge": "768",
|
|
||||||
"breakpointMedium": "500",
|
|
||||||
"params": {},
|
|
||||||
"path": "Header/Header"
|
|
||||||
},
|
|
||||||
"viewPath": "Framework/Breakpoint"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,11 +6,5 @@
|
|||||||
"files": [
|
"files": [
|
||||||
"config.json"
|
"config.json"
|
||||||
],
|
],
|
||||||
"attributes": {
|
"attributes": {}
|
||||||
"lastModificationSignature": "1178b10756952abe8fdfa8ebe062253c757d9bf195ebfcd3dea1cc39667f9d48",
|
}
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,26 @@
|
|||||||
{
|
{
|
||||||
"custom": {},
|
"custom": {
|
||||||
|
"PrimeControls": {
|
||||||
|
"query": {
|
||||||
|
"startMs": 0,
|
||||||
|
"endMs": 0,
|
||||||
|
"rangePreset": "8h",
|
||||||
|
"priorities": [],
|
||||||
|
"areas": [],
|
||||||
|
"states": [],
|
||||||
|
"search": "",
|
||||||
|
"refreshToken": 0
|
||||||
|
},
|
||||||
|
"ui": {
|
||||||
|
"selectedTab": 0,
|
||||||
|
"badActorFocus": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"propConfig": {
|
"propConfig": {
|
||||||
|
"custom.PrimeControls": {
|
||||||
|
"persistent": true
|
||||||
|
},
|
||||||
"props.auth": {
|
"props.auth": {
|
||||||
"access": "PRIVATE",
|
"access": "PRIVATE",
|
||||||
"persistent": false
|
"persistent": false
|
||||||
@@ -59,4 +79,4 @@
|
|||||||
"theme": "light-cool",
|
"theme": "light-cool",
|
||||||
"timeZoneId": "America/Los_Angeles"
|
"timeZoneId": "America/Los_Angeles"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,5 @@
|
|||||||
"files": [
|
"files": [
|
||||||
"props.json"
|
"props.json"
|
||||||
],
|
],
|
||||||
"attributes": {
|
"attributes": {}
|
||||||
"lastModificationSignature": "69e78feccb13d237af1bc1a686c7b63ece6dce7a1a57f3799b1b6b76bfa9f861",
|
}
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"style.json"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "6e39cd3d3db12a859cd7b16b710d068fff3fe19768a5e2a81b748d691a316fbf",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"base": {
|
|
||||||
"animation": {
|
|
||||||
"keyframes": {
|
|
||||||
"0%": {
|
|
||||||
"color": "#E7F5FF",
|
|
||||||
"fill": "#E7F5FF"
|
|
||||||
},
|
|
||||||
"100%": {
|
|
||||||
"color": "#FF2E2E",
|
|
||||||
"fill": "#FF2E2E"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"style.json"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "db4826afdca6732aaf2cd310bc00bedaee3706d5d206d54cc184d3ebe1e05b4c",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"base": {
|
|
||||||
"style": {
|
|
||||||
"backgroundColor": "var(--neutral-20)",
|
|
||||||
"borderTopLeftRadius": "5px",
|
|
||||||
"borderTopRightRadius": "5px",
|
|
||||||
"borderBottomLeftRadius": "5px",
|
|
||||||
"borderBottomRightRadius": "5px",
|
|
||||||
"color": "var(--neutral-100)",
|
|
||||||
"marginBottom": "10px",
|
|
||||||
"marginTop": "10px"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"style.json"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "c28cd10d331bb5be39013910c4f55858498c38e8e3210771ca3a697790f0dfec",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"base": {
|
|
||||||
"style": {
|
|
||||||
"backgroundColor": "#003E69",
|
|
||||||
"color": "#E7F5FF",
|
|
||||||
"fontSize": "14px",
|
|
||||||
"lineHeight": "17px",
|
|
||||||
"fill": "#FFFFFF"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"style.json"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "c5e095bbad7d490925ac24e3f759ea2d74ad726cc09c1cb856d7bd1444f63213",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"base": {
|
|
||||||
"style": {
|
|
||||||
"color": "#FFFFFF",
|
|
||||||
"cursor": "pointer",
|
|
||||||
"fill": "#FFFFFF"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"style.json"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "607b5d618bc88b56d65682c6c04585b7c154ac7993e2143977382dc4003afa6b",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"base": {
|
|
||||||
"style": {
|
|
||||||
"backgroundColor": "var(--neutral-80)",
|
|
||||||
"color": "var(--neutral-10)",
|
|
||||||
"fontSize": "14px",
|
|
||||||
"fontWeight": "bold",
|
|
||||||
"lineHeight": "17px",
|
|
||||||
"textTransform": "none"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"style.json"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "a6c5e0b96293d580ef315f10ea2b4a140ce8481b2511c10efd0cf3f24ce6d3ac",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"base": {
|
|
||||||
"style": {
|
|
||||||
"backgroundColor": "var(--neutral-20)",
|
|
||||||
"borderBottomStyle": "none",
|
|
||||||
"borderTopColor": "var(--neutral-60)",
|
|
||||||
"borderTopStyle": "solid",
|
|
||||||
"borderTopWidth": "1px",
|
|
||||||
"color": "var(--neutral-80)",
|
|
||||||
"fontSize": "14px",
|
|
||||||
"lineHeight": "16px",
|
|
||||||
"textTransform": "uppercase"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variants": [
|
|
||||||
{
|
|
||||||
"pseudo": "last-child",
|
|
||||||
"style": {
|
|
||||||
"borderBottomColor": "var(--neutral-60)",
|
|
||||||
"borderBottomStyle": "solid",
|
|
||||||
"borderBottomWidth": "1px"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pseudo": "hover",
|
|
||||||
"style": {
|
|
||||||
"backgroundColor": "var(--callToActionHighlight)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"style.json"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "b36499b99310cacc81571763b37d5744604ca494c16de445fd2ae0cc4dca5e32",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"base": {
|
|
||||||
"style": {
|
|
||||||
"backgroundColor": "var(--neutral-30)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"style.json"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "6176de1d1f29cb0a21052c24356abbfbf6e6d75a7f59e741f0f999a12a6b2f40",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"base": {
|
|
||||||
"style": {
|
|
||||||
"borderBottomStyle": "none",
|
|
||||||
"borderLeftColor": "var(--neutral-40)",
|
|
||||||
"borderLeftStyle": "solid",
|
|
||||||
"borderLeftWidth": "1px",
|
|
||||||
"borderRightColor": "var(--neutral-40)",
|
|
||||||
"borderRightStyle": "solid",
|
|
||||||
"borderRightWidth": "1px",
|
|
||||||
"borderTopStyle": "none"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"style.json"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "f3ab795abf985b237e402d061de7ee0707650690ca199b1ad028cc63f725e35f",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"base": {
|
|
||||||
"style": {
|
|
||||||
"backgroundColor": "var(--neutral-20)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"style.json"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "e5d6bc9707e89cb45f16bc55800c95a150904d3d2d79736685a3bba97c558159",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"base": {
|
|
||||||
"style": {
|
|
||||||
"fontWeight": "bold"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"style.json"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "463547a6e49901b11a23984ecf682e31048b29ab5590c7c0811ed61243b70cd8",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"base": {
|
|
||||||
"style": {
|
|
||||||
"marginBottom": "12px",
|
|
||||||
"marginLeft": "12px",
|
|
||||||
"marginRight": "12px",
|
|
||||||
"marginTop": "12px"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"style.json"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "0a679916d3e3b1ec10da44d59350746ad43fd686e6a878fe576f69d42b6ba4a8",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"base": {
|
|
||||||
"style": {
|
|
||||||
"borderLeftColor": "var(--neutral-60)",
|
|
||||||
"borderLeftStyle": "solid",
|
|
||||||
"borderLeftWidth": "1px",
|
|
||||||
"fontSize": "14px",
|
|
||||||
"lineHeight": "20px"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"style.json"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "4b2f894a84a1bf9135356109fa6c79266c0aea3a48e56fdaab1086259a230bdb",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"base": {
|
|
||||||
"style": {
|
|
||||||
"fontSize": "14px",
|
|
||||||
"lineHeight": "20px"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"style.json"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "731b1ec590ef2349558f752f42656f8b47cc6157596ff718b5357be5b326549c",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"base": {
|
|
||||||
"style": {
|
|
||||||
"fill": "var(--neutral-90)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"style.json"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "0f91562405222cdff5374db4a3c993d4ef2713b4088d38ea8eed0ce57081da3c",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"base": {
|
|
||||||
"style": {
|
|
||||||
"color": "var(--neutral-90)",
|
|
||||||
"fontSize": "16px",
|
|
||||||
"fontWeight": "bold",
|
|
||||||
"lineHeight": "19px",
|
|
||||||
"marginLeft": "6px",
|
|
||||||
"fill": "var(--neutral-90)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"style.json"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "2abac97a687965df9c5e832e6cfc15eeae3a7a792a512835655542d73a6ecdb5",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"base": {
|
|
||||||
"style": {
|
|
||||||
"backgroundColor": "var(--neutral-30)",
|
|
||||||
"borderBottomColor": "var(--neutral-60)",
|
|
||||||
"borderBottomStyle": "solid",
|
|
||||||
"borderBottomWidth": "1px",
|
|
||||||
"borderTopColor": "var(--neutral-60)",
|
|
||||||
"borderTopStyle": "solid",
|
|
||||||
"borderTopWidth": "1px"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"view.json",
|
|
||||||
"thumbnail.png"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "75100c2d87f37a3ad631acaa15d029ffa0386632a5025625bc6475391e0d6ec7",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 4.2 KiB |
@@ -1,135 +0,0 @@
|
|||||||
{
|
|
||||||
"custom": {},
|
|
||||||
"params": {},
|
|
||||||
"props": {
|
|
||||||
"defaultSize": {
|
|
||||||
"width": 260
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "Features"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"grow": 1,
|
|
||||||
"shrink": 0
|
|
||||||
},
|
|
||||||
"propConfig": {
|
|
||||||
"props.items[0].style.fontWeight": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"path": "page.props.path"
|
|
||||||
},
|
|
||||||
"transforms": [
|
|
||||||
{
|
|
||||||
"expression": "if ({value} \u003d {this.props.items[0].target}, \"bold\", \"normal\")",
|
|
||||||
"type": "expression"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"type": "property"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props.items[1].style.fontWeight": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"path": "page.props.path"
|
|
||||||
},
|
|
||||||
"transforms": [
|
|
||||||
{
|
|
||||||
"expression": "if ({value} \u003d {this.props.items[1].target}, \"bold\", \"normal\")",
|
|
||||||
"type": "expression"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"type": "property"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props.items[2].style.fontWeight": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"path": "page.props.path"
|
|
||||||
},
|
|
||||||
"transforms": [
|
|
||||||
{
|
|
||||||
"expression": "if ({value} \u003d {this.props.items[2].target}, \"bold\", \"normal\")",
|
|
||||||
"type": "expression"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"type": "property"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"backActionStyle": {
|
|
||||||
"classes": "Menu/All_Header"
|
|
||||||
},
|
|
||||||
"backActionText": "All Features",
|
|
||||||
"itemStyle": {
|
|
||||||
"classes": "Menu/Item"
|
|
||||||
},
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"items": [],
|
|
||||||
"label": {
|
|
||||||
"icon": {
|
|
||||||
"path": "material/home"
|
|
||||||
},
|
|
||||||
"text": "Home"
|
|
||||||
},
|
|
||||||
"navIcon": {},
|
|
||||||
"showHeader": false,
|
|
||||||
"style": {
|
|
||||||
"classes": ""
|
|
||||||
},
|
|
||||||
"target": "/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"items": [],
|
|
||||||
"label": {
|
|
||||||
"icon": {
|
|
||||||
"path": "material/show_chart"
|
|
||||||
},
|
|
||||||
"text": "Charts"
|
|
||||||
},
|
|
||||||
"navIcon": {},
|
|
||||||
"showHeader": false,
|
|
||||||
"style": {
|
|
||||||
"classes": ""
|
|
||||||
},
|
|
||||||
"target": "/charts"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"items": [],
|
|
||||||
"label": {
|
|
||||||
"icon": {
|
|
||||||
"path": "material/alarm"
|
|
||||||
},
|
|
||||||
"text": "Alarms"
|
|
||||||
},
|
|
||||||
"navIcon": {},
|
|
||||||
"showHeader": false,
|
|
||||||
"style": {
|
|
||||||
"classes": ""
|
|
||||||
},
|
|
||||||
"target": "/alarms"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"style": {
|
|
||||||
"classes": "Menu/Menu"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.navigation.menutree"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "root"
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"style": {
|
|
||||||
"classes": "Menu/Menu"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.container.flex"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"view.json",
|
|
||||||
"thumbnail.png"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "3ccf49cb05813e379514547dfed3f952393d9c1b05697e08be75eb6fc028b12e",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 270 B |
@@ -1,107 +0,0 @@
|
|||||||
{
|
|
||||||
"custom": {},
|
|
||||||
"params": {
|
|
||||||
"breakpoint": 500,
|
|
||||||
"params": {},
|
|
||||||
"path": "Header/Header"
|
|
||||||
},
|
|
||||||
"propConfig": {
|
|
||||||
"params.breakpoint": {
|
|
||||||
"paramDirection": "input",
|
|
||||||
"persistent": true
|
|
||||||
},
|
|
||||||
"params.params": {
|
|
||||||
"paramDirection": "input",
|
|
||||||
"persistent": true
|
|
||||||
},
|
|
||||||
"params.path": {
|
|
||||||
"paramDirection": "input",
|
|
||||||
"persistent": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"defaultSize": {
|
|
||||||
"height": 58,
|
|
||||||
"width": 512
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "Large"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"size": "large"
|
|
||||||
},
|
|
||||||
"propConfig": {
|
|
||||||
"props.params.params": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"path": "view.params.params"
|
|
||||||
},
|
|
||||||
"type": "property"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props.path": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"path": "view.params.path"
|
|
||||||
},
|
|
||||||
"type": "property"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"params": {
|
|
||||||
"size": "medium"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.display.view"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "Small"
|
|
||||||
},
|
|
||||||
"propConfig": {
|
|
||||||
"props.params.params": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"path": "view.params.params"
|
|
||||||
},
|
|
||||||
"type": "property"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props.path": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"path": "view.params.path"
|
|
||||||
},
|
|
||||||
"type": "property"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"params": {
|
|
||||||
"size": "small"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.display.view"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "root"
|
|
||||||
},
|
|
||||||
"propConfig": {
|
|
||||||
"props.breakpoint": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"path": "view.params.breakpoint"
|
|
||||||
},
|
|
||||||
"type": "property"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.container.breakpt"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"view.json",
|
|
||||||
"thumbnail.png"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "12b9bfe565becb15573e4c764975c880fa3363b0f4b39fd792ed620712bac0d2",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 357 B |
@@ -1,118 +0,0 @@
|
|||||||
{
|
|
||||||
"custom": {},
|
|
||||||
"params": {
|
|
||||||
"breakpointLarge": 768,
|
|
||||||
"breakpointMedium": 500,
|
|
||||||
"params": {},
|
|
||||||
"path": "Header/Header"
|
|
||||||
},
|
|
||||||
"propConfig": {
|
|
||||||
"params.breakpointLarge": {
|
|
||||||
"paramDirection": "input",
|
|
||||||
"persistent": true
|
|
||||||
},
|
|
||||||
"params.breakpointMedium": {
|
|
||||||
"paramDirection": "input",
|
|
||||||
"persistent": true
|
|
||||||
},
|
|
||||||
"params.params": {
|
|
||||||
"paramDirection": "input",
|
|
||||||
"persistent": true
|
|
||||||
},
|
|
||||||
"params.path": {
|
|
||||||
"paramDirection": "input",
|
|
||||||
"persistent": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"defaultSize": {
|
|
||||||
"height": 58,
|
|
||||||
"width": 818
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "Large"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"size": "large"
|
|
||||||
},
|
|
||||||
"propConfig": {
|
|
||||||
"props.params.params": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"path": "view.params.params"
|
|
||||||
},
|
|
||||||
"type": "property"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props.path": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"path": "view.params.path"
|
|
||||||
},
|
|
||||||
"type": "property"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"params": {
|
|
||||||
"size": "large"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.display.view"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "Small"
|
|
||||||
},
|
|
||||||
"propConfig": {
|
|
||||||
"props.params.breakpoint": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"path": "view.params.breakpointMedium"
|
|
||||||
},
|
|
||||||
"type": "property"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props.params.params": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"path": "view.params.params"
|
|
||||||
},
|
|
||||||
"type": "property"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props.params.path": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"path": "view.params.path"
|
|
||||||
},
|
|
||||||
"type": "property"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"path": "Framework/Breakpoint Embedded"
|
|
||||||
},
|
|
||||||
"type": "ia.display.view"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "root"
|
|
||||||
},
|
|
||||||
"propConfig": {
|
|
||||||
"props.breakpoint": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"path": "view.params.breakpointLarge"
|
|
||||||
},
|
|
||||||
"type": "property"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.container.breakpt"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"view.json",
|
|
||||||
"thumbnail.png"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "9e00070a2bf48325f01052c849970bd7d5919423207b466df4fd442ee24a800d",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 2.2 KiB |
@@ -1,643 +0,0 @@
|
|||||||
{
|
|
||||||
"custom": {},
|
|
||||||
"params": {
|
|
||||||
"params": {},
|
|
||||||
"size": "medium"
|
|
||||||
},
|
|
||||||
"propConfig": {
|
|
||||||
"params.params": {
|
|
||||||
"paramDirection": "input",
|
|
||||||
"persistent": true
|
|
||||||
},
|
|
||||||
"params.size": {
|
|
||||||
"paramDirection": "input"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"defaultSize": {
|
|
||||||
"height": 58
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"hasDelegate": true,
|
|
||||||
"name": "Spacer Start"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"basis": "16px",
|
|
||||||
"shrink": 0
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"text": " "
|
|
||||||
},
|
|
||||||
"type": "ia.display.label"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"events": {
|
|
||||||
"dom": {
|
|
||||||
"onClick": {
|
|
||||||
"config": {
|
|
||||||
"id": "menu",
|
|
||||||
"type": "toggle"
|
|
||||||
},
|
|
||||||
"scope": "C",
|
|
||||||
"type": "dock"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"meta": {
|
|
||||||
"name": "Menu Dock"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"basis": "24px",
|
|
||||||
"shrink": 0
|
|
||||||
},
|
|
||||||
"propConfig": {
|
|
||||||
"position.display": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"expression": "{view.params.size} !\u003d \"large\""
|
|
||||||
},
|
|
||||||
"type": "expr"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"path": "material/menu",
|
|
||||||
"style": {
|
|
||||||
"classes": "Header/Icon",
|
|
||||||
"marginRight": "10px"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.display.icon"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "path2"
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"fill": {
|
|
||||||
"opacity": "1"
|
|
||||||
},
|
|
||||||
"path": "m 37.344391,71.227685 v 25.297 h -3.817 v -25.297 z",
|
|
||||||
"style": {
|
|
||||||
"classes": "Header/Icon"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.shapes.path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "path4"
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"fill": {
|
|
||||||
"opacity": "1"
|
|
||||||
},
|
|
||||||
"path": "m 56.308391,96.148685 c 0,0.754 -0.029,1.417 -0.075,1.991 -0.049,0.574 -0.118,1.077 -0.205,1.513 -0.262,1.201995 -0.775,2.235995 -1.542,3.097995 -1.438,1.664 -3.425,2.491 -5.945,2.491 -2.13,0 -3.884,-0.575 -5.26,-1.728 -1.421,-1.186 -2.24,-2.821 -2.458,-4.907995 h 3.702 c 0.144,0.787 0.378,1.393998 0.706,1.818995 0.764,0.993 1.879,1.49 3.342,1.49 2.698,0 4.047,-1.646 4.047,-4.945995 v -2.228 c -1.464,1.496 -3.152,2.244 -5.063,2.244 -2.172,0 -3.953,-0.788 -5.341,-2.359 -1.396,-1.595 -2.096,-3.589 -2.096,-5.98 0,-2.327 0.649,-4.303 1.949,-5.93 1.398,-1.729 3.244,-2.59 5.538,-2.59 2.011,0 3.681,0.746 5.014,2.245 v -1.803 h 3.688 v 15.581 z m -3.54,-7.561 c 0,-1.549 -0.417,-2.789 -1.245,-3.713 -0.839,-0.949 -1.915,-1.424 -3.227,-1.424 -1.4,0 -2.503,0.518 -3.312,1.553 -0.73,0.927 -1.098,2.129 -1.098,3.599 0,1.451 0.367,2.639 1.098,3.566 0.797,1.016 1.902,1.523 3.312,1.523 1.408,0 2.522,-0.513 3.342,-1.539 0.751,-0.927 1.13,-2.114 1.13,-3.565 z",
|
|
||||||
"style": {
|
|
||||||
"classes": "Header/Icon"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.shapes.path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "path6"
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"fill": {
|
|
||||||
"opacity": "1"
|
|
||||||
},
|
|
||||||
"path": "m 59.950391,80.567685 h 3.705 v 1.474 c 1.29,-1.278 2.743,-1.916 4.36,-1.916 1.857,0 3.305,0.585 4.342,1.753 0.895,0.994 1.344,2.615 1.344,4.865 v 9.782 h -3.703 v -8.902 c 0,-1.569 -0.221,-2.656 -0.657,-3.257 -0.425,-0.609 -1.202,-0.916 -2.326,-0.916 -1.224,0 -2.093,0.403 -2.606,1.21 -0.502,0.797 -0.754,2.189 -0.754,4.173 v 7.692 h -3.705 z",
|
|
||||||
"style": {
|
|
||||||
"classes": "Header/Icon"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.shapes.path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "path8"
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"fill": {
|
|
||||||
"opacity": "1"
|
|
||||||
},
|
|
||||||
"path": "m 76.790391,73.930685 c 0,-0.644 0.233,-1.202 0.702,-1.67 0.473,-0.47 1.033,-0.703 1.691,-0.703 0.663,0 1.234,0.233 1.701,0.703 0.473,0.457 0.708,1.023 0.708,1.688 0,0.667 -0.235,1.234 -0.708,1.704 -0.456,0.468 -1.02,0.705 -1.685,0.705 -0.669,0 -1.234,-0.236 -1.707,-0.705 -0.469,-0.471 -0.702,-1.045 -0.702,-1.722 z m 4.241,6.637 v 15.958 h -3.687 v -15.958 z",
|
|
||||||
"style": {
|
|
||||||
"classes": "Header/Icon"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.shapes.path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "path10"
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"fill": {
|
|
||||||
"opacity": "1"
|
|
||||||
},
|
|
||||||
"path": "m 89.170391,84.006685 v 12.519 h -3.689 v -12.519 h -1.574 v -3.439 h 1.574 v -5.849 h 3.689 v 5.849 h 2.865 v 3.439 z",
|
|
||||||
"style": {
|
|
||||||
"classes": "Header/Icon"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.shapes.path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "path12"
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"fill": {
|
|
||||||
"opacity": "1"
|
|
||||||
},
|
|
||||||
"path": "m 93.649391,73.930685 c 0,-0.644 0.233,-1.202 0.705,-1.67 0.468,-0.47 1.031,-0.703 1.688,-0.703 0.667,0 1.233,0.233 1.704,0.703 0.468,0.457 0.705,1.023 0.705,1.688 0,0.667 -0.236,1.234 -0.705,1.704 -0.459,0.468 -1.021,0.705 -1.688,0.705 -0.666,0 -1.235,-0.236 -1.704,-0.705 -0.472,-0.471 -0.705,-1.045 -0.705,-1.722 z m 4.243,6.637 v 15.958 h -3.687 v -15.958 z",
|
|
||||||
"style": {
|
|
||||||
"classes": "Header/Icon"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.shapes.path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "path14"
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"fill": {
|
|
||||||
"opacity": "1"
|
|
||||||
},
|
|
||||||
"path": "m 100.80139,88.432685 c 0,-2.305 0.826,-4.266 2.476,-5.881 1.651,-1.619 3.66,-2.426 6.03,-2.426 2.381,0 4.4,0.813 6.062,2.442 1.636,1.627 2.459,3.628 2.459,5.998 0,2.389 -0.83,4.395 -2.476,6.011 -1.662,1.604 -3.698,2.408 -6.111,2.408 -2.393,0 -4.398,-0.816 -6.014,-2.458 -1.619,-1.616 -2.426,-3.646 -2.426,-6.094 z m 3.77,0.067 c 0,1.59 0.425,2.856 1.278,3.783 0.873,0.938 2.025,1.41 3.457,1.41 1.44,0 2.596,-0.463 3.457,-1.394 0.861,-0.927 1.294,-2.167 1.294,-3.721 0,-1.55 -0.433,-2.791 -1.294,-3.717 -0.873,-0.94 -2.028,-1.41 -3.457,-1.41 -1.411,0 -2.552,0.47 -3.425,1.41 -0.874,0.938 -1.31,2.151 -1.31,3.639 z",
|
|
||||||
"style": {
|
|
||||||
"classes": "Header/Icon"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.shapes.path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "path16"
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"fill": {
|
|
||||||
"opacity": "1"
|
|
||||||
},
|
|
||||||
"path": "m 132.36239,82.585685 c -0.544,-0.74 -1.026,-1.406 -1.483,-2.036 -0.715,-0.279 -1.523,-0.425 -2.434,-0.425 -1.619,0 -3.07,0.638 -4.36,1.916 v -1.474 h -3.703 v 15.958 h 3.703 v -7.692 c 0,-1.983 0.253,-3.375 0.755,-4.173 0.513,-0.807 1.384,-1.21 2.606,-1.21 1.125,0 1.898,0.307 2.326,0.916 0.434,0.601 0.652,1.688 0.652,3.257 v 8.902 h 3.705 v -9.782 c 0,-0.719 -0.05,-1.37 -0.143,-1.963 -0.587,-0.792 -1.142,-1.54 -1.624,-2.194 z",
|
|
||||||
"style": {
|
|
||||||
"classes": "Header/Icon"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.shapes.path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "path18"
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"fill": {
|
|
||||||
"paint": "#f7901e"
|
|
||||||
},
|
|
||||||
"path": "m 170.41439,49.972685 c -0.428,-0.949 -1.103,-1.685 -2.024,-2.208 -0.927,-0.521 -1.903,-0.723 -2.933,-0.598 -1.034,0.12 -1.923,0.836 -2.664,2.151 -0.14,0.241 -0.494,0.984 -1.069,2.232 -0.578,1.245 -1.313,2.821 -2.2,4.728 -0.885,1.903 -1.892,4.048 -3.013,6.43 -1.126,2.381 -2.287,4.887 -3.484,7.513 -1.202,2.627 -2.412,5.277 -3.638,7.956 -1.201,2.625 -2.346,5.116 -3.426,7.47 0.518,0.222 1.007,0.508 1.473,0.854 2.222,-3.257 4.599,-6.724 7.125,-10.401 2.557,-3.722 4.931,-7.207 7.126,-10.46 2.196,-3.25 4.064,-6.014 5.606,-8.284 1.544,-2.271 2.425,-3.602 2.644,-3.991 0.745,-1.316 0.905,-2.443 0.477,-3.392 z"
|
|
||||||
},
|
|
||||||
"type": "ia.shapes.path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "path20"
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"fill": {
|
|
||||||
"paint": "#f7901e"
|
|
||||||
},
|
|
||||||
"path": "m 139.79939,85.710685 c -0.701,-2.8 -1.275,-5.053 -1.715,-6.762 -0.449,-1.726 -0.823,-3.093 -1.114,-4.1 -0.29,-1.003 -0.521,-1.742 -0.69,-2.21 -0.171,-0.47 -0.335,-0.871 -0.493,-1.2 -0.377,-0.79 -0.934,-1.306 -1.666,-1.547 -0.734,-0.241 -1.518,-0.161 -2.351,0.237 -0.834,0.398 -1.389,0.96 -1.66,1.681 -0.276,0.724 -0.223,1.48 0.15,2.27 0.159,0.329 0.367,0.708 0.626,1.136 0.258,0.427 0.686,1.072 1.287,1.931 0.598,0.858 1.429,2.002 2.488,3.435 1.058,1.432 2.469,3.31 4.23,5.643 0.296,-0.193 0.599,-0.369 0.908,-0.514 z"
|
|
||||||
},
|
|
||||||
"type": "ia.shapes.path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "path64"
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"fill": {
|
|
||||||
"paint": "#f7901e"
|
|
||||||
},
|
|
||||||
"path": "m 336.294,345.251 c 0,-0.837 0.668,-1.505 1.513,-1.505 0.846,0 1.512,0.668 1.512,1.505 0,0.838 -0.666,1.504 -1.512,1.504 -0.845,0 -1.513,-0.666 -1.513,-1.504 z m 2.794,0 c 0,-0.709 -0.591,-1.274 -1.281,-1.274 -0.692,0 -1.28,0.565 -1.28,1.274 0,0.709 0.588,1.273 1.28,1.273 0.69,0 1.281,-0.564 1.281,-1.273 z m -0.564,0.814 h -0.279 l -0.494,-0.76 h -0.274 v 0.76 h -0.234 v -1.647 h 0.72 c 0.297,0 0.585,0.081 0.585,0.435 0,0.324 -0.226,0.444 -0.52,0.453 z m -0.773,-0.992 c 0.206,0 0.565,0.04 0.565,-0.223 0,-0.17 -0.226,-0.2 -0.402,-0.2 h -0.438 v 0.423 z"
|
|
||||||
},
|
|
||||||
"type": "ia.shapes.path"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "g66"
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"transform": "translate(-185.14061,-250.00331)"
|
|
||||||
},
|
|
||||||
"type": "ia.shapes.group"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "circle68"
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"cx": "142.94638",
|
|
||||||
"cy": "92.620682",
|
|
||||||
"fill": {
|
|
||||||
"paint": "#f7901e"
|
|
||||||
},
|
|
||||||
"r": "4.652"
|
|
||||||
},
|
|
||||||
"type": "ia.shapes.circle"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "g196"
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"transform": "translate(0,1.2700031)"
|
|
||||||
},
|
|
||||||
"type": "ia.shapes.group"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "g111"
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"transform": "translate(-33.527391,-48.400683)"
|
|
||||||
},
|
|
||||||
"type": "ia.shapes.group"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"events": {
|
|
||||||
"dom": {
|
|
||||||
"onClick": {
|
|
||||||
"config": {
|
|
||||||
"page": "/"
|
|
||||||
},
|
|
||||||
"scope": "C",
|
|
||||||
"type": "nav"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"meta": {
|
|
||||||
"name": "Ignition Logo"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"basis": "100px",
|
|
||||||
"shrink": 0
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"style": {
|
|
||||||
"cursor": "pointer"
|
|
||||||
},
|
|
||||||
"viewBox": "0 0 137.121 58.111001"
|
|
||||||
},
|
|
||||||
"type": "ia.container.drawing"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"hasDelegate": true,
|
|
||||||
"name": "Filler"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"grow": 1
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"text": " "
|
|
||||||
},
|
|
||||||
"type": "ia.display.label"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "Dropdown"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"basis": "124px",
|
|
||||||
"shrink": 0
|
|
||||||
},
|
|
||||||
"propConfig": {
|
|
||||||
"props.value": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"bidirectional": true,
|
|
||||||
"path": "session.props.theme"
|
|
||||||
},
|
|
||||||
"type": "property"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"options": [
|
|
||||||
{
|
|
||||||
"label": "light",
|
|
||||||
"value": "light"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "light-cool",
|
|
||||||
"value": "light-cool"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "light-warm",
|
|
||||||
"value": "light-warm"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "dark",
|
|
||||||
"value": "dark"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "dark-cool",
|
|
||||||
"value": "dark-cool"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "dark-warm",
|
|
||||||
"value": "dark-warm"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"search": {
|
|
||||||
"enabled": false
|
|
||||||
},
|
|
||||||
"style": {
|
|
||||||
"classes": "Header/DropDown",
|
|
||||||
"textAlign": "left"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.input.dropdown"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"hasDelegate": true,
|
|
||||||
"name": "Spacer 1"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"basis": "10px"
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"text": " "
|
|
||||||
},
|
|
||||||
"type": "ia.display.label"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"events": {
|
|
||||||
"dom": {
|
|
||||||
"onClick": {
|
|
||||||
"config": {
|
|
||||||
"script": "\tif self.session.props.auth.authenticated:\n\t\tsystem.perspective.logout()\n\telse:\n\t\tsystem.perspective.login()"
|
|
||||||
},
|
|
||||||
"scope": "G",
|
|
||||||
"type": "script"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"meta": {
|
|
||||||
"name": "User"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"basis": "30px",
|
|
||||||
"shrink": 0
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"path": "material/person",
|
|
||||||
"style": {
|
|
||||||
"classes": "Header/Icon"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.display.icon"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"events": {
|
|
||||||
"dom": {
|
|
||||||
"onClick": {
|
|
||||||
"config": {
|
|
||||||
"script": "\tif self.session.props.auth.authenticated:\n\t\tsystem.perspective.logout()\n\telse:\n\t\tsystem.perspective.login()"
|
|
||||||
},
|
|
||||||
"scope": "G",
|
|
||||||
"type": "script"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"meta": {
|
|
||||||
"hasDelegate": true,
|
|
||||||
"name": "Sign In"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"shrink": 0
|
|
||||||
},
|
|
||||||
"propConfig": {
|
|
||||||
"position.display": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"expression": "{view.params.size} !\u003d \"small\""
|
|
||||||
},
|
|
||||||
"type": "expr"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props.text": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"path": "session.props.auth.user.userName"
|
|
||||||
},
|
|
||||||
"transforms": [
|
|
||||||
{
|
|
||||||
"expression": "if({value} \u003d null || len({value}) \u003d 0, \"Sign In\", {value})",
|
|
||||||
"type": "expression"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"type": "property"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"style": {
|
|
||||||
"classes": "Header/Icon",
|
|
||||||
"cursor": "pointer",
|
|
||||||
"marginLeft": "4px"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.display.label"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"hasDelegate": true,
|
|
||||||
"name": "Spacer 2"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"basis": "10px",
|
|
||||||
"shrink": 0
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"text": " "
|
|
||||||
},
|
|
||||||
"type": "ia.display.label"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"events": {
|
|
||||||
"dom": {
|
|
||||||
"onClick": {
|
|
||||||
"config": {
|
|
||||||
"page": "/alarms"
|
|
||||||
},
|
|
||||||
"scope": "C",
|
|
||||||
"type": "nav"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"meta": {
|
|
||||||
"name": "Alarm Icon"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"basis": "26px",
|
|
||||||
"shrink": 0
|
|
||||||
},
|
|
||||||
"propConfig": {
|
|
||||||
"props.style.classes": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"path": "../Alarms.custom.numAlarms"
|
|
||||||
},
|
|
||||||
"transforms": [
|
|
||||||
{
|
|
||||||
"expression": "if({value} \u003e 0, \"Header/Alarm_Active\", \"Header/Icon\")",
|
|
||||||
"type": "expression"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"type": "property"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"path": "material/alarm"
|
|
||||||
},
|
|
||||||
"type": "ia.display.icon"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"events": {
|
|
||||||
"dom": {
|
|
||||||
"onClick": {
|
|
||||||
"config": {
|
|
||||||
"page": "/alarms"
|
|
||||||
},
|
|
||||||
"scope": "C",
|
|
||||||
"type": "nav"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"meta": {
|
|
||||||
"hasDelegate": true,
|
|
||||||
"name": "Alarms"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"shrink": 0
|
|
||||||
},
|
|
||||||
"propConfig": {
|
|
||||||
"custom.numAlarms": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"expression": "now(2000)"
|
|
||||||
},
|
|
||||||
"transforms": [
|
|
||||||
{
|
|
||||||
"code": "\treturn len(system.alarm.queryStatus(state\u003d[\"ActiveUnacked\"]))",
|
|
||||||
"type": "script"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"type": "expr"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"position.display": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"expression": "{view.params.size} !\u003d \"small\""
|
|
||||||
},
|
|
||||||
"type": "expr"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props.style.classes": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"path": "../Alarms.custom.numAlarms"
|
|
||||||
},
|
|
||||||
"transforms": [
|
|
||||||
{
|
|
||||||
"expression": "if({value} \u003e 0, \"Header/Alarm_Active\", \"\")",
|
|
||||||
"type": "expression"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"type": "property"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props.text": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"path": "this.custom.numAlarms"
|
|
||||||
},
|
|
||||||
"transforms": [
|
|
||||||
{
|
|
||||||
"expression": "numberFormat({value}, \"#,##0\") + \" alarm\" + if({value} \u003e 1 || {value} \u003d 0, \"s\", \"\")",
|
|
||||||
"type": "expression"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"type": "property"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"style": {
|
|
||||||
"cursor": "pointer",
|
|
||||||
"marginLeft": "6px"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.display.label"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"hasDelegate": true,
|
|
||||||
"name": "Spacer End"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"basis": "16px",
|
|
||||||
"shrink": 0
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"text": " "
|
|
||||||
},
|
|
||||||
"type": "ia.display.label"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "root"
|
|
||||||
},
|
|
||||||
"propConfig": {
|
|
||||||
"props.style.backgroundColor": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"path": "session.props.theme"
|
|
||||||
},
|
|
||||||
"transforms": [
|
|
||||||
{
|
|
||||||
"code": "\tif \"dark\" in value:\n\t\treturn \"var(--neutral-10)\"\n\telse:\n\t\treturn \"\"",
|
|
||||||
"type": "script"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"type": "property"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"style": {
|
|
||||||
"classes": "Header/Header"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.container.flex"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"view.json",
|
|
||||||
"thumbnail.png"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "295c4883382d0243d3e8270d5a208fec97cf3bd84a43573e894c552707c0480c",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 17 KiB |
@@ -1,66 +0,0 @@
|
|||||||
{
|
|
||||||
"custom": {},
|
|
||||||
"params": {},
|
|
||||||
"propConfig": {
|
|
||||||
"params.feature": {
|
|
||||||
"paramDirection": "input"
|
|
||||||
},
|
|
||||||
"params.key": {
|
|
||||||
"paramDirection": "input"
|
|
||||||
},
|
|
||||||
"params.tier1": {
|
|
||||||
"paramDirection": "input"
|
|
||||||
},
|
|
||||||
"params.tier2": {
|
|
||||||
"paramDirection": "input"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props": {},
|
|
||||||
"root": {
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "Title"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"basis": "56px",
|
|
||||||
"shrink": 0
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"params": {
|
|
||||||
"icon": "alarm",
|
|
||||||
"text": "Alarms"
|
|
||||||
},
|
|
||||||
"path": "Page/Embedded/Title"
|
|
||||||
},
|
|
||||||
"type": "ia.display.view"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "AlarmStatusTable"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"basis": "400px",
|
|
||||||
"grow": 1
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"style": {
|
|
||||||
"classes": "Page/Alarm/Alarm"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.display.alarmstatustable"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "root"
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"alignContent": "flex-start",
|
|
||||||
"direction": "column",
|
|
||||||
"style": {
|
|
||||||
"classes": "Page/Alarm/Page Page/Page"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.container.flex"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"view.json",
|
|
||||||
"thumbnail.png"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "5023f2710f4d702828d7fc9f6d63dc16ce483727872ce0ee0c71af7446129630",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 13 KiB |
@@ -1,60 +0,0 @@
|
|||||||
{
|
|
||||||
"custom": {},
|
|
||||||
"params": {},
|
|
||||||
"propConfig": {
|
|
||||||
"params.feature": {
|
|
||||||
"paramDirection": "input"
|
|
||||||
},
|
|
||||||
"params.key": {
|
|
||||||
"paramDirection": "input"
|
|
||||||
},
|
|
||||||
"params.tier1": {
|
|
||||||
"paramDirection": "input"
|
|
||||||
},
|
|
||||||
"params.tier2": {
|
|
||||||
"paramDirection": "input"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props": {},
|
|
||||||
"root": {
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "Title"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"basis": "56px",
|
|
||||||
"shrink": 0
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"params": {
|
|
||||||
"icon": "show_chart",
|
|
||||||
"text": "Charts"
|
|
||||||
},
|
|
||||||
"path": "Page/Embedded/Title"
|
|
||||||
},
|
|
||||||
"type": "ia.display.view"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "PowerChart"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"basis": "600px",
|
|
||||||
"grow": 1
|
|
||||||
},
|
|
||||||
"type": "ia.chart.powerchart"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "root"
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"direction": "column",
|
|
||||||
"style": {
|
|
||||||
"classes": "Page/Page"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.container.flex"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"view.json",
|
|
||||||
"thumbnail.png"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "4faccd858e984072a9442439dc3f60d3c0332ce5d8c8f116e14cb6037916b80e",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 836 B |
@@ -1,89 +0,0 @@
|
|||||||
{
|
|
||||||
"custom": {},
|
|
||||||
"params": {
|
|
||||||
"icon": "home",
|
|
||||||
"text": "Home"
|
|
||||||
},
|
|
||||||
"propConfig": {
|
|
||||||
"params.icon": {
|
|
||||||
"paramDirection": "input",
|
|
||||||
"persistent": true
|
|
||||||
},
|
|
||||||
"params.text": {
|
|
||||||
"paramDirection": "input",
|
|
||||||
"persistent": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"defaultSize": {
|
|
||||||
"height": 56,
|
|
||||||
"width": 600
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "Icon"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"basis": "24px",
|
|
||||||
"shrink": 0
|
|
||||||
},
|
|
||||||
"propConfig": {
|
|
||||||
"props.path": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"expression": "\"material/\" + {view.params.icon}"
|
|
||||||
},
|
|
||||||
"type": "expr"
|
|
||||||
},
|
|
||||||
"persistent": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"style": {
|
|
||||||
"classes": "Title/Icon",
|
|
||||||
"marginLeft": "10px"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.display.icon"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"hasDelegate": true,
|
|
||||||
"name": "Label"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"grow": 1
|
|
||||||
},
|
|
||||||
"propConfig": {
|
|
||||||
"props.text": {
|
|
||||||
"binding": {
|
|
||||||
"config": {
|
|
||||||
"path": "view.params.text"
|
|
||||||
},
|
|
||||||
"type": "property"
|
|
||||||
},
|
|
||||||
"persistent": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"style": {
|
|
||||||
"classes": "Title/Text"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.display.label"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "root"
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"style": {
|
|
||||||
"classes": "Title/Title"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.container.flex"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"scope": "G",
|
|
||||||
"version": 1,
|
|
||||||
"restricted": false,
|
|
||||||
"overridable": true,
|
|
||||||
"files": [
|
|
||||||
"view.json",
|
|
||||||
"thumbnail.png"
|
|
||||||
],
|
|
||||||
"attributes": {
|
|
||||||
"lastModificationSignature": "c74f714316b78db6782c355f8ab653ae63b8e66be4b7125ac0bd4ed52fc906ac",
|
|
||||||
"lastModification": {
|
|
||||||
"actor": "admin",
|
|
||||||
"timestamp": "2026-07-16T16:25:30Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 23 KiB |
@@ -1,92 +0,0 @@
|
|||||||
{
|
|
||||||
"custom": {},
|
|
||||||
"params": {},
|
|
||||||
"propConfig": {
|
|
||||||
"params.feature": {
|
|
||||||
"paramDirection": "input"
|
|
||||||
},
|
|
||||||
"params.key": {
|
|
||||||
"paramDirection": "input"
|
|
||||||
},
|
|
||||||
"params.tier1": {
|
|
||||||
"paramDirection": "input"
|
|
||||||
},
|
|
||||||
"params.tier2": {
|
|
||||||
"paramDirection": "input"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"props": {},
|
|
||||||
"root": {
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "Title"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"basis": "56px",
|
|
||||||
"shrink": 0
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"params": {
|
|
||||||
"icon": "home",
|
|
||||||
"text": "Home"
|
|
||||||
},
|
|
||||||
"path": "Page/Embedded/Title"
|
|
||||||
},
|
|
||||||
"type": "ia.display.view"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"hasDelegate": true,
|
|
||||||
"name": "Welcome"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"basis": "20px",
|
|
||||||
"shrink": 0
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"style": {
|
|
||||||
"classes": "Page/Bold Page/Margins Page/Text"
|
|
||||||
},
|
|
||||||
"text": "Welcome to Perspective!"
|
|
||||||
},
|
|
||||||
"type": "ia.display.label"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"hasDelegate": true,
|
|
||||||
"name": "Description"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"shrink": 0
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"style": {
|
|
||||||
"classes": "Page/Text Page/Margins"
|
|
||||||
},
|
|
||||||
"text": "The skeleton project is intended to help you get started with Perspective. The project is designed to be mobile-responsive and fully utilizes styles. Feel free to modify as desired."
|
|
||||||
},
|
|
||||||
"type": "ia.display.label"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"name": "CoordinateContainer"
|
|
||||||
},
|
|
||||||
"position": {
|
|
||||||
"grow": 1
|
|
||||||
},
|
|
||||||
"type": "ia.container.coord"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"name": "root"
|
|
||||||
},
|
|
||||||
"props": {
|
|
||||||
"direction": "column",
|
|
||||||
"style": {
|
|
||||||
"classes": "Page/Page"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "ia.container.flex"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"scope": "G",
|
||||||
|
"version": 1,
|
||||||
|
"restricted": false,
|
||||||
|
"overridable": true,
|
||||||
|
"files": [
|
||||||
|
"view.json"
|
||||||
|
],
|
||||||
|
"attributes": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"custom": {},
|
||||||
|
"params": {},
|
||||||
|
"propConfig": {},
|
||||||
|
"props": {
|
||||||
|
"defaultSize": {
|
||||||
|
"height": 900,
|
||||||
|
"width": 1600
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"meta": {
|
||||||
|
"name": "lblPlaceholder"
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"grow": 0
|
||||||
|
},
|
||||||
|
"props": {
|
||||||
|
"text": "PrimeControls Dashboard - under construction (Phase 0 placeholder)",
|
||||||
|
"textStyle": {
|
||||||
|
"fontSize": "1.2em"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "ia.display.label"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"custom": {},
|
||||||
|
"meta": {
|
||||||
|
"name": "root"
|
||||||
|
},
|
||||||
|
"props": {
|
||||||
|
"alignItems": "center",
|
||||||
|
"direction": "column",
|
||||||
|
"justify": "center"
|
||||||
|
},
|
||||||
|
"type": "ia.container.flex"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"pages": {
|
||||||
|
"/scratch": {
|
||||||
|
"title": "Scratch",
|
||||||
|
"viewPath": "Scratch/Current"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sharedDocks": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"scope": "G",
|
||||||
|
"version": 1,
|
||||||
|
"restricted": false,
|
||||||
|
"overridable": true,
|
||||||
|
"files": [
|
||||||
|
"config.json"
|
||||||
|
],
|
||||||
|
"attributes": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"scope": "G",
|
||||||
|
"version": 1,
|
||||||
|
"restricted": false,
|
||||||
|
"overridable": true,
|
||||||
|
"files": [
|
||||||
|
"view.json"
|
||||||
|
],
|
||||||
|
"attributes": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"custom": {},
|
||||||
|
"params": {},
|
||||||
|
"propConfig": {},
|
||||||
|
"props": {},
|
||||||
|
"root": {
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"meta": {
|
||||||
|
"name": "lblScratch"
|
||||||
|
},
|
||||||
|
"props": {
|
||||||
|
"text": "SimHarness scratch view - overwrite me to isolate a component under test."
|
||||||
|
},
|
||||||
|
"type": "ia.display.label"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"custom": {},
|
||||||
|
"meta": {
|
||||||
|
"name": "root"
|
||||||
|
},
|
||||||
|
"props": {
|
||||||
|
"direction": "column"
|
||||||
|
},
|
||||||
|
"type": "ia.container.flex"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
# alarm_simulator.py — Build-a-Thon alarm activity generator (Jython, Ignition 8.3)
|
||||||
|
#
|
||||||
|
# Drives the Boolean memory tags in [default]BuildathonSim/ (import
|
||||||
|
# simulation_tags.json first). Designed to be called every 5 seconds:
|
||||||
|
#
|
||||||
|
# RECOMMENDED — Gateway timer script (survives Designer close):
|
||||||
|
# 1. Designer > Project Library: create a script named "alarmsim", paste this file.
|
||||||
|
# 2. Project > Gateway Events > Timer: new script, Delay 5000 ms,
|
||||||
|
# Fixed Delay, Dedicated thread. Body: alarmsim.tick()
|
||||||
|
# 3. Save the project. Alarm activity starts immediately and runs forever.
|
||||||
|
#
|
||||||
|
# ALTERNATIVE — Designer Script Console (blocks the console while running):
|
||||||
|
# Paste this whole file, then add at the bottom:
|
||||||
|
# run_console(minutes=30)
|
||||||
|
#
|
||||||
|
# Patterns produced (all timestamps land in the alarm journal):
|
||||||
|
# - Baseline: random alarms across 5 areas / 3 priorities, active 30 s - 5 min,
|
||||||
|
# averaging a few activations per minute
|
||||||
|
# - Chattering: *_Chatter tags re-trigger every 30-60 s (short 5-15 s actives)
|
||||||
|
# - Standing: *_Standing tags go active on the first tick and never clear
|
||||||
|
# - Fleeting: *_Fleeting tags are active < 10 s
|
||||||
|
# - Flood: roughly every 30-60 min (or on demand via force_flood()), one area
|
||||||
|
# bursts 20-40 activations over 10 minutes
|
||||||
|
#
|
||||||
|
# Manual helpers (Script Console, gateway scope via system.util.sendRequest not
|
||||||
|
# needed — just call from a console if running console mode, or temporarily from
|
||||||
|
# the timer script):
|
||||||
|
# alarmsim.force_flood() -> start a flood burst now
|
||||||
|
# alarmsim.reset() -> clear all sim tags and internal state
|
||||||
|
|
||||||
|
import random
|
||||||
|
import time
|
||||||
|
|
||||||
|
BASE = "[default]BuildathonSim"
|
||||||
|
|
||||||
|
BASELINE = {
|
||||||
|
"Intake": ["Pump1_Fault", "Pump2_Fault", "ScreenDiffPressHigh", "InletFlowLow",
|
||||||
|
"ValveV101_FailToOpen", "WetWellLevelHigh", "SampleTempHigh", "PowerMonitorAlarm"],
|
||||||
|
"BoilerHouse": ["FeedPumpA_Fault", "FeedPumpB_Fault", "SteamPressHigh", "DrumLevelLow",
|
||||||
|
"StackTempHigh", "FuelGasPressLow", "EconomizerDPHigh", "BlowdownConductivityHigh"],
|
||||||
|
"Packaging": ["LabelerFault", "CapperTorqueLow", "FillerLevelDeviation", "ConveyorOverload",
|
||||||
|
"CaseSealerJam", "PrinterInkLow", "RejectRateHigh", "GuardDoorOpen"],
|
||||||
|
"Utilities": ["AirCompA_Fault", "AirHeaderPressLow", "ChillerTripped", "CoolingTowerVibration",
|
||||||
|
"GlycolTempHigh", "N2PressLow", "UPSOnBattery", "WaterSoftenerFault"],
|
||||||
|
"TankFarm": ["T101_LevelHigh", "T102_LevelHigh", "T103_TempHigh", "TransferPumpFault",
|
||||||
|
"ContainmentSumpHigh", "VaporRecoveryFault", "T104_PressHigh", "ManifoldLeakDetect"],
|
||||||
|
}
|
||||||
|
|
||||||
|
CHATTER = [
|
||||||
|
"Intake/ConveyorJam_Chatter",
|
||||||
|
"Packaging/ShrinkTunnelTemp_Chatter",
|
||||||
|
"Utilities/AirDryerDewpoint_Chatter",
|
||||||
|
]
|
||||||
|
STANDING = [
|
||||||
|
"BoilerHouse/DrumLevelXmtrFail_Standing",
|
||||||
|
"TankFarm/T105_LevelXmtrFail_Standing",
|
||||||
|
]
|
||||||
|
FLEETING = [
|
||||||
|
"Intake/CommsGlitch_Fleeting",
|
||||||
|
"BoilerHouse/FlameScannerFlicker_Fleeting",
|
||||||
|
"Packaging/EStopPulse_Fleeting",
|
||||||
|
"TankFarm/PumpSealFlushLow_Fleeting",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Tuning (per 5 s tick)
|
||||||
|
BASELINE_PROB = 0.30 # ~3-4 baseline activations/min across the plant
|
||||||
|
FLEETING_PROB = 0.08 # ~1 fleeting alarm/min
|
||||||
|
FLOOD_START_PROB = 0.0025 # expected flood every ~30-60 min
|
||||||
|
FLOOD_DURATION = 600 # 10 minutes
|
||||||
|
FLOOD_EVENT_PROB = 0.35 # per tick during flood -> ~25 activations / 10 min
|
||||||
|
|
||||||
|
|
||||||
|
def _path(rel):
|
||||||
|
return "%s/%s" % (BASE, rel)
|
||||||
|
|
||||||
|
|
||||||
|
def _state():
|
||||||
|
g = system.util.getGlobals()
|
||||||
|
if "buildathon_alarmsim" not in g:
|
||||||
|
g["buildathon_alarmsim"] = {
|
||||||
|
"clears": {}, # tag path -> epoch seconds to write False
|
||||||
|
"chatter_next": {}, # chatter path -> epoch seconds of next re-trigger
|
||||||
|
"flood": None, # {"area": name, "until": epoch} while flooding
|
||||||
|
"standing_set": False,
|
||||||
|
}
|
||||||
|
return g["buildathon_alarmsim"]
|
||||||
|
|
||||||
|
|
||||||
|
def _write(pairs):
|
||||||
|
if pairs:
|
||||||
|
system.tag.writeBlocking([p for p, v in pairs], [v for p, v in pairs])
|
||||||
|
|
||||||
|
|
||||||
|
def tick():
|
||||||
|
st = _state()
|
||||||
|
now = time.time()
|
||||||
|
writes = []
|
||||||
|
|
||||||
|
# 1. Standing alarms: activate once, never clear
|
||||||
|
if not st["standing_set"]:
|
||||||
|
writes += [(_path(p), True) for p in STANDING]
|
||||||
|
st["standing_set"] = True
|
||||||
|
|
||||||
|
# 2. Process scheduled clears
|
||||||
|
for path in list(st["clears"].keys()):
|
||||||
|
if now >= st["clears"][path]:
|
||||||
|
writes.append((path, False))
|
||||||
|
del st["clears"][path]
|
||||||
|
|
||||||
|
# 3. Baseline activity: random tag, active 30 s - 5 min
|
||||||
|
if random.random() < BASELINE_PROB:
|
||||||
|
area = random.choice(list(BASELINE.keys()))
|
||||||
|
path = _path("%s/%s" % (area, random.choice(BASELINE[area])))
|
||||||
|
if path not in st["clears"]:
|
||||||
|
writes.append((path, True))
|
||||||
|
st["clears"][path] = now + random.uniform(30, 300)
|
||||||
|
|
||||||
|
# 4. Chattering: re-trigger every 30-60 s, active 5-15 s each time
|
||||||
|
for rel in CHATTER:
|
||||||
|
path = _path(rel)
|
||||||
|
nxt = st["chatter_next"].get(path, 0)
|
||||||
|
if now >= nxt and path not in st["clears"]:
|
||||||
|
writes.append((path, True))
|
||||||
|
st["clears"][path] = now + random.uniform(5, 15)
|
||||||
|
st["chatter_next"][path] = now + random.uniform(30, 60)
|
||||||
|
|
||||||
|
# 5. Fleeting: active 2-8 s
|
||||||
|
if random.random() < FLEETING_PROB:
|
||||||
|
path = _path(random.choice(FLEETING))
|
||||||
|
if path not in st["clears"]:
|
||||||
|
writes.append((path, True))
|
||||||
|
st["clears"][path] = now + random.uniform(2, 8)
|
||||||
|
|
||||||
|
# 6. Flood burst: one area, 15+ activations inside 10 minutes
|
||||||
|
if st["flood"] is None:
|
||||||
|
if random.random() < FLOOD_START_PROB:
|
||||||
|
_start_flood(st, now)
|
||||||
|
elif now >= st["flood"]["until"]:
|
||||||
|
st["flood"] = None
|
||||||
|
else:
|
||||||
|
if random.random() < FLOOD_EVENT_PROB:
|
||||||
|
area = st["flood"]["area"]
|
||||||
|
path = _path("%s/%s" % (area, random.choice(BASELINE[area])))
|
||||||
|
# During a flood, alarms clear fast and may re-trigger, inflating the
|
||||||
|
# event rate the way a real upset does. Overwrite any pending clear.
|
||||||
|
writes.append((path, True))
|
||||||
|
st["clears"][path] = now + random.uniform(10, 45)
|
||||||
|
|
||||||
|
_write(writes)
|
||||||
|
|
||||||
|
|
||||||
|
def _start_flood(st, now):
|
||||||
|
area = random.choice(list(BASELINE.keys()))
|
||||||
|
st["flood"] = {"area": area, "until": now + FLOOD_DURATION}
|
||||||
|
system.util.getLogger("alarmsim").info("Flood burst started in area: %s" % area)
|
||||||
|
|
||||||
|
|
||||||
|
def force_flood():
|
||||||
|
"""Start a flood burst immediately (handy for demo/testing)."""
|
||||||
|
_start_flood(_state(), time.time())
|
||||||
|
|
||||||
|
|
||||||
|
def reset():
|
||||||
|
"""Clear all simulation tags and internal state."""
|
||||||
|
g = system.util.getGlobals()
|
||||||
|
g.pop("buildathon_alarmsim", None)
|
||||||
|
paths = []
|
||||||
|
for area, names in BASELINE.items():
|
||||||
|
paths += [_path("%s/%s" % (area, n)) for n in names]
|
||||||
|
paths += [_path(p) for p in CHATTER + STANDING + FLEETING]
|
||||||
|
system.tag.writeBlocking(paths, [False] * len(paths))
|
||||||
|
|
||||||
|
|
||||||
|
def run_console(minutes=30):
|
||||||
|
"""Script Console runner: calls tick() every 5 s for `minutes`. Blocks the console."""
|
||||||
|
end = time.time() + minutes * 60
|
||||||
|
while time.time() < end:
|
||||||
|
tick()
|
||||||
|
time.sleep(5)
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"scope": "A",
|
||||||
|
"version": 1,
|
||||||
|
"restricted": false,
|
||||||
|
"overridable": true,
|
||||||
|
"files": [
|
||||||
|
"code.py"
|
||||||
|
],
|
||||||
|
"attributes": {
|
||||||
|
"hintScope": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
# probe - gateway-side API ground truth (SimHarness, dev-only, Jython 2.7).
|
||||||
|
#
|
||||||
|
# Runs inside the gateway via the ProbeTick timer (enable it, scan, wait <=20s,
|
||||||
|
# read the output, disable it). Writes JSON to the bind-mounted repo path:
|
||||||
|
# container: /usr/local/bin/ignition/data/projects/.probe/out.json
|
||||||
|
# host repo: ignition/gateway/projects/.probe/out.json
|
||||||
|
#
|
||||||
|
# Edit PROBE_NAME / add sections as needed; every section is try-wrapped so a
|
||||||
|
# single API surprise never kills the whole probe.
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
OUT_DIR = "/usr/local/bin/ignition/data/projects/.probe"
|
||||||
|
PROBE_NAME = "P0"
|
||||||
|
|
||||||
|
|
||||||
|
def _safe(fn):
|
||||||
|
# Bare except is deliberate: in Jython, JAVA exceptions (e.g. bad kwargs
|
||||||
|
# into system.* calls) do NOT subclass Python's Exception and would fly
|
||||||
|
# straight past 'except Exception'.
|
||||||
|
try:
|
||||||
|
return {"ok": True, "value": fn()}
|
||||||
|
except:
|
||||||
|
import sys
|
||||||
|
et, ev = sys.exc_info()[0], sys.exc_info()[1]
|
||||||
|
return {"ok": False, "error": "%s: %s" % (getattr(et, "__name__", et), ev)}
|
||||||
|
|
||||||
|
|
||||||
|
def _write(result):
|
||||||
|
from java.io import File
|
||||||
|
File(OUT_DIR).mkdirs()
|
||||||
|
f = open(OUT_DIR + "/out.json", "w")
|
||||||
|
try:
|
||||||
|
f.write(json.dumps(result, indent=1, default=lambda o: repr(o)))
|
||||||
|
finally:
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
|
def _prop(evt, names):
|
||||||
|
out = {}
|
||||||
|
for n in names:
|
||||||
|
try:
|
||||||
|
v = evt.get(n)
|
||||||
|
out[n] = {"cls": v is not None and v.__class__.__name__ or None,
|
||||||
|
"repr": repr(v)[:200]}
|
||||||
|
except Exception, e:
|
||||||
|
out[n] = {"error": "%s" % e}
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def _entry_facts(evt):
|
||||||
|
d = {}
|
||||||
|
d["cls"] = evt.__class__.__name__
|
||||||
|
try:
|
||||||
|
d["id"] = str(evt.getId())
|
||||||
|
except Exception, e:
|
||||||
|
d["id_error"] = "%s" % e
|
||||||
|
try:
|
||||||
|
s = evt.getState()
|
||||||
|
d["state_str"] = str(s)
|
||||||
|
d["state_cls"] = s is not None and s.__class__.__name__ or None
|
||||||
|
except Exception, e:
|
||||||
|
d["state_error"] = "%s" % e
|
||||||
|
try:
|
||||||
|
d["source"] = str(evt.getSource())
|
||||||
|
except Exception, e:
|
||||||
|
d["source_error"] = "%s" % e
|
||||||
|
try:
|
||||||
|
d["displayPath"] = repr(evt.getDisplayPath())
|
||||||
|
except Exception, e:
|
||||||
|
d["displayPath_error"] = "%s" % e
|
||||||
|
try:
|
||||||
|
p = evt.getPriority()
|
||||||
|
d["priority_cls"] = p is not None and p.__class__.__name__ or None
|
||||||
|
d["priority_str"] = str(p)
|
||||||
|
try:
|
||||||
|
d["priority_int"] = int(p.ordinal())
|
||||||
|
except Exception:
|
||||||
|
try:
|
||||||
|
d["priority_int"] = int(p)
|
||||||
|
except Exception:
|
||||||
|
d["priority_int"] = None
|
||||||
|
except Exception, e:
|
||||||
|
d["priority_error"] = "%s" % e
|
||||||
|
d["props"] = _prop(evt, ["eventTime", "eventType", "eventtype", "ackUser",
|
||||||
|
"ackUserName", "isSystemEvent", "systemEvent",
|
||||||
|
"eventValue", "name", "label"])
|
||||||
|
for getter in ("getActiveData", "getClearedData", "getAckData"):
|
||||||
|
try:
|
||||||
|
v = getattr(evt, getter)()
|
||||||
|
d[getter] = v is not None and repr(v)[:200] or None
|
||||||
|
except Exception, e:
|
||||||
|
d[getter] = "ERR %s" % e
|
||||||
|
try:
|
||||||
|
from java.util import Date
|
||||||
|
t = evt.get("eventTime")
|
||||||
|
if t is not None and isinstance(t, Date):
|
||||||
|
d["eventTime_ms"] = t.getTime()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def _p0():
|
||||||
|
result = {}
|
||||||
|
end = system.date.now()
|
||||||
|
start = system.date.addHours(end, -8)
|
||||||
|
|
||||||
|
def q_basic():
|
||||||
|
r = system.alarm.queryJournal(startDate=start, endDate=end)
|
||||||
|
entries = [e for e in r]
|
||||||
|
by_id = {}
|
||||||
|
for e in entries:
|
||||||
|
try:
|
||||||
|
k = str(e.getId())
|
||||||
|
except Exception:
|
||||||
|
k = "?"
|
||||||
|
by_id.setdefault(k, []).append(e)
|
||||||
|
multi = {}
|
||||||
|
n = 0
|
||||||
|
for k, evts in by_id.items():
|
||||||
|
if len(evts) > 1 and n < 5:
|
||||||
|
states = []
|
||||||
|
for e in evts:
|
||||||
|
try:
|
||||||
|
states.append(str(e.getState()))
|
||||||
|
except Exception:
|
||||||
|
states.append("?")
|
||||||
|
multi[k] = states
|
||||||
|
n += 1
|
||||||
|
return {
|
||||||
|
"result_cls": r.__class__.__name__,
|
||||||
|
"len_works": _safe(lambda: len(r)),
|
||||||
|
"dataset_attr": hasattr(r, "getDataset"),
|
||||||
|
"entry_count": len(entries),
|
||||||
|
"distinct_ids": len(by_id),
|
||||||
|
"multi_state_id_samples": multi,
|
||||||
|
"first_entries": [_entry_facts(e) for e in entries[:6]],
|
||||||
|
"system_rows": [_entry_facts(e) for e in entries
|
||||||
|
if str(_safe(lambda: str(e.getSource()))["value"]).startswith("evt:")][:3],
|
||||||
|
}
|
||||||
|
result["basic"] = _safe(q_basic)
|
||||||
|
|
||||||
|
result["no_kwargs_at_all"] = _safe(
|
||||||
|
lambda: len([e for e in system.alarm.queryJournal(
|
||||||
|
startDate=start, endDate=end)]))
|
||||||
|
result["with_journal_name"] = _safe(
|
||||||
|
lambda: len([e for e in system.alarm.queryJournal(
|
||||||
|
journalName="Journal", startDate=start, endDate=end)]))
|
||||||
|
result["bad_journal_name"] = _safe(
|
||||||
|
lambda: len([e for e in system.alarm.queryJournal(
|
||||||
|
journalName="NoSuchJournal", startDate=start, endDate=end)]))
|
||||||
|
result["long_millis_dates"] = _safe(
|
||||||
|
lambda: len([e for e in system.alarm.queryJournal(
|
||||||
|
startDate=system.date.toMillis(start),
|
||||||
|
endDate=system.date.toMillis(end))]))
|
||||||
|
result["include_system_false"] = _safe(
|
||||||
|
lambda: len([e for e in system.alarm.queryJournal(
|
||||||
|
startDate=start, endDate=end, includeSystemEvents=False)]))
|
||||||
|
result["include_system_false_alt"] = _safe(
|
||||||
|
lambda: len([e for e in system.alarm.queryJournal(
|
||||||
|
startDate=start, endDate=end, isSystem=False)]))
|
||||||
|
|
||||||
|
def q_status():
|
||||||
|
r = system.alarm.queryStatus(state=["ActiveUnacked", "ActiveAcked"])
|
||||||
|
entries = [e for e in r]
|
||||||
|
return {"count": len(entries),
|
||||||
|
"first_entries": [_entry_facts(e) for e in entries[:5]]}
|
||||||
|
result["status"] = _safe(q_status)
|
||||||
|
result["shelved"] = _safe(lambda: repr(system.alarm.getShelvedPaths()))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def run():
|
||||||
|
result = {"probe": PROBE_NAME,
|
||||||
|
"ranAt": str(system.date.now())}
|
||||||
|
result["payload"] = _safe(_p0)
|
||||||
|
_write(result)
|
||||||
|
system.util.getLogger("probe").info("probe %s written to %s" % (PROBE_NAME, OUT_DIR))
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"scope": "A",
|
||||||
|
"version": 1,
|
||||||
|
"restricted": false,
|
||||||
|
"overridable": true,
|
||||||
|
"files": [
|
||||||
|
"code.py"
|
||||||
|
],
|
||||||
|
"attributes": {
|
||||||
|
"hintScope": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
def handleTimerEvent():
|
||||||
|
alarmsim.tick()
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"scope": "G",
|
||||||
|
"version": 1,
|
||||||
|
"restricted": false,
|
||||||
|
"overridable": true,
|
||||||
|
"files": [
|
||||||
|
"handleTimerEvent.py"
|
||||||
|
],
|
||||||
|
"attributes": {
|
||||||
|
"sharedThread": false,
|
||||||
|
"delay": 5000,
|
||||||
|
"fixedDelay": true,
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
def handleTimerEvent():
|
||||||
|
probe.run()
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"scope": "G",
|
||||||
|
"version": 1,
|
||||||
|
"restricted": false,
|
||||||
|
"overridable": true,
|
||||||
|
"files": [
|
||||||
|
"handleTimerEvent.py"
|
||||||
|
],
|
||||||
|
"attributes": {
|
||||||
|
"sharedThread": false,
|
||||||
|
"delay": 15000,
|
||||||
|
"fixedDelay": true,
|
||||||
|
"enabled": false
|
||||||
|
}
|
||||||
|
}
|
||||||
7
ignition/gateway/projects/SimHarness/project.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"title": "SimHarness",
|
||||||
|
"description": "Dev-only: alarm simulator + gateway probes + scratch views. NOT part of the Build-a-Thon submission.",
|
||||||
|
"enabled": true,
|
||||||
|
"inheritable": false,
|
||||||
|
"parent": ""
|
||||||
|
}
|
||||||
297
tools/lint_project.py
Normal file
@@ -0,0 +1,297 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""lint_project.py — deterministic contest/structure linter for the PrimeBAT project.
|
||||||
|
|
||||||
|
Checks (stdlib only, exit non-zero on any FAIL):
|
||||||
|
structure every .json parses; resource.json integrity (declared files exist,
|
||||||
|
no undeclared payloads, scope correct); no .resources authored
|
||||||
|
refs embedded view paths + flex-repeater paths resolve to real views
|
||||||
|
under PrimeControls/; style-class references resolve
|
||||||
|
bindings binding types from the known set; property-binding paths well-formed;
|
||||||
|
session.custom.* references resolve against session-props schema;
|
||||||
|
view.params.* references resolve against the view's declared params;
|
||||||
|
script transforms/events are tab-indented
|
||||||
|
contest page-config: exactly one page "/" -> PrimeControls/Dashboard, empty
|
||||||
|
sharedDocks; all view/style resources under PrimeControls/;
|
||||||
|
NO tag bindings anywhere in PrimeBAT; string bans (hardcoded local
|
||||||
|
paths/datasource/simulator/SQL/f-strings/journalName literal);
|
||||||
|
queryJournal calls bounded by start+end
|
||||||
|
--strict (Phase 4) additionally: no ignition/* resources besides
|
||||||
|
script-python/PrimeControls/* and global-props; session custom keys
|
||||||
|
only PrimeControls; dead view params reported as failures
|
||||||
|
|
||||||
|
Usage: python3 tools/lint_project.py [--strict] [--project PrimeBAT]
|
||||||
|
"""
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
PERSPECTIVE = "com.inductiveautomation.perspective"
|
||||||
|
|
||||||
|
KNOWN_BINDING_TYPES = {"property", "expr", "expression", "tag", "query", "expr-struct", "http"}
|
||||||
|
EMBED_TYPES = {"ia.display.view", "ia.display.flex-repeater"}
|
||||||
|
|
||||||
|
# (regex, message) — scanned over view.json raw text and PrimeControls *.py
|
||||||
|
STRING_BANS = [
|
||||||
|
(re.compile(r"\[default\]"), "hardcoded tag provider path '[default]'"),
|
||||||
|
(re.compile(r"BuildathonSim"), "hardcoded simulator tag path 'BuildathonSim'"),
|
||||||
|
(re.compile(r"Buildathon_DB"), "hardcoded local datasource 'Buildathon_DB'"),
|
||||||
|
(re.compile(r"\balarmsim\b"), "reference to dev simulator 'alarmsim'"),
|
||||||
|
(re.compile(r"journalName\s*="), "hardcoded journalName= (judges' journal name unknown)"),
|
||||||
|
(re.compile(r"\bsystem\.db\."), "system.db.* SQL access (journal API only)"),
|
||||||
|
(re.compile(r"\bSELECT\s+", re.IGNORECASE), "raw SQL SELECT"),
|
||||||
|
(re.compile(r"""(^|[^A-Za-z0-9_])[fF]["']"""), "f-string (Jython 2.7 cannot parse)"),
|
||||||
|
(re.compile(r"system\.util\.sendRequest\("), "sendRequest dev bridge leftover"),
|
||||||
|
]
|
||||||
|
|
||||||
|
FAILS = []
|
||||||
|
WARNS = []
|
||||||
|
|
||||||
|
|
||||||
|
def fail(path, msg):
|
||||||
|
FAILS.append("FAIL %s: %s" % (path, msg))
|
||||||
|
|
||||||
|
|
||||||
|
def warn(path, msg):
|
||||||
|
WARNS.append("warn %s: %s" % (path, msg))
|
||||||
|
|
||||||
|
|
||||||
|
def rel(p):
|
||||||
|
return os.path.relpath(p, ROOT)
|
||||||
|
|
||||||
|
|
||||||
|
def load_json(path):
|
||||||
|
try:
|
||||||
|
with open(path) as f:
|
||||||
|
return json.load(f)
|
||||||
|
except Exception as e:
|
||||||
|
fail(rel(path), "invalid JSON: %s" % e)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def walk_components(node, visit, path="root"):
|
||||||
|
"""Depth-first over a view component tree; visit(node, path)."""
|
||||||
|
if not isinstance(node, dict):
|
||||||
|
return
|
||||||
|
visit(node, path)
|
||||||
|
for i, child in enumerate(node.get("children") or []):
|
||||||
|
name = "?"
|
||||||
|
if isinstance(child, dict):
|
||||||
|
name = (child.get("meta") or {}).get("name", "?")
|
||||||
|
walk_components(child, visit, "%s/%s[%d]" % (path, name, i))
|
||||||
|
|
||||||
|
|
||||||
|
def iter_prop_configs(view):
|
||||||
|
"""Yield (owner_path, prop_key, config_dict) for view-level and component-level propConfig."""
|
||||||
|
for k, v in (view.get("propConfig") or {}).items():
|
||||||
|
yield ("view", k, v)
|
||||||
|
collected = []
|
||||||
|
|
||||||
|
def visit(node, path):
|
||||||
|
for k, v in (node.get("propConfig") or {}).items():
|
||||||
|
collected.append((path, k, v))
|
||||||
|
walk_components(view.get("root") or {}, visit)
|
||||||
|
for item in collected:
|
||||||
|
yield item
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_in_schema(schema, dotted):
|
||||||
|
"""Walk a dict tree by dotted path; list-typed nodes accept any index; return True if resolvable."""
|
||||||
|
cur = schema
|
||||||
|
for part in dotted.split("."):
|
||||||
|
part = part.split("[")[0]
|
||||||
|
if isinstance(cur, list):
|
||||||
|
return True # element access into arrays: shape unknown, accept
|
||||||
|
if not isinstance(cur, dict) or part not in cur:
|
||||||
|
return False
|
||||||
|
cur = cur[part]
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
ap = argparse.ArgumentParser()
|
||||||
|
ap.add_argument("--strict", action="store_true")
|
||||||
|
ap.add_argument("--project", default="PrimeBAT")
|
||||||
|
args = ap.parse_args()
|
||||||
|
|
||||||
|
proj = os.path.join(ROOT, "ignition", "gateway", "projects", args.project)
|
||||||
|
if not os.path.isdir(proj):
|
||||||
|
print("project dir not found: %s" % proj)
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
views_root = os.path.join(proj, PERSPECTIVE, "views")
|
||||||
|
styles_root = os.path.join(proj, PERSPECTIVE, "style-classes")
|
||||||
|
|
||||||
|
# ---------- collect resource inventory ----------
|
||||||
|
view_paths = set() # e.g. "PrimeControls/Dashboard"
|
||||||
|
style_paths = set() # e.g. "PrimeControls/Card"
|
||||||
|
for base, target, payload in ((views_root, view_paths, "view.json"),
|
||||||
|
(styles_root, style_paths, "style.json")):
|
||||||
|
if not os.path.isdir(base):
|
||||||
|
continue
|
||||||
|
for dirpath, _dirs, files in os.walk(base):
|
||||||
|
if payload in files:
|
||||||
|
target.add(os.path.relpath(dirpath, base).replace(os.sep, "/"))
|
||||||
|
|
||||||
|
# ---------- structure: parse every json + resource.json integrity ----------
|
||||||
|
session_schema = {}
|
||||||
|
for dirpath, dirs, files in os.walk(proj):
|
||||||
|
if ".resources" in dirs:
|
||||||
|
fail(rel(dirpath), "authored .resources directory (gateway-owned)")
|
||||||
|
dirs.remove(".resources")
|
||||||
|
for fn in files:
|
||||||
|
if fn.endswith(".json"):
|
||||||
|
load_json(os.path.join(dirpath, fn))
|
||||||
|
if "resource.json" in files:
|
||||||
|
res = load_json(os.path.join(dirpath, "resource.json"))
|
||||||
|
if res is None:
|
||||||
|
continue
|
||||||
|
declared = res.get("files") or []
|
||||||
|
payloads = [f for f in files if f != "resource.json"]
|
||||||
|
for f in declared:
|
||||||
|
if f not in payloads:
|
||||||
|
fail(rel(dirpath), "resource.json declares missing file %r" % f)
|
||||||
|
for f in payloads:
|
||||||
|
if f not in declared:
|
||||||
|
fail(rel(dirpath), "undeclared payload file %r" % f)
|
||||||
|
rp = rel(dirpath)
|
||||||
|
want_a = ("script-python" in rp) or ("global-props" in rp)
|
||||||
|
want_scope = "A" if want_a else "G"
|
||||||
|
if res.get("scope") != want_scope:
|
||||||
|
fail(rp, "scope %r, expected %r" % (res.get("scope"), want_scope))
|
||||||
|
|
||||||
|
# ---------- session props schema ----------
|
||||||
|
sp_path = os.path.join(proj, PERSPECTIVE, "session-props", "props.json")
|
||||||
|
sp = load_json(sp_path) if os.path.exists(sp_path) else None
|
||||||
|
if sp:
|
||||||
|
session_schema = sp.get("custom") or {}
|
||||||
|
if args.strict:
|
||||||
|
for key in session_schema:
|
||||||
|
if key != "PrimeControls":
|
||||||
|
fail(rel(sp_path), "session custom key %r outside PrimeControls" % key)
|
||||||
|
|
||||||
|
# ---------- page-config contest rules ----------
|
||||||
|
pc_path = os.path.join(proj, PERSPECTIVE, "page-config", "config.json")
|
||||||
|
pc = load_json(pc_path) if os.path.exists(pc_path) else None
|
||||||
|
if pc is not None:
|
||||||
|
pages = pc.get("pages") or {}
|
||||||
|
if list(pages.keys()) != ["/"]:
|
||||||
|
fail(rel(pc_path), "pages must be exactly ['/'], got %s" % list(pages.keys()))
|
||||||
|
elif (pages["/"] or {}).get("viewPath") != "PrimeControls/Dashboard":
|
||||||
|
fail(rel(pc_path), "page '/' must map to PrimeControls/Dashboard")
|
||||||
|
if pc.get("sharedDocks"):
|
||||||
|
fail(rel(pc_path), "sharedDocks must be empty (docked views prohibited)")
|
||||||
|
|
||||||
|
# ---------- namespace rule: everything under PrimeControls/ ----------
|
||||||
|
for p in sorted(view_paths):
|
||||||
|
if not p.startswith("PrimeControls/"):
|
||||||
|
fail("views/%s" % p, "view outside PrimeControls/ folder")
|
||||||
|
for p in sorted(style_paths):
|
||||||
|
if not p.startswith("PrimeControls/"):
|
||||||
|
fail("style-classes/%s" % p, "style class outside PrimeControls/ folder")
|
||||||
|
|
||||||
|
# ---------- per-view checks ----------
|
||||||
|
for vp in sorted(view_paths):
|
||||||
|
vfile = os.path.join(views_root, vp.replace("/", os.sep), "view.json")
|
||||||
|
view = load_json(vfile)
|
||||||
|
if view is None:
|
||||||
|
continue
|
||||||
|
rv = rel(vfile)
|
||||||
|
declared_params = set((view.get("params") or {}).keys())
|
||||||
|
raw = open(vfile).read()
|
||||||
|
|
||||||
|
for rx, msg in STRING_BANS:
|
||||||
|
if rx.search(raw):
|
||||||
|
fail(rv, msg)
|
||||||
|
|
||||||
|
def visit(node, cpath):
|
||||||
|
t = node.get("type")
|
||||||
|
if t in EMBED_TYPES:
|
||||||
|
path_prop = (node.get("props") or {}).get("path")
|
||||||
|
bound = "props.path" in (node.get("propConfig") or {})
|
||||||
|
if isinstance(path_prop, str) and path_prop:
|
||||||
|
if path_prop not in view_paths:
|
||||||
|
fail(rv, "%s embeds missing view %r" % (cpath, path_prop))
|
||||||
|
elif not path_prop.startswith("PrimeControls/"):
|
||||||
|
fail(rv, "%s embeds non-PrimeControls view %r" % (cpath, path_prop))
|
||||||
|
elif not bound:
|
||||||
|
warn(rv, "%s embed with no static path and no binding" % cpath)
|
||||||
|
classes = ((node.get("props") or {}).get("style") or {}).get("classes")
|
||||||
|
if isinstance(classes, str):
|
||||||
|
for cls in classes.split():
|
||||||
|
if cls not in style_paths:
|
||||||
|
fail(rv, "%s references missing style class %r" % (cpath, cls))
|
||||||
|
walk_components(view.get("root") or {}, visit)
|
||||||
|
|
||||||
|
for owner, key, cfg in iter_prop_configs(view):
|
||||||
|
binding = (cfg or {}).get("binding")
|
||||||
|
if not binding:
|
||||||
|
continue
|
||||||
|
btype = binding.get("type")
|
||||||
|
if btype not in KNOWN_BINDING_TYPES:
|
||||||
|
fail(rv, "%s %s: unknown binding type %r" % (owner, key, btype))
|
||||||
|
if btype == "tag":
|
||||||
|
fail(rv, "%s %s: tag binding (prohibited in PrimeBAT — journal API only)" % (owner, key))
|
||||||
|
text_blobs = [json.dumps(binding.get("config") or {})]
|
||||||
|
for tr in binding.get("transforms") or []:
|
||||||
|
code = tr.get("code", "")
|
||||||
|
text_blobs.append(code)
|
||||||
|
if tr.get("type") == "script" and code and not code.startswith(("\t", "\n")):
|
||||||
|
fail(rv, "%s %s: script transform not tab-indented" % (owner, key))
|
||||||
|
blob = " ".join(text_blobs)
|
||||||
|
for m in re.finditer(r"session\.custom\.([A-Za-z0-9_.\[\]]+)", blob):
|
||||||
|
if not resolve_in_schema(session_schema, m.group(1)):
|
||||||
|
fail(rv, "%s %s: unresolvable session.custom.%s" % (owner, key, m.group(1)))
|
||||||
|
for m in re.finditer(r"view\.params\.([A-Za-z0-9_]+)", blob):
|
||||||
|
if m.group(1) not in declared_params:
|
||||||
|
fail(rv, "%s %s: undeclared view param %r" % (owner, key, m.group(1)))
|
||||||
|
|
||||||
|
if args.strict:
|
||||||
|
for p in declared_params:
|
||||||
|
if not re.search(r"(view\.params\.|params\.)%s" % re.escape(p), raw.replace('"%s"' % p, "", 1)):
|
||||||
|
warn(rv, "param %r possibly unused" % p)
|
||||||
|
|
||||||
|
# ---------- scripts: string bans + bounded queries ----------
|
||||||
|
sp_root = os.path.join(proj, "ignition", "script-python")
|
||||||
|
if os.path.isdir(sp_root):
|
||||||
|
for dirpath, _dirs, files in os.walk(sp_root):
|
||||||
|
for fn in files:
|
||||||
|
if not fn.endswith(".py"):
|
||||||
|
continue
|
||||||
|
fpath = os.path.join(dirpath, fn)
|
||||||
|
src = open(fpath).read()
|
||||||
|
for rx, msg in STRING_BANS:
|
||||||
|
if rx.search(src):
|
||||||
|
fail(rel(fpath), msg)
|
||||||
|
for m in re.finditer(r"queryJournal\s*\(", src):
|
||||||
|
fstart = src.rfind("\ndef ", 0, m.start())
|
||||||
|
fend = src.find("\ndef ", m.start())
|
||||||
|
body = src[max(fstart, 0):fend if fend != -1 else len(src)]
|
||||||
|
if not (re.search(r"start", body) and re.search(r"end", body)):
|
||||||
|
fail(rel(fpath), "queryJournal call not visibly bounded by start/end")
|
||||||
|
|
||||||
|
# ---------- strict: no stray ignition resources ----------
|
||||||
|
if args.strict:
|
||||||
|
ig_root = os.path.join(proj, "ignition")
|
||||||
|
for entry in sorted(os.listdir(ig_root)) if os.path.isdir(ig_root) else []:
|
||||||
|
if entry not in ("script-python", "global-props"):
|
||||||
|
fail("ignition/%s" % entry, "unexpected project resource type for submission")
|
||||||
|
if os.path.isdir(sp_root):
|
||||||
|
for entry in sorted(os.listdir(sp_root)):
|
||||||
|
if entry != "PrimeControls":
|
||||||
|
fail("script-python/%s" % entry, "script package outside PrimeControls")
|
||||||
|
|
||||||
|
for w in WARNS:
|
||||||
|
print(w)
|
||||||
|
for f in FAILS:
|
||||||
|
print(f)
|
||||||
|
print("lint: %d view(s), %d style class(es), %d failure(s), %d warning(s)%s"
|
||||||
|
% (len(view_paths), len(style_paths), len(FAILS), len(WARNS),
|
||||||
|
" [strict]" if args.strict else ""))
|
||||||
|
sys.exit(1 if FAILS else 0)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
55
tools/schema_harvest.sh
Executable file
@@ -0,0 +1,55 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# schema_harvest.sh — extract Perspective component prop schemas from the running
|
||||||
|
# gateway's Perspective module into per-component JSON Schema files.
|
||||||
|
#
|
||||||
|
# Sources (verified on 8.3.7): perspective-common-<ver>.jar inside
|
||||||
|
# Perspective-module.modl carries ia.components.json (70 core components),
|
||||||
|
# perspective-amcharts.components.json (ia.chart.xy/pie/gauge/simple-gauge),
|
||||||
|
# perspective-timeseries.components.json, plus schemas/*.json (binding,
|
||||||
|
# transform, style, view-props, session-props schemas).
|
||||||
|
#
|
||||||
|
# Output layout:
|
||||||
|
# <out>/components/<component-id>.schema.json (the component's props JSON Schema)
|
||||||
|
# <out>/schemas/<name>.json (binding/transform/etc. schemas)
|
||||||
|
#
|
||||||
|
# Usage: tools/schema_harvest.sh [output_dir] (default: .schemas/)
|
||||||
|
set -euo pipefail
|
||||||
|
OUT="${1:-.schemas}"
|
||||||
|
TMP="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "$TMP"' EXIT
|
||||||
|
|
||||||
|
docker cp buildathon-ignition:"/usr/local/bin/ignition/user-lib/modules/Perspective-module.modl" "$TMP/perspective.modl"
|
||||||
|
|
||||||
|
python3 - "$TMP" "$OUT" <<'EOF'
|
||||||
|
import json, os, sys, zipfile
|
||||||
|
tmp, out = sys.argv[1], sys.argv[2]
|
||||||
|
comp_dir = os.path.join(out, "components")
|
||||||
|
misc_dir = os.path.join(out, "schemas")
|
||||||
|
os.makedirs(comp_dir, exist_ok=True)
|
||||||
|
os.makedirs(misc_dir, exist_ok=True)
|
||||||
|
|
||||||
|
modl = zipfile.ZipFile(os.path.join(tmp, "perspective.modl"))
|
||||||
|
total = 0
|
||||||
|
for jar in [n for n in modl.namelist() if n.endswith(".jar")]:
|
||||||
|
jp = os.path.join(tmp, os.path.basename(jar))
|
||||||
|
open(jp, "wb").write(modl.read(jar))
|
||||||
|
try:
|
||||||
|
z = zipfile.ZipFile(jp)
|
||||||
|
except zipfile.BadZipFile:
|
||||||
|
continue
|
||||||
|
for entry in z.namelist():
|
||||||
|
if entry.endswith(".components.json") or entry == "ia.components.json":
|
||||||
|
data = json.loads(z.read(entry))
|
||||||
|
for comp in data.get("components", []):
|
||||||
|
cid = comp.get("id")
|
||||||
|
if not cid:
|
||||||
|
continue
|
||||||
|
with open(os.path.join(comp_dir, cid + ".schema.json"), "w") as f:
|
||||||
|
json.dump(comp.get("schema", {}), f, indent=1)
|
||||||
|
total += 1
|
||||||
|
elif entry.startswith("schemas/") and entry.endswith(".json"):
|
||||||
|
with open(os.path.join(misc_dir, os.path.basename(entry)), "wb") as f:
|
||||||
|
f.write(z.read(entry))
|
||||||
|
print("extracted %d component schemas -> %s" % (total, comp_dir))
|
||||||
|
EOF
|
||||||
|
ls "$OUT/components" | wc -l
|
||||||