@mxtommy/kip 4.5.0 → 4.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/package.json +16 -6
  3. package/plugin/duckdb-parquet-storage.service.js +78 -102
  4. package/plugin/index.js +60 -40
  5. package/public/{chunk-6XFWUUDD.js → chunk-EQ2N7KDA.js} +1 -1
  6. package/public/{chunk-EDNYYQIZ.js → chunk-IYRLINL7.js} +1 -1
  7. package/public/{chunk-UYIJND2R.js → chunk-JGGMFMY5.js} +1 -1
  8. package/public/{chunk-DD4F6F4S.js → chunk-RONXIZ2U.js} +8 -8
  9. package/public/{chunk-2ICAVOT2.js → chunk-VCY32MWT.js} +1 -1
  10. package/public/{chunk-J3LDKVIS.js → chunk-ZV7IYYEQ.js} +1 -1
  11. package/public/index.html +1 -1
  12. package/public/{main-EG2WF4EO.js → main-FQESQQV6.js} +1 -1
  13. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -84
  14. package/.github/ISSUE_TEMPLATE/config.yml +0 -5
  15. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -35
  16. package/.github/copilot-instructions.md +0 -218
  17. package/.github/instructions/angular.instructions.md +0 -123
  18. package/.github/instructions/best-practices.instructions.md +0 -59
  19. package/.github/instructions/project.instructions.md +0 -468
  20. package/.github/workflows/ci.yml +0 -37
  21. package/docs/widget-schematic.md +0 -102
  22. package/images/ActionSidenav.png +0 -0
  23. package/images/ChartplotterMode.png +0 -0
  24. package/images/KIPDemo.png +0 -0
  25. package/images/KipBrightness-1024.png +0 -0
  26. package/images/KipConfig-Units-1024.png +0 -0
  27. package/images/KipConfig-display-1024x488.png +0 -0
  28. package/images/KipFreeboard-SK-1024.png +0 -0
  29. package/images/KipGaugeSample1-1024x545.png +0 -0
  30. package/images/KipGaugeSample2-1024x488.png +0 -0
  31. package/images/KipGaugeSample3-1024x508.png +0 -0
  32. package/images/KipNightMode-1024.png +0 -0
  33. package/images/KipWidgetConfig-layout-1024.png +0 -0
  34. package/images/KipWidgetConfig-paths-1024x488.png +0 -0
  35. package/images/Options.png +0 -0
  36. package/images/exterior_user_installs.png +0 -0
  37. package/images/formfactor.png +0 -0
  38. package/plugin-config-data/kip/historicalData/kip-history.duckdb +0 -0
  39. package/plugin-config-data/kip/historicalData/parquet/chart-1/1772344583976-1772344583976.parquet +0 -0
  40. package/plugin-config-data/kip/historicalData/parquet/live-1/1771408800000-1771408890000.parquet +0 -0
  41. package/plugin-config-data/kip/historicalData/parquet/live-1/1771412400000-1771412490000.parquet +0 -0
  42. package/plugin-config-data/kip/historicalData/parquet/live-1/1771419600000-1771419650000.parquet +0 -0
  43. package/plugin-config-data/kip/historicalData/parquet/live-1/1772344584154-1772344584154.parquet +0 -0
  44. package/plugin-config-data/kip/historicalData/parquet/live-1/1772344584191-1772344584191.parquet +0 -0
  45. package/plugin-config-data/kip/historicalData/parquet/live-1/1772344584268-1772344584268.parquet +0 -0
  46. package/plugin-config-data/kip/historicalData/parquet/live-2/1771502400000-1771502400000.parquet +0 -0
  47. package/plugin-config-data/kip/historicalData/parquet/live-3/1771408800000-1771408890000.parquet +0 -0
  48. package/plugin-config-data/kip/historicalData/parquet/live-3/1771412400000-1771412490000.parquet +0 -0
  49. package/plugin-config-data/kip/historicalData/parquet/live-3/1771419600000-1771419650000.parquet +0 -0
  50. package/plugin-config-data/kip/historicalData/parquet/live-3/1772344584268-1772344584268.parquet +0 -0
  51. package/plugin-config-data/kip/historicalData/parquet/live-4/1771408800000-1771408890000.parquet +0 -0
  52. package/plugin-config-data/kip/historicalData/parquet/live-4/1771412400000-1771412490000.parquet +0 -0
  53. package/plugin-config-data/kip/historicalData/parquet/live-4/1771419600000-1771419650000.parquet +0 -0
  54. package/plugin-config-data/kip/historicalData/parquet/live-5/1771412400000-1771412490000.parquet +0 -0
  55. package/plugin-config-data/kip/historicalData/parquet/live-5/1771419600000-1771419650000.parquet +0 -0
  56. package/plugin-config-data/kip/historicalData/parquet/live-6/1771419600000-1771419650000.parquet +0 -0
  57. package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1771408800000-1771408890000.parquet +0 -0
  58. package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1771412400000-1771412490000.parquet +0 -0
  59. package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1771419600000-1771419650000.parquet +0 -0
  60. package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1772344584191-1772344584191.parquet +0 -0
  61. package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1772344584268-1772344584268.parquet +0 -0
  62. package/tools/schematics/collection.json +0 -9
  63. package/tools/schematics/create-host2-widget/files/readme/README.md.template +0 -109
  64. package/tools/schematics/create-host2-widget/files/spec/widget-__name@dasherize__.component.spec.ts +0 -38
  65. package/tools/schematics/create-host2-widget/files/widget/widget-__name@dasherize__.component.html +0 -6
  66. package/tools/schematics/create-host2-widget/files/widget/widget-__name@dasherize__.component.scss +0 -5
  67. package/tools/schematics/create-host2-widget/files/widget/widget-__name@dasherize__.component.ts.template +0 -94
  68. package/tools/schematics/create-host2-widget/index.js +0 -138
  69. package/tools/schematics/create-host2-widget/schema.json +0 -89
  70. package/tools/schematics/create-host2-widget/test/create-host2-widget.spec.ts +0 -70
  71. package/tools/schematics/create-host2-widget/utils/formatting.js +0 -119
@@ -1 +1 @@
1
- import{a as xe,b as vt}from"./chunk-6XFWUUDD.js";import{a as Vt,b as A,c as H,i as he,k as E,l as _e,m as lt,o as ve,p as be,s as Ce,u as dt}from"./chunk-J3LDKVIS.js";import{a as Ie}from"./chunk-KZ5DUKAX.js";import{c as le}from"./chunk-DD4F6F4S.js";import{a as Oe,b as Pe,c as Ne,d as De,e as Ae,f as Te}from"./chunk-R7RQHWKJ.js";import{a as ke}from"./chunk-MGPPVLZ7.js";import{c as pe,d as Se,g as ye,h as we,j as Me}from"./chunk-S72JTJPN.js";import{b as Ee}from"./chunk-LQDSU4WS.js";import{e as ge}from"./chunk-CHGXAEKT.js";import{c as de,d as me,e as fe,f as ue}from"./chunk-DYTBBUMI.js";import{o as st,p as ct,q as B,r as z}from"./chunk-KPHICV76.js";import{a as Zt,b as rt,d as te,e as k,g as ee,h as ie,i as oe}from"./chunk-JB4YVVNW.js";import{a as ce}from"./chunk-CEB42O2C.js";import{f as ae,g as re,t as se}from"./chunk-D7VDX7ZF.js";import{c as Kt,e as Xt,g as ot,h as K,i as nt,k as D,l as at,m as x,n as ne}from"./chunk-IHURI4IH.js";import{$b as Pt,A as yt,Aa as Y,Ac as Et,Ad as Ht,Bb as V,Cb as F,Cd as $t,Db as M,Dd as qt,Eb as r,Ec as Rt,Ee as it,Fa as kt,Fb as s,Fc as tt,Ga as w,Gb as I,Ha as q,Hc as _t,Ic as Ut,Ja as It,K as U,Ke as Yt,Nb as v,Ne as Jt,Oe as R,Pb as h,Pe as _,Rb as g,Re as L,Se as T,U as wt,Vd as jt,Wa as f,Zb as X,_b as Z,a as Ct,ba as Mt,bc as Nt,c as St,cd as Ft,ce as Wt,ec as d,f as $,fc as j,gb as P,gc as Dt,ge as et,he as Gt,je as N,ka as S,kc as ut,ke as Qt,lc as ht,m as mt,mc as gt,pa as n,ra as xt,rb as ft,ua as p,va as m,vb as Ot,vc as At,vd as Lt,wd as Bt,xb as b,xc as Tt,xd as zt,ya as Q,yb as C,z as G,zb as J}from"./chunk-A6DQJFP4.js";var pt=(i,c)=>{let t=n(x),e=n(k),o=t.getSplitShellEnabled(),a="/"+c.map(y=>y.path).join("/"),l=a.startsWith("/chartplotter"),u=a.startsWith("/dashboard");if(o&&u&&!l){let y=c.length>1?c[1].path:void 0;return e.createUrlTree(["chartplotter",y??""])}if(!o&&l){let y=c.length>1?c[1].path:void 0;return e.createUrlTree(["dashboard",y??""])}return!0};var Re=[{path:"dashboard/:id",component:vt,canMatch:[pt]},{path:"chartplotter/:id",loadComponent:()=>import("./chunk-UYIJND2R.js").then(i=>i.SplitShellComponent),canMatch:[pt]},{path:"settings",loadComponent:()=>import("./chunk-EDNYYQIZ.js").then(i=>i.SettingsComponent),title:"KIP - Settings"},{path:"options",loadComponent:()=>import("./chunk-2ICAVOT2.js").then(i=>i.TabsComponent),title:"KIP - Options"},{path:"remote",loadComponent:()=>import("./chunk-B75MT7ND.js").then(i=>i.RemoteControlComponent),title:"KIP - Remote Control"},{path:"help/:page",loadComponent:()=>import("./chunk-FNF7M3AE.js").then(i=>i.AppHelpComponent),title:"KIP - Help"},{path:"help",loadComponent:()=>import("./chunk-FNF7M3AE.js").then(i=>i.AppHelpComponent),title:"KIP - Help"},{path:"data",loadComponent:()=>import("./chunk-YKJKIWXO.js").then(i=>i.DataInspectorComponent),title:"KIP - Data Inspector"},{path:"login",loadComponent:()=>import("./chunk-YCEXTKGG.js").then(i=>i.WidgetLoginComponent),title:"Login"},{path:"**",component:vt,canMatch:[pt]}];var Ue={production:!0};var Ye=(i,c)=>c.path;function Je(i,c){i&1&&(r(0,"mat-icon"),d(1,"info"),s())}function Xe(i,c){i&1&&(r(0,"mat-icon"),d(1,"info"),s())}function Ze(i,c){i&1&&(r(0,"mat-icon",3),d(1,"report"),s())}function ti(i,c){i&1&&(r(0,"mat-icon",4),d(1,"warning"),s())}function ei(i,c){i&1&&(r(0,"mat-icon",5),d(1,"error"),s())}function ii(i,c){i&1&&(r(0,"mat-icon",6),d(1,"emergency_home"),s())}function oi(i,c){if(i&1){let t=v();r(0,"div",2),b(1,Je,2,0,"mat-icon")(2,Xe,2,0,"mat-icon")(3,Ze,2,0,"mat-icon",3)(4,ti,2,0,"mat-icon",4)(5,ei,2,0,"mat-icon",5)(6,ii,2,0,"mat-icon",6),r(7,"div",7),d(8),s(),r(9,"div",8),d(10),At(11,"slice"),s(),r(12,"div",9),d(13),s(),r(14,"button",10),h("click",function(){let o=p(t).$implicit,a=g();return m(a.silence(o.path))}),r(15,"mat-icon"),d(16,"music_off"),s()(),r(17,"button",11),h("click",function(){let o=p(t).$implicit,a=g();return m(a.clear(o.path))}),r(18,"mat-icon"),d(19,"published_with_changes"),s()()(),I(20,"mat-divider",12)}if(i&2){let t,e=c.$implicit;f(),C((t=e.value.state)==="nominal"?1:t==="normal"?2:t==="alert"?3:t==="warn"?4:t==="alarm"?5:t==="emergency"?6:-1),f(7),j(e.value.state),f(2),Dt(" ",Tt(11,5,e.path,14)," "),f(3),j(e.value.message),f(),M("disabled",!(e.value.method!=null&&e.value.method.includes("sound")))}}function ni(i,c){i&1&&(r(0,"mat-list-item",13)(1,"span",15),d(2,"Notifications Disabled"),s(),r(3,"span")(4,"i"),d(5,"*Enable notifications in Settings."),s()()())}function ai(i,c){i&1&&(r(0,"mat-list-item",14)(1,"i"),d(2,'"No Notification"'),s()())}function ri(i,c){if(i&1&&b(0,ni,6,0,"mat-list-item",13)(1,ai,3,0,"mat-list-item",14),i&2){let t=g();C(t.notificationConfig().disableNotifications?0:1)}}function si(i,c){if(i&1){let t=v();r(0,"button",17),h("click",function(){p(t);let o=g(2);return m(o.mutePlayer(!o.isMuted))}),r(1,"span",18),d(2,"volume_up"),s(),d(3," Unmute Audio "),s()}}function ci(i,c){if(i&1){let t=v();r(0,"button",17),h("click",function(){p(t);let o=g(2);return m(o.mutePlayer(!o.isMuted))}),r(1,"span",18),d(2,"volume_off"),s(),d(3," Mute Audio "),s()}}function li(i,c){if(i&1&&b(0,si,4,0,"button",16)(1,ci,4,0,"button",16),i&2){let t=g();C(t.isMuted?0:1)}}var Ke=(()=>{class i{_notificationsService=n(E);_notifications$=this._notificationsService.observeNotifications();notificationConfig=_(this._notificationsService.observeNotificationConfiguration(),{requireSync:!0});menuNotifications=_(yt([this._notifications$,this._notificationsService.observeNotificationConfiguration()]).pipe(G(([t,e])=>{let o=[];return e.devices.showNormalState||o.push(st.Normal),e.devices.showNominalState||o.push(st.Nominal),t.filter(a=>a.value&&a.value.state&&!o.includes(a.value.state)).filter(a=>{let l=a.value?.method;return l?.length?l.includes(ct.Visual)||l.includes(ct.Sound):!1})})),{requireSync:!0,equal:Xt});isMuted=!1;mutePlayer(t){this.isMuted=t,this._notificationsService.mutePlayer(t)}silence(t){this._notificationsService.setSkMethod(t,[ct.Visual])}clear(t){this._notificationsService.setSkState(t,st.Normal)}static \u0275fac=function(e){return new(e||i)};static \u0275cmp=P({type:i,selectors:[["menu-notifications"]],decls:6,vars:2,consts:[[1,"menu-item-container"],[1,"actions-container","actions-bottom-container"],[1,"notification-container"],[1,"icon-alert-color"],[1,"icon-warn-color"],[1,"icon-alarm-color"],[1,"icon-emergency-color"],[1,"notification-title"],[1,"notification-path","scrollable-text"],[1,"notification-text"],["mat-icon-button","",1,"notification-action-btn",3,"click","disabled"],["mat-icon-button","",1,"notification-action-btn",3,"click"],[1,"notification-divider"],["lines","3","disabled","true",2,"text-align","center"],["disabled","true",2,"text-align","center"],["matListItemTitle",""],["mat-flat-button","","matTooltip","Temporally toggle all notification audio. To permanently disable/enable notification audio, use the configuration settings option",1,"action-button"],["mat-flat-button","","matTooltip","Temporally toggle all notification audio. To permanently disable/enable notification audio, use the configuration settings option",1,"action-button",3,"click"],[1,"material-icons"]],template:function(e,o){e&1&&(r(0,"mat-list",0),V(1,oi,21,8,null,null,Ye,!1,ri,2,1),s(),r(4,"div",1),b(5,li,2,1),s()),e&2&&(f(),F(o.menuNotifications()),f(4),C(o.notificationConfig().disableNotifications?-1:5))},dependencies:[Me,ye,we,ce,Se,N,et,Wt,lt,ue,fe,T,L,Ft],styles:[".notification-container[_ngcontent-%COMP%]{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-evenly;padding:2px 10px 7px;scroll-behavior:smooth}mat-icon[_ngcontent-%COMP%]{margin-right:10px}.scrollable-text[_ngcontent-%COMP%]{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.scrollable-text[_ngcontent-%COMP%]:hover{overflow:auto;white-space:normal;word-wrap:break-word}.notification-title[_ngcontent-%COMP%]{text-transform:capitalize;font-size:var(--mat-sys-headline-small-size);width:calc(100% - 34px)}.notification-path[_ngcontent-%COMP%]{font-size:var(--mat-sys-body-small-size);word-break:break-all;width:100%}.notification-text[_ngcontent-%COMP%]{font-size:var(--mat-sys-body-small-line-height);font-style:italic;width:100%;overflow:auto;white-space:normal;word-wrap:break-word}.notification-action-btn[_ngcontent-%COMP%]{background-color:var(--mat-sys-surface-container)}.notification-btn-container[_ngcontent-%COMP%]{display:inline-block;width:50%;height:48px;text-align:center}.menu-item-container[_ngcontent-%COMP%]{width:230px;overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;height:calc(100% - 48px)}.notification-bottom-container[_ngcontent-%COMP%]{position:absolute;bottom:0;width:100%;background-color:var(--mat-sys-surface-container)}.actions-container[_ngcontent-%COMP%]{display:grid;grid-auto-flow:column}.actions-bottom-container[_ngcontent-%COMP%]{position:absolute;bottom:0;width:100%;height:48px}.action-button[_ngcontent-%COMP%]{border-radius:0;height:48px;border-bottom-right-radius:var(--mat-sidenav-container-shape, var(--mat-sys-corner-large))}.icon-alert-color[_ngcontent-%COMP%]{color:var(--kip-zone-alert-color)}.icon-warn-color[_ngcontent-%COMP%]{color:var(--kip-zone-warn-color)}.icon-alarm-color[_ngcontent-%COMP%]{color:var(--kip-zone-alarm-color)}.icon-emergency-color[_ngcontent-%COMP%]{color:var(--kip-zone-emergency-color)}.alarm-emergency-blink[_ngcontent-%COMP%]{animation:_ngcontent-%COMP%_blinking-emergency 1.5s infinite}@keyframes _ngcontent-%COMP%_blinking-emergency{0%{background-color:var(--kip-zone-alarm-color)}50%{background-color:transparent}to{background-color:var(--kip-zone-alarm-color)}}.warn[_ngcontent-%COMP%]{color:var(--kip-zone-warn-color)}.notification-divider[_ngcontent-%COMP%]{padding-top:10px}"],changeDetection:0})}return i})();var di=["badgeButton"],Le=(()=>{class i{badgeButton=tt.required("badgeButton");_notifications=n(E);notificationsInfo=_(this._notifications.observerNotificationsInfo());openNotificationMenu(){let t=new Event("openRightSidenav",{bubbles:!0,cancelable:!0});window.document.dispatchEvent(t)}onKeyDown(t){let e=t.key?.toLowerCase();(e==="enter"||e===" "||e==="spacebar")&&(t.preventDefault(),this.openNotificationMenu())}focus(){try{let t=this.badgeButton&&this.badgeButton(),e=t&&t.nativeElement;e&&typeof e.focus=="function"&&e.focus()}catch(t){}}static \u0275fac=function(e){return new(e||i)};static \u0275cmp=P({type:i,selectors:[["notification-badge"]],viewQuery:function(e,o){e&1&&X(o.badgeButton,di,5),e&2&&Z()},decls:5,vars:7,consts:[["badgeButton",""],["mat-fab","","role","button","aria-label","Open notifications",1,"layout-action-btn",3,"click","keydown"],["aria-hidden","false","matBadgeSize","large","matBadgePosition","after","matBadgeOverlap","true",1,"icon-alert-color",3,"matBadgeHidden","matBadge"]],template:function(e,o){if(e&1){let a=v();r(0,"div")(1,"button",1,0),h("click",function(){return p(a),m(o.openNotificationMenu())})("keydown",function(u){return p(a),m(o.onKeyDown(u))}),r(3,"mat-icon",2),d(4,"notifications "),s()()()}e&2&&(f(),Nt("warn",o.notificationsInfo().isWarn)("alarm-emergency-blink",o.notificationsInfo().isAlarmEmergency),Ot("aria-haspopup",!0),f(2),M("matBadgeHidden",!o.notificationsInfo().alarmCount)("matBadge",o.notificationsInfo().alarmCount))},dependencies:[N,Gt,T,L,lt,_e],styles:["[_nghost-%COMP%]{display:block}.layout-action-btn[_ngcontent-%COMP%]{color:var(--mat-sys-on-primary);background-color:var(--mat-sys-primary)}.icon-alert-color[_ngcontent-%COMP%]{--mat-list-list-item-leading-icon-color: var(--kip-zone-alert-color)}.icon-warn-color[_ngcontent-%COMP%]{--mat-list-list-item-leading-icon-color: var(--kip-zone-warn-color)}.icon-alarm-color[_ngcontent-%COMP%]{--mat-list-list-item-leading-icon-color: var(--kip-zone-alarm-color)}.icon-emergency-color[_ngcontent-%COMP%]{--mat-list-list-item-leading-icon-color: var(--kip-zone-emergency-color)}.alarm-emergency-blink[_ngcontent-%COMP%]{animation:_ngcontent-%COMP%_blinking-emergency 1.5s infinite}@keyframes _ngcontent-%COMP%_blinking-emergency{0%{background-color:var(--kip-zone-alarm-color)}50%{background-color:var(--mat-sys-primary)}to{background-color:var(--kip-zone-alarm-color)}}.warn[_ngcontent-%COMP%]{color:var(--kip-zone-warn-color)}"]})}return i})();var Be=(()=>{class i{overlayRef=null;overlay=n(Yt);injector=n(Q);open(){if(this.overlayRef)return;this.overlayRef=this.overlay.create({hasBackdrop:!1,panelClass:"notification-overlay-panel",positionStrategy:this.overlay.position().global().bottom("20px").left("20px"),scrollStrategy:this.overlay.scrollStrategies.reposition()});let t=new Qt(Le,null,this.injector),e=this.overlayRef.attach(t);try{let o=e&&e.instance;if(o&&typeof o.focus=="function")o.focus();else{let a=this.overlayRef.overlayElement,l=a&&a.querySelector("button[mat-fab], .layout-action-btn");l&&typeof l.focus=="function"&&l.focus()}}catch(o){}}close(){try{this.overlayRef&&this.overlayRef.dispose()}catch(t){console.warn("[NotificationOverlayService] dispose failed",t)}finally{this.overlayRef=null}}toggle(t){t?this.open():this.close()}isOpen(){return!!this.overlayRef}ngOnDestroy(){try{this.overlayRef&&this.overlayRef.dispose()}catch(t){}finally{this.overlayRef=null}}static \u0275fac=function(e){return new(e||i)};static \u0275prov=S({token:i,factory:i.\u0275fac,providedIn:"root"})}return i})();function pi(i,c){if(i&1){let t=v();r(0,"button",12),h("click",function(){p(t);let o=g(2);return m(o.onActionItem("toggleFullScreen"))}),r(1,"span",10),d(2,"fullscreen"),s()()}}function mi(i,c){if(i&1){let t=v();r(0,"button",12),h("click",function(){p(t);let o=g(2);return m(o.onActionItem("toggleFullScreen"))}),r(1,"span",10),d(2,"close_fullscreen"),s()()}}function fi(i,c){if(i&1&&b(0,pi,3,0,"button",11)(1,mi,3,0,"button",11),i&2){let t=g();C(t.uiEvent.fullscreenStatus()?1:0)}}function ui(i,c){if(i&1){let t=v();r(0,"button",14),h("click",function(){p(t);let o=g(2);return m(o.onActionItem("nightMode"))}),r(1,"span",10),d(2,"mode_night"),s()()}}function hi(i,c){if(i&1){let t=v();r(0,"button",14),h("click",function(){p(t);let o=g(2);return m(o.onActionItem("nightMode"))}),r(1,"span",10),d(2,"light_mode"),s()()}}function gi(i,c){if(i&1&&b(0,ui,3,0,"button",13)(1,hi,3,0,"button",13),i&2){let t=g();C(t.app.isNightMode()?1:0)}}function _i(i,c){if(i&1){let t=v();r(0,"tile-large-icon",15,1),h("click",function(){let o=p(t).$index,a=g();return m(a.navigateToDashboard(o))}),s()}if(i&2){let t=c.$implicit;M("active",t.active)("svgIcon",t.svgIcon)("iconSize",t.iconSize)("label",t.label)}}var ze=(()=>{class i{actionsSidenav=Rt.required();_router=n(k);uiEvent=n(dt);dashboard=n(A);app=n(le);_settings=n(x);isAutoNightMode=_(this._settings.getAutoNightModeAsO(),{requireSync:!0});_initialDashboardMatch=(()=>{let e=this._router.parseUrl(this._router.url).root.children.primary,o=e?e.segments.map(a=>a.path):[];return o.length===0||o[0]==="dashboard"||o[0]==="chartplotter"})();isDashboardContext=_(this._router.events.pipe(U(t=>t instanceof rt),Mt(null),G(()=>{let e=this._router.parseUrl(this._router.url).root.children.primary,o=e?e.segments.map(a=>a.path):[];return o.length===0||o[0]==="dashboard"||o[0]==="chartplotter"}),wt()),{initialValue:this._initialDashboardMatch});menuItems=Et(()=>{let t=this.dashboard.dashboards(),e=this.dashboard.activeDashboard();return t.map((o,a)=>({id:Number(o.id),active:a===e,pinned:!1,svgIcon:o.icon||"dashboard-dashboard",iconSize:60,label:o.name||`Dashboard ${a+1}`}))});ngAfterViewInit(){this.uiEvent.addHotkeyListener((t,e)=>this.handleKeyDown(t,e),{ctrlKey:!0,shiftKey:!0,keys:["e","f","n"]})}ngOnDestroy(){this.uiEvent.removeHotkeyListener(this.handleKeyDown.bind(this))}handleKeyDown(t,e){switch(t){case"e":this.onActionItem("layout");break;case"f":this.onActionItem("toggleFullScreen");break;case"n":this.onActionItem("nightMode");break;default:break}}onActionItem(t){switch(this.actionsSidenav().close(),t){case"toggleFullScreen":this.uiEvent.toggleFullScreen();break;case"settings":this._router.navigate(["/settings"]);break;case"layout":this.dashboard.setStaticDashboard(!1);break;case"nightMode":this.app.isNightMode.set(!this.app.isNightMode()),this.app.toggleDayNightMode();break;default:break}}navigateToDashboard(t){this.actionsSidenav().close(),this._router.navigate([`dashboard/${t}`])}static \u0275fac=function(e){return new(e||i)};static \u0275cmp=P({type:i,selectors:[["menu-actions"]],inputs:{actionsSidenav:[1,"actionsSidenav"]},decls:14,vars:3,consts:[["tileContainer",""],["tile",""],[1,"actions-container"],[1,"actions-top-container"],["mat-flat-button","","tabindex","0",1,"action-button","home-btn",3,"click"],["height","24px","width","24px","svgIcon","kip","aria-hidden","false",1,"home-icon",2,"height","24px","width","24px"],[1,"menu-item-container"],[3,"active","svgIcon","iconSize","label"],[1,"actions-bottom-container"],["mat-flat-button","",1,"action-button",2,"width","135px",3,"click","disabled"],[1,"material-icons"],["mat-flat-button","","tabindex","0",1,"action-button"],["mat-flat-button","","tabindex","0",1,"action-button",3,"click"],["mat-flat-button","",1,"action-button"],["mat-flat-button","",1,"action-button",3,"click"],[3,"click","active","svgIcon","iconSize","label"]],template:function(e,o){if(e&1){let a=v();r(0,"div",2)(1,"div",3),b(2,fi,2,1),b(3,gi,2,1),r(4,"button",4),h("click",function(){return p(a),m(o.onActionItem("settings"))}),I(5,"mat-icon",5),s()(),r(6,"div",6,0),V(8,_i,2,4,"tile-large-icon",7,J),s(),r(10,"div",8)(11,"button",9),h("click",function(){return p(a),m(o.onActionItem("layout"))}),r(12,"span",10),d(13,"lock_open"),s()()()()}e&2&&(f(2),C(o.uiEvent.fullscreenSupported()?2:-1),f(),C(o.isAutoNightMode()?-1:3),f(5),F(o.menuItems()),f(3),M("disabled",!o.isDashboardContext()))},dependencies:[T,L,N,et,ke],styles:[".actions-container[_ngcontent-%COMP%]{display:flex;flex-direction:column;height:100%;width:135px}.actions-top-container[_ngcontent-%COMP%]{display:flex;flex-direction:row;flex-wrap:wrap;width:100%}.actions-bottom-container[_ngcontent-%COMP%]{height:48px;width:100%}.action-button[_ngcontent-%COMP%]{border-radius:0;height:48px;flex:1 1 48px;min-height:0;overflow:hidden;border:1px solid var(--mat-sidenav-container-background-color, var(--mat-sys-surface))}.home-btn[_ngcontent-%COMP%]{--mat-icon-button-icon-size: 24px;--mat-button-filled-icon-offset: 0px;--mat-button-filled-icon-spacing: 0px;--mat-button-filled-label-text-size: 0px}.home-icon[_ngcontent-%COMP%] .mat-mdc-unelevated-button[_ngcontent-%COMP%] > .mat-icon[_ngcontent-%COMP%]{font-size:0px}.full-size[_ngcontent-%COMP%]{width:135px}.menu-item-container[_ngcontent-%COMP%]{display:flex;flex-direction:column;flex-wrap:nowrap;padding:3px 1px;gap:5px;width:135px;overflow-y:auto;scrollbar-width:none;overflow-x:hidden;scroll-behavior:smooth;flex:1 1 auto;min-height:0}"]})}return i})();var He=(()=>{class i{COMMAND_SET_DISPLAY_PATH="self.kip.remote.setDisplay";COMMAND_SET_SCREEN_INDEX_PATH="self.kip.remote.setScreenIndex";COMMAND_REQUEST_ACTIVE_SCREEN_PATH="self.kip.remote.requestActiveScreen";settings=n(x);dashboard=n(A);data=n(z);requests=n(pe);KIP_UUID=this.settings.KipUUID;ACTIVE_SCREEN_PATH=`self.displays.${this.KIP_UUID}.screenIndex`;CHANGE_SCREEN_PATH=`self.displays.${this.KIP_UUID}.activeScreen`;displayName=_(this.settings.getInstanceNameAsO());isRemoteControl=_(this.settings.getIsRemoteControlAsO());remoteScreenPosition=_(this.data.subscribePath(this.ACTIVE_SCREEN_PATH,"default"));changeDashboardTo=_(this.data.subscribePath(this.CHANGE_SCREEN_PATH,"default"));previousIsRemoteControl=!1;constructor(){this.setActiveDashboardOnRemote(this.KIP_UUID,null),this.setScreensOnRemote(this.KIP_UUID,null),this.clearActiveScreenOnRemote(this.KIP_UUID,null),console.log("[Remote Dashboards] Cleaning paths on server"),w(()=>{let t=this.isRemoteControl(),e=this.displayName();q(()=>{if(!t&&!this.previousIsRemoteControl)return;this.previousIsRemoteControl=t;let o;t?(o=this.getScreensPayload(this.dashboard.dashboards()),this.dashboard.activeDashboard()!==null&&this.setActiveDashboardOnRemote(this.KIP_UUID,this.dashboard.activeDashboard())):(o=null,this.clearActiveDashboardOnServer()),this.shareScreens(o)})}),w(()=>{let t=this.dashboard.dashboards();q(()=>{if(!this.isRemoteControl())return;let e=this.getScreensPayload(t);this.shareScreens(e)})}),w(()=>{let t=this.dashboard.activeDashboard();q(()=>{this.isRemoteControl()&&t!==null&&(this.setActiveDashboardOnRemote(this.KIP_UUID,t),console.log(`[Remote Dashboards] Sent new dashboard highlight index ${t} to server.`))})}),w(()=>{let t=this.changeDashboardTo();q(()=>{if(!this.isRemoteControl()||t.data.value==null)return;let e=Number(t.data.value);!isNaN(e)&&e>=0&&e<this.dashboard.dashboards().length&&this.dashboard.activeDashboard()!==e&&(this.dashboard.navigateTo(e),console.log(`[Remote Dashboards] Executed remote request to change active dashboard to: ${e}`))})})}clearActiveDashboardOnServer(){this.setActiveDashboardOnRemote(this.KIP_UUID,null),console.log("[Remote Dashboards] Disabled: Cleared active dashboard on server")}getScreensPayload(t){let e=this.displayName(),o=t.map(u=>{var y=u,{configuration:a}=y,l=St(y,["configuration"]);return l});return{displayName:e,screens:o}}shareScreens(t){this.setScreensOnRemote(this.KIP_UUID,t),console.log("[Remote Dashboards] Sending dashboard configurations to server.")}setActiveDashboardOnRemote(t,e){let o={displayId:t,screenIdx:e};this.requests.putRequest(this.COMMAND_SET_SCREEN_INDEX_PATH,o,this.KIP_UUID)||console.error("[Remote Dashboards] Error sharing active dashboard: request was not accepted")}setScreensOnRemote(t,e){let o={displayId:t,display:e===null?null:Ct({},e)};this.requests.putRequest(this.COMMAND_SET_DISPLAY_PATH,o,this.KIP_UUID)||console.error("[Remote Dashboards] Error sharing screen configuration: request was not accepted")}clearActiveScreenOnRemote(t,e){let o={displayId:t,screenIdx:e};this.requests.putRequest(this.COMMAND_REQUEST_ACTIVE_SCREEN_PATH,o,this.KIP_UUID)||console.error("[Remote Dashboards] Error clearing active screen request path: request was not accepted")}static \u0275fac=function(e){return new(e||i)};static \u0275prov=S({token:i,factory:i.\u0275fac,providedIn:"root"})}return i})();var $e=11,qe="connectionConfig",W=(()=>{class i{config;isLoggedIn=null;loggedInSubscription=null;connection=n(nt);auth=n(D);connectionStateMachine=n(K);router=n(k);delta=n(B);data=n(z);storage=n(at);internetReachability=n(Ie);injector=n(Q);datasetService=null;_bootstrapStatus$=new mt("starting");_bootstrapIssue$=new mt({reason:"none"});constructor(){this.loggedInSubscription=this.auth.isLoggedIn$.subscribe(t=>{this.isLoggedIn=t})}initNetworkServices(){return $(this,null,function*(){let t=!1;this.loadLocalStorageConfig(),this.preloadFonts(),this.internetReachability.start();try{if(this.config?.signalKUrl!==void 0&&this.config.signalKUrl!==null&&(yield this.connection.initializeConnection({url:this.config.signalKUrl,new:!1},this.config.proxyEnabled,this.config.signalKSubscribeAll)),!this.isLoggedIn&&this.config?.signalKUrl&&this.config?.useSharedConfig&&this.config?.loginName&&this.config?.loginPassword&&(yield this.login()),this.isLoggedIn&&this.config?.useSharedConfig)if(yield this.storage.waitUntilReady()){let o=yield this.storage.getConfig("user",this.config.sharedConfigName,$e),a={sharedConfigName:this.config.sharedConfigName,configFileVersion:$e,initConfig:o};this.storage.bootstrapRemoteContext(a)}else throw new Error("[AppInit Network Service] StorageService did not become ready in time. Cannot bootstrap remote configuration.");this._bootstrapIssue$.next({reason:"none"}),yield this.getDatasetService().waitUntilReady(),!this.isLoggedIn&&this.config?.signalKUrl&&this.config?.useSharedConfig&&this.router.navigate(["/login"])}catch(e){if(t=!0,e?.status===404&&this.config?.useSharedConfig){let o=yield this.probeLegacyUpgradeAvailability(this.config.sharedConfigName);this._bootstrapIssue$.next({reason:"missing-shared-config",statusCode:404,sharedConfigName:this.config.sharedConfigName,legacyUpgradeAvailable:o})}else e?.status===0?this._bootstrapIssue$.next({reason:"network-unreachable",statusCode:0}):e?.status===401?this._bootstrapIssue$.next({reason:"unauthorized",statusCode:401}):this._bootstrapIssue$.next({reason:"unknown",statusCode:e?.status});e.status===0?(yield this.waitForHttpRetryCompletion())===ot.HTTPConnected||this.connectionStateMachine.isHTTPConnected()?console.warn("[AppInit Network Service] Initial connection recovered during retry cycle. Skipping fallback route."):(console.warn("[AppInit Network Service] Initialization failed after HTTP retries. Redirecting to settings page."),yield this.router.navigate(["/options"])):e.status===401?(console.warn("[AppInit Network Service] Initialization failed. Unauthorized access. Redirecting to login page."),yield this.router.navigate(["/login"])):(console.warn("[AppInit Network Service] Initialization failed. Error: ",JSON.stringify(e)),yield this.router.navigate(["/options"])),console.warn("[AppInit Network Service] Startup continuing in degraded mode to allow UI feedback."),this._bootstrapStatus$.next("degraded");return}finally{t||this._bootstrapStatus$.next("ready"),console.log("[AppInit Network Service] Initialization completed"),this.connectionStateMachine.enableWebSocketMode(),this.connectionStateMachine.isHTTPConnected()&&(console.log("[AppInit Network Service] Starting WebSocket connection after initialization"),this.connectionStateMachine.startWebSocketConnection())}})}get bootstrapStatus$(){return this._bootstrapStatus$.asObservable()}get bootstrapIssue$(){return this._bootstrapIssue$.asObservable()}getDatasetService(){return this.datasetService||(this.datasetService=this.injector.get(H)),this.datasetService}waitForHttpRetryCompletion(t){return $(this,null,function*(){let e=t??this.connectionStateMachine.getHttpRetryWindowMs(2e3),o=new Set([ot.HTTPConnected,ot.PermanentFailure]),a=this.connectionStateMachine.currentState;return o.has(a)?a:new Promise(l=>{let u=window.setTimeout(()=>{y.unsubscribe(),l(null)},e),y=this.connectionStateMachine.state$.subscribe(bt=>{o.has(bt)&&(clearTimeout(u),y.unsubscribe(),l(bt))})})})}probeLegacyUpgradeAvailability(t){return $(this,null,function*(){if(!t)return!1;try{return(yield this.storage.getConfig("user",t,9))?.app?.configVersion===10}catch(e){return!1}})}login(){return $(this,null,function*(){if(!this.isLoggedIn&&this.config.useSharedConfig&&this.config.loginName&&this.config.loginPassword)try{yield this.auth.login({usr:this.config.loginName,pwd:this.config.loginPassword})}catch(t){throw t.status===0?this.router.navigate(["/settings"]):t.status===401&&this.router.navigate(["/login"]),t}})}setLocalStorageConfig(){localStorage.setItem(qe,JSON.stringify(this.config))}loadLocalStorageConfig(){this.config=JSON.parse(localStorage.getItem(qe)),this.config?this.config.signalKUrl||(this.config.signalKUrl=window.location.origin,this.setLocalStorageConfig(),console.log(`[AppInit Network Service] Config found with no server URL. Setting Auto-Discovery URL: ${this.config.signalKUrl}`)):(this.config=Kt,this.config.signalKUrl=window.location.origin,console.log(`[AppInit Network Service] Connection Configuration not found. Creating configuration using Auto-Discovery URL: ${this.config.signalKUrl}`),this.setLocalStorageConfig()),this.config.configVersion==9&&(this.config.configVersion=10,this.setLocalStorageConfig(),console.log("[AppInit Network Service] Upgrading Connection version from 9 to 10")),this.config.configVersion==10&&(this.config.configVersion=11,this.setLocalStorageConfig(),console.log("[AppInit Network Service] Upgrading Connection version from 10 to 11")),this.config.configVersion==11&&(this.config.configVersion=12,this.setLocalStorageConfig(),console.log("[AppInit Network Service] Upgrading Connection version from 11 to 12"))}preloadFonts(){let t=[{family:"Roboto",src:"url(./assets/google-fonts/KFOlCnqEu92Fr1MmSU5fChc4AMP6lbBP.woff2)",options:{weight:"300",style:"normal"}},{family:"Roboto",src:"url(./assets/google-fonts/KFOlCnqEu92Fr1MmSU5fBBc4AMP6lQ.woff2)",options:{weight:"300",style:"normal"}},{family:"Roboto",src:"url(./assets/google-fonts/KFOmCnqEu92Fr1Mu7GxKKTU1Kvnz.woff2)",options:{weight:"400",style:"normal"}},{family:"Roboto",src:"url(./assets/google-fonts/KFOmCnqEu92Fr1Mu4mxKKTU1Kg.woff2)",options:{weight:"400",style:"normal"}},{family:"Roboto",src:"url(./assets/google-fonts/KFOlCnqEu92Fr1MmEU9fChc4AMP6lbBP.woff2)",options:{weight:"500",style:"normal"}},{family:"Roboto",src:"url(./assets/google-fonts/KFOlCnqEu92Fr1MmEU9fBBc4AMP6lQ.woff2)",options:{weight:"500",style:"normal"}}];for(let{family:e,src:o,options:a}of t){let l=new FontFace(e,o,a);l.load().then(()=>document.fonts.add(l)).catch(u=>console.log(`[AppInit Network Service] Error loading fonts: ${u}`))}}ngOnDestroy(){this.loggedInSubscription?.unsubscribe()}static \u0275fac=function(e){return new(e||i)};static \u0275prov=S({token:i,factory:i.\u0275fac})}return i})();var vi=["upgradeMessages"];function bi(i,c){if(i&1&&(r(0,"li"),d(1),s()),i&2){let t=c.$implicit;f(),j(t)}}function Ci(i,c){if(i&1&&(r(0,"ul",11,1),V(2,bi,2,1,"li",null,J),s()),i&2){let t=g(2);f(2),F(t.upgrade.messages())}}function Si(i,c){if(i&1&&(r(0,"div",7)(1,"div",8),I(2,"mat-progress-spinner",9),r(3,"div",10)(4,"h3"),d(5,"Upgrading Configuration\u2026"),s(),r(6,"p"),d(7,"Please wait a moment while we migrate your dashboards and widgets."),s(),b(8,Ci,4,0,"ul",11),s()()()),i&2){let t=g();f(8),C(t.upgrade.messages().length?8:-1)}}var je=(()=>{class i{_deltaService=n(B);_connectionStateMachine=n(K);_appNetworkInit=n(W);_historySeriesReconcile=n(xe);authenticationService=n(D);_dataSet=n(H);_dashboard=n(A);_remoteControl=n(He);toast=n(ne);_notifications=n(E);_uiEvent=n(dt);_dialog=n(be);settings=n(x);_responsive=n(Lt);_destroyRef=n(Y);_notificationOverlay=n(Be);_router=n(k);upgrade=n(ve);upgradeMessagesRef=tt("upgradeMessages");_upgradeShown=!1;actionsSidenavOpened=_t(!1);notificationsSidenavOpened=_t(!1);notificationsInfo=_(this._notifications.observerNotificationsInfo());bootstrapStatus=_(this._appNetworkInit.bootstrapStatus$,{initialValue:"starting"});bootstrapIssue=_(this._appNetworkInit.bootstrapIssue$,{initialValue:{reason:"none"}});dashboardVisible=kt(!1);isPhonePortrait;scheduledOpen=null;OPEN_DELAY_MS=300;missingConfigPromptShown=!1;_swipeLeftHandler=()=>this.onSwipeLeft();_swipeRightHandler=()=>this.onSwipeRight();_hotkeyHandler=t=>this.handleKeyDown(t);constructor(){w(()=>{if(this.settings.configUpgrade()){let t=this.settings.getConfigVersion();t===11&&this.upgrade.runUpgrade(t),t||this._upgradeShown||(this._upgradeShown=!0,this._dialog.openFrameDialog({title:"Upgrade Instructions",component:"upgrade-config"},!0).pipe(R(this._destroyRef)).subscribe())}}),w(()=>{let t=this.upgrade.messages();if(this.upgrade.upgrading()&&t.length&&this.upgradeMessagesRef()){let e=this.upgradeMessagesRef().nativeElement;e.scrollTop=e.scrollHeight}});try{this.dashboardVisible.set(this.isUrlDashboard(this._router.url))}catch(t){}this._router.events.pipe(U(t=>t instanceof rt),R(this._destroyRef)).subscribe(t=>{try{this.dashboardVisible.set(this.isUrlDashboard(t.urlAfterRedirects||t.url))}catch(e){}}),w(()=>{let t=this.dashboardVisible()&&this._dashboard.isDashboardStatic()&&this.notificationsInfo().alarmCount>0;if(this.notificationsSidenavOpened()){this.scheduledOpen&&(clearTimeout(this.scheduledOpen),this.scheduledOpen=null);try{this._notificationOverlay.close()}catch(o){}return}if(t){if(this.scheduledOpen)return;this.scheduledOpen=window.setTimeout(()=>{this.scheduledOpen=null;try{this._notificationOverlay.open()}catch(o){}},this.OPEN_DELAY_MS)}else{this.scheduledOpen&&(clearTimeout(this.scheduledOpen),this.scheduledOpen=null);try{this._notificationOverlay.close()}catch(o){}}}),w(()=>{if(this.notificationsSidenavOpened())try{this._notificationOverlay.close()}catch(e){}}),this.isPhonePortrait=_(this._responsive.observe(jt.HandsetPortrait)),this._connectionStateMachine.status$.pipe(R(this._destroyRef)).subscribe(t=>this.displayConnectionsStatusNotification(t)),w(()=>{let t=this.bootstrapIssue();if(t.reason!=="missing-shared-config"||this.missingConfigPromptShown)return;this.missingConfigPromptShown=!0;let e=t.sharedConfigName||"default",o=t.legacyUpgradeAvailable===!0,a=o?"Upgrade":"Create",l=o?`Server is reachable, but no current version shared configuration '${e}' exists for this user. A legacy configuration was found and can be upgraded. Upgrade now?`:`Server is reachable, but no shared configuration '${e}' exists for this user. Create a default configuration now?`;this.toast.show(l,0,!0,"warn",a).onAction().pipe(R(this._destroyRef)).subscribe(()=>{o?this.upgrade.runUpgrade():this.settings.resetSettings()})})}isUrlDashboard(t){if(!t)return!1;let e=t.split("?")[0].replace(/\/+$/,"");return e==="/"||e==="/dashboard"||/^\/dashboard(\/\d+)?$/.test(e)||e==="/chartplotter"||/^\/chartplotter(\/\d+)?$/.test(e)}ngOnInit(){this._uiEvent.addGestureListeners(this._swipeLeftHandler,this._swipeRightHandler)}ngAfterViewInit(){this._uiEvent.addHotkeyListener(this._hotkeyHandler,{ctrlKey:!0,keys:["arrowright","arrowleft"]})}handleKeyDown(t){switch(t){case"arrowright":this.onSwipeRight();break;case"arrowleft":this.onSwipeLeft();break;case"escape":this.backdropClicked();break}}escapeKeyPressed(t){t=t.toLowerCase(),t==="escape"&&this.backdropClicked()}displayConnectionsStatusNotification(t){let e=t.message,o=this.bootstrapStatus()!=="ready";switch(t.operation){case 0:this.toast.show(e,5e3,!0);break;case 1:case 2:break;case 3:this.toast.show(e,3e3,o,"warn");break;case 4:this.toast.show(e,3e3,!0,"info");break;case 5:this.toast.show(e,0,o);break;default:console.error("[AppComponent] Unknown operation code:",t.operation),this.toast.show(`Unknown connection status: ${t.state}`,0,o,"error")}}onSwipeRight(){this._dashboard.isDashboardStatic()&&!this._uiEvent.isDragging()&&(this.isPhonePortrait().matches?(this.actionsSidenavOpened.set(!1),this.notificationsSidenavOpened.set(!0)):(this.actionsSidenavOpened.set(!1),this.notificationsSidenavOpened.update(t=>!t)))}backdropClicked(){this.notificationsSidenavOpened.update(t=>t?!t:!1),this.actionsSidenavOpened.update(t=>t?!t:!1)}onSwipeLeft(){this._dashboard.isDashboardStatic()&&!this._uiEvent.isDragging()&&(this.isPhonePortrait().matches?(this.notificationsSidenavOpened.set(!1),this.actionsSidenavOpened.set(!0)):(this.notificationsSidenavOpened.set(!1),this.actionsSidenavOpened.update(t=>!t)))}ngOnDestroy(){this._uiEvent.removeGestureListeners(this._swipeLeftHandler,this._swipeRightHandler),this._uiEvent.removeHotkeyListener(this._hotkeyHandler),this.scheduledOpen&&(clearTimeout(this.scheduledOpen),this.scheduledOpen=null)}static \u0275fac=function(e){return new(e||i)};static \u0275cmp=P({type:i,selectors:[["app-root"]],viewQuery:function(e,o){e&1&&X(o.upgradeMessagesRef,vi,5),e&2&&Z()},inputs:{actionsSidenavOpened:[1,"actionsSidenavOpened"],notificationsSidenavOpened:[1,"notificationsSidenavOpened"]},outputs:{actionsSidenavOpened:"actionsSidenavOpenedChange",notificationsSidenavOpened:"notificationsSidenavOpenedChange"},decls:9,vars:6,consts:[["actionsSidenav",""],["upgradeMessages",""],["kipGestures","",1,"sidenav-container",3,"swipeleft","swiperight","backdropClick","mode","bridgeUiEvents"],["mode","over","position","start","autoFocus","true","disableClose","",1,"sidenav-notifications",3,"openedChange","keydown","opened"],["mode","over","position","end","autoFocus","true","disableClose","",1,"sidenav-actions",3,"openedChange","keydown","opened"],[3,"actionsSidenav"],[1,"router-outlet-container"],["role","alert","aria-live","polite",1,"config-upgrade-overlay"],[1,"config-upgrade-card"],["diameter","46","mode","indeterminate"],[1,"config-upgrade-text"],[1,"config-upgrade-messages"]],template:function(e,o){if(e&1){let a=v();r(0,"mat-sidenav-container",2),h("swipeleft",function(){return p(a),m(o.onSwipeLeft())})("swiperight",function(){return p(a),m(o.onSwipeRight())})("backdropClick",function(){return p(a),m(o.backdropClicked())}),r(1,"mat-sidenav",3),gt("openedChange",function(u){return p(a),ht(o.notificationsSidenavOpened,u)||(o.notificationsSidenavOpened=u),m(u)}),h("keydown",function(u){return p(a),m(o.escapeKeyPressed(u.key))}),I(2,"menu-notifications"),s(),r(3,"mat-sidenav",4,0),gt("openedChange",function(u){return p(a),ht(o.actionsSidenavOpened,u)||(o.actionsSidenavOpened=u),m(u)}),h("keydown",function(u){return p(a),m(o.escapeKeyPressed(u.key))}),I(5,"menu-actions",5),s(),r(6,"mat-sidenav-content"),I(7,"router-outlet",6),s()(),b(8,Si,9,1,"div",7)}if(e&2){let a=Pt(4);M("mode","horizontal")("bridgeUiEvents",!0),f(),ut("opened",o.notificationsSidenavOpened),f(2),ut("opened",o.actionsSidenavOpened),f(2),M("actionsSidenav",a),f(3),C(o.upgrade.upgrading()?8:-1)}},dependencies:[Ke,ze,N,ge,T,oe,te,De,Pe,Ne,Oe,Vt,Jt,Te,Ae],styles:[".sidenav-container[_ngcontent-%COMP%]{height:100%;width:100%;--mat-sidenav-scrim-color: color-mix(in srgb, var(--mat-sys-neutral-variant20) 70%, transparent)}mat-sidenav-content[_ngcontent-%COMP%]{overflow-y:hidden;overflow-x:hidden}mat-sidenav[_ngcontent-%COMP%]{box-shadow:0 0 1px 0 var(--kip-contrast-color)}mat-sidenav.sidenav-notifications[_ngcontent-%COMP%]{width:230px;z-index:1200}mat-sidenav.sidenav-actions[_ngcontent-%COMP%]{width:135px;z-index:1200;overflow-x:hidden}.config-upgrade-overlay[_ngcontent-%COMP%]{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:#00000073;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);z-index:2000;pointer-events:all}.config-upgrade-card[_ngcontent-%COMP%]{display:flex;flex-direction:row;align-items:center;gap:18px;padding:20px 24px;width:clamp(300px,60vw,640px);background:var(--kip-background, #1f1f1f);border:1px solid rgba(255,255,255,.18);border-radius:14px;color:var(--kip-contrast-color, #fff);box-shadow:0 6px 22px #0000008c}.config-upgrade-text[_ngcontent-%COMP%] h3[_ngcontent-%COMP%]{margin:0 0 4px;font-size:1.05rem;font-weight:600;letter-spacing:.5px}.config-upgrade-text[_ngcontent-%COMP%] p[_ngcontent-%COMP%]{margin:0 0 10px;font-size:.8rem;opacity:.85}.config-upgrade-messages[_ngcontent-%COMP%]{list-style:disc;margin:0;padding-left:18px;max-height:180px;font-size:.68rem;line-height:1.25;scrollbar-width:thin;overflow-y:auto}.config-upgrade-messages[_ngcontent-%COMP%] li[_ngcontent-%COMP%]{margin-bottom:2px}"]})}return i})();var We=(()=>{class i{auth=n(D);authToken=null;authTokenSubscription=null;constructor(){this.authTokenSubscription=this.auth.authToken$.subscribe(t=>{this.authToken=t})}intercept(t,e){let o=t.clone();return this.authToken&&(o=t.clone({headers:t.headers.set("authorization","JWT "+this.authToken.token)})),e.handle(o)}ngOnDestroy(){this.authTokenSubscription?.unsubscribe()}static \u0275fac=function(e){return new(e||i)};static \u0275prov=S({token:i,factory:i.\u0275fac})}return i})();var Ge=(()=>{class i extends it{_createContainer(){let t=document.createElement("div");t.classList.add("cdk-overlay-container"),(document.getElementById("app-filter-wrapper")||document.querySelector("app-root")||document.body).appendChild(t),this._containerElement=t}static \u0275fac=(()=>{let t;return function(o){return(t||(t=It(i)))(o||i)}})();static \u0275prov=S({token:i,factory:i.\u0275fac})}return i})();var Qe=(()=>{class i{_router=n(k);_dialog=n(re);_bottomSheet=n(Ce);_destroyRef=n(Y);constructor(){this._router.events.pipe(U(t=>t instanceof Zt),R(this._destroyRef)).subscribe(()=>{this._dialog.openDialogs.length>0&&this._dialog.closeAll(),this._bottomSheet.dismiss()})}static \u0275fac=function(e){return new(e||i)};static \u0275prov=S({token:i,factory:i.\u0275fac,providedIn:"root"})}return i})();Ue.production&&void 0;Bt(je,{providers:[Ut(),xt(zt),{provide:Ht,useClass:We,multi:!0},{provide:ae,useValue:{hasBackdrop:!0,disableClose:!1,autoFocus:"first-tabbable",delayFocusTrap:!0,backdropClass:"dialogBackdrop"}},{provide:se,useValue:{appearance:"outline",floatLabel:"always",subscriptSizing:"dynamic"}},{provide:me,useValue:{showDelay:1500,hideDelay:0}},D,z,nt,B,K,H,A,de,W,x,E,he,at,Ee(),$t(qt()),ee(Re,ie()),{provide:it,useClass:Ge},ft(()=>n(W).initNetworkServices()),ft(()=>{n(Qe)})]});
1
+ import{a as xe,b as vt}from"./chunk-EQ2N7KDA.js";import{a as Vt,b as A,c as H,i as he,k as E,l as _e,m as lt,o as ve,p as be,s as Ce,u as dt}from"./chunk-ZV7IYYEQ.js";import{a as Ie}from"./chunk-KZ5DUKAX.js";import{c as le}from"./chunk-RONXIZ2U.js";import{a as Oe,b as Pe,c as Ne,d as De,e as Ae,f as Te}from"./chunk-R7RQHWKJ.js";import{a as ke}from"./chunk-MGPPVLZ7.js";import{c as pe,d as Se,g as ye,h as we,j as Me}from"./chunk-S72JTJPN.js";import{b as Ee}from"./chunk-LQDSU4WS.js";import{e as ge}from"./chunk-CHGXAEKT.js";import{c as de,d as me,e as fe,f as ue}from"./chunk-DYTBBUMI.js";import{o as st,p as ct,q as B,r as z}from"./chunk-KPHICV76.js";import{a as Zt,b as rt,d as te,e as k,g as ee,h as ie,i as oe}from"./chunk-JB4YVVNW.js";import{a as ce}from"./chunk-CEB42O2C.js";import{f as ae,g as re,t as se}from"./chunk-D7VDX7ZF.js";import{c as Kt,e as Xt,g as ot,h as K,i as nt,k as D,l as at,m as x,n as ne}from"./chunk-IHURI4IH.js";import{$b as Pt,A as yt,Aa as Y,Ac as Et,Ad as Ht,Bb as V,Cb as F,Cd as $t,Db as M,Dd as qt,Eb as r,Ec as Rt,Ee as it,Fa as kt,Fb as s,Fc as tt,Ga as w,Gb as I,Ha as q,Hc as _t,Ic as Ut,Ja as It,K as U,Ke as Yt,Nb as v,Ne as Jt,Oe as R,Pb as h,Pe as _,Rb as g,Re as L,Se as T,U as wt,Vd as jt,Wa as f,Zb as X,_b as Z,a as Ct,ba as Mt,bc as Nt,c as St,cd as Ft,ce as Wt,ec as d,f as $,fc as j,gb as P,gc as Dt,ge as et,he as Gt,je as N,ka as S,kc as ut,ke as Qt,lc as ht,m as mt,mc as gt,pa as n,ra as xt,rb as ft,ua as p,va as m,vb as Ot,vc as At,vd as Lt,wd as Bt,xb as b,xc as Tt,xd as zt,ya as Q,yb as C,z as G,zb as J}from"./chunk-A6DQJFP4.js";var pt=(i,c)=>{let t=n(x),e=n(k),o=t.getSplitShellEnabled(),a="/"+c.map(y=>y.path).join("/"),l=a.startsWith("/chartplotter"),u=a.startsWith("/dashboard");if(o&&u&&!l){let y=c.length>1?c[1].path:void 0;return e.createUrlTree(["chartplotter",y??""])}if(!o&&l){let y=c.length>1?c[1].path:void 0;return e.createUrlTree(["dashboard",y??""])}return!0};var Re=[{path:"dashboard/:id",component:vt,canMatch:[pt]},{path:"chartplotter/:id",loadComponent:()=>import("./chunk-JGGMFMY5.js").then(i=>i.SplitShellComponent),canMatch:[pt]},{path:"settings",loadComponent:()=>import("./chunk-IYRLINL7.js").then(i=>i.SettingsComponent),title:"KIP - Settings"},{path:"options",loadComponent:()=>import("./chunk-VCY32MWT.js").then(i=>i.TabsComponent),title:"KIP - Options"},{path:"remote",loadComponent:()=>import("./chunk-B75MT7ND.js").then(i=>i.RemoteControlComponent),title:"KIP - Remote Control"},{path:"help/:page",loadComponent:()=>import("./chunk-FNF7M3AE.js").then(i=>i.AppHelpComponent),title:"KIP - Help"},{path:"help",loadComponent:()=>import("./chunk-FNF7M3AE.js").then(i=>i.AppHelpComponent),title:"KIP - Help"},{path:"data",loadComponent:()=>import("./chunk-YKJKIWXO.js").then(i=>i.DataInspectorComponent),title:"KIP - Data Inspector"},{path:"login",loadComponent:()=>import("./chunk-YCEXTKGG.js").then(i=>i.WidgetLoginComponent),title:"Login"},{path:"**",component:vt,canMatch:[pt]}];var Ue={production:!0};var Ye=(i,c)=>c.path;function Je(i,c){i&1&&(r(0,"mat-icon"),d(1,"info"),s())}function Xe(i,c){i&1&&(r(0,"mat-icon"),d(1,"info"),s())}function Ze(i,c){i&1&&(r(0,"mat-icon",3),d(1,"report"),s())}function ti(i,c){i&1&&(r(0,"mat-icon",4),d(1,"warning"),s())}function ei(i,c){i&1&&(r(0,"mat-icon",5),d(1,"error"),s())}function ii(i,c){i&1&&(r(0,"mat-icon",6),d(1,"emergency_home"),s())}function oi(i,c){if(i&1){let t=v();r(0,"div",2),b(1,Je,2,0,"mat-icon")(2,Xe,2,0,"mat-icon")(3,Ze,2,0,"mat-icon",3)(4,ti,2,0,"mat-icon",4)(5,ei,2,0,"mat-icon",5)(6,ii,2,0,"mat-icon",6),r(7,"div",7),d(8),s(),r(9,"div",8),d(10),At(11,"slice"),s(),r(12,"div",9),d(13),s(),r(14,"button",10),h("click",function(){let o=p(t).$implicit,a=g();return m(a.silence(o.path))}),r(15,"mat-icon"),d(16,"music_off"),s()(),r(17,"button",11),h("click",function(){let o=p(t).$implicit,a=g();return m(a.clear(o.path))}),r(18,"mat-icon"),d(19,"published_with_changes"),s()()(),I(20,"mat-divider",12)}if(i&2){let t,e=c.$implicit;f(),C((t=e.value.state)==="nominal"?1:t==="normal"?2:t==="alert"?3:t==="warn"?4:t==="alarm"?5:t==="emergency"?6:-1),f(7),j(e.value.state),f(2),Dt(" ",Tt(11,5,e.path,14)," "),f(3),j(e.value.message),f(),M("disabled",!(e.value.method!=null&&e.value.method.includes("sound")))}}function ni(i,c){i&1&&(r(0,"mat-list-item",13)(1,"span",15),d(2,"Notifications Disabled"),s(),r(3,"span")(4,"i"),d(5,"*Enable notifications in Settings."),s()()())}function ai(i,c){i&1&&(r(0,"mat-list-item",14)(1,"i"),d(2,'"No Notification"'),s()())}function ri(i,c){if(i&1&&b(0,ni,6,0,"mat-list-item",13)(1,ai,3,0,"mat-list-item",14),i&2){let t=g();C(t.notificationConfig().disableNotifications?0:1)}}function si(i,c){if(i&1){let t=v();r(0,"button",17),h("click",function(){p(t);let o=g(2);return m(o.mutePlayer(!o.isMuted))}),r(1,"span",18),d(2,"volume_up"),s(),d(3," Unmute Audio "),s()}}function ci(i,c){if(i&1){let t=v();r(0,"button",17),h("click",function(){p(t);let o=g(2);return m(o.mutePlayer(!o.isMuted))}),r(1,"span",18),d(2,"volume_off"),s(),d(3," Mute Audio "),s()}}function li(i,c){if(i&1&&b(0,si,4,0,"button",16)(1,ci,4,0,"button",16),i&2){let t=g();C(t.isMuted?0:1)}}var Ke=(()=>{class i{_notificationsService=n(E);_notifications$=this._notificationsService.observeNotifications();notificationConfig=_(this._notificationsService.observeNotificationConfiguration(),{requireSync:!0});menuNotifications=_(yt([this._notifications$,this._notificationsService.observeNotificationConfiguration()]).pipe(G(([t,e])=>{let o=[];return e.devices.showNormalState||o.push(st.Normal),e.devices.showNominalState||o.push(st.Nominal),t.filter(a=>a.value&&a.value.state&&!o.includes(a.value.state)).filter(a=>{let l=a.value?.method;return l?.length?l.includes(ct.Visual)||l.includes(ct.Sound):!1})})),{requireSync:!0,equal:Xt});isMuted=!1;mutePlayer(t){this.isMuted=t,this._notificationsService.mutePlayer(t)}silence(t){this._notificationsService.setSkMethod(t,[ct.Visual])}clear(t){this._notificationsService.setSkState(t,st.Normal)}static \u0275fac=function(e){return new(e||i)};static \u0275cmp=P({type:i,selectors:[["menu-notifications"]],decls:6,vars:2,consts:[[1,"menu-item-container"],[1,"actions-container","actions-bottom-container"],[1,"notification-container"],[1,"icon-alert-color"],[1,"icon-warn-color"],[1,"icon-alarm-color"],[1,"icon-emergency-color"],[1,"notification-title"],[1,"notification-path","scrollable-text"],[1,"notification-text"],["mat-icon-button","",1,"notification-action-btn",3,"click","disabled"],["mat-icon-button","",1,"notification-action-btn",3,"click"],[1,"notification-divider"],["lines","3","disabled","true",2,"text-align","center"],["disabled","true",2,"text-align","center"],["matListItemTitle",""],["mat-flat-button","","matTooltip","Temporally toggle all notification audio. To permanently disable/enable notification audio, use the configuration settings option",1,"action-button"],["mat-flat-button","","matTooltip","Temporally toggle all notification audio. To permanently disable/enable notification audio, use the configuration settings option",1,"action-button",3,"click"],[1,"material-icons"]],template:function(e,o){e&1&&(r(0,"mat-list",0),V(1,oi,21,8,null,null,Ye,!1,ri,2,1),s(),r(4,"div",1),b(5,li,2,1),s()),e&2&&(f(),F(o.menuNotifications()),f(4),C(o.notificationConfig().disableNotifications?-1:5))},dependencies:[Me,ye,we,ce,Se,N,et,Wt,lt,ue,fe,T,L,Ft],styles:[".notification-container[_ngcontent-%COMP%]{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-evenly;padding:2px 10px 7px;scroll-behavior:smooth}mat-icon[_ngcontent-%COMP%]{margin-right:10px}.scrollable-text[_ngcontent-%COMP%]{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.scrollable-text[_ngcontent-%COMP%]:hover{overflow:auto;white-space:normal;word-wrap:break-word}.notification-title[_ngcontent-%COMP%]{text-transform:capitalize;font-size:var(--mat-sys-headline-small-size);width:calc(100% - 34px)}.notification-path[_ngcontent-%COMP%]{font-size:var(--mat-sys-body-small-size);word-break:break-all;width:100%}.notification-text[_ngcontent-%COMP%]{font-size:var(--mat-sys-body-small-line-height);font-style:italic;width:100%;overflow:auto;white-space:normal;word-wrap:break-word}.notification-action-btn[_ngcontent-%COMP%]{background-color:var(--mat-sys-surface-container)}.notification-btn-container[_ngcontent-%COMP%]{display:inline-block;width:50%;height:48px;text-align:center}.menu-item-container[_ngcontent-%COMP%]{width:230px;overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;height:calc(100% - 48px)}.notification-bottom-container[_ngcontent-%COMP%]{position:absolute;bottom:0;width:100%;background-color:var(--mat-sys-surface-container)}.actions-container[_ngcontent-%COMP%]{display:grid;grid-auto-flow:column}.actions-bottom-container[_ngcontent-%COMP%]{position:absolute;bottom:0;width:100%;height:48px}.action-button[_ngcontent-%COMP%]{border-radius:0;height:48px;border-bottom-right-radius:var(--mat-sidenav-container-shape, var(--mat-sys-corner-large))}.icon-alert-color[_ngcontent-%COMP%]{color:var(--kip-zone-alert-color)}.icon-warn-color[_ngcontent-%COMP%]{color:var(--kip-zone-warn-color)}.icon-alarm-color[_ngcontent-%COMP%]{color:var(--kip-zone-alarm-color)}.icon-emergency-color[_ngcontent-%COMP%]{color:var(--kip-zone-emergency-color)}.alarm-emergency-blink[_ngcontent-%COMP%]{animation:_ngcontent-%COMP%_blinking-emergency 1.5s infinite}@keyframes _ngcontent-%COMP%_blinking-emergency{0%{background-color:var(--kip-zone-alarm-color)}50%{background-color:transparent}to{background-color:var(--kip-zone-alarm-color)}}.warn[_ngcontent-%COMP%]{color:var(--kip-zone-warn-color)}.notification-divider[_ngcontent-%COMP%]{padding-top:10px}"],changeDetection:0})}return i})();var di=["badgeButton"],Le=(()=>{class i{badgeButton=tt.required("badgeButton");_notifications=n(E);notificationsInfo=_(this._notifications.observerNotificationsInfo());openNotificationMenu(){let t=new Event("openRightSidenav",{bubbles:!0,cancelable:!0});window.document.dispatchEvent(t)}onKeyDown(t){let e=t.key?.toLowerCase();(e==="enter"||e===" "||e==="spacebar")&&(t.preventDefault(),this.openNotificationMenu())}focus(){try{let t=this.badgeButton&&this.badgeButton(),e=t&&t.nativeElement;e&&typeof e.focus=="function"&&e.focus()}catch(t){}}static \u0275fac=function(e){return new(e||i)};static \u0275cmp=P({type:i,selectors:[["notification-badge"]],viewQuery:function(e,o){e&1&&X(o.badgeButton,di,5),e&2&&Z()},decls:5,vars:7,consts:[["badgeButton",""],["mat-fab","","role","button","aria-label","Open notifications",1,"layout-action-btn",3,"click","keydown"],["aria-hidden","false","matBadgeSize","large","matBadgePosition","after","matBadgeOverlap","true",1,"icon-alert-color",3,"matBadgeHidden","matBadge"]],template:function(e,o){if(e&1){let a=v();r(0,"div")(1,"button",1,0),h("click",function(){return p(a),m(o.openNotificationMenu())})("keydown",function(u){return p(a),m(o.onKeyDown(u))}),r(3,"mat-icon",2),d(4,"notifications "),s()()()}e&2&&(f(),Nt("warn",o.notificationsInfo().isWarn)("alarm-emergency-blink",o.notificationsInfo().isAlarmEmergency),Ot("aria-haspopup",!0),f(2),M("matBadgeHidden",!o.notificationsInfo().alarmCount)("matBadge",o.notificationsInfo().alarmCount))},dependencies:[N,Gt,T,L,lt,_e],styles:["[_nghost-%COMP%]{display:block}.layout-action-btn[_ngcontent-%COMP%]{color:var(--mat-sys-on-primary);background-color:var(--mat-sys-primary)}.icon-alert-color[_ngcontent-%COMP%]{--mat-list-list-item-leading-icon-color: var(--kip-zone-alert-color)}.icon-warn-color[_ngcontent-%COMP%]{--mat-list-list-item-leading-icon-color: var(--kip-zone-warn-color)}.icon-alarm-color[_ngcontent-%COMP%]{--mat-list-list-item-leading-icon-color: var(--kip-zone-alarm-color)}.icon-emergency-color[_ngcontent-%COMP%]{--mat-list-list-item-leading-icon-color: var(--kip-zone-emergency-color)}.alarm-emergency-blink[_ngcontent-%COMP%]{animation:_ngcontent-%COMP%_blinking-emergency 1.5s infinite}@keyframes _ngcontent-%COMP%_blinking-emergency{0%{background-color:var(--kip-zone-alarm-color)}50%{background-color:var(--mat-sys-primary)}to{background-color:var(--kip-zone-alarm-color)}}.warn[_ngcontent-%COMP%]{color:var(--kip-zone-warn-color)}"]})}return i})();var Be=(()=>{class i{overlayRef=null;overlay=n(Yt);injector=n(Q);open(){if(this.overlayRef)return;this.overlayRef=this.overlay.create({hasBackdrop:!1,panelClass:"notification-overlay-panel",positionStrategy:this.overlay.position().global().bottom("20px").left("20px"),scrollStrategy:this.overlay.scrollStrategies.reposition()});let t=new Qt(Le,null,this.injector),e=this.overlayRef.attach(t);try{let o=e&&e.instance;if(o&&typeof o.focus=="function")o.focus();else{let a=this.overlayRef.overlayElement,l=a&&a.querySelector("button[mat-fab], .layout-action-btn");l&&typeof l.focus=="function"&&l.focus()}}catch(o){}}close(){try{this.overlayRef&&this.overlayRef.dispose()}catch(t){console.warn("[NotificationOverlayService] dispose failed",t)}finally{this.overlayRef=null}}toggle(t){t?this.open():this.close()}isOpen(){return!!this.overlayRef}ngOnDestroy(){try{this.overlayRef&&this.overlayRef.dispose()}catch(t){}finally{this.overlayRef=null}}static \u0275fac=function(e){return new(e||i)};static \u0275prov=S({token:i,factory:i.\u0275fac,providedIn:"root"})}return i})();function pi(i,c){if(i&1){let t=v();r(0,"button",12),h("click",function(){p(t);let o=g(2);return m(o.onActionItem("toggleFullScreen"))}),r(1,"span",10),d(2,"fullscreen"),s()()}}function mi(i,c){if(i&1){let t=v();r(0,"button",12),h("click",function(){p(t);let o=g(2);return m(o.onActionItem("toggleFullScreen"))}),r(1,"span",10),d(2,"close_fullscreen"),s()()}}function fi(i,c){if(i&1&&b(0,pi,3,0,"button",11)(1,mi,3,0,"button",11),i&2){let t=g();C(t.uiEvent.fullscreenStatus()?1:0)}}function ui(i,c){if(i&1){let t=v();r(0,"button",14),h("click",function(){p(t);let o=g(2);return m(o.onActionItem("nightMode"))}),r(1,"span",10),d(2,"mode_night"),s()()}}function hi(i,c){if(i&1){let t=v();r(0,"button",14),h("click",function(){p(t);let o=g(2);return m(o.onActionItem("nightMode"))}),r(1,"span",10),d(2,"light_mode"),s()()}}function gi(i,c){if(i&1&&b(0,ui,3,0,"button",13)(1,hi,3,0,"button",13),i&2){let t=g();C(t.app.isNightMode()?1:0)}}function _i(i,c){if(i&1){let t=v();r(0,"tile-large-icon",15,1),h("click",function(){let o=p(t).$index,a=g();return m(a.navigateToDashboard(o))}),s()}if(i&2){let t=c.$implicit;M("active",t.active)("svgIcon",t.svgIcon)("iconSize",t.iconSize)("label",t.label)}}var ze=(()=>{class i{actionsSidenav=Rt.required();_router=n(k);uiEvent=n(dt);dashboard=n(A);app=n(le);_settings=n(x);isAutoNightMode=_(this._settings.getAutoNightModeAsO(),{requireSync:!0});_initialDashboardMatch=(()=>{let e=this._router.parseUrl(this._router.url).root.children.primary,o=e?e.segments.map(a=>a.path):[];return o.length===0||o[0]==="dashboard"||o[0]==="chartplotter"})();isDashboardContext=_(this._router.events.pipe(U(t=>t instanceof rt),Mt(null),G(()=>{let e=this._router.parseUrl(this._router.url).root.children.primary,o=e?e.segments.map(a=>a.path):[];return o.length===0||o[0]==="dashboard"||o[0]==="chartplotter"}),wt()),{initialValue:this._initialDashboardMatch});menuItems=Et(()=>{let t=this.dashboard.dashboards(),e=this.dashboard.activeDashboard();return t.map((o,a)=>({id:Number(o.id),active:a===e,pinned:!1,svgIcon:o.icon||"dashboard-dashboard",iconSize:60,label:o.name||`Dashboard ${a+1}`}))});ngAfterViewInit(){this.uiEvent.addHotkeyListener((t,e)=>this.handleKeyDown(t,e),{ctrlKey:!0,shiftKey:!0,keys:["e","f","n"]})}ngOnDestroy(){this.uiEvent.removeHotkeyListener(this.handleKeyDown.bind(this))}handleKeyDown(t,e){switch(t){case"e":this.onActionItem("layout");break;case"f":this.onActionItem("toggleFullScreen");break;case"n":this.onActionItem("nightMode");break;default:break}}onActionItem(t){switch(this.actionsSidenav().close(),t){case"toggleFullScreen":this.uiEvent.toggleFullScreen();break;case"settings":this._router.navigate(["/settings"]);break;case"layout":this.dashboard.setStaticDashboard(!1);break;case"nightMode":this.app.isNightMode.set(!this.app.isNightMode()),this.app.toggleDayNightMode();break;default:break}}navigateToDashboard(t){this.actionsSidenav().close(),this._router.navigate([`dashboard/${t}`])}static \u0275fac=function(e){return new(e||i)};static \u0275cmp=P({type:i,selectors:[["menu-actions"]],inputs:{actionsSidenav:[1,"actionsSidenav"]},decls:14,vars:3,consts:[["tileContainer",""],["tile",""],[1,"actions-container"],[1,"actions-top-container"],["mat-flat-button","","tabindex","0",1,"action-button","home-btn",3,"click"],["height","24px","width","24px","svgIcon","kip","aria-hidden","false",1,"home-icon",2,"height","24px","width","24px"],[1,"menu-item-container"],[3,"active","svgIcon","iconSize","label"],[1,"actions-bottom-container"],["mat-flat-button","",1,"action-button",2,"width","135px",3,"click","disabled"],[1,"material-icons"],["mat-flat-button","","tabindex","0",1,"action-button"],["mat-flat-button","","tabindex","0",1,"action-button",3,"click"],["mat-flat-button","",1,"action-button"],["mat-flat-button","",1,"action-button",3,"click"],[3,"click","active","svgIcon","iconSize","label"]],template:function(e,o){if(e&1){let a=v();r(0,"div",2)(1,"div",3),b(2,fi,2,1),b(3,gi,2,1),r(4,"button",4),h("click",function(){return p(a),m(o.onActionItem("settings"))}),I(5,"mat-icon",5),s()(),r(6,"div",6,0),V(8,_i,2,4,"tile-large-icon",7,J),s(),r(10,"div",8)(11,"button",9),h("click",function(){return p(a),m(o.onActionItem("layout"))}),r(12,"span",10),d(13,"lock_open"),s()()()()}e&2&&(f(2),C(o.uiEvent.fullscreenSupported()?2:-1),f(),C(o.isAutoNightMode()?-1:3),f(5),F(o.menuItems()),f(3),M("disabled",!o.isDashboardContext()))},dependencies:[T,L,N,et,ke],styles:[".actions-container[_ngcontent-%COMP%]{display:flex;flex-direction:column;height:100%;width:135px}.actions-top-container[_ngcontent-%COMP%]{display:flex;flex-direction:row;flex-wrap:wrap;width:100%}.actions-bottom-container[_ngcontent-%COMP%]{height:48px;width:100%}.action-button[_ngcontent-%COMP%]{border-radius:0;height:48px;flex:1 1 48px;min-height:0;overflow:hidden;border:1px solid var(--mat-sidenav-container-background-color, var(--mat-sys-surface))}.home-btn[_ngcontent-%COMP%]{--mat-icon-button-icon-size: 24px;--mat-button-filled-icon-offset: 0px;--mat-button-filled-icon-spacing: 0px;--mat-button-filled-label-text-size: 0px}.home-icon[_ngcontent-%COMP%] .mat-mdc-unelevated-button[_ngcontent-%COMP%] > .mat-icon[_ngcontent-%COMP%]{font-size:0px}.full-size[_ngcontent-%COMP%]{width:135px}.menu-item-container[_ngcontent-%COMP%]{display:flex;flex-direction:column;flex-wrap:nowrap;padding:3px 1px;gap:5px;width:135px;overflow-y:auto;scrollbar-width:none;overflow-x:hidden;scroll-behavior:smooth;flex:1 1 auto;min-height:0}"]})}return i})();var He=(()=>{class i{COMMAND_SET_DISPLAY_PATH="self.kip.remote.setDisplay";COMMAND_SET_SCREEN_INDEX_PATH="self.kip.remote.setScreenIndex";COMMAND_REQUEST_ACTIVE_SCREEN_PATH="self.kip.remote.requestActiveScreen";settings=n(x);dashboard=n(A);data=n(z);requests=n(pe);KIP_UUID=this.settings.KipUUID;ACTIVE_SCREEN_PATH=`self.displays.${this.KIP_UUID}.screenIndex`;CHANGE_SCREEN_PATH=`self.displays.${this.KIP_UUID}.activeScreen`;displayName=_(this.settings.getInstanceNameAsO());isRemoteControl=_(this.settings.getIsRemoteControlAsO());remoteScreenPosition=_(this.data.subscribePath(this.ACTIVE_SCREEN_PATH,"default"));changeDashboardTo=_(this.data.subscribePath(this.CHANGE_SCREEN_PATH,"default"));previousIsRemoteControl=!1;constructor(){this.setActiveDashboardOnRemote(this.KIP_UUID,null),this.setScreensOnRemote(this.KIP_UUID,null),this.clearActiveScreenOnRemote(this.KIP_UUID,null),console.log("[Remote Dashboards] Cleaning paths on server"),w(()=>{let t=this.isRemoteControl(),e=this.displayName();q(()=>{if(!t&&!this.previousIsRemoteControl)return;this.previousIsRemoteControl=t;let o;t?(o=this.getScreensPayload(this.dashboard.dashboards()),this.dashboard.activeDashboard()!==null&&this.setActiveDashboardOnRemote(this.KIP_UUID,this.dashboard.activeDashboard())):(o=null,this.clearActiveDashboardOnServer()),this.shareScreens(o)})}),w(()=>{let t=this.dashboard.dashboards();q(()=>{if(!this.isRemoteControl())return;let e=this.getScreensPayload(t);this.shareScreens(e)})}),w(()=>{let t=this.dashboard.activeDashboard();q(()=>{this.isRemoteControl()&&t!==null&&(this.setActiveDashboardOnRemote(this.KIP_UUID,t),console.log(`[Remote Dashboards] Sent new dashboard highlight index ${t} to server.`))})}),w(()=>{let t=this.changeDashboardTo();q(()=>{if(!this.isRemoteControl()||t.data.value==null)return;let e=Number(t.data.value);!isNaN(e)&&e>=0&&e<this.dashboard.dashboards().length&&this.dashboard.activeDashboard()!==e&&(this.dashboard.navigateTo(e),console.log(`[Remote Dashboards] Executed remote request to change active dashboard to: ${e}`))})})}clearActiveDashboardOnServer(){this.setActiveDashboardOnRemote(this.KIP_UUID,null),console.log("[Remote Dashboards] Disabled: Cleared active dashboard on server")}getScreensPayload(t){let e=this.displayName(),o=t.map(u=>{var y=u,{configuration:a}=y,l=St(y,["configuration"]);return l});return{displayName:e,screens:o}}shareScreens(t){this.setScreensOnRemote(this.KIP_UUID,t),console.log("[Remote Dashboards] Sending dashboard configurations to server.")}setActiveDashboardOnRemote(t,e){let o={displayId:t,screenIdx:e};this.requests.putRequest(this.COMMAND_SET_SCREEN_INDEX_PATH,o,this.KIP_UUID)||console.error("[Remote Dashboards] Error sharing active dashboard: request was not accepted")}setScreensOnRemote(t,e){let o={displayId:t,display:e===null?null:Ct({},e)};this.requests.putRequest(this.COMMAND_SET_DISPLAY_PATH,o,this.KIP_UUID)||console.error("[Remote Dashboards] Error sharing screen configuration: request was not accepted")}clearActiveScreenOnRemote(t,e){let o={displayId:t,screenIdx:e};this.requests.putRequest(this.COMMAND_REQUEST_ACTIVE_SCREEN_PATH,o,this.KIP_UUID)||console.error("[Remote Dashboards] Error clearing active screen request path: request was not accepted")}static \u0275fac=function(e){return new(e||i)};static \u0275prov=S({token:i,factory:i.\u0275fac,providedIn:"root"})}return i})();var $e=11,qe="connectionConfig",W=(()=>{class i{config;isLoggedIn=null;loggedInSubscription=null;connection=n(nt);auth=n(D);connectionStateMachine=n(K);router=n(k);delta=n(B);data=n(z);storage=n(at);internetReachability=n(Ie);injector=n(Q);datasetService=null;_bootstrapStatus$=new mt("starting");_bootstrapIssue$=new mt({reason:"none"});constructor(){this.loggedInSubscription=this.auth.isLoggedIn$.subscribe(t=>{this.isLoggedIn=t})}initNetworkServices(){return $(this,null,function*(){let t=!1;this.loadLocalStorageConfig(),this.preloadFonts(),this.internetReachability.start();try{if(this.config?.signalKUrl!==void 0&&this.config.signalKUrl!==null&&(yield this.connection.initializeConnection({url:this.config.signalKUrl,new:!1},this.config.proxyEnabled,this.config.signalKSubscribeAll)),!this.isLoggedIn&&this.config?.signalKUrl&&this.config?.useSharedConfig&&this.config?.loginName&&this.config?.loginPassword&&(yield this.login()),this.isLoggedIn&&this.config?.useSharedConfig)if(yield this.storage.waitUntilReady()){let o=yield this.storage.getConfig("user",this.config.sharedConfigName,$e),a={sharedConfigName:this.config.sharedConfigName,configFileVersion:$e,initConfig:o};this.storage.bootstrapRemoteContext(a)}else throw new Error("[AppInit Network Service] StorageService did not become ready in time. Cannot bootstrap remote configuration.");this._bootstrapIssue$.next({reason:"none"}),yield this.getDatasetService().waitUntilReady(),!this.isLoggedIn&&this.config?.signalKUrl&&this.config?.useSharedConfig&&this.router.navigate(["/login"])}catch(e){if(t=!0,e?.status===404&&this.config?.useSharedConfig){let o=yield this.probeLegacyUpgradeAvailability(this.config.sharedConfigName);this._bootstrapIssue$.next({reason:"missing-shared-config",statusCode:404,sharedConfigName:this.config.sharedConfigName,legacyUpgradeAvailable:o})}else e?.status===0?this._bootstrapIssue$.next({reason:"network-unreachable",statusCode:0}):e?.status===401?this._bootstrapIssue$.next({reason:"unauthorized",statusCode:401}):this._bootstrapIssue$.next({reason:"unknown",statusCode:e?.status});e.status===0?(yield this.waitForHttpRetryCompletion())===ot.HTTPConnected||this.connectionStateMachine.isHTTPConnected()?console.warn("[AppInit Network Service] Initial connection recovered during retry cycle. Skipping fallback route."):(console.warn("[AppInit Network Service] Initialization failed after HTTP retries. Redirecting to settings page."),yield this.router.navigate(["/options"])):e.status===401?(console.warn("[AppInit Network Service] Initialization failed. Unauthorized access. Redirecting to login page."),yield this.router.navigate(["/login"])):(console.warn("[AppInit Network Service] Initialization failed. Error: ",JSON.stringify(e)),yield this.router.navigate(["/options"])),console.warn("[AppInit Network Service] Startup continuing in degraded mode to allow UI feedback."),this._bootstrapStatus$.next("degraded");return}finally{t||this._bootstrapStatus$.next("ready"),console.log("[AppInit Network Service] Initialization completed"),this.connectionStateMachine.enableWebSocketMode(),this.connectionStateMachine.isHTTPConnected()&&(console.log("[AppInit Network Service] Starting WebSocket connection after initialization"),this.connectionStateMachine.startWebSocketConnection())}})}get bootstrapStatus$(){return this._bootstrapStatus$.asObservable()}get bootstrapIssue$(){return this._bootstrapIssue$.asObservable()}getDatasetService(){return this.datasetService||(this.datasetService=this.injector.get(H)),this.datasetService}waitForHttpRetryCompletion(t){return $(this,null,function*(){let e=t??this.connectionStateMachine.getHttpRetryWindowMs(2e3),o=new Set([ot.HTTPConnected,ot.PermanentFailure]),a=this.connectionStateMachine.currentState;return o.has(a)?a:new Promise(l=>{let u=window.setTimeout(()=>{y.unsubscribe(),l(null)},e),y=this.connectionStateMachine.state$.subscribe(bt=>{o.has(bt)&&(clearTimeout(u),y.unsubscribe(),l(bt))})})})}probeLegacyUpgradeAvailability(t){return $(this,null,function*(){if(!t)return!1;try{return(yield this.storage.getConfig("user",t,9))?.app?.configVersion===10}catch(e){return!1}})}login(){return $(this,null,function*(){if(!this.isLoggedIn&&this.config.useSharedConfig&&this.config.loginName&&this.config.loginPassword)try{yield this.auth.login({usr:this.config.loginName,pwd:this.config.loginPassword})}catch(t){throw t.status===0?this.router.navigate(["/settings"]):t.status===401&&this.router.navigate(["/login"]),t}})}setLocalStorageConfig(){localStorage.setItem(qe,JSON.stringify(this.config))}loadLocalStorageConfig(){this.config=JSON.parse(localStorage.getItem(qe)),this.config?this.config.signalKUrl||(this.config.signalKUrl=window.location.origin,this.setLocalStorageConfig(),console.log(`[AppInit Network Service] Config found with no server URL. Setting Auto-Discovery URL: ${this.config.signalKUrl}`)):(this.config=Kt,this.config.signalKUrl=window.location.origin,console.log(`[AppInit Network Service] Connection Configuration not found. Creating configuration using Auto-Discovery URL: ${this.config.signalKUrl}`),this.setLocalStorageConfig()),this.config.configVersion==9&&(this.config.configVersion=10,this.setLocalStorageConfig(),console.log("[AppInit Network Service] Upgrading Connection version from 9 to 10")),this.config.configVersion==10&&(this.config.configVersion=11,this.setLocalStorageConfig(),console.log("[AppInit Network Service] Upgrading Connection version from 10 to 11")),this.config.configVersion==11&&(this.config.configVersion=12,this.setLocalStorageConfig(),console.log("[AppInit Network Service] Upgrading Connection version from 11 to 12"))}preloadFonts(){let t=[{family:"Roboto",src:"url(./assets/google-fonts/KFOlCnqEu92Fr1MmSU5fChc4AMP6lbBP.woff2)",options:{weight:"300",style:"normal"}},{family:"Roboto",src:"url(./assets/google-fonts/KFOlCnqEu92Fr1MmSU5fBBc4AMP6lQ.woff2)",options:{weight:"300",style:"normal"}},{family:"Roboto",src:"url(./assets/google-fonts/KFOmCnqEu92Fr1Mu7GxKKTU1Kvnz.woff2)",options:{weight:"400",style:"normal"}},{family:"Roboto",src:"url(./assets/google-fonts/KFOmCnqEu92Fr1Mu4mxKKTU1Kg.woff2)",options:{weight:"400",style:"normal"}},{family:"Roboto",src:"url(./assets/google-fonts/KFOlCnqEu92Fr1MmEU9fChc4AMP6lbBP.woff2)",options:{weight:"500",style:"normal"}},{family:"Roboto",src:"url(./assets/google-fonts/KFOlCnqEu92Fr1MmEU9fBBc4AMP6lQ.woff2)",options:{weight:"500",style:"normal"}}];for(let{family:e,src:o,options:a}of t){let l=new FontFace(e,o,a);l.load().then(()=>document.fonts.add(l)).catch(u=>console.log(`[AppInit Network Service] Error loading fonts: ${u}`))}}ngOnDestroy(){this.loggedInSubscription?.unsubscribe()}static \u0275fac=function(e){return new(e||i)};static \u0275prov=S({token:i,factory:i.\u0275fac})}return i})();var vi=["upgradeMessages"];function bi(i,c){if(i&1&&(r(0,"li"),d(1),s()),i&2){let t=c.$implicit;f(),j(t)}}function Ci(i,c){if(i&1&&(r(0,"ul",11,1),V(2,bi,2,1,"li",null,J),s()),i&2){let t=g(2);f(2),F(t.upgrade.messages())}}function Si(i,c){if(i&1&&(r(0,"div",7)(1,"div",8),I(2,"mat-progress-spinner",9),r(3,"div",10)(4,"h3"),d(5,"Upgrading Configuration\u2026"),s(),r(6,"p"),d(7,"Please wait a moment while we migrate your dashboards and widgets."),s(),b(8,Ci,4,0,"ul",11),s()()()),i&2){let t=g();f(8),C(t.upgrade.messages().length?8:-1)}}var je=(()=>{class i{_deltaService=n(B);_connectionStateMachine=n(K);_appNetworkInit=n(W);_historySeriesReconcile=n(xe);authenticationService=n(D);_dataSet=n(H);_dashboard=n(A);_remoteControl=n(He);toast=n(ne);_notifications=n(E);_uiEvent=n(dt);_dialog=n(be);settings=n(x);_responsive=n(Lt);_destroyRef=n(Y);_notificationOverlay=n(Be);_router=n(k);upgrade=n(ve);upgradeMessagesRef=tt("upgradeMessages");_upgradeShown=!1;actionsSidenavOpened=_t(!1);notificationsSidenavOpened=_t(!1);notificationsInfo=_(this._notifications.observerNotificationsInfo());bootstrapStatus=_(this._appNetworkInit.bootstrapStatus$,{initialValue:"starting"});bootstrapIssue=_(this._appNetworkInit.bootstrapIssue$,{initialValue:{reason:"none"}});dashboardVisible=kt(!1);isPhonePortrait;scheduledOpen=null;OPEN_DELAY_MS=300;missingConfigPromptShown=!1;_swipeLeftHandler=()=>this.onSwipeLeft();_swipeRightHandler=()=>this.onSwipeRight();_hotkeyHandler=t=>this.handleKeyDown(t);constructor(){w(()=>{if(this.settings.configUpgrade()){let t=this.settings.getConfigVersion();t===11&&this.upgrade.runUpgrade(t),t||this._upgradeShown||(this._upgradeShown=!0,this._dialog.openFrameDialog({title:"Upgrade Instructions",component:"upgrade-config"},!0).pipe(R(this._destroyRef)).subscribe())}}),w(()=>{let t=this.upgrade.messages();if(this.upgrade.upgrading()&&t.length&&this.upgradeMessagesRef()){let e=this.upgradeMessagesRef().nativeElement;e.scrollTop=e.scrollHeight}});try{this.dashboardVisible.set(this.isUrlDashboard(this._router.url))}catch(t){}this._router.events.pipe(U(t=>t instanceof rt),R(this._destroyRef)).subscribe(t=>{try{this.dashboardVisible.set(this.isUrlDashboard(t.urlAfterRedirects||t.url))}catch(e){}}),w(()=>{let t=this.dashboardVisible()&&this._dashboard.isDashboardStatic()&&this.notificationsInfo().alarmCount>0;if(this.notificationsSidenavOpened()){this.scheduledOpen&&(clearTimeout(this.scheduledOpen),this.scheduledOpen=null);try{this._notificationOverlay.close()}catch(o){}return}if(t){if(this.scheduledOpen)return;this.scheduledOpen=window.setTimeout(()=>{this.scheduledOpen=null;try{this._notificationOverlay.open()}catch(o){}},this.OPEN_DELAY_MS)}else{this.scheduledOpen&&(clearTimeout(this.scheduledOpen),this.scheduledOpen=null);try{this._notificationOverlay.close()}catch(o){}}}),w(()=>{if(this.notificationsSidenavOpened())try{this._notificationOverlay.close()}catch(e){}}),this.isPhonePortrait=_(this._responsive.observe(jt.HandsetPortrait)),this._connectionStateMachine.status$.pipe(R(this._destroyRef)).subscribe(t=>this.displayConnectionsStatusNotification(t)),w(()=>{let t=this.bootstrapIssue();if(t.reason!=="missing-shared-config"||this.missingConfigPromptShown)return;this.missingConfigPromptShown=!0;let e=t.sharedConfigName||"default",o=t.legacyUpgradeAvailable===!0,a=o?"Upgrade":"Create",l=o?`Server is reachable, but no current version shared configuration '${e}' exists for this user. A legacy configuration was found and can be upgraded. Upgrade now?`:`Server is reachable, but no shared configuration '${e}' exists for this user. Create a default configuration now?`;this.toast.show(l,0,!0,"warn",a).onAction().pipe(R(this._destroyRef)).subscribe(()=>{o?this.upgrade.runUpgrade():this.settings.resetSettings()})})}isUrlDashboard(t){if(!t)return!1;let e=t.split("?")[0].replace(/\/+$/,"");return e==="/"||e==="/dashboard"||/^\/dashboard(\/\d+)?$/.test(e)||e==="/chartplotter"||/^\/chartplotter(\/\d+)?$/.test(e)}ngOnInit(){this._uiEvent.addGestureListeners(this._swipeLeftHandler,this._swipeRightHandler)}ngAfterViewInit(){this._uiEvent.addHotkeyListener(this._hotkeyHandler,{ctrlKey:!0,keys:["arrowright","arrowleft"]})}handleKeyDown(t){switch(t){case"arrowright":this.onSwipeRight();break;case"arrowleft":this.onSwipeLeft();break;case"escape":this.backdropClicked();break}}escapeKeyPressed(t){t=t.toLowerCase(),t==="escape"&&this.backdropClicked()}displayConnectionsStatusNotification(t){let e=t.message,o=this.bootstrapStatus()!=="ready";switch(t.operation){case 0:this.toast.show(e,5e3,!0);break;case 1:case 2:break;case 3:this.toast.show(e,3e3,o,"warn");break;case 4:this.toast.show(e,3e3,!0,"info");break;case 5:this.toast.show(e,0,o);break;default:console.error("[AppComponent] Unknown operation code:",t.operation),this.toast.show(`Unknown connection status: ${t.state}`,0,o,"error")}}onSwipeRight(){this._dashboard.isDashboardStatic()&&!this._uiEvent.isDragging()&&(this.isPhonePortrait().matches?(this.actionsSidenavOpened.set(!1),this.notificationsSidenavOpened.set(!0)):(this.actionsSidenavOpened.set(!1),this.notificationsSidenavOpened.update(t=>!t)))}backdropClicked(){this.notificationsSidenavOpened.update(t=>t?!t:!1),this.actionsSidenavOpened.update(t=>t?!t:!1)}onSwipeLeft(){this._dashboard.isDashboardStatic()&&!this._uiEvent.isDragging()&&(this.isPhonePortrait().matches?(this.notificationsSidenavOpened.set(!1),this.actionsSidenavOpened.set(!0)):(this.notificationsSidenavOpened.set(!1),this.actionsSidenavOpened.update(t=>!t)))}ngOnDestroy(){this._uiEvent.removeGestureListeners(this._swipeLeftHandler,this._swipeRightHandler),this._uiEvent.removeHotkeyListener(this._hotkeyHandler),this.scheduledOpen&&(clearTimeout(this.scheduledOpen),this.scheduledOpen=null)}static \u0275fac=function(e){return new(e||i)};static \u0275cmp=P({type:i,selectors:[["app-root"]],viewQuery:function(e,o){e&1&&X(o.upgradeMessagesRef,vi,5),e&2&&Z()},inputs:{actionsSidenavOpened:[1,"actionsSidenavOpened"],notificationsSidenavOpened:[1,"notificationsSidenavOpened"]},outputs:{actionsSidenavOpened:"actionsSidenavOpenedChange",notificationsSidenavOpened:"notificationsSidenavOpenedChange"},decls:9,vars:6,consts:[["actionsSidenav",""],["upgradeMessages",""],["kipGestures","",1,"sidenav-container",3,"swipeleft","swiperight","backdropClick","mode","bridgeUiEvents"],["mode","over","position","start","autoFocus","true","disableClose","",1,"sidenav-notifications",3,"openedChange","keydown","opened"],["mode","over","position","end","autoFocus","true","disableClose","",1,"sidenav-actions",3,"openedChange","keydown","opened"],[3,"actionsSidenav"],[1,"router-outlet-container"],["role","alert","aria-live","polite",1,"config-upgrade-overlay"],[1,"config-upgrade-card"],["diameter","46","mode","indeterminate"],[1,"config-upgrade-text"],[1,"config-upgrade-messages"]],template:function(e,o){if(e&1){let a=v();r(0,"mat-sidenav-container",2),h("swipeleft",function(){return p(a),m(o.onSwipeLeft())})("swiperight",function(){return p(a),m(o.onSwipeRight())})("backdropClick",function(){return p(a),m(o.backdropClicked())}),r(1,"mat-sidenav",3),gt("openedChange",function(u){return p(a),ht(o.notificationsSidenavOpened,u)||(o.notificationsSidenavOpened=u),m(u)}),h("keydown",function(u){return p(a),m(o.escapeKeyPressed(u.key))}),I(2,"menu-notifications"),s(),r(3,"mat-sidenav",4,0),gt("openedChange",function(u){return p(a),ht(o.actionsSidenavOpened,u)||(o.actionsSidenavOpened=u),m(u)}),h("keydown",function(u){return p(a),m(o.escapeKeyPressed(u.key))}),I(5,"menu-actions",5),s(),r(6,"mat-sidenav-content"),I(7,"router-outlet",6),s()(),b(8,Si,9,1,"div",7)}if(e&2){let a=Pt(4);M("mode","horizontal")("bridgeUiEvents",!0),f(),ut("opened",o.notificationsSidenavOpened),f(2),ut("opened",o.actionsSidenavOpened),f(2),M("actionsSidenav",a),f(3),C(o.upgrade.upgrading()?8:-1)}},dependencies:[Ke,ze,N,ge,T,oe,te,De,Pe,Ne,Oe,Vt,Jt,Te,Ae],styles:[".sidenav-container[_ngcontent-%COMP%]{height:100%;width:100%;--mat-sidenav-scrim-color: color-mix(in srgb, var(--mat-sys-neutral-variant20) 70%, transparent)}mat-sidenav-content[_ngcontent-%COMP%]{overflow-y:hidden;overflow-x:hidden}mat-sidenav[_ngcontent-%COMP%]{box-shadow:0 0 1px 0 var(--kip-contrast-color)}mat-sidenav.sidenav-notifications[_ngcontent-%COMP%]{width:230px;z-index:1200}mat-sidenav.sidenav-actions[_ngcontent-%COMP%]{width:135px;z-index:1200;overflow-x:hidden}.config-upgrade-overlay[_ngcontent-%COMP%]{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:#00000073;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);z-index:2000;pointer-events:all}.config-upgrade-card[_ngcontent-%COMP%]{display:flex;flex-direction:row;align-items:center;gap:18px;padding:20px 24px;width:clamp(300px,60vw,640px);background:var(--kip-background, #1f1f1f);border:1px solid rgba(255,255,255,.18);border-radius:14px;color:var(--kip-contrast-color, #fff);box-shadow:0 6px 22px #0000008c}.config-upgrade-text[_ngcontent-%COMP%] h3[_ngcontent-%COMP%]{margin:0 0 4px;font-size:1.05rem;font-weight:600;letter-spacing:.5px}.config-upgrade-text[_ngcontent-%COMP%] p[_ngcontent-%COMP%]{margin:0 0 10px;font-size:.8rem;opacity:.85}.config-upgrade-messages[_ngcontent-%COMP%]{list-style:disc;margin:0;padding-left:18px;max-height:180px;font-size:.68rem;line-height:1.25;scrollbar-width:thin;overflow-y:auto}.config-upgrade-messages[_ngcontent-%COMP%] li[_ngcontent-%COMP%]{margin-bottom:2px}"]})}return i})();var We=(()=>{class i{auth=n(D);authToken=null;authTokenSubscription=null;constructor(){this.authTokenSubscription=this.auth.authToken$.subscribe(t=>{this.authToken=t})}intercept(t,e){let o=t.clone();return this.authToken&&(o=t.clone({headers:t.headers.set("authorization","JWT "+this.authToken.token)})),e.handle(o)}ngOnDestroy(){this.authTokenSubscription?.unsubscribe()}static \u0275fac=function(e){return new(e||i)};static \u0275prov=S({token:i,factory:i.\u0275fac})}return i})();var Ge=(()=>{class i extends it{_createContainer(){let t=document.createElement("div");t.classList.add("cdk-overlay-container"),(document.getElementById("app-filter-wrapper")||document.querySelector("app-root")||document.body).appendChild(t),this._containerElement=t}static \u0275fac=(()=>{let t;return function(o){return(t||(t=It(i)))(o||i)}})();static \u0275prov=S({token:i,factory:i.\u0275fac})}return i})();var Qe=(()=>{class i{_router=n(k);_dialog=n(re);_bottomSheet=n(Ce);_destroyRef=n(Y);constructor(){this._router.events.pipe(U(t=>t instanceof Zt),R(this._destroyRef)).subscribe(()=>{this._dialog.openDialogs.length>0&&this._dialog.closeAll(),this._bottomSheet.dismiss()})}static \u0275fac=function(e){return new(e||i)};static \u0275prov=S({token:i,factory:i.\u0275fac,providedIn:"root"})}return i})();Ue.production&&void 0;Bt(je,{providers:[Ut(),xt(zt),{provide:Ht,useClass:We,multi:!0},{provide:ae,useValue:{hasBackdrop:!0,disableClose:!1,autoFocus:"first-tabbable",delayFocusTrap:!0,backdropClass:"dialogBackdrop"}},{provide:se,useValue:{appearance:"outline",floatLabel:"always",subscriptSizing:"dynamic"}},{provide:me,useValue:{showDelay:1500,hideDelay:0}},D,z,nt,B,K,H,A,de,W,x,E,he,at,Ee(),$t(qt()),ee(Re,ie()),{provide:it,useClass:Ge},ft(()=>n(W).initNetworkServices()),ft(()=>{n(Qe)})]});
@@ -1,84 +0,0 @@
1
- name: Bug Report
2
- description: Report a bug or issue
3
- title: "[Bug]: "
4
- labels: ["bug"]
5
- body:
6
- - type: markdown
7
- attributes:
8
- value: |
9
- Thanks for reporting a bug! Please provide the following information to help us investigate.
10
-
11
- - type: dropdown
12
- id: operating-system
13
- attributes:
14
- label: Operating System
15
- description: Which operating system(s) are you using?
16
- multiple: true
17
- options:
18
- - Raspberry Pi OS
19
- - macOS
20
- - iOS
21
- - Windows
22
- - Linux
23
- - Android
24
- - Other
25
- validations:
26
- required: true
27
-
28
- - type: dropdown
29
- id: browser
30
- attributes:
31
- label: Browser
32
- description: Which browser(s) are you using?
33
- multiple: true
34
- options:
35
- - Chromium
36
- - Chrome
37
- - Safari
38
- - Edge
39
- - Firefox
40
- - Brave
41
- - Opera
42
- - Other
43
- validations:
44
- required: true
45
-
46
- - type: input
47
- id: kip-version
48
- attributes:
49
- label: KIP Version
50
- description: What version of Kip are you using (Found in Settings -> Options -> Connectivity)?
51
- placeholder: e.g., v2.5.1
52
- validations:
53
- required: true
54
-
55
- - type: input
56
- id: signalk-version
57
- attributes:
58
- label: Signal K Server Version
59
- description: What version of Signal K server are you using?
60
- placeholder: e.g., v2.5.1
61
- validations:
62
- required: false
63
-
64
- - type: textarea
65
- id: bug-description
66
- attributes:
67
- label: Bug Description
68
- description: A clear and concise description of what the bug is - What did you expect, what actually happened and any other context about the problem here, including screenshots, logs, or error messages.
69
- placeholder: What happened?
70
- validations:
71
- required: true
72
-
73
- - type: textarea
74
- id: steps-to-reproduce
75
- attributes:
76
- label: Steps to Reproduce
77
- description: Steps to reproduce the behavior
78
- placeholder: |
79
- 1. Go to '...'
80
- 2. Click on '....'
81
- 3. Scroll down to '....'
82
- 4. See error
83
- validations:
84
- required: true
@@ -1,5 +0,0 @@
1
- blank_issues_enabled: false
2
- contact_links:
3
- - name: Community Support (Discord)
4
- url: https://discord.gg/AMDYT2DQga
5
- about: Please ask questions and discuss ideas in near real time here
@@ -1,35 +0,0 @@
1
- name: Feature Request
2
- description: Suggest a new feature or enhancement
3
- title: "[Feature]: "
4
- labels: ["enhancement"]
5
- body:
6
- - type: markdown
7
- attributes:
8
- value: |
9
- Thanks for suggesting a feature! Please provide details below.
10
-
11
- - type: textarea
12
- id: feature-request
13
- attributes:
14
- label: Feature Request
15
- description: |
16
- Please describe the feature you'd like to see:
17
- - What problem does this solve? What are you trying to accomplish?
18
- - Provide a clear description of what you'd like to see added or changed.
19
- placeholder: |
20
- **Problem/Use Case:**
21
- Describe what you're trying to accomplish...
22
-
23
- **Proposed Solution:**
24
- Describe how you envision this feature working...
25
- validations:
26
- required: true
27
-
28
- - type: textarea
29
- id: concepts-ideas-research
30
- attributes:
31
- label: Concepts, Ideas & Research
32
- description: Add any other information, screenshots, mockups, links similar apps or existing documentation about the feature request here.
33
- placeholder: Paste links, mockups, screenshots or related documentation to help us come up with a good and informed design...
34
- validations:
35
- required: false
@@ -1,218 +0,0 @@
1
- # KIP – Copilot Instructions (for AI coding agents)
2
-
3
- Use this quick-start map to be productive in this repo. Prefer these concrete patterns over generic Angular tips. For depth, see `COPILOT.md` (root entrypoint), this file, and `.github/instructions/angular.instructions.md`.
4
-
5
- ## Big picture
6
- - Angular v20+ PWA served under base path /@mxtommy/kip/ (angular.json baseHref, package.json scripts).
7
- - Data flow: SignalKConnectionService → SignalKDeltaService → DataService → Widgets.
8
- - UI: Dashboard(s) with draggable/resizable widgets (gridstack). Themes: light/dark/night via SCSS roles + CSS variables.
9
- - Storage: Config lives in Signal K when logged in, else local (StorageService). App init via APP_INITIALIZER (AppNetworkInitService).
10
-
11
- ## Final architecture (2026 Q1)
12
- - Historical-series orchestration path: `DashboardService` → `DashboardHistorySeriesSyncService` → `KipSeriesApiClientService` → plugin `/plugins/kip/series/reconcile`.
13
- - Dataset write ownership is centralized in `WidgetDatasetOrchestratorService`; avoid direct dataset create/edit/remove calls from widget/dashboard flows.
14
- - Shared history mapping path: `HistoryToChartMapperService` performs history-values → chart datapoint adaptation; `DatasetStreamService` delegates to it.
15
- - Widget delete cleanup uses owner UUID matching (`ownerUuid` and `ownerUuid-*`) through lifecycle service, replacing selector-specific cleanup.
16
-
17
- ### Migration guardrails
18
- 1. For chart/trend widgets, use lifecycle sync helpers (`syncDataChartDataset`, `syncNumericMiniChartDataset`, `syncWindTrendsDatasets`).
19
- 2. Keep widget UUIDs stable and unique; ownership drives both dataset cleanup and history-series reconciliation.
20
- 3. Route history response mapping changes through `HistoryToChartMapperService` only.
21
- 4. Do not reintroduce legacy selector-branch dataset cleanup in dashboard/widget code.
22
-
23
- ## Daily workflows
24
- - Dev: npm run dev, then open http://localhost:4200/@mxtommy/kip/ (needs a running Signal K server).
25
- - Build KIP app: npm run build:dev | npm run build:prod (outputs KIP to public/ and respects baseHref).
26
- - Build KIP app and KIP plugin: npm run build:all (outputs KIP to public/ and respects baseHref. Outputs plugin to kip-plugin).
27
- - Quality: npm run lint, npm test (Karma). E2E (Protractor) is legacy/optional.
28
-
29
- ## Host2 widget contract (critical)
30
- All widgets now follow the Host2 architecture (legacy BaseWidgetComponent removed).
31
-
32
- 1. Standalone component with required functional inputs:
33
- ```ts
34
- id = input.required<string>();
35
- type = input.required<string>();
36
- theme = input.required<ITheme | null>();
37
- ```
38
- 2. Provide a static `DEFAULT_CONFIG: IWidgetSvcConfig` fully describing initial config (paths + options).
39
- 3. Inject directives for runtime + streams (and optionally metadata):
40
- ```ts
41
- private runtime = inject(WidgetRuntimeDirective);
42
- private streams = inject(WidgetStreamsDirective);
43
- // optional
44
- // private meta = inject(WidgetMetadataDirective);
45
- ```
46
- 4. Register data observers in a single effect:
47
- ```ts
48
- effect(() => {
49
- const cfg = this.runtime.options();
50
- if (!cfg) return;
51
- untracked(() => {
52
- if (cfg.paths?.numericPath?.path) {
53
- this.streams.observe('numericPath', pkt => this.value.set(pkt?.data?.value ?? null));
54
- }
55
- // repeat for other path keys
56
- });
57
- });
58
- ```
59
- 5. Always guard for missing config or optional paths (check `cfg?.paths?.key?.path`).
60
- 6. Avoid mutating the merged config object; store transient UI state in signals.
61
- 7. Use UnitsService and existing formatting helpers; do not hardcode conversions. Using streams directive handles path unit conversion settings automatically for number types.
62
- 8. Timeout settings honored automatically (`enableTimeout`, `dataTimeout`)—`WidgetStreamsDirective`.
63
- 9. Provide meaningful path keys (e.g. `numericPath`, `headingTrue`, `windSpeed`) and keep them stable.
64
- 10. Destroy logic is usually implicit (streams directive centralizes subscriptions); only tear down custom resources manually if you allocate them (e.g., canvases, animation frames).
65
-
66
- ### Path definition recap
67
- Each entry in `DEFAULT_CONFIG.paths`:
68
- ```ts
69
- someKey: {
70
- description: 'User label',
71
- path: 'navigation.speedThroughWater',
72
- pathType: 'number' | 'string' | 'Date' | 'boolean',
73
- convertUnitTo: 'knots', // For numeric path only. Sets automatic conversion to this unit
74
- sampleTime: 1000, // ms, typical 500+
75
- source: null, // optional source selection. null = default source
76
- isPathConfigurable: true, // false to hide path in path options UI
77
- pathRequired: true, // set false for optional
78
- showPathSkUnitsFilter: false, // Show numeric UI filter support
79
- pathSkUnitsFilter: null // Set and apply a path unit filter (e.g. 'knots' for speed)
80
- }
81
- ```
82
-
83
- ### Data stream behavior (via WidgetStreamsDirective)
84
- - Respects per-path `sampleTime`.
85
- - Converts units for number paths using UnitsService.
86
- - Optional timeout logic based on widget config flags.
87
- - Centralized unsubscribe when host destroys the widget.
88
-
89
- ### Embedded widgets (composite pattern)
90
- Use this patterns when a parent widget (e.g. Autopilot) displays other widgets:
91
-
92
- #### `<widget-embedded>`
93
- Supply a complete `widgetProperties` object (no persistence writes):
94
- ```ts
95
- xteWidgetProps = {
96
- uuid: this.id() + '-xte',
97
- type: 'widget-numeric',
98
- config: {
99
- type: 'widget-numeric',
100
- title: 'XTE',
101
- paths: { numericPath: { description: 'Cross Track Error', path: 'navigation.course.crossTrackError', pathType: 'number', convertUnitTo: 'nm', sampleTime: 1000, isPathConfigurable: false } },
102
- numDecimal: 2
103
- }
104
- };
105
- ```
106
- Template:
107
- ```html
108
- <widget-embedded [widgetProperties]="xteWidgetProps"></widget-embedded>
109
- ```
110
- `widget-embedded` internally wires runtime + streams + metadata and instantiates the child.
111
-
112
- ### Safety patterns
113
- - Null guard every `runtime.options()` access in effects & template (`runtime.options()?.paths?.key`).
114
- - Avoid repeated `runtime.options()` chains in template: expose a computed `cfg = computed(() => this.runtime.options())`.
115
- - For performance, do all `streams.observe` calls in one untracked block.
116
-
117
- ## Widget path options (important)
118
- - pathType: Controls pipeline behavior (see features above). Must be accurate: 'number' | 'string' | 'Date' | 'boolean'.
119
- - path: Signal K path string (e.g., navigation.speedThroughWater). Empty allowed only when pathRequired=false.
120
- - sampleTime: Sampling period for the observer (ms). Keep modest (e.g., 250–1000) to reduce churn.
121
- - convertUnitTo: Target display unit understood by UnitsService (e.g., 'knots', 'celsius', 'deg'). If omitted, treat value as base/metadata unit.
122
- - source: Optional Signal K source filter; omit to accept any uniquely available source.
123
- - isPathConfigurable: When false, hides the path from the widget-config UI (for fixed/internal paths). Validation is skipped for this key.
124
- - pathRequired: Defaults to true. When false, empty path is valid; your widget must handle “no path” gracefully (don’t subscribe; show placeholder).
125
- - Timeouts: At widgetProperties.config level, enableTimeout + dataTimeout are respected by observeDataStream—don’t add custom timeouts downstream.
126
-
127
- ## Data, metadata, zones
128
- - Use DataService for values and metadata. observeDataStream wraps DataService.subscribePath.
129
- - zones$ emits Signal K zones metadata when observeMetaStream is used; map states to theme roles.
130
-
131
- ## Theming
132
- - TS: live theme via this.theme().<role> (from AppService.cssThemeColorRoles$).
133
- - SCSS: use variables from src/themes/_m3*.scss; avoid hardcoded hex.
134
-
135
- ## Datasets & charts
136
- - Historical/trend data: DatasetStreamService (src/app/core/services/dataset-stream.service.ts). Create/update/remove in widget lifecycle.
137
- - Example: src/app/widgets/widget-windtrends-chart uses Chart.js + date-fns and DatasetStreamService for batch-then-live streams.
138
- - Preferred write path: `WidgetDatasetOrchestratorService` (centralized dataset orchestration for Data Chart / Numeric minichart / Windtrends and owner-based cleanup).
139
-
140
- ## Signal K PUT/requests
141
- - Read via DataService; write via SignalKRequestsService. UI filters PUT-enabled paths (see src/assets/help-docs/putcontrols.md).
142
-
143
- ## Project specifics & gotchas
144
- - Always respect serve path /@mxtommy/kip/ (dev/prod). Assets and routing assume this base.
145
- - CommonJS deps are explicitly allowed (js-quantities). Avoid introducing new CJS without adding to allowedCommonJsDependencies.
146
- - Use standalone components, signals, @if/@for; follow .github/instructions/angular.instructions.md for style.
147
- - Widget config UIs live under src/app/widget-config; path controls use custom validators (no Validators.required). Respect isPathConfigurable and pathRequired.
148
- - Documentation standard: Every public property and public method in TypeScript code MUST include full JSDoc with: purpose, parameters, return value, and at least one usage example. Apply this by default for all generated/edited code unless a file explicitly cannot use comments.
149
-
150
- ## Widgets: do this, not that (Host2)
151
- - Do: Provide a complete `DEFAULT_CONFIG` with all paths & options. Don’t: Scatter defaults across lifecycle hooks.
152
- - Do: Centralize `streams.observe` calls in a single effect. Don’t: Register observers in multiple hooks.
153
- - Do: Keep transient state in signals. Don’t: Mutate merged config objects.
154
- - Do: Use UnitsService / formatting helpers. Don’t: Hardcode conversion factors.
155
- - Do: Guard `options()` & path existence. Don’t: Assume presence.
156
- - Do: Use widget-embedded or inline directives for composites. Don’t: Reintroduce legacy host wrappers.
157
-
158
- ## Key files/dirs
159
- - Core services: `src/app/core/services/` (DataService, SignalKConnectionService, SignalKDeltaService, AppNetworkInitService, UnitsService, DatasetStreamService, NotificationsService)
160
- - Plugin config foundation: `src/app/core/services/signalk-plugin-config.service.ts` (plugin-only detection, dependency validation, schema normalization metadata, and config persistence via `/plugins` endpoints)
161
- - Directives: `src/app/core/directives/` (widget-runtime, widget-streams, widget-metadata)
162
- - Widgets: `src/app/widgets/` (e.g., widget-numeric, widget-gauge-ng-*, widget-data-chart, widget-windtrends-chart, widget-autopilot)
163
- - Embedded host: `src/app/core/components/widget-embedded/`
164
- - Config UI: `src/app/widget-config/`
165
- - Plugin management (server plugins) is handled separately through `PluginConfigClientService` and `/plugins` REST endpoints. Keep install/uninstall out of scope unless explicitly added.
166
- - Build: `angular.json`, `package.json` scripts
167
-
168
- ## Debugging
169
- - Use Data Inspector (src/app/core/components/data-inspector) to verify live paths/metadata.
170
- - Dev with source maps: npm run dev. Watch console from DataService/DatasetStreamService for timeouts/lifecycle logs.
171
- - Embeds (widget-iframe): prefer same-origin or relative URLs to avoid CORS and input-injection limits (see embedwidget.md).
172
-
173
- ## SVG Animation Helpers (rAF)
174
- High-frequency SVG updates (rotations, path morphs) should NOT trigger Angular change detection every frame.
175
-
176
- Core utilities (src/app/widgets/utils/svg-animate.util.ts):
177
- - animateRotation(el, fromDeg, toDeg, durationMs, onDone?, ngZone?)
178
- - animateRudderWidth(rectEl, from, to, durationMs, onDone?, ngZone?)
179
- - animateAngleTransition(fromDeg, toDeg, durationMs, applyFn(angle), onDone?, ngZone?)
180
- - animateSectorTransition(fromAngles, toAngles, durationMs, applyFn(sector), onDone?, ngZone?)
181
-
182
- Pattern:
183
- 1. Inject NgZone; pass it so frames run outside Angular.
184
- 2. Cancel prior frame id before starting a new conceptual animation (store returned id from the generic helpers).
185
- 3. Skip tiny angle deltas (< ~0.25°) to prevent jitter.
186
- 4. On destroy: cancel outstanding ids (including those tracked internally for animateRotation/animateRudderWidth via element refs).
187
-
188
- Example (angle interpolation):
189
- ```
190
- if (this.portLaylineAnimId) cancelAnimationFrame(this.portLaylineAnimId);
191
- this.portLaylineAnimId = animateAngleTransition(
192
- prev,
193
- next,
194
- 300,
195
- angle => this.drawLayline(angle, true),
196
- () => { this.portLaylineAnimId = null; },
197
- this.ngZone
198
- );
199
- ```
200
-
201
- See COPILOT.md Section 12 for full rationale, cancellation rules, and future extension ideas.
202
-
203
- ## Pointer Swipe Guard (tap vs swipe)
204
- Use the shared swipe guard utility to prevent swipe gestures from triggering click/tap actions on SVG controls.
205
-
206
- Utility (core): `src/app/core/utils/pointer-swipe-guard.util.ts`
207
-
208
- When to use:
209
- - Any widget that accepts pointer input and should ignore swipe gestures (e.g., multi-state switch, boolean switch).
210
-
211
- Pattern:
212
- 1. Create a guard in the component: `private readonly swipeGuard = createSwipeGuard();`
213
- 2. Wire `pointerdown`, `pointermove`, `pointerup`, and `pointercancel` events.
214
- 3. Trigger action only when `swipeGuard.onPointerUp(...)` returns true.
215
-
216
- Notes:
217
- - The guard uses pointer capture for robust fast drags and releases capture on `pointerup`/`pointercancel`.
218
- - Default swipe threshold is 30px (override via `createSwipeGuard({ threshold })` if needed).