diff --git a/ignition/gateway/config/ignition/tags/valueStore.idb b/ignition/gateway/config/ignition/tags/valueStore.idb index ae8f8d5..19bdb53 100644 Binary files a/ignition/gateway/config/ignition/tags/valueStore.idb and b/ignition/gateway/config/ignition/tags/valueStore.idb differ diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/page-config/config.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/page-config/config.json index d05891f..b7fcb8e 100644 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/page-config/config.json +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/page-config/config.json @@ -1,53 +1,9 @@ { "pages": { "/": { - "viewPath": "Page/Home" - }, - "/alarms": { - "viewPath": "Page/Alarms" - }, - "/charts": { - "viewPath": "Page/Charts" + "title": "Alarm Analysis", + "viewPath": "PrimeControls/Dashboard" } }, - "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" - } - ] - } -} \ No newline at end of file + "sharedDocks": {} +} diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/page-config/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/page-config/resource.json index 2b56aec..b219fa3 100644 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/page-config/resource.json +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/page-config/resource.json @@ -6,11 +6,5 @@ "files": [ "config.json" ], - "attributes": { - "lastModificationSignature": "1178b10756952abe8fdfa8ebe062253c757d9bf195ebfcd3dea1cc39667f9d48", - "lastModification": { - "actor": "admin", - "timestamp": "2026-07-16T16:25:30Z" - } - } -} \ No newline at end of file + "attributes": {} +} diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/session-props/props.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/session-props/props.json index 79a7331..eed3c9f 100644 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/session-props/props.json +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/session-props/props.json @@ -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": { + "custom.PrimeControls": { + "persistent": true + }, "props.auth": { "access": "PRIVATE", "persistent": false @@ -59,4 +79,4 @@ "theme": "light-cool", "timeZoneId": "America/Los_Angeles" } -} \ No newline at end of file +} diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/session-props/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/session-props/resource.json index 62e33de..edab5eb 100644 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/session-props/resource.json +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/session-props/resource.json @@ -6,11 +6,5 @@ "files": [ "props.json" ], - "attributes": { - "lastModificationSignature": "69e78feccb13d237af1bc1a686c7b63ece6dce7a1a57f3799b1b6b76bfa9f861", - "lastModification": { - "actor": "admin", - "timestamp": "2026-07-16T16:25:30Z" - } - } -} \ No newline at end of file + "attributes": {} +} diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/Alarm_Active/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/Alarm_Active/resource.json deleted file mode 100644 index 86ad4dd..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/Alarm_Active/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/Alarm_Active/style.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/Alarm_Active/style.json deleted file mode 100644 index 12b22bb..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/Alarm_Active/style.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "base": { - "animation": { - "keyframes": { - "0%": { - "color": "#E7F5FF", - "fill": "#E7F5FF" - }, - "100%": { - "color": "#FF2E2E", - "fill": "#FF2E2E" - } - } - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/DropDown/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/DropDown/resource.json deleted file mode 100644 index f77674a..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/DropDown/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/DropDown/style.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/DropDown/style.json deleted file mode 100644 index b85e4e4..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/DropDown/style.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/Header/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/Header/resource.json deleted file mode 100644 index 4f8cd2c..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/Header/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/Header/style.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/Header/style.json deleted file mode 100644 index ead30c9..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/Header/style.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "base": { - "style": { - "backgroundColor": "#003E69", - "color": "#E7F5FF", - "fontSize": "14px", - "lineHeight": "17px", - "fill": "#FFFFFF" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/Icon/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/Icon/resource.json deleted file mode 100644 index 13b92b7..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/Icon/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/Icon/style.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/Icon/style.json deleted file mode 100644 index f4c79c9..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Header/Icon/style.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "base": { - "style": { - "color": "#FFFFFF", - "cursor": "pointer", - "fill": "#FFFFFF" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Menu/All_Header/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Menu/All_Header/resource.json deleted file mode 100644 index 99c7d6e..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Menu/All_Header/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Menu/All_Header/style.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Menu/All_Header/style.json deleted file mode 100644 index 089beee..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Menu/All_Header/style.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "base": { - "style": { - "backgroundColor": "var(--neutral-80)", - "color": "var(--neutral-10)", - "fontSize": "14px", - "fontWeight": "bold", - "lineHeight": "17px", - "textTransform": "none" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Menu/Item/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Menu/Item/resource.json deleted file mode 100644 index dc4d4a0..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Menu/Item/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Menu/Item/style.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Menu/Item/style.json deleted file mode 100644 index 9f16a1e..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Menu/Item/style.json +++ /dev/null @@ -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)" - } - } - ] -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Menu/Menu/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Menu/Menu/resource.json deleted file mode 100644 index a77e0c8..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Menu/Menu/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Menu/Menu/style.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Menu/Menu/style.json deleted file mode 100644 index ad360ac..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Menu/Menu/style.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "base": { - "style": { - "backgroundColor": "var(--neutral-30)" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Alarm/Alarm/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Alarm/Alarm/resource.json deleted file mode 100644 index 40089f7..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Alarm/Alarm/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Alarm/Alarm/style.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Alarm/Alarm/style.json deleted file mode 100644 index fce00e2..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Alarm/Alarm/style.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Alarm/Page/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Alarm/Page/resource.json deleted file mode 100644 index 10a4f19..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Alarm/Page/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Alarm/Page/style.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Alarm/Page/style.json deleted file mode 100644 index e1ffe94..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Alarm/Page/style.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "base": { - "style": { - "backgroundColor": "var(--neutral-20)" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Bold/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Bold/resource.json deleted file mode 100644 index 14083c3..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Bold/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Bold/style.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Bold/style.json deleted file mode 100644 index b21b980..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Bold/style.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "base": { - "style": { - "fontWeight": "bold" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Margins/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Margins/resource.json deleted file mode 100644 index 508b758..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Margins/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Margins/style.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Margins/style.json deleted file mode 100644 index 39b32c0..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Margins/style.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "base": { - "style": { - "marginBottom": "12px", - "marginLeft": "12px", - "marginRight": "12px", - "marginTop": "12px" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Page/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Page/resource.json deleted file mode 100644 index e591515..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Page/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Page/style.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Page/style.json deleted file mode 100644 index 375aba8..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Page/style.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "base": { - "style": { - "borderLeftColor": "var(--neutral-60)", - "borderLeftStyle": "solid", - "borderLeftWidth": "1px", - "fontSize": "14px", - "lineHeight": "20px" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Text/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Text/resource.json deleted file mode 100644 index 4b6de1c..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Text/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Text/style.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Text/style.json deleted file mode 100644 index fa11e3a..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Page/Text/style.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "base": { - "style": { - "fontSize": "14px", - "lineHeight": "20px" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Title/Icon/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Title/Icon/resource.json deleted file mode 100644 index 24b8060..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Title/Icon/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Title/Icon/style.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Title/Icon/style.json deleted file mode 100644 index 46405dd..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Title/Icon/style.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "base": { - "style": { - "fill": "var(--neutral-90)" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Title/Text/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Title/Text/resource.json deleted file mode 100644 index 2bab45f..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Title/Text/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Title/Text/style.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Title/Text/style.json deleted file mode 100644 index 8f0e712..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Title/Text/style.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "base": { - "style": { - "color": "var(--neutral-90)", - "fontSize": "16px", - "fontWeight": "bold", - "lineHeight": "19px", - "marginLeft": "6px", - "fill": "var(--neutral-90)" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Title/Title/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Title/Title/resource.json deleted file mode 100644 index 1c741d2..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Title/Title/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Title/Title/style.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Title/Title/style.json deleted file mode 100644 index c0ca567..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/style-classes/Title/Title/style.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Docks/Menu/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Docks/Menu/resource.json deleted file mode 100644 index d2774c2..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Docks/Menu/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Docks/Menu/thumbnail.png b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Docks/Menu/thumbnail.png deleted file mode 100644 index 1a3a793..0000000 Binary files a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Docks/Menu/thumbnail.png and /dev/null differ diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Docks/Menu/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Docks/Menu/view.json deleted file mode 100644 index 3def2c5..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Docks/Menu/view.json +++ /dev/null @@ -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" - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Framework/Breakpoint Embedded/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Framework/Breakpoint Embedded/resource.json deleted file mode 100644 index 082d9a5..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Framework/Breakpoint Embedded/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Framework/Breakpoint Embedded/thumbnail.png b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Framework/Breakpoint Embedded/thumbnail.png deleted file mode 100644 index 84cb0a2..0000000 Binary files a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Framework/Breakpoint Embedded/thumbnail.png and /dev/null differ diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Framework/Breakpoint Embedded/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Framework/Breakpoint Embedded/view.json deleted file mode 100644 index 3c7eb95..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Framework/Breakpoint Embedded/view.json +++ /dev/null @@ -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" - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Framework/Breakpoint/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Framework/Breakpoint/resource.json deleted file mode 100644 index a20c573..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Framework/Breakpoint/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Framework/Breakpoint/thumbnail.png b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Framework/Breakpoint/thumbnail.png deleted file mode 100644 index 2c2cea9..0000000 Binary files a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Framework/Breakpoint/thumbnail.png and /dev/null differ diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Framework/Breakpoint/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Framework/Breakpoint/view.json deleted file mode 100644 index 3ccd164..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Framework/Breakpoint/view.json +++ /dev/null @@ -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" - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Header/Header/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Header/Header/resource.json deleted file mode 100644 index de29fa2..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Header/Header/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Header/Header/thumbnail.png b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Header/Header/thumbnail.png deleted file mode 100644 index 2eba3b8..0000000 Binary files a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Header/Header/thumbnail.png and /dev/null differ diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Header/Header/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Header/Header/view.json deleted file mode 100644 index 6542e6f..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Header/Header/view.json +++ /dev/null @@ -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" - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Alarms/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Alarms/resource.json deleted file mode 100644 index a85e7ee..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Alarms/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Alarms/thumbnail.png b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Alarms/thumbnail.png deleted file mode 100644 index e39679f..0000000 Binary files a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Alarms/thumbnail.png and /dev/null differ diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Alarms/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Alarms/view.json deleted file mode 100644 index 9808906..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Alarms/view.json +++ /dev/null @@ -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" - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Charts/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Charts/resource.json deleted file mode 100644 index 30c91c3..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Charts/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Charts/thumbnail.png b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Charts/thumbnail.png deleted file mode 100644 index 08d7f6d..0000000 Binary files a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Charts/thumbnail.png and /dev/null differ diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Charts/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Charts/view.json deleted file mode 100644 index 622f8d8..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Charts/view.json +++ /dev/null @@ -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" - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Embedded/Title/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Embedded/Title/resource.json deleted file mode 100644 index 2e9fc54..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Embedded/Title/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Embedded/Title/thumbnail.png b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Embedded/Title/thumbnail.png deleted file mode 100644 index e6045aa..0000000 Binary files a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Embedded/Title/thumbnail.png and /dev/null differ diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Embedded/Title/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Embedded/Title/view.json deleted file mode 100644 index f7bd8c6..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Embedded/Title/view.json +++ /dev/null @@ -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" - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Home/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Home/resource.json deleted file mode 100644 index 5fbeeef..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Home/resource.json +++ /dev/null @@ -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" - } - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Home/thumbnail.png b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Home/thumbnail.png deleted file mode 100644 index c9be19f..0000000 Binary files a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Home/thumbnail.png and /dev/null differ diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Home/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Home/view.json deleted file mode 100644 index 20c2372..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/Page/Home/view.json +++ /dev/null @@ -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" - } -} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Dashboard/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Dashboard/resource.json new file mode 100644 index 0000000..276dced --- /dev/null +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Dashboard/resource.json @@ -0,0 +1,10 @@ +{ + "scope": "G", + "version": 1, + "restricted": false, + "overridable": true, + "files": [ + "view.json" + ], + "attributes": {} +} diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Dashboard/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Dashboard/view.json new file mode 100644 index 0000000..c7c454b --- /dev/null +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Dashboard/view.json @@ -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" + } +} diff --git a/ignition/gateway/projects/SimHarness/com.inductiveautomation.perspective/page-config/config.json b/ignition/gateway/projects/SimHarness/com.inductiveautomation.perspective/page-config/config.json new file mode 100644 index 0000000..0058275 --- /dev/null +++ b/ignition/gateway/projects/SimHarness/com.inductiveautomation.perspective/page-config/config.json @@ -0,0 +1,9 @@ +{ + "pages": { + "/scratch": { + "title": "Scratch", + "viewPath": "Scratch/Current" + } + }, + "sharedDocks": {} +} diff --git a/ignition/gateway/projects/SimHarness/com.inductiveautomation.perspective/page-config/resource.json b/ignition/gateway/projects/SimHarness/com.inductiveautomation.perspective/page-config/resource.json new file mode 100644 index 0000000..b219fa3 --- /dev/null +++ b/ignition/gateway/projects/SimHarness/com.inductiveautomation.perspective/page-config/resource.json @@ -0,0 +1,10 @@ +{ + "scope": "G", + "version": 1, + "restricted": false, + "overridable": true, + "files": [ + "config.json" + ], + "attributes": {} +} diff --git a/ignition/gateway/projects/SimHarness/com.inductiveautomation.perspective/views/Scratch/Current/resource.json b/ignition/gateway/projects/SimHarness/com.inductiveautomation.perspective/views/Scratch/Current/resource.json new file mode 100644 index 0000000..276dced --- /dev/null +++ b/ignition/gateway/projects/SimHarness/com.inductiveautomation.perspective/views/Scratch/Current/resource.json @@ -0,0 +1,10 @@ +{ + "scope": "G", + "version": 1, + "restricted": false, + "overridable": true, + "files": [ + "view.json" + ], + "attributes": {} +} diff --git a/ignition/gateway/projects/SimHarness/com.inductiveautomation.perspective/views/Scratch/Current/view.json b/ignition/gateway/projects/SimHarness/com.inductiveautomation.perspective/views/Scratch/Current/view.json new file mode 100644 index 0000000..85185c1 --- /dev/null +++ b/ignition/gateway/projects/SimHarness/com.inductiveautomation.perspective/views/Scratch/Current/view.json @@ -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" + } +} diff --git a/ignition/gateway/projects/SimHarness/ignition/script-python/alarmsim/code.py b/ignition/gateway/projects/SimHarness/ignition/script-python/alarmsim/code.py new file mode 100644 index 0000000..3efb76c --- /dev/null +++ b/ignition/gateway/projects/SimHarness/ignition/script-python/alarmsim/code.py @@ -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) diff --git a/ignition/gateway/projects/SimHarness/ignition/script-python/alarmsim/resource.json b/ignition/gateway/projects/SimHarness/ignition/script-python/alarmsim/resource.json new file mode 100644 index 0000000..e160ebe --- /dev/null +++ b/ignition/gateway/projects/SimHarness/ignition/script-python/alarmsim/resource.json @@ -0,0 +1,12 @@ +{ + "scope": "A", + "version": 1, + "restricted": false, + "overridable": true, + "files": [ + "code.py" + ], + "attributes": { + "hintScope": 2 + } +} diff --git a/ignition/gateway/projects/SimHarness/ignition/script-python/probe/code.py b/ignition/gateway/projects/SimHarness/ignition/script-python/probe/code.py new file mode 100644 index 0000000..56d2618 --- /dev/null +++ b/ignition/gateway/projects/SimHarness/ignition/script-python/probe/code.py @@ -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)) diff --git a/ignition/gateway/projects/SimHarness/ignition/script-python/probe/resource.json b/ignition/gateway/projects/SimHarness/ignition/script-python/probe/resource.json new file mode 100644 index 0000000..e160ebe --- /dev/null +++ b/ignition/gateway/projects/SimHarness/ignition/script-python/probe/resource.json @@ -0,0 +1,12 @@ +{ + "scope": "A", + "version": 1, + "restricted": false, + "overridable": true, + "files": [ + "code.py" + ], + "attributes": { + "hintScope": 2 + } +} diff --git a/ignition/gateway/projects/SimHarness/ignition/timer/AlarmSimTick/handleTimerEvent.py b/ignition/gateway/projects/SimHarness/ignition/timer/AlarmSimTick/handleTimerEvent.py new file mode 100644 index 0000000..fdc2e92 --- /dev/null +++ b/ignition/gateway/projects/SimHarness/ignition/timer/AlarmSimTick/handleTimerEvent.py @@ -0,0 +1,2 @@ +def handleTimerEvent(): + alarmsim.tick() diff --git a/ignition/gateway/projects/SimHarness/ignition/timer/AlarmSimTick/resource.json b/ignition/gateway/projects/SimHarness/ignition/timer/AlarmSimTick/resource.json new file mode 100644 index 0000000..c5b6a70 --- /dev/null +++ b/ignition/gateway/projects/SimHarness/ignition/timer/AlarmSimTick/resource.json @@ -0,0 +1,15 @@ +{ + "scope": "G", + "version": 1, + "restricted": false, + "overridable": true, + "files": [ + "handleTimerEvent.py" + ], + "attributes": { + "sharedThread": false, + "delay": 5000, + "fixedDelay": true, + "enabled": true + } +} diff --git a/ignition/gateway/projects/SimHarness/ignition/timer/ProbeTick/handleTimerEvent.py b/ignition/gateway/projects/SimHarness/ignition/timer/ProbeTick/handleTimerEvent.py new file mode 100644 index 0000000..5c41195 --- /dev/null +++ b/ignition/gateway/projects/SimHarness/ignition/timer/ProbeTick/handleTimerEvent.py @@ -0,0 +1,2 @@ +def handleTimerEvent(): + probe.run() diff --git a/ignition/gateway/projects/SimHarness/ignition/timer/ProbeTick/resource.json b/ignition/gateway/projects/SimHarness/ignition/timer/ProbeTick/resource.json new file mode 100644 index 0000000..1b34bba --- /dev/null +++ b/ignition/gateway/projects/SimHarness/ignition/timer/ProbeTick/resource.json @@ -0,0 +1,15 @@ +{ + "scope": "G", + "version": 1, + "restricted": false, + "overridable": true, + "files": [ + "handleTimerEvent.py" + ], + "attributes": { + "sharedThread": false, + "delay": 15000, + "fixedDelay": true, + "enabled": false + } +} diff --git a/ignition/gateway/projects/SimHarness/project.json b/ignition/gateway/projects/SimHarness/project.json new file mode 100644 index 0000000..778bb16 --- /dev/null +++ b/ignition/gateway/projects/SimHarness/project.json @@ -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": "" +} diff --git a/tools/lint_project.py b/tools/lint_project.py new file mode 100644 index 0000000..b39f5d0 --- /dev/null +++ b/tools/lint_project.py @@ -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() diff --git a/tools/schema_harvest.sh b/tools/schema_harvest.sh new file mode 100755 index 0000000..26edd69 --- /dev/null +++ b/tools/schema_harvest.sh @@ -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-.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: +# /components/.schema.json (the component's props JSON Schema) +# /schemas/.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