diff --git a/webclient/config.php b/webclient/config.php
index 2c5cb56..d44b498 100644
--- a/webclient/config.php
+++ b/webclient/config.php
@@ -2,7 +2,7 @@
return [
"version" => "0.1 dev",
- "server" => "http://192.168.1.31",
+ "server" => "http://192.168.1.101",
// Какие пути разрешены (белый список) — подстрой под себя
"allowed_prefixes" => [
"/api/v1/",
diff --git a/webclient/dist/js/main.js b/webclient/dist/js/main.js
index 89fb467..5130fe1 100644
--- a/webclient/dist/js/main.js
+++ b/webclient/dist/js/main.js
@@ -1,4 +1,4 @@
-(()=>{var Y=Object.defineProperty;var A=Object.getOwnPropertySymbols;var G=Object.prototype.hasOwnProperty,K=Object.prototype.propertyIsEnumerable;var D=(i,e,t)=>e in i?Y(i,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):i[e]=t,b=(i,e)=>{for(var t in e||(e={}))G.call(e,t)&&D(i,t,e[t]);if(A)for(var t of A(e))K.call(e,t)&&D(i,t,e[t]);return i};var M=(i,e,t)=>new Promise((r,s)=>{var n=o=>{try{c(t.next(o))}catch(u){s(u)}},a=o=>{try{c(t.throw(o))}catch(u){s(u)}},c=o=>o.done?r(o.value):Promise.resolve(o.value).then(n,a);c((t=t.apply(i,e)).next())});var m,S,C;function Q(){m.dataset.navState="displayed",m.classList.remove("state-off"),m.classList.add("state-on"),S.classList.add("a-show")}function O(){m.dataset.navState="hidden",m.classList.remove("state-on"),m.classList.add("state-off"),S.classList.add("a-hide"),S.classList.remove("a-show"),setTimeout(()=>{S.classList.remove("a-hide")},300)}function N(){console.log("HUD init"),m=document.querySelector(".hud .nav-toggle"),S=document.querySelector(".hud .navigation"),C=document.querySelector(".hud .reload-screen"),m.addEventListener("click",i=>{i.currentTarget.dataset.navState!="displayed"?Q():O()}),C.addEventListener("click",i=>{Screens.reload()})}var w=class{constructor(e,t,r){this.screens={},this.routesMap={},this.currentScreen=null,this.eventsHandlers={switch:[],reload:[]},this.screensContainer=document.querySelector(e),this.loader=document.querySelector(t),this.errorScreen=document.querySelector(r),console.log("Screens Init")}add(e,t){if(typeof t!="object")return console.error("Screens: screens must be object");if(typeof(t==null?void 0:t.alias)=="undefined")return console.error("Screens: undefined alias");if(typeof(t==null?void 0:t.renderer)!="function")return console.error("Screens: renderer must be function");this.screens[t.alias]=b({route:e},t),this.routesMap[e]=t.alias}switch(e){var r;if(this.runSwitchHandlers(e),this.hideErrorScreen(),this.showLoader(),(r=this.currentScreen)==null||r.DOMObject.remove(),typeof this.screens[e]=="undefined"){console.error(`Screens: "${e}" not found`);return}this.currentScreen=this.screens[e];let t=document.createElement("div");t.classList.add("screen"),t.id=e,t.dataset.alias=e,t.innerHTML=this.currentScreen.renderer(),this.currentScreen.DOMObject=t,this.screensContainer.append(this.currentScreen.DOMObject),this.currentScreen.initer(this)}reload(){this.currentScreen&&(this.runReloadHandlers(this.currentScreen.alias),this.switch(this.currentScreen.alias))}routing(){setInterval(()=>{let e=document.location.hash.split("#!")[1];if(typeof e=="undefined"||e=="")return;let t=typeof this.routesMap[e]=="undefined"?"not-found-screen":this.routesMap[e];(!this.currentScreen||this.currentScreen.alias!=t)&&this.switch(t)},50)}ready(){this.currentScreen!=null&&(this.currentScreen.DOMObject||(this.currentScreen.DOMObject=document.getElementsById(this.currentScreen.alias)),this.hideLoader(),this.currentScreen.DOMObject.classList.add("a-show"))}error(e,t){var r;(r=this.currentScreen)==null||r.DOMObject.remove(),this.errorScreen.querySelector(".error-title").innerHTML=e,this.errorScreen.querySelector(".error-text").innerHTML=t,this.showErrorScreen()}hideLoader(){this.loader.classList.remove("a-show")}showLoader(){this.loader.classList.add("a-show")}showErrorScreen(){this.errorScreen.classList.add("a-show")}hideErrorScreen(){this.errorScreen.classList.remove("a-show")}getScreens(){return this.screens}getRoutesMap(){return this.routesMap}onSwitch(e){this.eventsHandlers.switch.push(e)}onReaload(e){this.eventsHandlers.reload.push(e)}runSwitchHandlers(e){for(let t of this.eventsHandlers.switch)t(this,e)}runReloadHandlers(e){for(let t of this.eventsHandlers.reload)t(this,e)}};function V(i,e,t,r){return`
+(()=>{var K=Object.defineProperty;var D=Object.getOwnPropertySymbols;var Q=Object.prototype.hasOwnProperty,V=Object.prototype.propertyIsEnumerable;var M=(i,e,t)=>e in i?K(i,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):i[e]=t,b=(i,e)=>{for(var t in e||(e={}))Q.call(e,t)&&M(i,t,e[t]);if(D)for(var t of D(e))V.call(e,t)&&M(i,t,e[t]);return i};var C=(i,e,t)=>new Promise((r,s)=>{var n=o=>{try{c(t.next(o))}catch(u){s(u)}},a=o=>{try{c(t.throw(o))}catch(u){s(u)}},c=o=>o.done?r(o.value):Promise.resolve(o.value).then(n,a);c((t=t.apply(i,e)).next())});var v,S,N;function X(){v.dataset.navState="displayed",v.classList.remove("state-off"),v.classList.add("state-on"),S.classList.add("a-show")}function R(){v.dataset.navState="hidden",v.classList.remove("state-on"),v.classList.add("state-off"),S.classList.add("a-hide"),S.classList.remove("a-show"),setTimeout(()=>{S.classList.remove("a-hide")},300)}function q(){console.log("HUD init"),v=document.querySelector(".hud .nav-toggle"),S=document.querySelector(".hud .navigation"),N=document.querySelector(".hud .reload-screen"),v.addEventListener("click",i=>{i.currentTarget.dataset.navState!="displayed"?X():R()}),N.addEventListener("click",i=>{Screens.reload()})}var w=class{constructor(e,t,r){this.screens={},this.routesMap={},this.currentScreen=null,this.eventsHandlers={switch:[],reload:[]},this.screensContainer=document.querySelector(e),this.loader=document.querySelector(t),this.errorScreen=document.querySelector(r),console.log("Screens Init")}add(e,t){if(typeof t!="object")return console.error("Screens: screens must be object");if(typeof(t==null?void 0:t.alias)=="undefined")return console.error("Screens: undefined alias");if(typeof(t==null?void 0:t.renderer)!="function")return console.error("Screens: renderer must be function");this.screens[t.alias]=b({route:e},t),this.routesMap[e]=t.alias}switch(e){var r;if(this.runSwitchHandlers(e),this.hideErrorScreen(),this.showLoader(),(r=this.currentScreen)==null||r.DOMObject.remove(),typeof this.screens[e]=="undefined"){console.error(`Screens: "${e}" not found`);return}this.currentScreen=this.screens[e];let t=document.createElement("div");t.classList.add("screen"),t.id=e,t.dataset.alias=e,t.innerHTML=this.currentScreen.renderer(),this.currentScreen.DOMObject=t,this.screensContainer.append(this.currentScreen.DOMObject),this.currentScreen.initer(this)}reload(){this.currentScreen&&(this.runReloadHandlers(this.currentScreen.alias),this.switch(this.currentScreen.alias))}routing(){setInterval(()=>{let e=document.location.hash.split("#!")[1];if(typeof e=="undefined"||e=="")return;let t=typeof this.routesMap[e]=="undefined"?"not-found-screen":this.routesMap[e];(!this.currentScreen||this.currentScreen.alias!=t)&&this.switch(t)},50)}ready(){this.currentScreen!=null&&(this.currentScreen.DOMObject||(this.currentScreen.DOMObject=document.getElementsById(this.currentScreen.alias)),this.hideLoader(),this.currentScreen.DOMObject.classList.add("a-show"))}error(e,t){var r;(r=this.currentScreen)==null||r.DOMObject.remove(),this.errorScreen.querySelector(".error-title").innerHTML=e,this.errorScreen.querySelector(".error-text").innerHTML=t,this.showErrorScreen()}hideLoader(){this.loader.classList.remove("a-show")}showLoader(){this.loader.classList.add("a-show")}showErrorScreen(){this.errorScreen.classList.add("a-show")}hideErrorScreen(){this.errorScreen.classList.remove("a-show")}getScreens(){return this.screens}getRoutesMap(){return this.routesMap}onSwitch(e){this.eventsHandlers.switch.push(e)}onReaload(e){this.eventsHandlers.reload.push(e)}runSwitchHandlers(e){for(let t of this.eventsHandlers.switch)t(this,e)}runReloadHandlers(e){for(let t of this.eventsHandlers.reload)t(this,e)}};function Z(i,e,t,r){return`
${e} ${t}
@@ -6,7 +6,7 @@
\u2715
- `}function X(i,e){if(e!=null&&e.alone&&document.querySelectorAll(".toast").forEach(t=>t.close()),i.close=function(){this.classList.add("a-hide"),setTimeout(()=>{this.remove()},300)},i.querySelector(".toast-close").addEventListener("click",t=>{i.close()}),i.show=function(){document.querySelector("body").append(i),setTimeout(()=>{i.classList.add("a-show")},10)},Screens.onSwitch((t,r)=>{setTimeout(()=>{i==null||i.close()},1e4)}),i.addEventListener("mouseover",t=>i.ishovered=!0),i.addEventListener("mouseout",t=>i.ishovered=!1),e!=null&&e.lifetime){console.log(e);let t=setInterval(()=>{i.ishovered||(i.close(),clearInterval(t))},e==null?void 0:e.lifetime)}return i}function y(i,e,t,r,s){let n=document.createElement("div");return n.innerHTML=V(i,e,t,r),X(n.childNodes[1],s)}function Z(i,e,t){return typeof t=="undefined"&&(t={}),typeof t.lifetime=="undefined"&&(t.lifetime=4e3),typeof t.alone=="undefined"&&(t.alone=!0),y("success",' ',i,e,t)}function ee(i,e,t){return y("info",' ',i,e,t)}function te(i,e,t){return y("warning",' ',i,e,t)}function q(i,e,t){return y("danger",' ',i,e,t)}var x={create:y,createInfo:ee,createSuccess:Z,createWarning:te,createError:q,createDanger:q};function ie(i){let e="";for(let t of i){let r="",s="";t.route&&(r=``,s=" "),e+=`
+ `}function ee(i,e){if(e!=null&&e.alone&&document.querySelectorAll(".toast").forEach(t=>t.close()),i.close=function(){this.classList.add("a-hide"),setTimeout(()=>{this.remove()},300)},i.querySelector(".toast-close").addEventListener("click",t=>{i.close()}),i.show=function(){document.querySelector("body").append(i),setTimeout(()=>{i.classList.add("a-show")},10)},Screens.onSwitch((t,r)=>{setTimeout(()=>{i==null||i.close()},1e4)}),i.addEventListener("mouseover",t=>i.ishovered=!0),i.addEventListener("mouseout",t=>i.ishovered=!1),e!=null&&e.lifetime){console.log(e);let t=setInterval(()=>{i.ishovered||(i.close(),clearInterval(t))},e==null?void 0:e.lifetime)}return i}function y(i,e,t,r,s){let n=document.createElement("div");return n.innerHTML=Z(i,e,t,r),ee(n.childNodes[1],s)}function te(i,e,t){return typeof t=="undefined"&&(t={}),typeof t.lifetime=="undefined"&&(t.lifetime=4e3),typeof t.alone=="undefined"&&(t.alone=!0),y("success",' ',i,e,t)}function ie(i,e,t){return y("info",' ',i,e,t)}function re(i,e,t){return y("warning",' ',i,e,t)}function x(i,e,t){return y("danger",' ',i,e,t)}var U={create:y,createInfo:ie,createSuccess:te,createWarning:re,createError:x,createDanger:x};function se(i){let e="";for(let t of i){let r="",s="";t.route&&(r=``,s=" "),e+=`
${r}${t.content}${s}
@@ -16,7 +16,7 @@
${e}
- `}function re(i,e,t,r){let s='',n=0;for(let o in e)s+=`${e[o]} `,n++;s+=" ";let a="";for(let o of t){a+='';for(let u in e)a+=`${o[u]} `;a+=" "}let c="";return typeof r!="undefined"&&(c=`
+ `}function ne(i,e,t,r){let s='',n=0;for(let o in e)s+=`${e[o]} `,n++;s+=" ";let a="";for(let o of t){a+='';for(let u in e)a+=`${o[u]} `;a+=" "}let c="";return typeof r!="undefined"&&(c=`
${a}
${c}
- `}function U(i,e,t){let r=document.createElement(i);for(let[s,n]of Object.entries(e))s==="class"?r.className=n:s==="dataset"?Object.assign(r.dataset,n):r.setAttribute(s,n);return r.innerHTML=typeof t!="undefined"?t:"",r}function se(i,e){return["primary","success","secondary","info","warning","error","danger"].indexOf(i)<0?console.error("createAlert()","Error of type: "+i):U("div",{class:`alert alert-${i}`},e)}function ne(i){let e={device_name:"name",device_hard_id:"device_id",device_ip:"ip",device_type:"type",ip_address:"ip",mac_address:"mac",device_mac:"mac",core_version:"firmware_core_version"},t={};for(let r in i){if(typeof e[r]!="undefined"){t[e[r]]=i[r];continue}t[r]=i[r]}return t}function ae(i,e){if((i==null?void 0:i.isLoading)==e)return!1;if(e)i.isLoading=!0,i.originalContent=i.innerHTML,i.classList.contains("with-icon")?i.originalWithIcon=!0:i.classList.add("with-icon"),i.classList.add("loading-state"),i.setAttribute("disabled","disabled"),i.innerHTML=' Loading';else{if(i.isLoading=!1,!i.originalContent)return!1;i.removeAttribute("disabled"),i.classList.remove("loading-state"),i.originalWithIcon||i.classList.remove("with-icon"),i.innerHTML=i.originalContent}return i}var j={template:{sidebarNav:ie,table:re,createElement:U,createAlert:se},unification:{deviceFieldsUnification:ne},states:{btnLoadingState:ae}};var $=class{constructor(e){this.core=e}actions_list(e){return this.core.api_get("/api/v1/scripts/actions/list",e)}scopes_list(e){return this.core.api_get("/api/v1/scripts/scopes/list",e)}regular_list(e){return this.core.api_get("/api/v1/scripts/regular/list",e)}scope_get_by_filename(e,t){let r=encodeURIComponent(String(e||""));return this.core.api_get(`/api/v1/scripts/scopes/name/${r}`,t,{})}scope_create(e,t){return this.core.api_post("/api/v1/scripts/scopes/new",e,t)}scope_update(e,t){return this.core.api_post("/api/v1/scripts/scopes/update",e,t)}action_enable(e,t){let r=encodeURIComponent(String(e||""));return this.core.api_get(`/api/v1/scripts/actions/alias/${r}/enable`,t)}action_disable(e,t){let r=encodeURIComponent(String(e||""));return this.core.api_get(`/api/v1/scripts/actions/alias/${r}/disable`,t)}regular_enable(e,t){let r=encodeURIComponent(String(e||""));return this.core.api_get(`/api/v1/scripts/actions/regular/${r}/enable`,t)}regular_disable(e,t){let r=encodeURIComponent(String(e||""));return this.core.api_get(`/api/v1/scripts/actions/regular/${r}/disable`,t)}scope_enable(e,t){let r=encodeURIComponent(String(e||""));return this.core.api_get(`/api/v1/scripts/actions/scope/${r}/enable`,t)}scope_disable(e,t){let r=encodeURIComponent(String(e||""));return this.core.api_get(`/api/v1/scripts/actions/scope/${r}/disable`,t)}scope_remove(e,t){let r=encodeURIComponent(String(e||""));return this.core.api_get(`/api/v1/scripts/scopes/name/${r}/remove`,t)}run(e,t){return this.core.api_post("/api/v1/scripts/actions/run",e,t)}};var L=class{constructor(e){this.core=e}list(e){return this.core.api_get("/api/v1/devices/list",e)}scanning_setup(e){return this.core.api_get("/api/v1/devices/scanning/setup",e)}scanning_all(e){return this.core.api_get("/api/v1/devices/scanning/all",e)}setup_new_device(e,t){return this.core.api_post("/api/v1/devices/setup/new-device",e,t)}info(e,t){let r=encodeURIComponent(String(e));return this.core.api_get(`/api/v1/devices/id/${r}/info`,t)}get(e,t){let r=encodeURIComponent(String(e));return this.core.api_get(`/api/v1/devices/id/${r}`,t)}status(e,t){let r=encodeURIComponent(String(e));return this.core.api_get(`/api/v1/devices/id/${r}/status`,t)}action(e,t){return this.core.api_post("/api/v1/devices/action",e,t)}remove(e,t){let r=encodeURIComponent(String(e));return this.core.api_get(`/api/v1/devices/id/${r}/remove`,t)}reboot(e,t){let r=encodeURIComponent(String(e));return this.core.api_get(`/api/v1/devices/id/${r}/reboot`,t)}};var E=class{constructor(e){this.core=e}list(e){return this.core.api_get("/api/v1/areas/list",e)}inner_list(e,t){let r=encodeURIComponent(String(e));return this.core.api_get(`/api/v1/areas/id/${r}/list`,t)}new_area(e,t){return this.core.api_post("/api/v1/areas/new-area",e,t)}remove(e,t){let r=encodeURIComponent(String(e));return this.core.api_get(`/api/v1/areas/id/${r}/remove`,t)}place_in_area(e,t){return this.core.api_post("/api/v1/areas/place-in-area",e,t)}update_display_name(e,t){return this.core.api_post("/api/v1/areas/update-display-name",e,t)}update_alias(e,t){return this.core.api_post("/api/v1/areas/update-alias",e,t)}devices(e,t){let r=encodeURIComponent(String(e));return this.core.api_get(`/api/v1/areas/id/${r}/devices`,t)}unassign_from_area(e,t){let r=encodeURIComponent(String(e));return this.core.api_get(`/api/v1/areas/id/${r}/unassign-from-area`,t)}types_list(e){return this.core.api_get("/api/v1/areas/types/list",e)}reboot_devices(e,t){if(e==null)return this.core.api_get("/api/v1/areas/reboot_devices",t);let r=encodeURIComponent(String(e));return this.core.api_get(`/api/v1/areas/id/${r}/reboot_devices`,t)}};function P(i){if(!i||typeof i!="object")return"";let e=new URLSearchParams;Object.entries(i).forEach(([r,s])=>{s!=null&&e.append(r,String(s))});let t=e.toString();return t?`?${t}`:""}function oe(i,e){let t=String(i||"").replace(/\/+$/,""),r=String(e||"").replace(/^\/+/,"");return`${t}/${r}`}function ce(i){try{return{ok:!0,data:JSON.parse(i)}}catch(e){return{ok:!1,error:e}}}var T=class{constructor(e){this.base_url=(e==null?void 0:e.base_url)||"",this.token=(e==null?void 0:e.token)||"",this.timeout_ms=Number.isFinite(e==null?void 0:e.timeout_ms)?e.timeout_ms:15e3,this.default_headers=(e==null?void 0:e.default_headers)||{},this.on_unauthorized=typeof(e==null?void 0:e.on_unauthorized)=="function"?e.on_unauthorized:null,this.proxy_path=(e==null?void 0:e.proxy_path)||"",this.scripts=new $(this),this.devices=new L(this),this.areas=new E(this)}set_base_url(e){this.base_url=e||""}set_token(e){this.token=e||""}set_proxy_path(e){this.proxy_path=e||""}_wrap_path(e,t){if(!this.proxy_path)return t?`${e}${P(t)}`:e;let r=b({path:e},t||{});return`${this.proxy_path}${P(r)}`}request(e,t,r,s,n){let a=typeof s=="function"?s:()=>{},c=oe(this.base_url,t),o=new AbortController,u=Number.isFinite(n==null?void 0:n.timeout_ms)?n.timeout_ms:this.timeout_ms,d=setTimeout(()=>o.abort(),u),h=b(b({},this.default_headers),(n==null?void 0:n.headers)||{});this.token&&(h.Authorization=`Bearer ${this.token}`);let g;r!=null&&(h["Content-Type"]="application/json",g=JSON.stringify(r)),fetch(c,{method:e,headers:h,body:g,signal:o.signal}).then(l=>M(this,null,function*(){clearTimeout(d);let f={url:c,method:e,status_code:l.status,headers:l.headers},p=yield l.text(),H=ce(p),v=H.ok?H.data:p;if(!l.ok){let _={type:"http_error",message:`HTTP ${l.status}`,status_code:l.status,raw:v};if((l.status===401||l.status===403)&&this.on_unauthorized)try{this.on_unauthorized({error:_,meta:f})}catch(k){}return a(_,null,f)}if(H.ok&&v&&typeof v=="object"){let _=v.status;if(_===!1||_==="error"){let k={type:"api_error",message:v.message||"API error",status_code:l.status,raw:v,field:v.field};return a(k,null,f)}}return a(null,v,f)})).catch(l=>{clearTimeout(d);let p=l&&(l.name==="AbortError"||String(l).includes("AbortError"))?{type:"timeout",message:`Timeout after ${u}ms`}:{type:"network_error",message:(l==null?void 0:l.message)||"Network error",details:l};return a(p,null,{url:c,method:e,status_code:0,headers:null})})}get(e,t,r){return this.request("GET",e,null,t,r)}post(e,t,r,s){return this.request("POST",e,t,r,s)}api_get(e,t,r,s){return this.get(this._wrap_path(e,r),t,s)}api_post(e,t,r,s,n){return this.post(this._wrap_path(e,s),t,r,n)}};function F(i,e){return console.log(i),Modals.create("device-popup",{title:`Device ${i.name}`,body:t=>{let r="";for(let s in i)r+=`
+ `}function j(i,e,t){let r=document.createElement(i);for(let[s,n]of Object.entries(e))s==="class"?r.className=n:s==="dataset"?Object.assign(r.dataset,n):r.setAttribute(s,n);return r.innerHTML=typeof t!="undefined"?t:"",r}function ae(i,e){return["primary","success","secondary","info","warning","error","danger"].indexOf(i)<0?console.error("createAlert()","Error of type: "+i):j("div",{class:`alert alert-${i}`},e)}function oe(i){let e={device_name:"name",device_hard_id:"device_id",device_ip:"ip",device_type:"type",ip_address:"ip",mac_address:"mac",device_mac:"mac",core_version:"firmware_core_version"},t={};for(let r in i){if(typeof e[r]!="undefined"){t[e[r]]=i[r];continue}t[r]=i[r]}return t}function ce(i,e){if((i==null?void 0:i.isLoading)==e)return!1;if(e)i.isLoading=!0,i.originalContent=i.innerHTML,i.classList.contains("with-icon")?i.originalWithIcon=!0:i.classList.add("with-icon"),i.classList.add("loading-state"),i.setAttribute("disabled","disabled"),i.innerHTML=' Loading';else{if(i.isLoading=!1,!i.originalContent)return!1;i.removeAttribute("disabled"),i.classList.remove("loading-state"),i.originalWithIcon||i.classList.remove("with-icon"),i.innerHTML=i.originalContent}return i}var P={template:{sidebarNav:se,table:ne,createElement:j,createAlert:ae},unification:{deviceFieldsUnification:oe},states:{btnLoadingState:ce}};var $=class{constructor(e){this.core=e}actions_list(e){return this.core.api_get("/api/v1/scripts/actions/list",e)}scopes_list(e){return this.core.api_get("/api/v1/scripts/scopes/list",e)}regular_list(e){return this.core.api_get("/api/v1/scripts/regular/list",e)}scope_get_by_filename(e,t){let r=encodeURIComponent(String(e||""));return this.core.api_get(`/api/v1/scripts/scopes/name/${r}`,t,{})}scope_create(e,t){return this.core.api_post("/api/v1/scripts/scopes/new",e,t)}scope_update(e,t){return this.core.api_post("/api/v1/scripts/scopes/update",e,t)}action_enable(e,t){let r=encodeURIComponent(String(e||""));return this.core.api_get(`/api/v1/scripts/actions/alias/${r}/enable`,t)}action_disable(e,t){let r=encodeURIComponent(String(e||""));return this.core.api_get(`/api/v1/scripts/actions/alias/${r}/disable`,t)}regular_enable(e,t){let r=encodeURIComponent(String(e||""));return this.core.api_get(`/api/v1/scripts/actions/regular/${r}/enable`,t)}regular_disable(e,t){let r=encodeURIComponent(String(e||""));return this.core.api_get(`/api/v1/scripts/actions/regular/${r}/disable`,t)}scope_enable(e,t){let r=encodeURIComponent(String(e||""));return this.core.api_get(`/api/v1/scripts/actions/scope/${r}/enable`,t)}scope_disable(e,t){let r=encodeURIComponent(String(e||""));return this.core.api_get(`/api/v1/scripts/actions/scope/${r}/disable`,t)}scope_remove(e,t){let r=encodeURIComponent(String(e||""));return this.core.api_get(`/api/v1/scripts/scopes/name/${r}/remove`,t)}run(e,t){return this.core.api_post("/api/v1/scripts/actions/run",e,t)}};var L=class{constructor(e){this.core=e}list(e){return this.core.api_get("/api/v1/devices/list",e)}scanning_setup(e){return this.core.api_get("/api/v1/devices/scanning/setup",e)}scanning_all(e){return this.core.api_get("/api/v1/devices/scanning/all",e)}setup_new_device(e,t){return this.core.api_post("/api/v1/devices/setup/new-device",e,t)}info(e,t){let r=encodeURIComponent(String(e));return this.core.api_get(`/api/v1/devices/id/${r}/info`,t)}get(e,t){let r=encodeURIComponent(String(e));return this.core.api_get(`/api/v1/devices/id/${r}`,t)}status(e,t){let r=encodeURIComponent(String(e));return this.core.api_get(`/api/v1/devices/id/${r}/status`,t)}action(e,t){return this.core.api_post("/api/v1/devices/action",e,t)}remove(e,t){let r=encodeURIComponent(String(e));return this.core.api_get(`/api/v1/devices/id/${r}/remove`,t)}reboot(e,t){let r=encodeURIComponent(String(e));return this.core.api_get(`/api/v1/devices/id/${r}/reboot`,t)}};var T=class{constructor(e){this.core=e}list(e){return this.core.api_get("/api/v1/areas/list",e)}inner_list(e,t){let r=encodeURIComponent(String(e));return this.core.api_get(`/api/v1/areas/id/${r}/list`,t)}new_area(e,t){return this.core.api_post("/api/v1/areas/new-area",e,t)}remove(e,t){let r=encodeURIComponent(String(e));return this.core.api_get(`/api/v1/areas/id/${r}/remove`,t)}place_in_area(e,t){return this.core.api_post("/api/v1/areas/place-in-area",e,t)}update_display_name(e,t){return this.core.api_post("/api/v1/areas/update-display-name",e,t)}update_alias(e,t){return this.core.api_post("/api/v1/areas/update-alias",e,t)}devices(e,t){let r=encodeURIComponent(String(e));return this.core.api_get(`/api/v1/areas/id/${r}/devices`,t)}unassign_from_area(e,t){let r=encodeURIComponent(String(e));return this.core.api_get(`/api/v1/areas/id/${r}/unassign-from-area`,t)}types_list(e){return this.core.api_get("/api/v1/areas/types/list",e)}reboot_devices(e,t){if(e==null)return this.core.api_get("/api/v1/areas/reboot_devices",t);let r=encodeURIComponent(String(e));return this.core.api_get(`/api/v1/areas/id/${r}/reboot_devices`,t)}};function F(i){if(!i||typeof i!="object")return"";let e=new URLSearchParams;Object.entries(i).forEach(([r,s])=>{s!=null&&e.append(r,String(s))});let t=e.toString();return t?`?${t}`:""}function le(i,e){let t=String(i||"").replace(/\/+$/,""),r=String(e||"").replace(/^\/+/,"");return`${t}/${r}`}function de(i){try{return{ok:!0,data:JSON.parse(i)}}catch(e){return{ok:!1,error:e}}}var E=class{constructor(e){this.base_url=(e==null?void 0:e.base_url)||"",this.token=(e==null?void 0:e.token)||"",this.timeout_ms=Number.isFinite(e==null?void 0:e.timeout_ms)?e.timeout_ms:15e3,this.default_headers=(e==null?void 0:e.default_headers)||{},this.on_unauthorized=typeof(e==null?void 0:e.on_unauthorized)=="function"?e.on_unauthorized:null,this.proxy_path=(e==null?void 0:e.proxy_path)||"",this.scripts=new $(this),this.devices=new L(this),this.areas=new T(this)}set_base_url(e){this.base_url=e||""}set_token(e){this.token=e||""}set_proxy_path(e){this.proxy_path=e||""}_wrap_path(e,t){if(!this.proxy_path)return t?`${e}${F(t)}`:e;let r=b({path:e},t||{});return`${this.proxy_path}${F(r)}`}request(e,t,r,s,n){let a=typeof s=="function"?s:()=>{},c=le(this.base_url,t),o=new AbortController,u=Number.isFinite(n==null?void 0:n.timeout_ms)?n.timeout_ms:this.timeout_ms,d=setTimeout(()=>o.abort(),u),h=b(b({},this.default_headers),(n==null?void 0:n.headers)||{});this.token&&(h.Authorization=`Bearer ${this.token}`);let g;r!=null&&(h["Content-Type"]="application/json",g=JSON.stringify(r)),fetch(c,{method:e,headers:h,body:g,signal:o.signal}).then(l=>C(this,null,function*(){clearTimeout(d);let f={url:c,method:e,status_code:l.status,headers:l.headers},p=yield l.text(),O=de(p),m=O.ok?O.data:p;if(!l.ok){let _={type:"http_error",message:`HTTP ${l.status}`,status_code:l.status,raw:m};if((l.status===401||l.status===403)&&this.on_unauthorized)try{this.on_unauthorized({error:_,meta:f})}catch(A){}return a(_,null,f)}if(O.ok&&m&&typeof m=="object"){let _=m.status;if(_===!1||_==="error"){let A={type:"api_error",message:m.message||"API error",status_code:l.status,raw:m,field:m.field};return a(A,null,f)}}return a(null,m,f)})).catch(l=>{clearTimeout(d);let p=l&&(l.name==="AbortError"||String(l).includes("AbortError"))?{type:"timeout",message:`Timeout after ${u}ms`}:{type:"network_error",message:(l==null?void 0:l.message)||"Network error",details:l};return a(p,null,{url:c,method:e,status_code:0,headers:null})})}get(e,t,r){return this.request("GET",e,null,t,r)}post(e,t,r,s){return this.request("POST",e,t,r,s)}api_get(e,t,r,s){return this.get(this._wrap_path(e,r),t,s)}api_post(e,t,r,s,n){return this.post(this._wrap_path(e,s),t,r,n)}};function H(i){return Helper.template.sidebarNav([{content:' Devices ',route:"/#!/devices",is_active:i=="devices"},{content:' Scanning ',route:"/#!/devices/scanning",is_active:i=="scanning"}])}function z(i,e){return console.log(i),Modals.create("device-popup",{title:`Device ${i.name}`,body:t=>{let r="";for(let s in i)r+=`
${s}:
${i[s]}
@@ -50,7 +50,32 @@
Device: ${i.name}
Alias: ${i.alias}
IP: ${i.ip}
- `).show()},300)})},()=>{Helper.states.btnLoadingState(n,!1),console.log("CANCELED")}))}),[r,s,n]}})}function z(i,e){return i=Helper.unification.deviceFieldsUnification(i),Modals.create("device-setup",{title:`Setup new device ${i.ip}`,body:t=>{let r="";for(let n in i)n[0]!="_"&&(r+=`
+ `).show()},300)})},()=>{Helper.states.btnLoadingState(n,!1),console.log("CANCELED")}))}),[r,s,n]}})}function J(i){return{alias:"devices",renderer:()=>`
+
+ `,initer:e=>{i.devices.list((t,r,s)=>{if(console.log("sh_api.devices.list",t,r,s),s.status_code!=200)return e.error("Server API ERROR","");let n=[];for(let a of r.data.devices){a=Helper.unification.deviceFieldsUnification(a);let c=a.connection_state=="active"?'Online ':'Offline ';n.push({deviceName:a.name,alias:a.alias,status:c,ip:`${a.ip}`,actions:`
+ Details
+
+ Reboot
+ `})}e.currentScreen.DOMObject.querySelector(".devices-container").innerHTML=Helper.template.table("Devices list",{deviceName:"Device name",alias:"Device alias",status:"Status",ip:"IP",actions:"Actions"},n,`Total: ${r.data.total} devices `),e.currentScreen.DOMObject.querySelectorAll(".reboot-btn").forEach(a=>{a.addEventListener("click",c=>{if(c.currentTarget.getAttribute("disabled"))return;let o=c.currentTarget;Helper.states.btnLoadingState(o,!0);let u=c.currentTarget.dataset.deviceId,d=c.currentTarget.dataset.deviceName,h=c.currentTarget.dataset.deviceAlias;i.devices.reboot(u,(g,l,f)=>{Helper.states.btnLoadingState(o,!1),console.log("Reboot done",g,l,f),l?Toasts.createSuccess("Reboot successful",`Device: ${d}
+ Alias: ${h} `).show():Toasts.createError("Reboot failed",`Device: ${d}
+ Alias: ${h} `).show()})})}),e.currentScreen.DOMObject.querySelectorAll(".details-btn").forEach(a=>{a.addEventListener("click",c=>{let o=JSON.parse(c.currentTarget.dataset.device);z(o,i).show()})}),e.ready()})}}}function B(i,e){return i=Helper.unification.deviceFieldsUnification(i),Modals.create("device-setup",{title:`Setup new device ${i.ip}`,body:t=>{let r="";for(let n in i)n[0]!="_"&&(r+=`
${n}:
${i[n]}
@@ -97,36 +122,11 @@
- `},actions:t=>{let r=Helper.template.createElement("button",{class:"btn btn-primary"},"Cancel");r.addEventListener("click",n=>{t.close()});let s=Helper.template.createElement("button",{class:"btn btn-success with-icon"},' Setup');return s.addEventListener("click",n=>{if(n.currentTarget.getAttribute("disabled"))return!1;let a={device_ip:i.ip},c=document.querySelector("#device-setup .setup-form");if(c.querySelectorAll("input[type='text']").forEach(d=>{d.dispatchEvent(new Event("input",{bubbles:!0}))}),c.querySelectorAll(".label.error").length)return!1;let o=c.querySelectorAll("input"),u=c.querySelector("textarea");for(let d of o)a[d.getAttribute("name")]=d.value;a[u.getAttribute("name")]=u.value,Helper.states.btnLoadingState(s,!0),e.devices.setup_new_device(a,(d,h,g)=>{var l,f;if(Helper.states.btnLoadingState(s,!1),(d==null?void 0:d.type)=="api_error"){if(console.error("ERR! sh_api.devices.setup_new_device",d.raw),(l=d.raw)!=null&&l.failed_fields)for(let p of d.raw.failed_fields)t.querySelector(`[name="${p}"]`).parentNode.classList.add("error");if((f=d.raw)!=null&&f.msg){let p=t.querySelector(".setup-form .alert-container");p.innerHTML="",p==null||p.append(Helper.template.createAlert("error",d.raw.msg))}return!1}if(!h)return!1;o.forEach(p=>p.value=""),u.value="",t.close(),setTimeout(()=>{Toasts.createSuccess("Setup successful",`Added new device ID ${i.device_id} `).show()},300)})}),[r,s]},onready:t=>{t.querySelector(".setup-form").querySelectorAll("input").forEach(s=>{s.addEventListener("input",n=>{var a;n.currentTarget.value.length?(n.currentTarget.parentNode.classList.remove("error"),(a=n.currentTarget.parentNode.parentNode.querySelector(".input-info.error"))==null||a.remove()):(n.currentTarget.parentNode.classList.add("error"),n.currentTarget.parentNode.parentNode.querySelector(".input-info.error")||n.currentTarget.parentNode.parentNode.append(Helper.template.createElement("div",{class:"input-info error"},' Field cannot be empty')))})})}})}function J(i){return Helper.template.sidebarNav([{content:' Devices ',route:"/#!/devices",is_active:i=="devices"},{content:' Scanning ',route:"/#!/devices/scanning",is_active:i=="scanning"}])}function le(i){return{alias:"devices",renderer:()=>`
+ `},actions:t=>{let r=Helper.template.createElement("button",{class:"btn btn-primary"},"Cancel");r.addEventListener("click",n=>{t.close()});let s=Helper.template.createElement("button",{class:"btn btn-success with-icon"},' Setup');return s.addEventListener("click",n=>{if(n.currentTarget.getAttribute("disabled"))return!1;let a={device_ip:i.ip},c=document.querySelector("#device-setup .setup-form");if(c.querySelectorAll("input[type='text']").forEach(d=>{d.dispatchEvent(new Event("input",{bubbles:!0}))}),c.querySelectorAll(".label.error").length)return!1;let o=c.querySelectorAll("input"),u=c.querySelector("textarea");for(let d of o)a[d.getAttribute("name")]=d.value;a[u.getAttribute("name")]=u.value,Helper.states.btnLoadingState(s,!0),e.devices.setup_new_device(a,(d,h,g)=>{var l,f;if(Helper.states.btnLoadingState(s,!1),(d==null?void 0:d.type)=="api_error"){if(console.error("ERR! sh_api.devices.setup_new_device",d.raw),(l=d.raw)!=null&&l.failed_fields)for(let p of d.raw.failed_fields)t.querySelector(`[name="${p}"]`).parentNode.classList.add("error");if((f=d.raw)!=null&&f.msg){let p=t.querySelector(".setup-form .alert-container");p.innerHTML="",p==null||p.append(Helper.template.createAlert("error",d.raw.msg))}return!1}if(!h)return!1;o.forEach(p=>p.value=""),u.value="",t.close(),setTimeout(()=>{Toasts.createSuccess("Setup successful",`Added new device ID ${i.device_id} `).show()},300)})}),[r,s]},onready:t=>{t.querySelector(".setup-form").querySelectorAll("input").forEach(s=>{s.addEventListener("input",n=>{var a;n.currentTarget.value.length?(n.currentTarget.parentNode.classList.remove("error"),(a=n.currentTarget.parentNode.parentNode.querySelector(".input-info.error"))==null||a.remove()):(n.currentTarget.parentNode.classList.add("error"),n.currentTarget.parentNode.parentNode.querySelector(".input-info.error")||n.currentTarget.parentNode.parentNode.append(Helper.template.createElement("div",{class:"input-info error"},' Field cannot be empty')))})})}})}function W(i){return{alias:"devices-scanning",renderer:()=>`
- `,initer:e=>{i.devices.list((t,r,s)=>{if(console.log("sh_api.devices.list",t,r,s),s.status_code!=200)return e.error("Server API ERROR","");let n=[];for(let a of r.data.devices){a=Helper.unification.deviceFieldsUnification(a);let c=a.connection_state=="active"?'Online ':'Offline ';n.push({deviceName:a.name,alias:a.alias,status:c,ip:`${a.ip}`,actions:`
- Details
-
- Reboot
- `})}e.currentScreen.DOMObject.querySelector(".devices-container").innerHTML=Helper.template.table("Devices list",{deviceName:"Device name",alias:"Device alias",status:"Status",ip:"IP",actions:"Actions"},n,`Total: ${r.data.total} devices `),e.currentScreen.DOMObject.querySelectorAll(".reboot-btn").forEach(a=>{a.addEventListener("click",c=>{if(c.currentTarget.getAttribute("disabled"))return;let o=c.currentTarget;Helper.states.btnLoadingState(o,!0);let u=c.currentTarget.dataset.deviceId,d=c.currentTarget.dataset.deviceName,h=c.currentTarget.dataset.deviceAlias;i.devices.reboot(u,(g,l,f)=>{Helper.states.btnLoadingState(o,!1),console.log("Reboot done",g,l,f),l?Toasts.createSuccess("Reboot successful",`Device: ${d}
- Alias: ${h} `).show():Toasts.createError("Reboot failed",`Device: ${d}
- Alias: ${h} `).show()})})}),e.currentScreen.DOMObject.querySelectorAll(".details-btn").forEach(a=>{a.addEventListener("click",c=>{let o=JSON.parse(c.currentTarget.dataset.device);F(o,i).show()})}),e.ready()})}}}function de(i){return{alias:"devices-scanning",renderer:()=>`
-
-
@@ -137,7 +137,7 @@
data-device='${JSON.stringify(a)}'
type="button"
>Setup
- `:""});e.currentScreen.DOMObject.querySelector(".devices-container").innerHTML=Helper.template.table("Found devices",{deviceId:"Device ID",deviceName:"Device name",deviceType:"Type",status:"Status",ip:"IP",mac:"Mac",wifiSignal:"Signal",actions:"Actions"},n,`
Total: ${r.data.devices.length} devices `),e.currentScreen.DOMObject.querySelectorAll(".setup-btn").forEach(a=>{a.addEventListener("click",c=>{let o=JSON.parse(c.currentTarget.dataset.device);z(o,i).show()})}),e.ready()})}}}var R={list:le,scanning:de};function B(i,e){i.add("/",{alias:"home",renderer:()=>'
Hello world ',initer:t=>{setTimeout(()=>t.ready(),1e3),setTimeout(()=>t.error("Error","Just testing"),2e3)}}),i.add("-",{alias:"not-found-screen",renderer:()=>'
404 NOT FOUND ',initer:t=>{t.ready()}}),i.add("/devices",R.list(e)),i.add("/devices/scanning",R.scanning(e))}function ue(i,e,t){return`
+ `:""});e.currentScreen.DOMObject.querySelector(".devices-container").innerHTML=Helper.template.table("Found devices",{deviceId:"Device ID",deviceName:"Device name",deviceType:"Type",status:"Status",ip:"IP",mac:"Mac",wifiSignal:"Signal",actions:"Actions"},n,`
Total: ${r.data.devices.length} devices `),e.currentScreen.DOMObject.querySelectorAll(".setup-btn").forEach(a=>{a.addEventListener("click",c=>{let o=JSON.parse(c.currentTarget.dataset.device);B(o,i).show()})}),e.ready()})}}}var I={list:J,scanning:W};function Y(i,e){i.add("/",{alias:"home",renderer:()=>'
Hello world ',initer:t=>{setTimeout(()=>t.ready(),1e3),setTimeout(()=>t.error("Error","Just testing"),2e3)}}),i.add("-",{alias:"not-found-screen",renderer:()=>'
404 NOT FOUND ',initer:t=>{t.ready()}}),i.add("/devices",I.list(e)),i.add("/devices/scanning",I.scanning(e))}function ue(i,e,t){return`
- `}function pe(i,e){return i.show=function(){document.querySelector("body").append(i),setTimeout(()=>{this.classList.add("a-show")},10)},i.close=function(){this.classList.add("a-hide"),setTimeout(()=>{this.remove()},300)},i.querySelector(".modal-close").addEventListener("click",t=>{i.close()}),typeof e=="function"&&e(i),i}function fe(i,e){let t=e.title||"",r=e.footer||"",s=document.createElement("div");s.innerHTML=ue(i,t,r);let n=s.childNodes[1],a=n.querySelector(".modal-body"),c=n.querySelector(".modal-footer");if(typeof e.actions=="function"){let o=e.actions(n);if(typeof o[0]=="object"){let u=document.createElement("div");u.classList.add("actions");for(let d of o)u.append(d);c.append(u)}}if(typeof e.body=="function"){let o=e.body(n);typeof o=="object"?a.append(o):typeof o=="string"&&(a.innerHTML=o)}return pe(n,e==null?void 0:e.onready)}var W={create:fe};function I(i,e,t){Modals.create("confirm-popup",{title:"Requires confirmation",body:r=>`
+ `}function pe(i,e){return i.show=function(){document.querySelector("body").append(i),setTimeout(()=>{this.classList.add("a-show")},10)},i.close=function(){this.classList.add("a-hide"),setTimeout(()=>{this.remove()},300)},i.querySelector(".modal-close").addEventListener("click",t=>{i.close()}),typeof e=="function"&&e(i),i}function fe(i,e){let t=e.title||"",r=e.footer||"",s=document.createElement("div");s.innerHTML=ue(i,t,r);let n=s.childNodes[1],a=n.querySelector(".modal-body"),c=n.querySelector(".modal-footer");if(typeof e.actions=="function"){let o=e.actions(n);if(typeof o[0]=="object"){let u=document.createElement("div");u.classList.add("actions");for(let d of o)u.append(d);c.append(u)}}if(typeof e.body=="function"){let o=e.body(n);typeof o=="object"?a.append(o):typeof o=="string"&&(a.innerHTML=o)}return pe(n,e==null?void 0:e.onready)}var G={create:fe};function k(i,e,t){Modals.create("confirm-popup",{title:"Requires confirmation",body:r=>`
${i}
- `,actions:r=>{let s=Helper.template.createElement("button",{class:"btn btn-primary"},"NO"),n=Helper.template.createElement("button",{class:"btn btn-warning"},"YES");return s.addEventListener("click",a=>{r.close(),t()}),n.addEventListener("click",a=>{r.close(),e()}),[s,n]}}).show()}document.addEventListener("DOMContentLoaded",i=>{console.log("App init"),window.Toasts=x,window.Helper=j,window.Modals=W,window.confirmPopup=I,N();let e=new T({base_url:"http://shswebclient.local",token:"YOUR_TOKEN",timeout_ms:3e3,on_unauthorized:({error:r})=>console.log("auth problem:",r),proxy_path:"/proxy.php"}),t=new w(".screens",".load-screen",".error-screen");B(t,e),console.log(t.getScreens()),t.onSwitch((r,s)=>{O()}),t.routing(),window.Screens=t});})();
+ `,actions:r=>{let s=Helper.template.createElement("button",{class:"btn btn-primary"},"NO"),n=Helper.template.createElement("button",{class:"btn btn-warning"},"YES");return s.addEventListener("click",a=>{r.close(),t()}),n.addEventListener("click",a=>{r.close(),e()}),[s,n]}}).show()}document.addEventListener("DOMContentLoaded",i=>{console.log("App init"),window.Toasts=U,window.Helper=P,window.Modals=G,window.confirmPopup=k,q();let e=new E({base_url:"http://shswebclient.local",token:"YOUR_TOKEN",timeout_ms:3e3,on_unauthorized:({error:r})=>console.log("auth problem:",r),proxy_path:"/proxy.php"}),t=new w(".screens",".load-screen",".error-screen");Y(t,e),console.log(t.getScreens()),t.onSwitch((r,s)=>{R()}),t.routing(),window.Screens=t});})();
//# sourceMappingURL=main.js.map
diff --git a/webclient/dist/js/main.js.map b/webclient/dist/js/main.js.map
index d701930..56f39c6 100644
--- a/webclient/dist/js/main.js.map
+++ b/webclient/dist/js/main.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
- "sources": ["../../src/js/components/hud.js", "../../src/js/components/Screens.js", "../../src/js/components/toasts.js", "../../src/js/components/helper.js", "../../src/js/sh/modules/ScriptsApi.js", "../../src/js/sh/modules/DevicesApi.js", "../../src/js/sh/modules/AreasApi.js", "../../src/js/sh/SmartHomeApi.js", "../../src/js/components/screens/devices/device-details-popup.js", "../../src/js/components/screens/devices/device-setup-form-popup.js", "../../src/js/components/screens/devices/devices.js", "../../src/js/routes.js", "../../src/js/components/modals.js", "../../src/js/components/confirm-popup.js", "../../src/js/index.js"],
- "sourcesContent": ["let navToggleBtn;\nlet navigation;\nlet reloadScreenBtn;\n\nfunction navigationShow() {\n\tnavToggleBtn.dataset.navState = \"displayed\";\n\tnavToggleBtn.classList.remove(\"state-off\");\n\tnavToggleBtn.classList.add(\"state-on\");\n\n\tnavigation.classList.add(\"a-show\");\n}\n\nfunction navigationHide() {\n\tnavToggleBtn.dataset.navState = \"hidden\";\n\tnavToggleBtn.classList.remove(\"state-on\");\n\tnavToggleBtn.classList.add(\"state-off\");\n\n\tnavigation.classList.add(\"a-hide\");\n\tnavigation.classList.remove(\"a-show\");\n\n\tsetTimeout(() => {\n\t\tnavigation.classList.remove(\"a-hide\");\n\t}, 300);\n}\n\nfunction hud() {\n\tconsole.log(\"HUD init\");\n\n\tnavToggleBtn = document.querySelector(\".hud .nav-toggle\");\n\tnavigation = document.querySelector(\".hud .navigation\");\n\treloadScreenBtn = document.querySelector(\".hud .reload-screen\");\n\n\tnavToggleBtn.addEventListener(\"click\", e => {\n\t\tif(e.currentTarget.dataset.navState != \"displayed\") {\n\t\t\tnavigationShow();\n\t\t} else {\n\t\t\tnavigationHide();\n\t\t}\n\t});\n\n\treloadScreenBtn.addEventListener(\"click\", e => {\n\t\tScreens.reload();\n\t});\n}\n\nexport {\n\thud,\n\tnavigationShow,\n\tnavigationHide\n}", "export class Screens {\n\tconstructor(screensContainerSelector, loaderSelector, errorScreenSelector) {\n\t\tthis.screens = {};\n\t\tthis.routesMap = {};\n\t\tthis.currentScreen = null;\n\t\tthis.eventsHandlers = {\n\t\t\tswitch: [],\n\t\t\treload: []\n\t\t};\n\n\t\tthis.screensContainer = document.querySelector(screensContainerSelector);\n\t\tthis.loader = document.querySelector(loaderSelector);\n\t\tthis.errorScreen = document.querySelector(errorScreenSelector);\n\t\tconsole.log(\"Screens Init\");\n\t}\n\n\t/**\n\t * \u0414\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043C\u0430\u0440\u0448\u0440\u0443\u0442\u0430 \u0438 \u043E\u0431\u044A\u0435\u043A\u0442\u0430 \u0441 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0430\u043C\u0438 \u044D\u043A\u0440\u0430\u043D\u0430\n\t * @param {string} route Like `/path/name`\n\t * @param {void} screen {alias, renderer, initer}\n\t */\n\tadd(route, screen) {\n\t\tif(typeof screen != \"object\") {\n\t\t\treturn console.error(\"Screens: screens must be object\");\n\t\t}\n\t\t\n\t\tif(typeof screen?.alias == \"undefined\") {\n\t\t\treturn console.error(\"Screens: undefined alias\");\n\t\t}\n\n\t\tif(typeof screen?.renderer != \"function\") {\n\t\t\treturn console.error(\"Screens: renderer must be function\");\n\t\t}\n\n\t\tthis.screens[screen.alias] = {\n\t\t\troute: route,\n\t\t\t...screen\n\t\t};\n\n\t\tthis.routesMap[route] = screen.alias;\n\t}\n\n\tswitch(alias) {\t\t\n\t\tthis.runSwitchHandlers(alias);\n\t\tthis.hideErrorScreen();\n\t\tthis.showLoader();\n\t\tthis.currentScreen?.DOMObject.remove();\n\t\t\n\t\tif(typeof this.screens[alias] == \"undefined\") {\n\t\t\tconsole.error(`Screens: \"${alias}\" not found`);\n\t\t\treturn ;\n\t\t}\n\n\t\tthis.currentScreen = this.screens[alias];\n\t\t\n\t\tconst screenContainer = document.createElement(\"div\");\n\t\tscreenContainer.classList.add(\"screen\");\n\t\tscreenContainer.id = alias;\n\t\tscreenContainer.dataset.alias = alias;\n\t\tscreenContainer.innerHTML = this.currentScreen.renderer();\n\t\tthis.currentScreen.DOMObject = screenContainer;\n\t\tthis.screensContainer.append(this.currentScreen.DOMObject);\n\n\t\tthis.currentScreen.initer(this);\n\t}\n\n\treload() {\n\t\tif(!this.currentScreen) {\n\t\t\treturn ;\n\t\t}\n\n\t\tthis.runReloadHandlers(this.currentScreen.alias);\n\t\tthis.switch(this.currentScreen.alias);\n\t}\n\n\trouting() {\n\t\tsetInterval(() => {\n\t\t\tconst route = document.location.hash.split(\"#!\")[1];\n\t\t\tif(typeof route == \"undefined\" || route == \"\") {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tconst alias = (typeof this.routesMap[route] == \"undefined\") \n\t\t\t\t? \"not-found-screen\"\n\t\t\t\t: this.routesMap[route];\n\n\t\t\tif(!this.currentScreen || this.currentScreen.alias != alias) {\n\t\t\t\tthis.switch(alias);\n\t\t\t}\n\t\t}, 50);\n\t}\n\n\tready() {\n\t\tif(this.currentScreen == null) {\n\t\t\treturn;\n\t\t}\n\n\t\tif(!this.currentScreen.DOMObject) {\n\t\t\tthis.currentScreen.DOMObject = document.getElementsById(this.currentScreen.alias);\n\t\t}\n\n\t\tthis.hideLoader();\n\t\tthis.currentScreen.DOMObject.classList.add(\"a-show\");\n\t}\n\n\terror(title, text) {\n\t\tthis.currentScreen?.DOMObject.remove();\n\t\tthis.errorScreen.querySelector(\".error-title\").innerHTML = title;\n\t\tthis.errorScreen.querySelector(\".error-text\").innerHTML = text;\n\t\tthis.showErrorScreen();\n\t}\n\n\thideLoader() {\n\t\tthis.loader.classList.remove(\"a-show\");\n\t}\n\n\tshowLoader() {\n\t\tthis.loader.classList.add(\"a-show\");\n\t}\n\n\tshowErrorScreen() {\n\t\tthis.errorScreen.classList.add(\"a-show\");\n\t}\n\n\thideErrorScreen() {\n\t\tthis.errorScreen.classList.remove(\"a-show\");\n\t}\n\n\tgetScreens() {\n\t\treturn this.screens;\n\t}\n\n\tgetRoutesMap() {\n\t\treturn this.routesMap;\n\t}\n\n\tonSwitch(cb) {\n\t\tthis.eventsHandlers.switch.push(cb);\n\t}\n\n\tonReaload(cb) {\n\t\tthis.eventsHandlers.reload.push(cb);\n\t}\n\n\trunSwitchHandlers(alias) {\n\t\tfor(let handler of this.eventsHandlers.switch) {\n\t\t\thandler(this, alias);\n\t\t}\n\t}\n\n\trunReloadHandlers(alias) {\n\t\tfor(let handler of this.eventsHandlers.reload) {\n\t\t\thandler(this, alias);\n\t\t}\n\t}\n}", "function template(type, icon, title, text) {\n\treturn `\n\t\t\n\t
\n\t
${icon} ${title} \n\t
${text}
\n\t
\n\t
\u2715 \n\t
\n\t`;\n}\n\nfunction init(toast, props) {\n\tif(props?.alone) {\n\t\tdocument.querySelectorAll(\".toast\").forEach(i => i.close());\n\t}\n\n\ttoast.close = function() {\n\t\tthis.classList.add(\"a-hide\");\n\t\tsetTimeout(() => {\n\t\t\tthis.remove();\n\t\t}, 300);\n\t}\n\n\ttoast.querySelector(\".toast-close\").addEventListener(\"click\", e => {\n\t\ttoast.close();\n\t});\n\n\ttoast.show = function() {\n\t\tdocument.querySelector(\"body\").append(toast);\n\n\t\tsetTimeout(() => {\n\t\t\ttoast.classList.add(\"a-show\");\n\t\t}, 10);\n\t}\n\n\tScreens.onSwitch((scr, alias) => {\n\t\tsetTimeout(() => {\n\t\t\ttoast?.close();\n\t\t}, 10000);\n\t});\n\n\ttoast.addEventListener(\"mouseover\", e => toast.ishovered = true);\n\ttoast.addEventListener(\"mouseout\", e => toast.ishovered = false);\n\n\tif(props?.lifetime) {\n\t\tconsole.log(props);\n\t\tconst lifetimeInterval = setInterval(() => {\n\t\t\tif(!toast.ishovered) {\n\t\t\t\ttoast.close();\n\t\t\t\tclearInterval(lifetimeInterval);\n\t\t\t}\n\t\t}, props?.lifetime);\n\t}\n\n\treturn toast;\n}\n\nfunction create(type, icon, title, text, props) {\n\tconst div = document.createElement(\"div\");\n\tdiv.innerHTML = template(type, icon, title, text);\n\n\treturn init(div.childNodes[1], props);\n}\n\nfunction createSuccess(title, text, props) {\n\tif(typeof props == \"undefined\") {\n\t\tprops = {};\n\t}\n\n\tif(typeof props.lifetime == \"undefined\") {\n\t\tprops.lifetime = 4000;\n\t}\n\n\tif(typeof props.alone == \"undefined\") {\n\t\tprops.alone = true;\n\t}\n\n\treturn create(\n\t\t\"success\", \n\t\t` `, \n\t\ttitle, \n\t\ttext,\n\t\tprops\n\t);\n}\n\nfunction createInfo(title, text, props) {\n\treturn create(\n\t\t\"info\", \n\t\t` `, \n\t\ttitle, \n\t\ttext,\n\t\tprops\n\t);\n}\n\nfunction createWarning(title, text, props) {\n\treturn create(\n\t\t\"warning\", \n\t\t` `, \n\t\ttitle, \n\t\ttext,\n\t\tprops\n\t);\n}\n\nfunction createError(title, text, props) {\n\treturn create(\n\t\t\"danger\", \n\t\t` `, \n\t\ttitle, \n\t\ttext,\n\t\tprops\n\t);\n}\n\nexport default {\n create,\n createInfo,\n createSuccess,\n createWarning,\n createError,\n \"createDanger\": createError\n};", "function sidebarNav(items) {\n\tlet listItems = \"\";\n\n\tfor(let item of items) {\n\t\tlet aOpen = \"\";\n\t\tlet aClose = \"\";\n\t\tif(item.route) {\n\t\t\taOpen = ``;\n\t\t\taClose = ` `;\n\t\t}\n\n\t\tlistItems += `\n\t\t\t\n\t\t\t\t${aOpen}${item.content}${aClose}\n\t\t\t \n\t\t`;\n\t}\n\n\treturn `\n\t\t\n\t`;\n}\n\nfunction table(caption, columns, data, tfoot) {\n\tlet head = ` `;\n\tlet totalColumns = 0;\n\tfor(let key in columns) {\n\t\thead += `${columns[key]} `;\n\t\ttotalColumns++;\n\t}\n\thead += \" \";\n\n\tlet body = ``;\n\tfor(let item of data) {\n\t\tbody += ``;\n\t\tfor(let column in columns) {\n\t\t\tbody += `${item[column]} `;\n\t\t}\n\t\tbody += ` `;\n\t}\n\n\tlet foot = \"\";\n\tif(typeof tfoot != \"undefined\") {\n\t\tfoot = `\n\t\t\t\n\t\t`\n\t}\n\n\treturn `\n\t\t\n\t\t\t${caption} \n\t\t\t${head} \n\t\t\t${body} \n\t\t\t${foot}\n\t\t
\n\t`;\n}\n\nfunction createElement(type, props, content) {\n\tconst node = document.createElement(type);\n\n\tfor (const [key, value] of Object.entries(props)) {\n\t\tif (key === \"class\") {\n\t\t\tnode.className = value;\n\t\t} else if (key === \"dataset\") {\n\t\t\tObject.assign(node.dataset, value);\n\t\t} else {\n\t\t\tnode.setAttribute(key, value);\n\t\t}\n\t}\n\n\tnode.innerHTML = (typeof content != \"undefined\") ? content : \"\";\n\treturn node; \n}\n\nfunction createAlert(type, content) {\n\tif([\"primary\", \"success\", \"secondary\", \"info\", \"warning\", \"error\", \"danger\"].indexOf(type) < 0) {\n\t\treturn console.error(\"createAlert()\", \"Error of type: \" + type);\n\t}\n\n\treturn createElement(\"div\", {\n\t\tclass: `alert alert-${type}`,\n\t}, content);\n}\n\nfunction deviceFieldsUnification(data) {\n\tconst map = {\n\t\t\"device_name\": \"name\",\n\t\t\"device_hard_id\": \"device_id\",\n\t\t\"device_ip\": \"ip\",\n\t\t\"device_type\": \"type\",\n\t\t\"ip_address\": \"ip\",\n\t\t\"mac_address\": \"mac\",\n\t\t\"device_mac\": \"mac\",\n\t\t\"core_version\": \"firmware_core_version\"\n\t};\n\n\tconst dataObj = {};\n\n\tfor(let field in data) {\n\t\tif(typeof map[field] != \"undefined\") {\n\t\t\tdataObj[ map[field] ] = data[field];\n\t\t\tcontinue;\n\t\t}\n\n\t\tdataObj[field] = data[field];\n\t}\n\n\treturn dataObj;\n}\n\nfunction btnLoadingState(btn, isLoading) {\n\tif(btn?.isLoading == isLoading) {\n\t\treturn false;\n\t}\n\n\tif(isLoading) {\n\t\tbtn.isLoading = true;\n\t\tbtn.originalContent = btn.innerHTML;\n\t\tif(btn.classList.contains(\"with-icon\")) {\n\t\t\tbtn.originalWithIcon = true;\n\t\t} else {\n\t\t\tbtn.classList.add(\"with-icon\");\n\t\t}\n\n\t\tbtn.classList.add(\"loading-state\");\n\t\tbtn.setAttribute(\"disabled\", \"disabled\");\n\t\tbtn.innerHTML = ` Loading`;\n\t} else {\n\t\tbtn.isLoading = false;\n\t\tif(!btn.originalContent) {\n\t\t\treturn false;\n\t\t}\n\t\tbtn.removeAttribute(\"disabled\");\n\t\tbtn.classList.remove(\"loading-state\");\n\t\tif(!btn.originalWithIcon) {\n\t\t\tbtn.classList.remove(\"with-icon\");\n\t\t}\n\t\tbtn.innerHTML = btn.originalContent;\n\t}\n\n\treturn btn;\n}\n\nexport default {\n\ttemplate: {\n\t\tsidebarNav,\n\t\ttable,\n\t\tcreateElement,\n\t\tcreateAlert\n\t},\n\tunification: {\n\t\tdeviceFieldsUnification\n\t},\n\tstates: {\n\t\tbtnLoadingState\n\t}\n}", "/* =========================\n Scripts module\n========================= */\n\nexport class ScriptsApi {\n\tconstructor(core) {\n\t\tthis.core = core;\n\t}\n\n\t// GET /api/v1/scripts/actions/list\n\tactions_list(cb) {\n\t\treturn this.core.api_get(\"/api/v1/scripts/actions/list\", cb);\n\t}\n\n\t// GET /api/v1/scripts/scopes/list\n\tscopes_list(cb) {\n\t\treturn this.core.api_get(\"/api/v1/scripts/scopes/list\", cb);\n\t}\n\n\t// GET /api/v1/scripts/regular/list\n\tregular_list(cb) {\n\t\treturn this.core.api_get(\"/api/v1/scripts/regular/list\", cb);\n\t}\n\n\t// GET /api/v1/scripts/scopes/name/{{filename}}\n\tscope_get_by_filename(filename, cb) {\n\t\tconst safe = encodeURIComponent(String(filename || \"\"));\n\t\treturn this.core.api_get(`/api/v1/scripts/scopes/name/${safe}`, cb, {\n\t\t\t// \u0442\u0443\u0442 \u0441\u0435\u0440\u0432\u0435\u0440 \u043C\u043E\u0436\u0435\u0442 \u0432\u0435\u0440\u043D\u0443\u0442\u044C PHP-\u043A\u043E\u0434 \u0442\u0435\u043A\u0441\u0442\u043E\u043C; request \u0443\u043C\u0435\u0435\u0442 \u044D\u0442\u043E \u043F\u0435\u0440\u0435\u0436\u0438\u0442\u044C\n\t\t});\n\t}\n\n\t// POST /api/v1/scripts/scopes/new\n\tscope_create(payload, cb) {\n\t\t// payload: { alias, filename, path }\n\t\treturn this.core.api_post(\"/api/v1/scripts/scopes/new\", payload, cb);\n\t}\n\n\t// POST /api/v1/scripts/scopes/update\n\tscope_update(payload, cb) {\n\t\t// payload: { name, filename, path }\n\t\treturn this.core.api_post(\"/api/v1/scripts/scopes/update\", payload, cb);\n\t}\n\n\t// GET /api/v1/scripts/actions/alias/{{alias}}/enable\n\taction_enable(alias, cb) {\n\t\tconst safe = encodeURIComponent(String(alias || \"\"));\n\t\treturn this.core.api_get(`/api/v1/scripts/actions/alias/${safe}/enable`, cb);\n\t}\n\n\t// GET /api/v1/scripts/actions/alias/{{alias}}/disable\n\taction_disable(alias, cb) {\n\t\tconst safe = encodeURIComponent(String(alias || \"\"));\n\t\treturn this.core.api_get(`/api/v1/scripts/actions/alias/${safe}/disable`, cb);\n\t}\n\n\t// GET /api/v1/scripts/actions/regular/{{alias}}/enable\n\tregular_enable(alias, cb) {\n\t\tconst safe = encodeURIComponent(String(alias || \"\"));\n\t\treturn this.core.api_get(`/api/v1/scripts/actions/regular/${safe}/enable`, cb);\n\t}\n\n\t// GET /api/v1/scripts/actions/regular/{{alias}}/disable\n\tregular_disable(alias, cb) {\n\t\tconst safe = encodeURIComponent(String(alias || \"\"));\n\t\treturn this.core.api_get(`/api/v1/scripts/actions/regular/${safe}/disable`, cb);\n\t}\n\n\t// GET /api/v1/scripts/actions/scope/{{name}}/enable\n\tscope_enable(name, cb) {\n\t\tconst safe = encodeURIComponent(String(name || \"\"));\n\t\treturn this.core.api_get(`/api/v1/scripts/actions/scope/${safe}/enable`, cb);\n\t}\n\n\t// GET /api/v1/scripts/actions/scope/{{name}}/disable\n\tscope_disable(name, cb) {\n\t\tconst safe = encodeURIComponent(String(name || \"\"));\n\t\treturn this.core.api_get(`/api/v1/scripts/actions/scope/${safe}/disable`, cb);\n\t}\n\n\t// GET /api/v1/scripts/scopes/name/{{name}}/remove\n\tscope_remove(name, cb) {\n\t\tconst safe = encodeURIComponent(String(name || \"\"));\n\t\treturn this.core.api_get(`/api/v1/scripts/scopes/name/${safe}/remove`, cb);\n\t}\n\n\t// POST /api/v1/scripts/actions/run\n\trun(payload, cb) {\n\t\t// payload: { alias, params: {...} }\n\t\treturn this.core.api_post(\"/api/v1/scripts/actions/run\", payload, cb);\n\t}\n}", "/* =========================\n Devices module\n========================= */\n\nexport class DevicesApi {\n\tconstructor(core) {\n\t\tthis.core = core;\n\t}\n\n\t// GET /api/v1/devices/list\n\tlist(cb) {\n\t\treturn this.core.api_get(\"/api/v1/devices/list\", cb);\n\t}\n\n\t// GET /api/v1/devices/scanning/setup\n\tscanning_setup(cb) {\n\t\treturn this.core.api_get(\"/api/v1/devices/scanning/setup\", cb);\n\t}\n\n\t// GET /api/v1/devices/scanning/all\n\tscanning_all(cb) {\n\t\treturn this.core.api_get(\"/api/v1/devices/scanning/all\", cb);\n\t}\n\n\t// POST /api/v1/devices/setup/new-device\n\tsetup_new_device(payload, cb) {\n\t\t// payload: { device_ip, alias, name, description }\n\t\treturn this.core.api_post(\"/api/v1/devices/setup/new-device\", payload, cb);\n\t}\n\n\t// GET /api/v1/devices/id/{{id}}/info\n\tinfo(id, cb) {\n\t\tconst safe = encodeURIComponent(String(id));\n\t\treturn this.core.api_get(`/api/v1/devices/id/${safe}/info`, cb);\n\t}\n\n\t// GET /api/v1/devices/id/{{id}}\n\tget(id, cb) {\n\t\tconst safe = encodeURIComponent(String(id));\n\t\treturn this.core.api_get(`/api/v1/devices/id/${safe}`, cb);\n\t}\n\n\t// GET /api/v1/devices/id/{{id}}/status\n\tstatus(id, cb) {\n\t\tconst safe = encodeURIComponent(String(id));\n\t\treturn this.core.api_get(`/api/v1/devices/id/${safe}/status`, cb);\n\t}\n\n\t// POST /api/v1/devices/action\n\taction(payload, cb) {\n\t\t// payload: { device_id, action, params }\n\t\treturn this.core.api_post(\"/api/v1/devices/action\", payload, cb);\n\t}\n\n\t// GET /api/v1/devices/id/{{id}}/remove\n\tremove(id, cb) {\n\t\tconst safe = encodeURIComponent(String(id));\n\t\treturn this.core.api_get(`/api/v1/devices/id/${safe}/remove`, cb);\n\t}\n\n\t// GET /api/v1/devices/id/{{id}}/reboot\n\treboot(id, cb) {\n\t\tconst safe = encodeURIComponent(String(id));\n\t\treturn this.core.api_get(`/api/v1/devices/id/${safe}/reboot`, cb);\n\t}\n}\n", "export class AreasApi {\n\tconstructor(core) {\n\t\tthis.core = core;\n\t}\n\n\t// GET /api/v1/areas/list\n\tlist(cb) {\n\t\treturn this.core.api_get(\"/api/v1/areas/list\", cb);\n\t}\n\n\t// GET /api/v1/areas/id/{{area_id}}/list\n\tinner_list(area_id, cb) {\n\t\tconst safe = encodeURIComponent(String(area_id));\n\t\treturn this.core.api_get(`/api/v1/areas/id/${safe}/list`, cb);\n\t}\n\n\t// POST /api/v1/areas/new-area\n\tnew_area(payload, cb) {\n\t\t// payload: { type, alias, display_name }\n\t\treturn this.core.api_post(\"/api/v1/areas/new-area\", payload, cb);\n\t}\n\n\t// GET /api/v1/areas/id/{{area_id}}/remove\n\tremove(area_id, cb) {\n\t\tconst safe = encodeURIComponent(String(area_id));\n\t\treturn this.core.api_get(`/api/v1/areas/id/${safe}/remove`, cb);\n\t}\n\n\t// POST /api/v1/areas/place-in-area\n\tplace_in_area(payload, cb) {\n\t\t// payload: { target_area_id, place_in_area_id }\n\t\treturn this.core.api_post(\"/api/v1/areas/place-in-area\", payload, cb);\n\t}\n\n\t// POST /api/v1/areas/update-display-name\n\tupdate_display_name(payload, cb) {\n\t\t// payload: { area_id, display_name }\n\t\treturn this.core.api_post(\"/api/v1/areas/update-display-name\", payload, cb);\n\t}\n\n\t// POST /api/v1/areas/update-alias\n\tupdate_alias(payload, cb) {\n\t\t// payload: { area_id, new_alias }\n\t\treturn this.core.api_post(\"/api/v1/areas/update-alias\", payload, cb);\n\t}\n\n\t// GET /api/v1/areas/id/{{area_id}}/devices\n\tdevices(area_id, cb) {\n\t\tconst safe = encodeURIComponent(String(area_id));\n\t\treturn this.core.api_get(`/api/v1/areas/id/${safe}/devices`, cb);\n\t}\n\n\t// GET /api/v1/areas/id/{{area_id}}/unassign-from-area\n\tunassign_from_area(area_id, cb) {\n\t\tconst safe = encodeURIComponent(String(area_id));\n\t\treturn this.core.api_get(`/api/v1/areas/id/${safe}/unassign-from-area`, cb);\n\t}\n\n\t// GET /api/v1/areas/types/list\n\ttypes_list(cb) {\n\t\treturn this.core.api_get(\"/api/v1/areas/types/list\", cb);\n\t}\n\n\t// GET /api/v1/areas/reboot_devices\n\t// GET /api/v1/areas/id/{{area_id}}/reboot_devices\n\treboot_devices(area_id, cb) {\n\t\tif (area_id === undefined || area_id === null) {\n\t\t\treturn this.core.api_get(\"/api/v1/areas/reboot_devices\", cb);\n\t\t}\n\t\tconst safe = encodeURIComponent(String(area_id));\n\t\treturn this.core.api_get(`/api/v1/areas/id/${safe}/reboot_devices`, cb);\n\t}\n}", "/**\n * smart_home_api.js\n *\n * \u041C\u0438\u043D\u0438\u043C\u0430\u043B\u044C\u043D\u0430\u044F JS-\u0431\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0430 \u0434\u043B\u044F REST-\u0437\u0430\u043F\u0440\u043E\u0441\u043E\u0432 \u043A \u0441\u0435\u0440\u0432\u0435\u0440\u0443 (callback-style).\n * - \u0410\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F: Bearer token (\u0438\u043B\u0438 \u043A\u0430\u0441\u0442\u043E\u043C\u043D\u044B\u0439 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A, \u0435\u0441\u043B\u0438 \u043F\u043E\u043C\u0435\u043D\u044F\u0435\u0448\u044C)\n * - \u0415\u0434\u0438\u043D\u0430\u044F \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u043A\u0430 \u043E\u0448\u0438\u0431\u043E\u043A: \u0441\u0435\u0442\u0435\u0432\u044B\u0435, \u0442\u0430\u0439\u043C\u0430\u0443\u0442, \u043D\u0435-JSON, \u0441\u0442\u0430\u0442\u0443\u0441=false/error\n * - \u041C\u043E\u0434\u0443\u043B\u0438: \u0441\u0435\u0439\u0447\u0430\u0441 \u0442\u043E\u043B\u044C\u043A\u043E Scripts, \u043E\u0441\u0442\u0430\u043B\u044C\u043D\u044B\u0435 \u043F\u043E \u0430\u043D\u0430\u043B\u043E\u0433\u0438\u0438\n */\n\nimport { ScriptsApi } from \"./modules/ScriptsApi.js\";\nimport { DevicesApi } from \"./modules/DevicesApi.js\";\nimport { AreasApi } from \"./modules/AreasApi.js\";\n\n/* =========================\n Utils\n========================= */\n\nfunction build_query(params) {\n\tif (!params || typeof params !== \"object\") return \"\";\n\tconst usp = new URLSearchParams();\n\tObject.entries(params).forEach(([k, v]) => {\n\t\tif (v === undefined || v === null) return;\n\t\tusp.append(k, String(v));\n\t});\n\tconst s = usp.toString();\n\treturn s ? `?${s}` : \"\";\n}\n\nfunction join_url(base_url, path) {\n\tconst b = String(base_url || \"\").replace(/\\/+$/, \"\");\n\tconst p = String(path || \"\").replace(/^\\/+/, \"\");\n\treturn `${b}/${p}`;\n}\n\nfunction safe_json_parse(text) {\n\ttry {\n\t\treturn { ok: true, data: JSON.parse(text) };\n\t} catch (e) {\n\t\treturn { ok: false, error: e };\n\t}\n}\n\n/* =========================\n Core client\n========================= */\n\nexport class SmartHomeApi {\n\t/**\n\t * @param {Object} opts\n\t * @param {string} opts.base_url - \u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440: http://192.168.2.101\n\t * @param {string} [opts.token] - \u0442\u043E\u043A\u0435\u043D \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438\n\t * @param {number} [opts.timeout_ms=15000]\n\t * @param {Object} [opts.default_headers]\n\t * @param {Function} [opts.on_unauthorized] - cb(details)\n\t * @param {string} [opts.proxy_path] \u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440 \"/proxy.php\" (\u0432\u043A\u043B\u044E\u0447\u0430\u0435\u0442 \u0430\u0432\u0442\u043E-\u043F\u0440\u043E\u043A\u0441\u0438)\n\t */\n\tconstructor(opts) {\n\t\tthis.base_url = opts?.base_url || \"\";\n\t\tthis.token = opts?.token || \"\";\n\t\tthis.timeout_ms = Number.isFinite(opts?.timeout_ms) ? opts.timeout_ms : 15000;\n\t\tthis.default_headers = opts?.default_headers || {};\n\t\tthis.on_unauthorized = typeof opts?.on_unauthorized === \"function\" ? opts.on_unauthorized : null;\n\t\tthis.proxy_path = opts?.proxy_path || \"\"; // \"\" => \u0431\u0435\u0437 \u043F\u0440\u043E\u043A\u0441\u0438\n\n\t\t// modules\n\t\tthis.scripts = new ScriptsApi(this);\n\t\tthis.devices = new DevicesApi(this);\n\t\tthis.areas = new AreasApi(this);\n\t}\n\n\tset_base_url(base_url) {\n\t\tthis.base_url = base_url || \"\";\n\t}\n\n\tset_token(token) {\n\t\tthis.token = token || \"\";\n\t}\n\n\tset_proxy_path(proxy_path) {\n\t\tthis.proxy_path = proxy_path || \"\";\n\t}\n\n\t_wrap_path(path, extra_query) {\n\t\t// \u0415\u0441\u043B\u0438 \u0432\u043A\u043B\u044E\u0447\u0451\u043D \u043F\u0440\u043E\u043A\u0441\u0438 \u2014 \u0445\u043E\u0434\u0438\u043C \u043D\u0430 /proxy.php?path=&...\n\t\tif (!this.proxy_path) {\n\t\t\tif (!extra_query) return path;\n\t\t\treturn `${path}${build_query(extra_query)}`;\n\t\t}\n\n\t\tconst q = { path, ...(extra_query || {}) };\n\t\treturn `${this.proxy_path}${build_query(q)}`;\n\t}\n\n\t/**\n\t * \u0423\u043D\u0438\u0444\u0438\u0446\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0437\u0430\u043F\u0440\u043E\u0441.\n\t *\n\t * cb(err, data, meta)\n\t * - err: { type, message, status_code?, raw?, details? }\n\t * - data: \u0440\u0430\u0441\u043F\u0430\u0440\u0441\u0435\u043D\u043D\u044B\u0439 json (\u0438\u043B\u0438 string, \u0435\u0441\u043B\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u043D\u0435 \u0432\u0435\u0440\u043D\u0443\u043B json)\n\t * - meta: { url, method, status_code, headers }\n\t */\n\trequest(method, path, body, cb, opts) {\n\t\tconst callback = typeof cb === \"function\" ? cb : () => {};\n\t\tconst url = join_url(this.base_url, path);\n\n\t\tconst controller = new AbortController();\n\t\tconst timeout_ms = Number.isFinite(opts?.timeout_ms) ? opts.timeout_ms : this.timeout_ms;\n\n\t\tconst t = setTimeout(() => controller.abort(), timeout_ms);\n\n\t\tconst headers = {\n\t\t\t...this.default_headers,\n\t\t\t...(opts?.headers || {}),\n\t\t};\n\n\t\t// \u0410\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F (\u043F\u043E\u0434\u0441\u0442\u0440\u043E\u0439, \u0435\u0441\u043B\u0438 \u0443 \u0442\u0435\u0431\u044F \u0434\u0440\u0443\u0433\u043E\u0439 \u0444\u043E\u0440\u043C\u0430\u0442)\n\t\tif (this.token) headers[\"Authorization\"] = `Bearer ${this.token}`;\n\n\t\tlet payload = undefined;\n\t\tif (body !== undefined && body !== null) {\n\t\t\theaders[\"Content-Type\"] = \"application/json\";\n\t\t\tpayload = JSON.stringify(body);\n\t\t}\n\n\t\tfetch(url, {\n\t\t\tmethod,\n\t\t\theaders,\n\t\t\tbody: payload,\n\t\t\tsignal: controller.signal,\n\t\t})\n\t\t\t.then(async (res) => {\n\t\t\t\tclearTimeout(t);\n\n\t\t\t\tconst meta = {\n\t\t\t\t\turl,\n\t\t\t\t\tmethod,\n\t\t\t\t\tstatus_code: res.status,\n\t\t\t\t\theaders: res.headers,\n\t\t\t\t};\n\n\t\t\t\tconst text = await res.text();\n\t\t\t\tconst parsed = safe_json_parse(text);\n\t\t\t\tconst data = parsed.ok ? parsed.data : text;\n\n\t\t\t\t// HTTP-level \u043E\u0448\u0438\u0431\u043A\u0438\n\t\t\t\tif (!res.ok) {\n\t\t\t\t\tconst err = {\n\t\t\t\t\t\ttype: \"http_error\",\n\t\t\t\t\t\tmessage: `HTTP ${res.status}`,\n\t\t\t\t\t\tstatus_code: res.status,\n\t\t\t\t\t\traw: data,\n\t\t\t\t\t};\n\n\t\t\t\t\tif (res.status === 401 || res.status === 403) {\n\t\t\t\t\t\tif (this.on_unauthorized) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tthis.on_unauthorized({ error: err, meta });\n\t\t\t\t\t\t\t} catch (_) {}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn callback(err, null, meta);\n\t\t\t\t}\n\n\t\t\t\t// API-level \u043E\u0448\u0438\u0431\u043A\u0438 (\u043F\u043E \u0442\u0432\u043E\u0438\u043C \u043F\u0440\u0438\u043C\u0435\u0440\u0430\u043C \u0431\u044B\u0432\u0430\u0435\u0442 status:false \u0438\u043B\u0438 status:\"error\")\n\t\t\t\tif (parsed.ok && data && typeof data === \"object\") {\n\t\t\t\t\tconst st = data.status;\n\t\t\t\t\tif (st === false || st === \"error\") {\n\t\t\t\t\t\tconst err = {\n\t\t\t\t\t\t\ttype: \"api_error\",\n\t\t\t\t\t\t\tmessage: data.message || \"API error\",\n\t\t\t\t\t\t\tstatus_code: res.status,\n\t\t\t\t\t\t\traw: data,\n\t\t\t\t\t\t\tfield: data.field,\n\t\t\t\t\t\t};\n\t\t\t\t\t\treturn callback(err, null, meta);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn callback(null, data, meta);\n\t\t\t})\n\t\t\t.catch((e) => {\n\t\t\t\tclearTimeout(t);\n\n\t\t\t\tconst is_abort = e && (e.name === \"AbortError\" || String(e).includes(\"AbortError\"));\n\t\t\t\tconst err = is_abort\n\t\t\t\t\t? { type: \"timeout\", message: `Timeout after ${timeout_ms}ms` }\n\t\t\t\t\t: { type: \"network_error\", message: e?.message || \"Network error\", details: e };\n\n\t\t\t\treturn callback(err, null, { url, method, status_code: 0, headers: null });\n\t\t\t});\n\t}\n\n\tget(path, cb, opts) {\n\t\treturn this.request(\"GET\", path, null, cb, opts);\n\t}\n\n\tpost(path, body, cb, opts) {\n\t\treturn this.request(\"POST\", path, body, cb, opts);\n\t}\n\n\tapi_get(api_path, cb, extra_query, opts) {\n\t\treturn this.get(this._wrap_path(api_path, extra_query), cb, opts);\n\t}\n\n\tapi_post(api_path, body, cb, extra_query, opts) {\n\t\treturn this.post(this._wrap_path(api_path, extra_query), body, cb, opts);\n\t}\n}\n\n/* =========================\n Example usage\n========================= */\n\n// import { SmartHomeApi } from \"./smart_home_api.js\";\n//\n// const api = new SmartHomeApi({\n// base_url: \"http://192.168.2.101\",\n// token: \"YOUR_TOKEN\",\n// timeout_ms: 20000,\n// on_unauthorized: ({ error }) => console.log(\"auth problem:\", error),\n// });\n//\n// api.scripts.actions_list((err, res) => {\n// if (err) return console.error(\"actions_list error:\", err);\n// console.log(\"actions:\", res);\n// });\n//\n// api.scripts.run({ alias: \"script_alias\", params: { x: 1 } }, (err, res) => {\n// if (err) return console.error(\"run error:\", err);\n// console.log(\"run result:\", res);\n// });\n", "export function deviceDetailsPopup(device, sh_api) {\n\tconsole.log(device);\n\n\treturn Modals.create(\"device-popup\", {\n\t\ttitle: `Device ${device.name}`,\n\t\tbody: modal => {\n\t\t\tlet deviceProperties = \"\";\n\t\t\tfor(let field in device) {\n\t\t\t\tdeviceProperties += `\n\t\t\t\t\t\n\t\t\t\t\t\t${field}: \n\t\t\t\t\t\t${device[field]} \n\t\t\t\t\t \n\t\t\t\t`;\n\t\t\t}\n\n\t\t\treturn `\n\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t${deviceProperties}\n\t\t\t\t\t\t \n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t`;\n\t\t},\n\t\tactions: modal => {\n\t\t\tconst buttonCancel = Helper.template.createElement(\"button\", {\n\t\t\t\tclass: \"btn btn-primary\"\n\t\t\t}, \"Close\");\n\n\t\t\tconst buttonReboot = Helper.template.createElement(\"button\", {\n\t\t\t\tclass: \"btn btn-warning with-icon\"\n\t\t\t}, ' Reboot');\n\n\t\t\tconst buttonRemove = Helper.template.createElement(\"button\", {\n\t\t\t\tclass: \"btn btn-danger with-icon\"\n\t\t\t}, ' Remove');\n\n\t\t\tbuttonCancel.addEventListener(\"click\", e => {\n\t\t\t\tmodal.close();\n\t\t\t});\n\n\t\t\tbuttonReboot.addEventListener(\"click\", e => {\n\t\t\t\tif(buttonReboot.getAttribute(\"disabled\")) {\n\t\t\t\t\treturn ;\n\t\t\t\t}\n\n\t\t\t\tHelper.states.btnLoadingState(buttonReboot, true);\n\t\t\t\tsh_api.devices.reboot(\n\t\t\t\t\tdevice.id,\n\t\t\t\t\t(err, data, meta) => {\n\t\t\t\t\t\tHelper.states.btnLoadingState(buttonReboot, false);\n\t\t\t\t\t\tconsole.log(\"Reboot done\");\n\n\t\t\t\t\t\tmodal.close();\n\n\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\tif(data) {\n\t\t\t\t\t\t\t\tToasts.createSuccess(\n\t\t\t\t\t\t\t\t\t\"Reboot successful\",\n\t\t\t\t\t\t\t\t\t`Device: ${device.name} \n\t\t\t\t\t\t\t\t\tAlias: ${device.alias} `\n\t\t\t\t\t\t\t\t).show();\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tToasts.createError(\n\t\t\t\t\t\t\t\t\t\"Reboot failed\",\n\t\t\t\t\t\t\t\t\t`Device: ${device.name} \n\t\t\t\t\t\t\t\t\tAlias: ${device.alias} `\n\t\t\t\t\t\t\t\t).show();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, 300);\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tbuttonRemove.addEventListener(\"click\", e => {\n\t\t\t\tif(buttonRemove.getAttribute(\"disabled\")) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tHelper.states.btnLoadingState(buttonRemove, true);\n\t\t\t\tconfirmPopup(\n\t\t\t\t\t\"Are you sure you want to remove this device?\", \n\t\t\t\t\t() => {\n\t\t\t\t\t\tsh_api.devices.remove(\n\t\t\t\t\t\t\tdevice.id,\n\t\t\t\t\t\t\t(err, data, meta) => {\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tHelper.states.btnLoadingState(buttonRemove, false);\n\t\t\t\t\t\t\t\tconsole.log(\"Was removed\");\n\n\t\t\t\t\t\t\t\tmodal.close();\n\n\t\t\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\t\t\tToasts.createSuccess(\n\t\t\t\t\t\t\t\t\t\t\"Removed\",\n\t\t\t\t\t\t\t\t\t\t`\n\t\t\t\t\t\t\t\t\t\tDevice: ${device.name} \n\t\t\t\t\t\t\t\t\t\tAlias: ${device.alias} \n\t\t\t\t\t\t\t\t\t\tIP: ${device.ip} \n\t\t\t\t\t\t\t\t\t\t`\n\t\t\t\t\t\t\t\t\t).show();\n\t\t\t\t\t\t\t\t}, 300);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t);\n\t\t\t\t}, \n\t\t\t\t() => {\n\t\t\t\t\tHelper.states.btnLoadingState(buttonRemove, false);\n\t\t\t\t\tconsole.log(\"CANCELED\");\n\t\t\t\t});\n\t\t\t});\n\n\t\t\treturn [ buttonCancel, buttonReboot, buttonRemove ];\n\t\t}\n\t});\n}", "export function deviceSetupFormPopup(device, sh_api) {\n\tdevice = Helper.unification.deviceFieldsUnification(device);\n\n\treturn Modals.create(\"device-setup\", {\n\t\ttitle: `Setup new device ${device.ip}`,\n\t\tbody: modal => {\n\n\t\t\tlet deviceProperties = \"\";\n\t\t\tfor(let field in device) {\n\t\t\t\tif(field[0] == \"_\") continue;\n\t\t\t\tdeviceProperties += `\n\t\t\t\t\t\n\t\t\t\t\t\t${field}: \n\t\t\t\t\t\t${device[field]} \n\t\t\t\t\t \n\t\t\t\t`;\n\t\t\t}\n\n\t\t\tconst deviceInfo = `\n\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t${deviceProperties}\n\t\t\t\t\t\t \n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t`;\n\n\t\t\treturn `\n\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\t\t${deviceInfo}\n\t\t\t\t\t
\n\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tDevice alias\n\t\t\t\t\t\t\t\t \n\t\t\t\t\t\t\t\t \n\t\t\t\t\t\t\t \n\t\t\t\t\t\t
\n\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tDevice name\n\t\t\t\t\t\t\t\t \n\t\t\t\t\t\t\t\t \n\t\t\t\t\t\t\t \n\t\t\t\t\t\t
\n\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tAbout device\n\t\t\t\t\t\t\t\t \n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t \n\t\t\t\t\t\t
\n\n\t\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t`;\n\t\t},\n\t\tactions: modal => {\n\t\t\tconst buttonCancel = Helper.template.createElement(\"button\", { class: \"btn btn-primary\" }, \"Cancel\");\n\t\t\tbuttonCancel.addEventListener(\"click\", e => {\n\t\t\t\tmodal.close();\n\t\t\t});\n\n\t\t\tconst buttonSubmit = Helper.template.createElement(\"button\", \n\t\t\t\t{ class: \"btn btn-success with-icon\" }, \n\t\t\t\t` Setup`\n\t\t\t);\n\n\t\t\tbuttonSubmit.addEventListener(\"click\", e => {\n\t\t\t\tif(e.currentTarget.getAttribute(\"disabled\")) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst inputs = {\n\t\t\t\t\tdevice_ip: device.ip\n\t\t\t\t};\n\n\t\t\t\tconst setupForm = document.querySelector(\"#device-setup .setup-form\");\n\t\t\t\tsetupForm.querySelectorAll(\"input[type='text']\").forEach(i => {\n\t\t\t\t\ti.dispatchEvent(\n\t\t\t\t\t\tnew Event(\"input\", { bubbles: true })\n\t\t\t\t\t);\n\t\t\t\t});\n\n\t\t\t\tif(setupForm.querySelectorAll(\".label.error\").length) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst inputElements = setupForm.querySelectorAll(\"input\");\n\t\t\t\tconst textareaElement = setupForm.querySelector(\"textarea\");\n\n\t\t\t\tfor(let input of inputElements) {\n\t\t\t\t\tinputs[input.getAttribute(\"name\")] = input.value;\n\t\t\t\t}\n\n\t\t\t\tinputs[textareaElement.getAttribute(\"name\")] = textareaElement.value;\n\n\t\t\t\tHelper.states.btnLoadingState(buttonSubmit, true);\n\t\t\t\t\n\t\t\t\tsh_api.devices.setup_new_device(inputs, (err, resp, meta) => {\n\t\t\t\t\tHelper.states.btnLoadingState(buttonSubmit, false);\n\n\t\t\t\t\tif(err?.type == \"api_error\") {\n\t\t\t\t\t\tconsole.error(\"ERR! sh_api.devices.setup_new_device\", err.raw);\n\n\t\t\t\t\t\tif(err.raw?.failed_fields) {\n\t\t\t\t\t\t\tfor(let errFieldName of err.raw.failed_fields) {\n\t\t\t\t\t\t\t\tmodal.querySelector(`[name=\"${errFieldName}\"]`).parentNode.classList.add(\"error\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\t\t\t\t\t\t\n\n\t\t\t\t\t\tif(err.raw?.msg) {\n\t\t\t\t\t\t\tconst alertContainer = modal.querySelector(\".setup-form .alert-container\");\n\t\t\t\t\t\t\talertContainer.innerHTML = \"\";\n\t\t\t\t\t\t\talertContainer?.append(Helper.template.createAlert( \"error\", err.raw.msg ));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\t\t\t\t\t\n\n\t\t\t\t\tif(!resp) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\tinputElements.forEach(i => i.value = \"\");\n\t\t\t\t\ttextareaElement.value = \"\";\n\t\t\t\t\tmodal.close();\n\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tToasts.createSuccess(\"Setup successful\", `Added new device ID ${device.device_id} `).show();\n\t\t\t\t\t}, 300);\n\t\t\t\t});\n\t\t\t});\n\n\t\t\treturn [ buttonCancel, buttonSubmit ];\n\t\t},\n\n\t\tonready: modal => {\n\t\t\tconst setupForm = modal.querySelector(\".setup-form\");\n\t\t\tsetupForm.querySelectorAll(\"input\").forEach(i => {\n\t\t\t\ti.addEventListener(\"input\", e => {\n\t\t\t\t\tif(!e.currentTarget.value.length) {\n\t\t\t\t\t\te.currentTarget.parentNode.classList.add(\"error\");\n\t\t\t\t\t\tif(!e.currentTarget.parentNode.parentNode.querySelector(\".input-info.error\")) {\n\t\t\t\t\t\t\te.currentTarget.parentNode.parentNode.append(Helper.template.createElement(\"div\", {\n\t\t\t\t\t\t\t\tclass: \"input-info error\"\n\t\t\t\t\t\t\t}, ` Field cannot be empty`));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\te.currentTarget.parentNode.classList.remove(\"error\");\n\t\t\t\t\t\te.currentTarget.parentNode.parentNode.querySelector(\".input-info.error\")?.remove();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t})\n}", "import { deviceDetailsPopup } from \"./device-details-popup.js\";\nimport { deviceSetupFormPopup } from \"./device-setup-form-popup.js\";\n\nfunction sidebarTemplate(active) {\n\treturn Helper.template.sidebarNav([\n\t\t{\n\t\t\tcontent: ` Devices `,\n\t\t\troute: \"/#!/devices\",\n\t\t\tis_active: active == \"devices\"\n\t\t},\n\t\t{\n\t\t\tcontent: ` Scanning `,\n\t\t\troute: \"/#!/devices/scanning\",\n\t\t\tis_active: active == \"scanning\"\n\t\t}\n\t]);\n}\n\n\nfunction list(sh_api) {\n\treturn {\n\t\talias: \"devices\",\n\t\trenderer: () => {\n\t\t\tconst sidebar = sidebarTemplate(\"devices\");\n\n\t\t\treturn `\n\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t${sidebar}\n\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t`;\n\t\t},\n\n\t\tiniter: scr => {\n\t\t\tsh_api.devices.list((err, resp, meta) => {\n\t\t\t\tconsole.log(\"sh_api.devices.list\", err, resp, meta);\n\n\t\t\t\tif(meta.status_code != 200) {\n\t\t\t\t\treturn scr.error(\"Server API ERROR\", \"\");\n\t\t\t\t}\n\n\t\t\t\tconst preparedData = [];\n\t\t\t\tfor(let device of resp.data.devices) {\n\t\t\t\t\tdevice = Helper.unification.deviceFieldsUnification(device);\n\n\t\t\t\t\tconst connectionState = device.connection_state == \"active\"\n\t\t\t\t\t\t? `Online `\n\t\t\t\t\t\t: `Offline `;\n\n\t\t\t\t\tpreparedData.push({\n\t\t\t\t\t\tdeviceName: device.name,\n\t\t\t\t\t\talias: device.alias,\n\t\t\t\t\t\tstatus: connectionState,\n\t\t\t\t\t\tip: `${device.ip}`,\n\t\t\t\t\t\tactions: `\n\t\t\t\t\t\t\tDetails \n\n\t\t\t\t\t\t\tReboot \n\t\t\t\t\t\t`\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tscr.currentScreen.DOMObject.querySelector(\".devices-container\").innerHTML = Helper.template.table(\n\t\t\t\t\t\"Devices list\", \n\t\t\t\t\t{\n\t\t\t\t\t\tdeviceName: \"Device name\", \n\t\t\t\t\t\talias: \"Device alias\", \n\t\t\t\t\t\tstatus: \"Status\", \n\t\t\t\t\t\tip: \"IP\", \n\t\t\t\t\t\tactions: \"Actions\"\n\t\t\t\t\t},\n\t\t\t\t\tpreparedData,\n\t\t\t\t\t`Total: ${resp.data.total} devices `\n\t\t\t\t);\n\n\t\t\t\tscr.currentScreen.DOMObject.querySelectorAll(\".reboot-btn\").forEach(btn => {\n\t\t\t\t\tbtn.addEventListener(\"click\", e => {\n\t\t\t\t\t\tif(e.currentTarget.getAttribute(\"disabled\")) {\n\t\t\t\t\t\t\treturn ;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst btnReboot = e.currentTarget;\n\t\t\t\t\t\tHelper.states.btnLoadingState(btnReboot, true);\n\t\t\t\t\t\tconst deviceId = e.currentTarget.dataset.deviceId;\n\t\t\t\t\t\tconst deviceName = e.currentTarget.dataset.deviceName;\n\t\t\t\t\t\tconst deviceAlias = e.currentTarget.dataset.deviceAlias;\n\t\t\t\t\t\tsh_api.devices.reboot(\n\t\t\t\t\t\t\tdeviceId,\n\t\t\t\t\t\t\t(err, data, meta) => {\n\t\t\t\t\t\t\t\tHelper.states.btnLoadingState(btnReboot, false);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tconsole.log(\"Reboot done\", err, data, meta);\n\t\t\t\t\t\t\t\tif(data) {\n\t\t\t\t\t\t\t\t\tToasts.createSuccess(\n\t\t\t\t\t\t\t\t\t\t\"Reboot successful\",\n\t\t\t\t\t\t\t\t\t\t`Device: ${deviceName} \n\t\t\t\t\t\t\t\t\t\tAlias: ${deviceAlias} `\n\t\t\t\t\t\t\t\t\t).show();\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tToasts.createError(\n\t\t\t\t\t\t\t\t\t\t\"Reboot failed\",\n\t\t\t\t\t\t\t\t\t\t`Device: ${deviceName} \n\t\t\t\t\t\t\t\t\t\tAlias: ${deviceAlias} `\n\t\t\t\t\t\t\t\t\t).show();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\t\t\t\t});\n\n\t\t\t\tscr.currentScreen.DOMObject.querySelectorAll(\".details-btn\").forEach(btn => {\n\t\t\t\t\tbtn.addEventListener(\"click\", e => {\n\t\t\t\t\t\tconst device = JSON.parse(e.currentTarget.dataset.device);\n\t\t\t\t\t\tdeviceDetailsPopup(device, sh_api).show();\n\t\t\t\t\t});\n\t\t\t\t});\n\n\t\t\t\tscr.ready();\n\t\t\t});\n\t\t}\n\t};\n}\n\nfunction scanning(sh_api) {\n\treturn {\n\t\talias: \"devices-scanning\",\n\t\trenderer: () => {\t\n\t\t\tconst sidebar = sidebarTemplate(\"scanning\");\n\n\t\t\treturn `\n\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t${sidebar}\n\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t`;\n\t\t},\n\t\tiniter: scr => {\n\t\t\tsh_api.devices.scanning_all((err, resp, meta) => {\n\t\t\t\tconsole.log(\"sh_api.devices.scanning_all\", err, resp);\n\n\t\t\t\tif(meta.status_code != 200) {\n\t\t\t\t\treturn scr.error(\"Server API ERROR\", \"\");\n\t\t\t\t}\n\n\t\t\t\tconst preparedData = [];\n\t\t\t\tfor(let device of resp.data.devices) {\n\t\t\t\t\tdevice = Helper.unification.deviceFieldsUnification(device);\n\n\t\t\t\t\tpreparedData.push({\n\t\t\t\t\t\tdeviceId: device.device_id,\n\t\t\t\t\t\tdeviceName: device.name,\n\t\t\t\t\t\tdeviceType: device.type,\n\t\t\t\t\t\tstatus: `${device.status} `,\n\t\t\t\t\t\tip: `${device.ip}`,\n\t\t\t\t\t\tmac: `${device.mac}`,\n\t\t\t\t\t\twifiSignal: device.wifi_signal,\n\t\t\t\t\t\tactions: device.status == \"setup\" ? `\n\t\t\t\t\t\t\tSetup \n\t\t\t\t\t\t` : \"\"\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tscr.currentScreen.DOMObject.querySelector(\".devices-container\").innerHTML = Helper.template.table(\n\t\t\t\t\t\"Found devices\", \n\t\t\t\t\t{\n\t\t\t\t\t\tdeviceId: \"Device ID\",\n\t\t\t\t\t\tdeviceName: \"Device name\", \n\t\t\t\t\t\tdeviceType: \"Type\", \n\t\t\t\t\t\tstatus: \"Status\", \n\t\t\t\t\t\tip: \"IP\", \n\t\t\t\t\t\tmac: \"Mac\",\n\t\t\t\t\t\twifiSignal: \"Signal\", \n\t\t\t\t\t\tactions: \"Actions\"\n\t\t\t\t\t},\n\t\t\t\t\tpreparedData,\n\t\t\t\t\t`Total: ${resp.data.devices.length} devices `\n\t\t\t\t);\n\n\t\t\t\tscr.currentScreen.DOMObject.querySelectorAll(\".setup-btn\").forEach(btn => {\n\t\t\t\t\tbtn.addEventListener(\"click\", e => {\n\t\t\t\t\t\tconst device = JSON.parse(e.currentTarget.dataset.device);\n\t\t\t\t\t\tdeviceSetupFormPopup(device, sh_api).show();\n\t\t\t\t\t});\n\t\t\t\t});\n\n\t\t\t\tscr.ready();\n\t\t\t});\n\t\t}\n\t};\n}\n\nexport default {\n\tlist,\n\tscanning\n}", "import devices from \"./components/screens/devices/devices.js\";\n\nfunction routes(screens, sh_api) {\n\tscreens.add(\"/\", {\n\t\talias: \"home\",\n\t\trenderer: () => {\n\t\t\treturn `Hello world `;\n\t\t},\n\t\tiniter: scr => {\n\t\t\tsetTimeout(() => scr.ready(), 1000);\n\t\t\tsetTimeout(() => scr.error(\"Error\", \"Just testing\"), 2000);\n\t\t}\n\t});\n\n\tscreens.add(\"-\", {\n\t\talias: \"not-found-screen\",\n\t\trenderer: () => {\n\t\t\treturn `404 NOT FOUND `;\n\t\t},\n\t\tiniter: scr => {\n\t\t\tscr.ready();\n\t\t}\n\t});\n\n\tscreens.add(\"/devices\", devices.list(sh_api));\n\tscreens.add(\"/devices/scanning\", devices.scanning(sh_api));\n}\n\nexport {\n\troutes\n}", "function template(id, title, footer) {\n\treturn `\n\t\t\n\t`;\n}\n\nfunction init(modal, onready) {\n\tmodal.show = function() {\n\t\tdocument.querySelector(\"body\").append(modal);\n\n\t\tsetTimeout(() => {\n\t\t\tthis.classList.add(\"a-show\");\n\t\t}, 10);\n\t}\n\n\tmodal.close = function() {\n\t\tthis.classList.add(\"a-hide\");\n\t\tsetTimeout(() => {\n\t\t\tthis.remove();\n\t\t}, 300);\n\t}\n\n\tmodal.querySelector(\".modal-close\").addEventListener(\"click\", e => {\n\t\tmodal.close();\n\t});\n\n\tif(typeof onready == \"function\") {\n\t\tonready(modal);\n\t}\n\n\treturn modal;\n}\n\n\t/**\n\t * Create new modal window;\n\t * @param {string} id Uniq id (selector)\n\t * @param {string} title Display title\n\t * @param {object} props { body: modal => {}, actions => modal => {} }\n\t * @return {object} DOM object\n\t */\nfunction create(id, props) {\n\tconst title = props.title || \"\";\n\tconst footer = props.footer || \"\";\n\n\tconst div = document.createElement(\"div\");\n\tdiv.innerHTML = template(id, title, footer);\n\tconst modal = div.childNodes[1];\n\n\tconst modalBody = modal.querySelector(\".modal-body\");\n\tconst modalFooter = modal.querySelector(\".modal-footer\");\n\n\tif(typeof props.actions == \"function\") {\n\t\tconst actionsResult = props.actions(modal);\n\n\t\tif(typeof actionsResult[0] == \"object\") {\n\t\t\tconst actions = document.createElement(\"div\");\n\t\t\tactions.classList.add(\"actions\");\n\t\t\tfor(let actionElement of actionsResult) {\n\t\t\t\tactions.append(actionElement);\n\t\t\t}\n\n\t\t\tmodalFooter.append(actions);\n\t\t}\n\t}\n\n\tif(typeof props.body == \"function\") {\n\t\tconst bodyResult = props.body(modal);\n\n\t\tif(typeof bodyResult == \"object\") {\n\t\t\tmodalBody.append(bodyResult);\n\t\t} else if(typeof bodyResult == \"string\") {\n\t\t\tmodalBody.innerHTML = bodyResult;\n\t\t}\n\t}\n\n\treturn init(modal, props?.onready);\n}\n\nexport default {\n\tcreate\n}", "export default function confirmPopup(text, confirmedCb, canceledCb) {\n\tModals.create(\"confirm-popup\", {\n\t\ttitle: `Requires confirmation`,\n\t\tbody: modal => {\n\t\t\treturn `\n\t\t\t\t${text}
\n\t\t\t`;\n\t\t},\n\t\tactions: modal => {\n\t\t\tconst buttonNO = Helper.template.createElement(\"button\", { class: \"btn btn-primary\" }, \"NO\");\n\t\t\tconst buttonYES = Helper.template.createElement(\"button\", { class: \"btn btn-warning\" }, \"YES\");\n\n\t\t\tbuttonNO.addEventListener(\"click\", e => {\n\t\t\t\tmodal.close();\n\t\t\t\tcanceledCb();\n\t\t\t});\n\n\t\t\tbuttonYES.addEventListener(\"click\", e => {\n\t\t\t\tmodal.close();\n\t\t\t\tconfirmedCb();\n\t\t\t});\n\n\t\t\treturn [ buttonNO, buttonYES ];\n\t\t}\n\t}).show();\n}", "import { hud, navigationShow, navigationHide } from \"./components/hud.js\";\nimport { Screens } from \"./components/Screens.js\";\nimport Toasts from \"./components/toasts.js\"\nimport Helper from \"./components/helper.js\"\nimport { SmartHomeApi } from \"./sh/SmartHomeApi.js\";\nimport { routes } from \"./routes.js\";\nimport Modals from \"./components/modals.js\";\nimport confirmPopup from \"./components/confirm-popup.js\";\n\ndocument.addEventListener(\"DOMContentLoaded\", e => {\n\tconsole.log(\"App init\");\n\n\twindow.Toasts = Toasts;\n\twindow.Helper = Helper;\n\twindow.Modals = Modals;\n\twindow.confirmPopup = confirmPopup;\n\n\thud();\n\tconst sh_api = new SmartHomeApi({\n\t base_url: \"http://shswebclient.local\",\n\t token: \"YOUR_TOKEN\",\n\t timeout_ms: 3000,\n\t on_unauthorized: ({ error }) => console.log(\"auth problem:\", error),\n\t proxy_path: \"/proxy.php\",\n\t});\n\n\t// api.scripts.actions_list((err, data, meta) => console.log(data));\n\t// api.scripts.scopes_list((err, data, meta) => console.log(data));\n\t// api.devices.info(4, (err, data, meta) => console.log(data));\n\n\tconst screens = new Screens(\".screens\", \".load-screen\", \".error-screen\");\n\t\n\troutes(screens, sh_api);\n\n\tconsole.log(screens.getScreens());\n\n\tscreens.onSwitch((scr, alias) => {\n\t\tnavigationHide();\n\t});\n\n\tscreens.routing();\n\n\twindow.Screens = screens;\n});"],
- "mappings": "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",
- "names": ["navToggleBtn", "navigation", "reloadScreenBtn", "navigationShow", "navigationHide", "hud", "e", "Screens", "screensContainerSelector", "loaderSelector", "errorScreenSelector", "route", "screen", "__spreadValues", "alias", "_a", "screenContainer", "title", "text", "cb", "handler", "template", "type", "icon", "title", "text", "init", "toast", "props", "i", "e", "scr", "alias", "lifetimeInterval", "create", "div", "createSuccess", "createInfo", "createWarning", "createError", "toasts_default", "sidebarNav", "items", "listItems", "item", "aOpen", "aClose", "table", "caption", "columns", "data", "tfoot", "head", "totalColumns", "key", "body", "column", "foot", "createElement", "type", "props", "content", "node", "value", "createAlert", "deviceFieldsUnification", "map", "dataObj", "field", "btnLoadingState", "btn", "isLoading", "helper_default", "ScriptsApi", "core", "cb", "filename", "safe", "payload", "alias", "name", "DevicesApi", "core", "cb", "payload", "id", "safe", "AreasApi", "core", "cb", "area_id", "safe", "payload", "build_query", "params", "usp", "k", "v", "s", "join_url", "base_url", "path", "b", "p", "safe_json_parse", "text", "SmartHomeApi", "opts", "ScriptsApi", "DevicesApi", "AreasApi", "token", "proxy_path", "extra_query", "q", "__spreadValues", "method", "body", "cb", "callback", "url", "controller", "timeout_ms", "t", "headers", "payload", "res", "__async", "meta", "parsed", "data", "err", "_", "st", "e", "api_path", "deviceDetailsPopup", "device", "sh_api", "modal", "deviceProperties", "field", "buttonCancel", "buttonReboot", "buttonRemove", "e", "err", "data", "meta", "deviceSetupFormPopup", "device", "sh_api", "modal", "deviceProperties", "field", "buttonCancel", "e", "buttonSubmit", "inputs", "setupForm", "i", "inputElements", "textareaElement", "input", "err", "resp", "meta", "_a", "_b", "errFieldName", "alertContainer", "sidebarTemplate", "active", "list", "sh_api", "scr", "err", "resp", "meta", "preparedData", "device", "connectionState", "btn", "e", "btnReboot", "deviceId", "deviceName", "deviceAlias", "data", "deviceDetailsPopup", "scanning", "deviceSetupFormPopup", "devices_default", "routes", "screens", "sh_api", "scr", "devices_default", "template", "id", "title", "footer", "init", "modal", "onready", "e", "create", "props", "div", "modalBody", "modalFooter", "actionsResult", "actions", "actionElement", "bodyResult", "modals_default", "confirmPopup", "text", "confirmedCb", "canceledCb", "modal", "buttonNO", "buttonYES", "e", "e", "toasts_default", "helper_default", "modals_default", "confirmPopup", "hud", "sh_api", "SmartHomeApi", "error", "screens", "Screens", "routes", "scr", "alias", "navigationHide"]
+ "sources": ["../../src/js/components/hud.js", "../../src/js/components/Screens.js", "../../src/js/components/toasts.js", "../../src/js/components/helper.js", "../../src/js/sh/modules/ScriptsApi.js", "../../src/js/sh/modules/DevicesApi.js", "../../src/js/sh/modules/AreasApi.js", "../../src/js/sh/SmartHomeApi.js", "../../src/js/components/screens/devices/devices-funcs.js", "../../src/js/components/screens/devices/device-details-popup.js", "../../src/js/components/screens/devices/devices-list-screen.js", "../../src/js/components/screens/devices/device-setup-form-popup.js", "../../src/js/components/screens/devices/devices-scanning-screen.js", "../../src/js/components/screens/devices/devices.js", "../../src/js/routes.js", "../../src/js/components/modals.js", "../../src/js/components/confirm-popup.js", "../../src/js/index.js"],
+ "sourcesContent": ["let navToggleBtn;\nlet navigation;\nlet reloadScreenBtn;\n\nfunction navigationShow() {\n\tnavToggleBtn.dataset.navState = \"displayed\";\n\tnavToggleBtn.classList.remove(\"state-off\");\n\tnavToggleBtn.classList.add(\"state-on\");\n\n\tnavigation.classList.add(\"a-show\");\n}\n\nfunction navigationHide() {\n\tnavToggleBtn.dataset.navState = \"hidden\";\n\tnavToggleBtn.classList.remove(\"state-on\");\n\tnavToggleBtn.classList.add(\"state-off\");\n\n\tnavigation.classList.add(\"a-hide\");\n\tnavigation.classList.remove(\"a-show\");\n\n\tsetTimeout(() => {\n\t\tnavigation.classList.remove(\"a-hide\");\n\t}, 300);\n}\n\nfunction hud() {\n\tconsole.log(\"HUD init\");\n\n\tnavToggleBtn = document.querySelector(\".hud .nav-toggle\");\n\tnavigation = document.querySelector(\".hud .navigation\");\n\treloadScreenBtn = document.querySelector(\".hud .reload-screen\");\n\n\tnavToggleBtn.addEventListener(\"click\", e => {\n\t\tif(e.currentTarget.dataset.navState != \"displayed\") {\n\t\t\tnavigationShow();\n\t\t} else {\n\t\t\tnavigationHide();\n\t\t}\n\t});\n\n\treloadScreenBtn.addEventListener(\"click\", e => {\n\t\tScreens.reload();\n\t});\n}\n\nexport {\n\thud,\n\tnavigationShow,\n\tnavigationHide\n}", "export class Screens {\n\tconstructor(screensContainerSelector, loaderSelector, errorScreenSelector) {\n\t\tthis.screens = {};\n\t\tthis.routesMap = {};\n\t\tthis.currentScreen = null;\n\t\tthis.eventsHandlers = {\n\t\t\tswitch: [],\n\t\t\treload: []\n\t\t};\n\n\t\tthis.screensContainer = document.querySelector(screensContainerSelector);\n\t\tthis.loader = document.querySelector(loaderSelector);\n\t\tthis.errorScreen = document.querySelector(errorScreenSelector);\n\t\tconsole.log(\"Screens Init\");\n\t}\n\n\t/**\n\t * \u0414\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043C\u0430\u0440\u0448\u0440\u0443\u0442\u0430 \u0438 \u043E\u0431\u044A\u0435\u043A\u0442\u0430 \u0441 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0430\u043C\u0438 \u044D\u043A\u0440\u0430\u043D\u0430\n\t * @param {string} route Like `/path/name`\n\t * @param {void} screen {alias, renderer, initer}\n\t */\n\tadd(route, screen) {\n\t\tif(typeof screen != \"object\") {\n\t\t\treturn console.error(\"Screens: screens must be object\");\n\t\t}\n\t\t\n\t\tif(typeof screen?.alias == \"undefined\") {\n\t\t\treturn console.error(\"Screens: undefined alias\");\n\t\t}\n\n\t\tif(typeof screen?.renderer != \"function\") {\n\t\t\treturn console.error(\"Screens: renderer must be function\");\n\t\t}\n\n\t\tthis.screens[screen.alias] = {\n\t\t\troute: route,\n\t\t\t...screen\n\t\t};\n\n\t\tthis.routesMap[route] = screen.alias;\n\t}\n\n\tswitch(alias) {\t\t\n\t\tthis.runSwitchHandlers(alias);\n\t\tthis.hideErrorScreen();\n\t\tthis.showLoader();\n\t\tthis.currentScreen?.DOMObject.remove();\n\t\t\n\t\tif(typeof this.screens[alias] == \"undefined\") {\n\t\t\tconsole.error(`Screens: \"${alias}\" not found`);\n\t\t\treturn ;\n\t\t}\n\n\t\tthis.currentScreen = this.screens[alias];\n\t\t\n\t\tconst screenContainer = document.createElement(\"div\");\n\t\tscreenContainer.classList.add(\"screen\");\n\t\tscreenContainer.id = alias;\n\t\tscreenContainer.dataset.alias = alias;\n\t\tscreenContainer.innerHTML = this.currentScreen.renderer();\n\t\tthis.currentScreen.DOMObject = screenContainer;\n\t\tthis.screensContainer.append(this.currentScreen.DOMObject);\n\n\t\tthis.currentScreen.initer(this);\n\t}\n\n\treload() {\n\t\tif(!this.currentScreen) {\n\t\t\treturn ;\n\t\t}\n\n\t\tthis.runReloadHandlers(this.currentScreen.alias);\n\t\tthis.switch(this.currentScreen.alias);\n\t}\n\n\trouting() {\n\t\tsetInterval(() => {\n\t\t\tconst route = document.location.hash.split(\"#!\")[1];\n\t\t\tif(typeof route == \"undefined\" || route == \"\") {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tconst alias = (typeof this.routesMap[route] == \"undefined\") \n\t\t\t\t? \"not-found-screen\"\n\t\t\t\t: this.routesMap[route];\n\n\t\t\tif(!this.currentScreen || this.currentScreen.alias != alias) {\n\t\t\t\tthis.switch(alias);\n\t\t\t}\n\t\t}, 50);\n\t}\n\n\tready() {\n\t\tif(this.currentScreen == null) {\n\t\t\treturn;\n\t\t}\n\n\t\tif(!this.currentScreen.DOMObject) {\n\t\t\tthis.currentScreen.DOMObject = document.getElementsById(this.currentScreen.alias);\n\t\t}\n\n\t\tthis.hideLoader();\n\t\tthis.currentScreen.DOMObject.classList.add(\"a-show\");\n\t}\n\n\terror(title, text) {\n\t\tthis.currentScreen?.DOMObject.remove();\n\t\tthis.errorScreen.querySelector(\".error-title\").innerHTML = title;\n\t\tthis.errorScreen.querySelector(\".error-text\").innerHTML = text;\n\t\tthis.showErrorScreen();\n\t}\n\n\thideLoader() {\n\t\tthis.loader.classList.remove(\"a-show\");\n\t}\n\n\tshowLoader() {\n\t\tthis.loader.classList.add(\"a-show\");\n\t}\n\n\tshowErrorScreen() {\n\t\tthis.errorScreen.classList.add(\"a-show\");\n\t}\n\n\thideErrorScreen() {\n\t\tthis.errorScreen.classList.remove(\"a-show\");\n\t}\n\n\tgetScreens() {\n\t\treturn this.screens;\n\t}\n\n\tgetRoutesMap() {\n\t\treturn this.routesMap;\n\t}\n\n\tonSwitch(cb) {\n\t\tthis.eventsHandlers.switch.push(cb);\n\t}\n\n\tonReaload(cb) {\n\t\tthis.eventsHandlers.reload.push(cb);\n\t}\n\n\trunSwitchHandlers(alias) {\n\t\tfor(let handler of this.eventsHandlers.switch) {\n\t\t\thandler(this, alias);\n\t\t}\n\t}\n\n\trunReloadHandlers(alias) {\n\t\tfor(let handler of this.eventsHandlers.reload) {\n\t\t\thandler(this, alias);\n\t\t}\n\t}\n}", "function template(type, icon, title, text) {\n\treturn `\n\t\t\n\t
\n\t
${icon} ${title} \n\t
${text}
\n\t
\n\t
\u2715 \n\t
\n\t`;\n}\n\nfunction init(toast, props) {\n\tif(props?.alone) {\n\t\tdocument.querySelectorAll(\".toast\").forEach(i => i.close());\n\t}\n\n\ttoast.close = function() {\n\t\tthis.classList.add(\"a-hide\");\n\t\tsetTimeout(() => {\n\t\t\tthis.remove();\n\t\t}, 300);\n\t}\n\n\ttoast.querySelector(\".toast-close\").addEventListener(\"click\", e => {\n\t\ttoast.close();\n\t});\n\n\ttoast.show = function() {\n\t\tdocument.querySelector(\"body\").append(toast);\n\n\t\tsetTimeout(() => {\n\t\t\ttoast.classList.add(\"a-show\");\n\t\t}, 10);\n\t}\n\n\tScreens.onSwitch((scr, alias) => {\n\t\tsetTimeout(() => {\n\t\t\ttoast?.close();\n\t\t}, 10000);\n\t});\n\n\ttoast.addEventListener(\"mouseover\", e => toast.ishovered = true);\n\ttoast.addEventListener(\"mouseout\", e => toast.ishovered = false);\n\n\tif(props?.lifetime) {\n\t\tconsole.log(props);\n\t\tconst lifetimeInterval = setInterval(() => {\n\t\t\tif(!toast.ishovered) {\n\t\t\t\ttoast.close();\n\t\t\t\tclearInterval(lifetimeInterval);\n\t\t\t}\n\t\t}, props?.lifetime);\n\t}\n\n\treturn toast;\n}\n\nfunction create(type, icon, title, text, props) {\n\tconst div = document.createElement(\"div\");\n\tdiv.innerHTML = template(type, icon, title, text);\n\n\treturn init(div.childNodes[1], props);\n}\n\nfunction createSuccess(title, text, props) {\n\tif(typeof props == \"undefined\") {\n\t\tprops = {};\n\t}\n\n\tif(typeof props.lifetime == \"undefined\") {\n\t\tprops.lifetime = 4000;\n\t}\n\n\tif(typeof props.alone == \"undefined\") {\n\t\tprops.alone = true;\n\t}\n\n\treturn create(\n\t\t\"success\", \n\t\t` `, \n\t\ttitle, \n\t\ttext,\n\t\tprops\n\t);\n}\n\nfunction createInfo(title, text, props) {\n\treturn create(\n\t\t\"info\", \n\t\t` `, \n\t\ttitle, \n\t\ttext,\n\t\tprops\n\t);\n}\n\nfunction createWarning(title, text, props) {\n\treturn create(\n\t\t\"warning\", \n\t\t` `, \n\t\ttitle, \n\t\ttext,\n\t\tprops\n\t);\n}\n\nfunction createError(title, text, props) {\n\treturn create(\n\t\t\"danger\", \n\t\t` `, \n\t\ttitle, \n\t\ttext,\n\t\tprops\n\t);\n}\n\nexport default {\n create,\n createInfo,\n createSuccess,\n createWarning,\n createError,\n \"createDanger\": createError\n};", "function sidebarNav(items) {\n\tlet listItems = \"\";\n\n\tfor(let item of items) {\n\t\tlet aOpen = \"\";\n\t\tlet aClose = \"\";\n\t\tif(item.route) {\n\t\t\taOpen = ``;\n\t\t\taClose = ` `;\n\t\t}\n\n\t\tlistItems += `\n\t\t\t\n\t\t\t\t${aOpen}${item.content}${aClose}\n\t\t\t \n\t\t`;\n\t}\n\n\treturn `\n\t\t\n\t`;\n}\n\nfunction table(caption, columns, data, tfoot) {\n\tlet head = ``;\n\tlet totalColumns = 0;\n\tfor(let key in columns) {\n\t\thead += `${columns[key]} `;\n\t\ttotalColumns++;\n\t}\n\thead += \" \";\n\n\tlet body = ``;\n\tfor(let item of data) {\n\t\tbody += ``;\n\t\tfor(let column in columns) {\n\t\t\tbody += `${item[column]} `;\n\t\t}\n\t\tbody += ` `;\n\t}\n\n\tlet foot = \"\";\n\tif(typeof tfoot != \"undefined\") {\n\t\tfoot = `\n\t\t\t\n\t\t`\n\t}\n\n\treturn `\n\t\t\n\t\t\t${caption} \n\t\t\t${head} \n\t\t\t${body} \n\t\t\t${foot}\n\t\t
\n\t`;\n}\n\nfunction createElement(type, props, content) {\n\tconst node = document.createElement(type);\n\n\tfor (const [key, value] of Object.entries(props)) {\n\t\tif (key === \"class\") {\n\t\t\tnode.className = value;\n\t\t} else if (key === \"dataset\") {\n\t\t\tObject.assign(node.dataset, value);\n\t\t} else {\n\t\t\tnode.setAttribute(key, value);\n\t\t}\n\t}\n\n\tnode.innerHTML = (typeof content != \"undefined\") ? content : \"\";\n\treturn node; \n}\n\nfunction createAlert(type, content) {\n\tif([\"primary\", \"success\", \"secondary\", \"info\", \"warning\", \"error\", \"danger\"].indexOf(type) < 0) {\n\t\treturn console.error(\"createAlert()\", \"Error of type: \" + type);\n\t}\n\n\treturn createElement(\"div\", {\n\t\tclass: `alert alert-${type}`,\n\t}, content);\n}\n\nfunction deviceFieldsUnification(data) {\n\tconst map = {\n\t\t\"device_name\": \"name\",\n\t\t\"device_hard_id\": \"device_id\",\n\t\t\"device_ip\": \"ip\",\n\t\t\"device_type\": \"type\",\n\t\t\"ip_address\": \"ip\",\n\t\t\"mac_address\": \"mac\",\n\t\t\"device_mac\": \"mac\",\n\t\t\"core_version\": \"firmware_core_version\"\n\t};\n\n\tconst dataObj = {};\n\n\tfor(let field in data) {\n\t\tif(typeof map[field] != \"undefined\") {\n\t\t\tdataObj[ map[field] ] = data[field];\n\t\t\tcontinue;\n\t\t}\n\n\t\tdataObj[field] = data[field];\n\t}\n\n\treturn dataObj;\n}\n\nfunction btnLoadingState(btn, isLoading) {\n\tif(btn?.isLoading == isLoading) {\n\t\treturn false;\n\t}\n\n\tif(isLoading) {\n\t\tbtn.isLoading = true;\n\t\tbtn.originalContent = btn.innerHTML;\n\t\tif(btn.classList.contains(\"with-icon\")) {\n\t\t\tbtn.originalWithIcon = true;\n\t\t} else {\n\t\t\tbtn.classList.add(\"with-icon\");\n\t\t}\n\n\t\tbtn.classList.add(\"loading-state\");\n\t\tbtn.setAttribute(\"disabled\", \"disabled\");\n\t\tbtn.innerHTML = ` Loading`;\n\t} else {\n\t\tbtn.isLoading = false;\n\t\tif(!btn.originalContent) {\n\t\t\treturn false;\n\t\t}\n\t\tbtn.removeAttribute(\"disabled\");\n\t\tbtn.classList.remove(\"loading-state\");\n\t\tif(!btn.originalWithIcon) {\n\t\t\tbtn.classList.remove(\"with-icon\");\n\t\t}\n\t\tbtn.innerHTML = btn.originalContent;\n\t}\n\n\treturn btn;\n}\n\nexport default {\n\ttemplate: {\n\t\tsidebarNav,\n\t\ttable,\n\t\tcreateElement,\n\t\tcreateAlert\n\t},\n\tunification: {\n\t\tdeviceFieldsUnification\n\t},\n\tstates: {\n\t\tbtnLoadingState\n\t}\n}", "/* =========================\n Scripts module\n========================= */\n\nexport class ScriptsApi {\n\tconstructor(core) {\n\t\tthis.core = core;\n\t}\n\n\t// GET /api/v1/scripts/actions/list\n\tactions_list(cb) {\n\t\treturn this.core.api_get(\"/api/v1/scripts/actions/list\", cb);\n\t}\n\n\t// GET /api/v1/scripts/scopes/list\n\tscopes_list(cb) {\n\t\treturn this.core.api_get(\"/api/v1/scripts/scopes/list\", cb);\n\t}\n\n\t// GET /api/v1/scripts/regular/list\n\tregular_list(cb) {\n\t\treturn this.core.api_get(\"/api/v1/scripts/regular/list\", cb);\n\t}\n\n\t// GET /api/v1/scripts/scopes/name/{{filename}}\n\tscope_get_by_filename(filename, cb) {\n\t\tconst safe = encodeURIComponent(String(filename || \"\"));\n\t\treturn this.core.api_get(`/api/v1/scripts/scopes/name/${safe}`, cb, {\n\t\t\t// \u0442\u0443\u0442 \u0441\u0435\u0440\u0432\u0435\u0440 \u043C\u043E\u0436\u0435\u0442 \u0432\u0435\u0440\u043D\u0443\u0442\u044C PHP-\u043A\u043E\u0434 \u0442\u0435\u043A\u0441\u0442\u043E\u043C; request \u0443\u043C\u0435\u0435\u0442 \u044D\u0442\u043E \u043F\u0435\u0440\u0435\u0436\u0438\u0442\u044C\n\t\t});\n\t}\n\n\t// POST /api/v1/scripts/scopes/new\n\tscope_create(payload, cb) {\n\t\t// payload: { alias, filename, path }\n\t\treturn this.core.api_post(\"/api/v1/scripts/scopes/new\", payload, cb);\n\t}\n\n\t// POST /api/v1/scripts/scopes/update\n\tscope_update(payload, cb) {\n\t\t// payload: { name, filename, path }\n\t\treturn this.core.api_post(\"/api/v1/scripts/scopes/update\", payload, cb);\n\t}\n\n\t// GET /api/v1/scripts/actions/alias/{{alias}}/enable\n\taction_enable(alias, cb) {\n\t\tconst safe = encodeURIComponent(String(alias || \"\"));\n\t\treturn this.core.api_get(`/api/v1/scripts/actions/alias/${safe}/enable`, cb);\n\t}\n\n\t// GET /api/v1/scripts/actions/alias/{{alias}}/disable\n\taction_disable(alias, cb) {\n\t\tconst safe = encodeURIComponent(String(alias || \"\"));\n\t\treturn this.core.api_get(`/api/v1/scripts/actions/alias/${safe}/disable`, cb);\n\t}\n\n\t// GET /api/v1/scripts/actions/regular/{{alias}}/enable\n\tregular_enable(alias, cb) {\n\t\tconst safe = encodeURIComponent(String(alias || \"\"));\n\t\treturn this.core.api_get(`/api/v1/scripts/actions/regular/${safe}/enable`, cb);\n\t}\n\n\t// GET /api/v1/scripts/actions/regular/{{alias}}/disable\n\tregular_disable(alias, cb) {\n\t\tconst safe = encodeURIComponent(String(alias || \"\"));\n\t\treturn this.core.api_get(`/api/v1/scripts/actions/regular/${safe}/disable`, cb);\n\t}\n\n\t// GET /api/v1/scripts/actions/scope/{{name}}/enable\n\tscope_enable(name, cb) {\n\t\tconst safe = encodeURIComponent(String(name || \"\"));\n\t\treturn this.core.api_get(`/api/v1/scripts/actions/scope/${safe}/enable`, cb);\n\t}\n\n\t// GET /api/v1/scripts/actions/scope/{{name}}/disable\n\tscope_disable(name, cb) {\n\t\tconst safe = encodeURIComponent(String(name || \"\"));\n\t\treturn this.core.api_get(`/api/v1/scripts/actions/scope/${safe}/disable`, cb);\n\t}\n\n\t// GET /api/v1/scripts/scopes/name/{{name}}/remove\n\tscope_remove(name, cb) {\n\t\tconst safe = encodeURIComponent(String(name || \"\"));\n\t\treturn this.core.api_get(`/api/v1/scripts/scopes/name/${safe}/remove`, cb);\n\t}\n\n\t// POST /api/v1/scripts/actions/run\n\trun(payload, cb) {\n\t\t// payload: { alias, params: {...} }\n\t\treturn this.core.api_post(\"/api/v1/scripts/actions/run\", payload, cb);\n\t}\n}", "/* =========================\n Devices module\n========================= */\n\nexport class DevicesApi {\n\tconstructor(core) {\n\t\tthis.core = core;\n\t}\n\n\t// GET /api/v1/devices/list\n\tlist(cb) {\n\t\treturn this.core.api_get(\"/api/v1/devices/list\", cb);\n\t}\n\n\t// GET /api/v1/devices/scanning/setup\n\tscanning_setup(cb) {\n\t\treturn this.core.api_get(\"/api/v1/devices/scanning/setup\", cb);\n\t}\n\n\t// GET /api/v1/devices/scanning/all\n\tscanning_all(cb) {\n\t\treturn this.core.api_get(\"/api/v1/devices/scanning/all\", cb);\n\t}\n\n\t// POST /api/v1/devices/setup/new-device\n\tsetup_new_device(payload, cb) {\n\t\t// payload: { device_ip, alias, name, description }\n\t\treturn this.core.api_post(\"/api/v1/devices/setup/new-device\", payload, cb);\n\t}\n\n\t// GET /api/v1/devices/id/{{id}}/info\n\tinfo(id, cb) {\n\t\tconst safe = encodeURIComponent(String(id));\n\t\treturn this.core.api_get(`/api/v1/devices/id/${safe}/info`, cb);\n\t}\n\n\t// GET /api/v1/devices/id/{{id}}\n\tget(id, cb) {\n\t\tconst safe = encodeURIComponent(String(id));\n\t\treturn this.core.api_get(`/api/v1/devices/id/${safe}`, cb);\n\t}\n\n\t// GET /api/v1/devices/id/{{id}}/status\n\tstatus(id, cb) {\n\t\tconst safe = encodeURIComponent(String(id));\n\t\treturn this.core.api_get(`/api/v1/devices/id/${safe}/status`, cb);\n\t}\n\n\t// POST /api/v1/devices/action\n\taction(payload, cb) {\n\t\t// payload: { device_id, action, params }\n\t\treturn this.core.api_post(\"/api/v1/devices/action\", payload, cb);\n\t}\n\n\t// GET /api/v1/devices/id/{{id}}/remove\n\tremove(id, cb) {\n\t\tconst safe = encodeURIComponent(String(id));\n\t\treturn this.core.api_get(`/api/v1/devices/id/${safe}/remove`, cb);\n\t}\n\n\t// GET /api/v1/devices/id/{{id}}/reboot\n\treboot(id, cb) {\n\t\tconst safe = encodeURIComponent(String(id));\n\t\treturn this.core.api_get(`/api/v1/devices/id/${safe}/reboot`, cb);\n\t}\n}\n", "export class AreasApi {\n\tconstructor(core) {\n\t\tthis.core = core;\n\t}\n\n\t// GET /api/v1/areas/list\n\tlist(cb) {\n\t\treturn this.core.api_get(\"/api/v1/areas/list\", cb);\n\t}\n\n\t// GET /api/v1/areas/id/{{area_id}}/list\n\tinner_list(area_id, cb) {\n\t\tconst safe = encodeURIComponent(String(area_id));\n\t\treturn this.core.api_get(`/api/v1/areas/id/${safe}/list`, cb);\n\t}\n\n\t// POST /api/v1/areas/new-area\n\tnew_area(payload, cb) {\n\t\t// payload: { type, alias, display_name }\n\t\treturn this.core.api_post(\"/api/v1/areas/new-area\", payload, cb);\n\t}\n\n\t// GET /api/v1/areas/id/{{area_id}}/remove\n\tremove(area_id, cb) {\n\t\tconst safe = encodeURIComponent(String(area_id));\n\t\treturn this.core.api_get(`/api/v1/areas/id/${safe}/remove`, cb);\n\t}\n\n\t// POST /api/v1/areas/place-in-area\n\tplace_in_area(payload, cb) {\n\t\t// payload: { target_area_id, place_in_area_id }\n\t\treturn this.core.api_post(\"/api/v1/areas/place-in-area\", payload, cb);\n\t}\n\n\t// POST /api/v1/areas/update-display-name\n\tupdate_display_name(payload, cb) {\n\t\t// payload: { area_id, display_name }\n\t\treturn this.core.api_post(\"/api/v1/areas/update-display-name\", payload, cb);\n\t}\n\n\t// POST /api/v1/areas/update-alias\n\tupdate_alias(payload, cb) {\n\t\t// payload: { area_id, new_alias }\n\t\treturn this.core.api_post(\"/api/v1/areas/update-alias\", payload, cb);\n\t}\n\n\t// GET /api/v1/areas/id/{{area_id}}/devices\n\tdevices(area_id, cb) {\n\t\tconst safe = encodeURIComponent(String(area_id));\n\t\treturn this.core.api_get(`/api/v1/areas/id/${safe}/devices`, cb);\n\t}\n\n\t// GET /api/v1/areas/id/{{area_id}}/unassign-from-area\n\tunassign_from_area(area_id, cb) {\n\t\tconst safe = encodeURIComponent(String(area_id));\n\t\treturn this.core.api_get(`/api/v1/areas/id/${safe}/unassign-from-area`, cb);\n\t}\n\n\t// GET /api/v1/areas/types/list\n\ttypes_list(cb) {\n\t\treturn this.core.api_get(\"/api/v1/areas/types/list\", cb);\n\t}\n\n\t// GET /api/v1/areas/reboot_devices\n\t// GET /api/v1/areas/id/{{area_id}}/reboot_devices\n\treboot_devices(area_id, cb) {\n\t\tif (area_id === undefined || area_id === null) {\n\t\t\treturn this.core.api_get(\"/api/v1/areas/reboot_devices\", cb);\n\t\t}\n\t\tconst safe = encodeURIComponent(String(area_id));\n\t\treturn this.core.api_get(`/api/v1/areas/id/${safe}/reboot_devices`, cb);\n\t}\n}", "/**\n * smart_home_api.js\n *\n * \u041C\u0438\u043D\u0438\u043C\u0430\u043B\u044C\u043D\u0430\u044F JS-\u0431\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0430 \u0434\u043B\u044F REST-\u0437\u0430\u043F\u0440\u043E\u0441\u043E\u0432 \u043A \u0441\u0435\u0440\u0432\u0435\u0440\u0443 (callback-style).\n * - \u0410\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F: Bearer token (\u0438\u043B\u0438 \u043A\u0430\u0441\u0442\u043E\u043C\u043D\u044B\u0439 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A, \u0435\u0441\u043B\u0438 \u043F\u043E\u043C\u0435\u043D\u044F\u0435\u0448\u044C)\n * - \u0415\u0434\u0438\u043D\u0430\u044F \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u043A\u0430 \u043E\u0448\u0438\u0431\u043E\u043A: \u0441\u0435\u0442\u0435\u0432\u044B\u0435, \u0442\u0430\u0439\u043C\u0430\u0443\u0442, \u043D\u0435-JSON, \u0441\u0442\u0430\u0442\u0443\u0441=false/error\n * - \u041C\u043E\u0434\u0443\u043B\u0438: \u0441\u0435\u0439\u0447\u0430\u0441 \u0442\u043E\u043B\u044C\u043A\u043E Scripts, \u043E\u0441\u0442\u0430\u043B\u044C\u043D\u044B\u0435 \u043F\u043E \u0430\u043D\u0430\u043B\u043E\u0433\u0438\u0438\n */\n\nimport { ScriptsApi } from \"./modules/ScriptsApi.js\";\nimport { DevicesApi } from \"./modules/DevicesApi.js\";\nimport { AreasApi } from \"./modules/AreasApi.js\";\n\n/* =========================\n Utils\n========================= */\n\nfunction build_query(params) {\n\tif (!params || typeof params !== \"object\") return \"\";\n\tconst usp = new URLSearchParams();\n\tObject.entries(params).forEach(([k, v]) => {\n\t\tif (v === undefined || v === null) return;\n\t\tusp.append(k, String(v));\n\t});\n\tconst s = usp.toString();\n\treturn s ? `?${s}` : \"\";\n}\n\nfunction join_url(base_url, path) {\n\tconst b = String(base_url || \"\").replace(/\\/+$/, \"\");\n\tconst p = String(path || \"\").replace(/^\\/+/, \"\");\n\treturn `${b}/${p}`;\n}\n\nfunction safe_json_parse(text) {\n\ttry {\n\t\treturn { ok: true, data: JSON.parse(text) };\n\t} catch (e) {\n\t\treturn { ok: false, error: e };\n\t}\n}\n\n/* =========================\n Core client\n========================= */\n\nexport class SmartHomeApi {\n\t/**\n\t * @param {Object} opts\n\t * @param {string} opts.base_url - \u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440: http://192.168.2.101\n\t * @param {string} [opts.token] - \u0442\u043E\u043A\u0435\u043D \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438\n\t * @param {number} [opts.timeout_ms=15000]\n\t * @param {Object} [opts.default_headers]\n\t * @param {Function} [opts.on_unauthorized] - cb(details)\n\t * @param {string} [opts.proxy_path] \u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440 \"/proxy.php\" (\u0432\u043A\u043B\u044E\u0447\u0430\u0435\u0442 \u0430\u0432\u0442\u043E-\u043F\u0440\u043E\u043A\u0441\u0438)\n\t */\n\tconstructor(opts) {\n\t\tthis.base_url = opts?.base_url || \"\";\n\t\tthis.token = opts?.token || \"\";\n\t\tthis.timeout_ms = Number.isFinite(opts?.timeout_ms) ? opts.timeout_ms : 15000;\n\t\tthis.default_headers = opts?.default_headers || {};\n\t\tthis.on_unauthorized = typeof opts?.on_unauthorized === \"function\" ? opts.on_unauthorized : null;\n\t\tthis.proxy_path = opts?.proxy_path || \"\"; // \"\" => \u0431\u0435\u0437 \u043F\u0440\u043E\u043A\u0441\u0438\n\n\t\t// modules\n\t\tthis.scripts = new ScriptsApi(this);\n\t\tthis.devices = new DevicesApi(this);\n\t\tthis.areas = new AreasApi(this);\n\t}\n\n\tset_base_url(base_url) {\n\t\tthis.base_url = base_url || \"\";\n\t}\n\n\tset_token(token) {\n\t\tthis.token = token || \"\";\n\t}\n\n\tset_proxy_path(proxy_path) {\n\t\tthis.proxy_path = proxy_path || \"\";\n\t}\n\n\t_wrap_path(path, extra_query) {\n\t\t// \u0415\u0441\u043B\u0438 \u0432\u043A\u043B\u044E\u0447\u0451\u043D \u043F\u0440\u043E\u043A\u0441\u0438 \u2014 \u0445\u043E\u0434\u0438\u043C \u043D\u0430 /proxy.php?path=&...\n\t\tif (!this.proxy_path) {\n\t\t\tif (!extra_query) return path;\n\t\t\treturn `${path}${build_query(extra_query)}`;\n\t\t}\n\n\t\tconst q = { path, ...(extra_query || {}) };\n\t\treturn `${this.proxy_path}${build_query(q)}`;\n\t}\n\n\t/**\n\t * \u0423\u043D\u0438\u0444\u0438\u0446\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0437\u0430\u043F\u0440\u043E\u0441.\n\t *\n\t * cb(err, data, meta)\n\t * - err: { type, message, status_code?, raw?, details? }\n\t * - data: \u0440\u0430\u0441\u043F\u0430\u0440\u0441\u0435\u043D\u043D\u044B\u0439 json (\u0438\u043B\u0438 string, \u0435\u0441\u043B\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u043D\u0435 \u0432\u0435\u0440\u043D\u0443\u043B json)\n\t * - meta: { url, method, status_code, headers }\n\t */\n\trequest(method, path, body, cb, opts) {\n\t\tconst callback = typeof cb === \"function\" ? cb : () => {};\n\t\tconst url = join_url(this.base_url, path);\n\n\t\tconst controller = new AbortController();\n\t\tconst timeout_ms = Number.isFinite(opts?.timeout_ms) ? opts.timeout_ms : this.timeout_ms;\n\n\t\tconst t = setTimeout(() => controller.abort(), timeout_ms);\n\n\t\tconst headers = {\n\t\t\t...this.default_headers,\n\t\t\t...(opts?.headers || {}),\n\t\t};\n\n\t\t// \u0410\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F (\u043F\u043E\u0434\u0441\u0442\u0440\u043E\u0439, \u0435\u0441\u043B\u0438 \u0443 \u0442\u0435\u0431\u044F \u0434\u0440\u0443\u0433\u043E\u0439 \u0444\u043E\u0440\u043C\u0430\u0442)\n\t\tif (this.token) headers[\"Authorization\"] = `Bearer ${this.token}`;\n\n\t\tlet payload = undefined;\n\t\tif (body !== undefined && body !== null) {\n\t\t\theaders[\"Content-Type\"] = \"application/json\";\n\t\t\tpayload = JSON.stringify(body);\n\t\t}\n\n\t\tfetch(url, {\n\t\t\tmethod,\n\t\t\theaders,\n\t\t\tbody: payload,\n\t\t\tsignal: controller.signal,\n\t\t})\n\t\t\t.then(async (res) => {\n\t\t\t\tclearTimeout(t);\n\n\t\t\t\tconst meta = {\n\t\t\t\t\turl,\n\t\t\t\t\tmethod,\n\t\t\t\t\tstatus_code: res.status,\n\t\t\t\t\theaders: res.headers,\n\t\t\t\t};\n\n\t\t\t\tconst text = await res.text();\n\t\t\t\tconst parsed = safe_json_parse(text);\n\t\t\t\tconst data = parsed.ok ? parsed.data : text;\n\n\t\t\t\t// HTTP-level \u043E\u0448\u0438\u0431\u043A\u0438\n\t\t\t\tif (!res.ok) {\n\t\t\t\t\tconst err = {\n\t\t\t\t\t\ttype: \"http_error\",\n\t\t\t\t\t\tmessage: `HTTP ${res.status}`,\n\t\t\t\t\t\tstatus_code: res.status,\n\t\t\t\t\t\traw: data,\n\t\t\t\t\t};\n\n\t\t\t\t\tif (res.status === 401 || res.status === 403) {\n\t\t\t\t\t\tif (this.on_unauthorized) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tthis.on_unauthorized({ error: err, meta });\n\t\t\t\t\t\t\t} catch (_) {}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn callback(err, null, meta);\n\t\t\t\t}\n\n\t\t\t\t// API-level \u043E\u0448\u0438\u0431\u043A\u0438 (\u043F\u043E \u0442\u0432\u043E\u0438\u043C \u043F\u0440\u0438\u043C\u0435\u0440\u0430\u043C \u0431\u044B\u0432\u0430\u0435\u0442 status:false \u0438\u043B\u0438 status:\"error\")\n\t\t\t\tif (parsed.ok && data && typeof data === \"object\") {\n\t\t\t\t\tconst st = data.status;\n\t\t\t\t\tif (st === false || st === \"error\") {\n\t\t\t\t\t\tconst err = {\n\t\t\t\t\t\t\ttype: \"api_error\",\n\t\t\t\t\t\t\tmessage: data.message || \"API error\",\n\t\t\t\t\t\t\tstatus_code: res.status,\n\t\t\t\t\t\t\traw: data,\n\t\t\t\t\t\t\tfield: data.field,\n\t\t\t\t\t\t};\n\t\t\t\t\t\treturn callback(err, null, meta);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn callback(null, data, meta);\n\t\t\t})\n\t\t\t.catch((e) => {\n\t\t\t\tclearTimeout(t);\n\n\t\t\t\tconst is_abort = e && (e.name === \"AbortError\" || String(e).includes(\"AbortError\"));\n\t\t\t\tconst err = is_abort\n\t\t\t\t\t? { type: \"timeout\", message: `Timeout after ${timeout_ms}ms` }\n\t\t\t\t\t: { type: \"network_error\", message: e?.message || \"Network error\", details: e };\n\n\t\t\t\treturn callback(err, null, { url, method, status_code: 0, headers: null });\n\t\t\t});\n\t}\n\n\tget(path, cb, opts) {\n\t\treturn this.request(\"GET\", path, null, cb, opts);\n\t}\n\n\tpost(path, body, cb, opts) {\n\t\treturn this.request(\"POST\", path, body, cb, opts);\n\t}\n\n\tapi_get(api_path, cb, extra_query, opts) {\n\t\treturn this.get(this._wrap_path(api_path, extra_query), cb, opts);\n\t}\n\n\tapi_post(api_path, body, cb, extra_query, opts) {\n\t\treturn this.post(this._wrap_path(api_path, extra_query), body, cb, opts);\n\t}\n}\n\n/* =========================\n Example usage\n========================= */\n\n// import { SmartHomeApi } from \"./smart_home_api.js\";\n//\n// const api = new SmartHomeApi({\n// base_url: \"http://192.168.2.101\",\n// token: \"YOUR_TOKEN\",\n// timeout_ms: 20000,\n// on_unauthorized: ({ error }) => console.log(\"auth problem:\", error),\n// });\n//\n// api.scripts.actions_list((err, res) => {\n// if (err) return console.error(\"actions_list error:\", err);\n// console.log(\"actions:\", res);\n// });\n//\n// api.scripts.run({ alias: \"script_alias\", params: { x: 1 } }, (err, res) => {\n// if (err) return console.error(\"run error:\", err);\n// console.log(\"run result:\", res);\n// });\n", "function sidebarTemplate(active) {\n\treturn Helper.template.sidebarNav([\n\t\t{\n\t\t\tcontent: ` Devices `,\n\t\t\troute: \"/#!/devices\",\n\t\t\tis_active: active == \"devices\"\n\t\t},\n\t\t{\n\t\t\tcontent: ` Scanning `,\n\t\t\troute: \"/#!/devices/scanning\",\n\t\t\tis_active: active == \"scanning\"\n\t\t}\n\t]);\n}\n\nexport {\n\tsidebarTemplate\n}", "export function deviceDetailsPopup(device, sh_api) {\n\tconsole.log(device);\n\n\treturn Modals.create(\"device-popup\", {\n\t\ttitle: `Device ${device.name}`,\n\t\tbody: modal => {\n\t\t\tlet deviceProperties = \"\";\n\t\t\tfor(let field in device) {\n\t\t\t\tdeviceProperties += `\n\t\t\t\t\t\n\t\t\t\t\t\t${field}: \n\t\t\t\t\t\t${device[field]} \n\t\t\t\t\t \n\t\t\t\t`;\n\t\t\t}\n\n\t\t\treturn `\n\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t${deviceProperties}\n\t\t\t\t\t\t \n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t`;\n\t\t},\n\t\tactions: modal => {\n\t\t\tconst buttonCancel = Helper.template.createElement(\"button\", {\n\t\t\t\tclass: \"btn btn-primary\"\n\t\t\t}, \"Close\");\n\n\t\t\tconst buttonReboot = Helper.template.createElement(\"button\", {\n\t\t\t\tclass: \"btn btn-warning with-icon\"\n\t\t\t}, ' Reboot');\n\n\t\t\tconst buttonRemove = Helper.template.createElement(\"button\", {\n\t\t\t\tclass: \"btn btn-danger with-icon\"\n\t\t\t}, ' Remove');\n\n\t\t\tbuttonCancel.addEventListener(\"click\", e => {\n\t\t\t\tmodal.close();\n\t\t\t});\n\n\t\t\tbuttonReboot.addEventListener(\"click\", e => {\n\t\t\t\tif(buttonReboot.getAttribute(\"disabled\")) {\n\t\t\t\t\treturn ;\n\t\t\t\t}\n\n\t\t\t\tHelper.states.btnLoadingState(buttonReboot, true);\n\t\t\t\tsh_api.devices.reboot(\n\t\t\t\t\tdevice.id,\n\t\t\t\t\t(err, data, meta) => {\n\t\t\t\t\t\tHelper.states.btnLoadingState(buttonReboot, false);\n\t\t\t\t\t\tconsole.log(\"Reboot done\");\n\n\t\t\t\t\t\tmodal.close();\n\n\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\tif(data) {\n\t\t\t\t\t\t\t\tToasts.createSuccess(\n\t\t\t\t\t\t\t\t\t\"Reboot successful\",\n\t\t\t\t\t\t\t\t\t`Device: ${device.name} \n\t\t\t\t\t\t\t\t\tAlias: ${device.alias} `\n\t\t\t\t\t\t\t\t).show();\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tToasts.createError(\n\t\t\t\t\t\t\t\t\t\"Reboot failed\",\n\t\t\t\t\t\t\t\t\t`Device: ${device.name} \n\t\t\t\t\t\t\t\t\tAlias: ${device.alias} `\n\t\t\t\t\t\t\t\t).show();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, 300);\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tbuttonRemove.addEventListener(\"click\", e => {\n\t\t\t\tif(buttonRemove.getAttribute(\"disabled\")) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tHelper.states.btnLoadingState(buttonRemove, true);\n\t\t\t\tconfirmPopup(\n\t\t\t\t\t\"Are you sure you want to remove this device?\", \n\t\t\t\t\t() => {\n\t\t\t\t\t\tsh_api.devices.remove(\n\t\t\t\t\t\t\tdevice.id,\n\t\t\t\t\t\t\t(err, data, meta) => {\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tHelper.states.btnLoadingState(buttonRemove, false);\n\t\t\t\t\t\t\t\tconsole.log(\"Was removed\");\n\n\t\t\t\t\t\t\t\tmodal.close();\n\n\t\t\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\t\t\tToasts.createSuccess(\n\t\t\t\t\t\t\t\t\t\t\"Removed\",\n\t\t\t\t\t\t\t\t\t\t`\n\t\t\t\t\t\t\t\t\t\tDevice: ${device.name} \n\t\t\t\t\t\t\t\t\t\tAlias: ${device.alias} \n\t\t\t\t\t\t\t\t\t\tIP: ${device.ip} \n\t\t\t\t\t\t\t\t\t\t`\n\t\t\t\t\t\t\t\t\t).show();\n\t\t\t\t\t\t\t\t}, 300);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t);\n\t\t\t\t}, \n\t\t\t\t() => {\n\t\t\t\t\tHelper.states.btnLoadingState(buttonRemove, false);\n\t\t\t\t\tconsole.log(\"CANCELED\");\n\t\t\t\t});\n\t\t\t});\n\n\t\t\treturn [ buttonCancel, buttonReboot, buttonRemove ];\n\t\t}\n\t});\n}", "import { sidebarTemplate } from \"./devices-funcs.js\";\nimport { deviceDetailsPopup } from \"./device-details-popup.js\";\n\nfunction list(sh_api) {\n\treturn {\n\t\talias: \"devices\",\n\t\trenderer: () => {\n\t\t\tconst sidebar = sidebarTemplate(\"devices\");\n\n\t\t\treturn `\n\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t${sidebar}\n\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t`;\n\t\t},\n\n\t\tiniter: scr => {\n\t\t\tsh_api.devices.list((err, resp, meta) => {\n\t\t\t\tconsole.log(\"sh_api.devices.list\", err, resp, meta);\n\n\t\t\t\tif(meta.status_code != 200) {\n\t\t\t\t\treturn scr.error(\"Server API ERROR\", \"\");\n\t\t\t\t}\n\n\t\t\t\tconst preparedData = [];\n\t\t\t\tfor(let device of resp.data.devices) {\n\t\t\t\t\tdevice = Helper.unification.deviceFieldsUnification(device);\n\n\t\t\t\t\tconst connectionState = device.connection_state == \"active\"\n\t\t\t\t\t\t? `Online `\n\t\t\t\t\t\t: `Offline `;\n\n\t\t\t\t\tpreparedData.push({\n\t\t\t\t\t\tdeviceName: device.name,\n\t\t\t\t\t\talias: device.alias,\n\t\t\t\t\t\tstatus: connectionState,\n\t\t\t\t\t\tip: `${device.ip}`,\n\t\t\t\t\t\tactions: `\n\t\t\t\t\t\t\tDetails \n\n\t\t\t\t\t\t\tReboot \n\t\t\t\t\t\t`\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tscr.currentScreen.DOMObject.querySelector(\".devices-container\").innerHTML = Helper.template.table(\n\t\t\t\t\t\"Devices list\", \n\t\t\t\t\t{\n\t\t\t\t\t\tdeviceName: \"Device name\", \n\t\t\t\t\t\talias: \"Device alias\", \n\t\t\t\t\t\tstatus: \"Status\", \n\t\t\t\t\t\tip: \"IP\", \n\t\t\t\t\t\tactions: \"Actions\"\n\t\t\t\t\t},\n\t\t\t\t\tpreparedData,\n\t\t\t\t\t`Total: ${resp.data.total} devices `\n\t\t\t\t);\n\n\t\t\t\tscr.currentScreen.DOMObject.querySelectorAll(\".reboot-btn\").forEach(btn => {\n\t\t\t\t\tbtn.addEventListener(\"click\", e => {\n\t\t\t\t\t\tif(e.currentTarget.getAttribute(\"disabled\")) {\n\t\t\t\t\t\t\treturn ;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst btnReboot = e.currentTarget;\n\t\t\t\t\t\tHelper.states.btnLoadingState(btnReboot, true);\n\t\t\t\t\t\tconst deviceId = e.currentTarget.dataset.deviceId;\n\t\t\t\t\t\tconst deviceName = e.currentTarget.dataset.deviceName;\n\t\t\t\t\t\tconst deviceAlias = e.currentTarget.dataset.deviceAlias;\n\t\t\t\t\t\tsh_api.devices.reboot(\n\t\t\t\t\t\t\tdeviceId,\n\t\t\t\t\t\t\t(err, data, meta) => {\n\t\t\t\t\t\t\t\tHelper.states.btnLoadingState(btnReboot, false);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tconsole.log(\"Reboot done\", err, data, meta);\n\t\t\t\t\t\t\t\tif(data) {\n\t\t\t\t\t\t\t\t\tToasts.createSuccess(\n\t\t\t\t\t\t\t\t\t\t\"Reboot successful\",\n\t\t\t\t\t\t\t\t\t\t`Device: ${deviceName} \n\t\t\t\t\t\t\t\t\t\tAlias: ${deviceAlias} `\n\t\t\t\t\t\t\t\t\t).show();\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tToasts.createError(\n\t\t\t\t\t\t\t\t\t\t\"Reboot failed\",\n\t\t\t\t\t\t\t\t\t\t`Device: ${deviceName} \n\t\t\t\t\t\t\t\t\t\tAlias: ${deviceAlias} `\n\t\t\t\t\t\t\t\t\t).show();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\t\t\t\t});\n\n\t\t\t\tscr.currentScreen.DOMObject.querySelectorAll(\".details-btn\").forEach(btn => {\n\t\t\t\t\tbtn.addEventListener(\"click\", e => {\n\t\t\t\t\t\tconst device = JSON.parse(e.currentTarget.dataset.device);\n\t\t\t\t\t\tdeviceDetailsPopup(device, sh_api).show();\n\t\t\t\t\t});\n\t\t\t\t});\n\n\t\t\t\tscr.ready();\n\t\t\t});\n\t\t}\n\t};\n}\n\nexport {\n\tlist\n}", "export function deviceSetupFormPopup(device, sh_api) {\n\tdevice = Helper.unification.deviceFieldsUnification(device);\n\n\treturn Modals.create(\"device-setup\", {\n\t\ttitle: `Setup new device ${device.ip}`,\n\t\tbody: modal => {\n\n\t\t\tlet deviceProperties = \"\";\n\t\t\tfor(let field in device) {\n\t\t\t\tif(field[0] == \"_\") continue;\n\t\t\t\tdeviceProperties += `\n\t\t\t\t\t\n\t\t\t\t\t\t${field}: \n\t\t\t\t\t\t${device[field]} \n\t\t\t\t\t \n\t\t\t\t`;\n\t\t\t}\n\n\t\t\tconst deviceInfo = `\n\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t${deviceProperties}\n\t\t\t\t\t\t \n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t`;\n\n\t\t\treturn `\n\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\t\t${deviceInfo}\n\t\t\t\t\t
\n\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tDevice alias\n\t\t\t\t\t\t\t\t \n\t\t\t\t\t\t\t\t \n\t\t\t\t\t\t\t \n\t\t\t\t\t\t
\n\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tDevice name\n\t\t\t\t\t\t\t\t \n\t\t\t\t\t\t\t\t \n\t\t\t\t\t\t\t \n\t\t\t\t\t\t
\n\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tAbout device\n\t\t\t\t\t\t\t\t \n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t \n\t\t\t\t\t\t
\n\n\t\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t`;\n\t\t},\n\t\tactions: modal => {\n\t\t\tconst buttonCancel = Helper.template.createElement(\"button\", { class: \"btn btn-primary\" }, \"Cancel\");\n\t\t\tbuttonCancel.addEventListener(\"click\", e => {\n\t\t\t\tmodal.close();\n\t\t\t});\n\n\t\t\tconst buttonSubmit = Helper.template.createElement(\"button\", \n\t\t\t\t{ class: \"btn btn-success with-icon\" }, \n\t\t\t\t` Setup`\n\t\t\t);\n\n\t\t\tbuttonSubmit.addEventListener(\"click\", e => {\n\t\t\t\tif(e.currentTarget.getAttribute(\"disabled\")) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst inputs = {\n\t\t\t\t\tdevice_ip: device.ip\n\t\t\t\t};\n\n\t\t\t\tconst setupForm = document.querySelector(\"#device-setup .setup-form\");\n\t\t\t\tsetupForm.querySelectorAll(\"input[type='text']\").forEach(i => {\n\t\t\t\t\ti.dispatchEvent(\n\t\t\t\t\t\tnew Event(\"input\", { bubbles: true })\n\t\t\t\t\t);\n\t\t\t\t});\n\n\t\t\t\tif(setupForm.querySelectorAll(\".label.error\").length) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst inputElements = setupForm.querySelectorAll(\"input\");\n\t\t\t\tconst textareaElement = setupForm.querySelector(\"textarea\");\n\n\t\t\t\tfor(let input of inputElements) {\n\t\t\t\t\tinputs[input.getAttribute(\"name\")] = input.value;\n\t\t\t\t}\n\n\t\t\t\tinputs[textareaElement.getAttribute(\"name\")] = textareaElement.value;\n\n\t\t\t\tHelper.states.btnLoadingState(buttonSubmit, true);\n\t\t\t\t\n\t\t\t\tsh_api.devices.setup_new_device(inputs, (err, resp, meta) => {\n\t\t\t\t\tHelper.states.btnLoadingState(buttonSubmit, false);\n\n\t\t\t\t\tif(err?.type == \"api_error\") {\n\t\t\t\t\t\tconsole.error(\"ERR! sh_api.devices.setup_new_device\", err.raw);\n\n\t\t\t\t\t\tif(err.raw?.failed_fields) {\n\t\t\t\t\t\t\tfor(let errFieldName of err.raw.failed_fields) {\n\t\t\t\t\t\t\t\tmodal.querySelector(`[name=\"${errFieldName}\"]`).parentNode.classList.add(\"error\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\t\t\t\t\t\t\n\n\t\t\t\t\t\tif(err.raw?.msg) {\n\t\t\t\t\t\t\tconst alertContainer = modal.querySelector(\".setup-form .alert-container\");\n\t\t\t\t\t\t\talertContainer.innerHTML = \"\";\n\t\t\t\t\t\t\talertContainer?.append(Helper.template.createAlert( \"error\", err.raw.msg ));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\t\t\t\t\t\n\n\t\t\t\t\tif(!resp) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\tinputElements.forEach(i => i.value = \"\");\n\t\t\t\t\ttextareaElement.value = \"\";\n\t\t\t\t\tmodal.close();\n\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tToasts.createSuccess(\"Setup successful\", `Added new device ID ${device.device_id} `).show();\n\t\t\t\t\t}, 300);\n\t\t\t\t});\n\t\t\t});\n\n\t\t\treturn [ buttonCancel, buttonSubmit ];\n\t\t},\n\n\t\tonready: modal => {\n\t\t\tconst setupForm = modal.querySelector(\".setup-form\");\n\t\t\tsetupForm.querySelectorAll(\"input\").forEach(i => {\n\t\t\t\ti.addEventListener(\"input\", e => {\n\t\t\t\t\tif(!e.currentTarget.value.length) {\n\t\t\t\t\t\te.currentTarget.parentNode.classList.add(\"error\");\n\t\t\t\t\t\tif(!e.currentTarget.parentNode.parentNode.querySelector(\".input-info.error\")) {\n\t\t\t\t\t\t\te.currentTarget.parentNode.parentNode.append(Helper.template.createElement(\"div\", {\n\t\t\t\t\t\t\t\tclass: \"input-info error\"\n\t\t\t\t\t\t\t}, ` Field cannot be empty`));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\te.currentTarget.parentNode.classList.remove(\"error\");\n\t\t\t\t\t\te.currentTarget.parentNode.parentNode.querySelector(\".input-info.error\")?.remove();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t})\n}", "import { sidebarTemplate } from \"./devices-funcs.js\";\nimport { deviceSetupFormPopup } from \"./device-setup-form-popup.js\";\n\nfunction scanning(sh_api) {\n\treturn {\n\t\talias: \"devices-scanning\",\n\t\trenderer: () => {\t\n\t\t\tconst sidebar = sidebarTemplate(\"scanning\");\n\n\t\t\treturn `\n\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t${sidebar}\n\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t`;\n\t\t},\n\t\tiniter: scr => {\n\t\t\tsh_api.devices.scanning_all((err, resp, meta) => {\n\t\t\t\tconsole.log(\"sh_api.devices.scanning_all\", err, resp);\n\n\t\t\t\tif(meta.status_code != 200) {\n\t\t\t\t\treturn scr.error(\"Server API ERROR\", \"\");\n\t\t\t\t}\n\n\t\t\t\tconst preparedData = [];\n\t\t\t\tfor(let device of resp.data.devices) {\n\t\t\t\t\tdevice = Helper.unification.deviceFieldsUnification(device);\n\n\t\t\t\t\tpreparedData.push({\n\t\t\t\t\t\tdeviceId: device.device_id,\n\t\t\t\t\t\tdeviceName: device.name,\n\t\t\t\t\t\tdeviceType: device.type,\n\t\t\t\t\t\tstatus: `${device.status} `,\n\t\t\t\t\t\tip: `${device.ip}`,\n\t\t\t\t\t\tmac: `${device.mac}`,\n\t\t\t\t\t\twifiSignal: device.wifi_signal,\n\t\t\t\t\t\tactions: device.status == \"setup\" ? `\n\t\t\t\t\t\t\tSetup \n\t\t\t\t\t\t` : \"\"\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tscr.currentScreen.DOMObject.querySelector(\".devices-container\").innerHTML = Helper.template.table(\n\t\t\t\t\t\"Found devices\", \n\t\t\t\t\t{\n\t\t\t\t\t\tdeviceId: \"Device ID\",\n\t\t\t\t\t\tdeviceName: \"Device name\", \n\t\t\t\t\t\tdeviceType: \"Type\", \n\t\t\t\t\t\tstatus: \"Status\", \n\t\t\t\t\t\tip: \"IP\", \n\t\t\t\t\t\tmac: \"Mac\",\n\t\t\t\t\t\twifiSignal: \"Signal\", \n\t\t\t\t\t\tactions: \"Actions\"\n\t\t\t\t\t},\n\t\t\t\t\tpreparedData,\n\t\t\t\t\t`Total: ${resp.data.devices.length} devices `\n\t\t\t\t);\n\n\t\t\t\tscr.currentScreen.DOMObject.querySelectorAll(\".setup-btn\").forEach(btn => {\n\t\t\t\t\tbtn.addEventListener(\"click\", e => {\n\t\t\t\t\t\tconst device = JSON.parse(e.currentTarget.dataset.device);\n\t\t\t\t\t\tdeviceSetupFormPopup(device, sh_api).show();\n\t\t\t\t\t});\n\t\t\t\t});\n\n\t\t\t\tscr.ready();\n\t\t\t});\n\t\t}\n\t};\n}\n\nexport {\n\tscanning\n}", "import { list } from \"./devices-list-screen.js\";\nimport { scanning } from \"./devices-scanning-screen.js\";\n\nexport default {\n\tlist,\n\tscanning\n}", "import devices from \"./components/screens/devices/devices.js\";\n\nfunction routes(screens, sh_api) {\n\tscreens.add(\"/\", {\n\t\talias: \"home\",\n\t\trenderer: () => {\n\t\t\treturn `Hello world `;\n\t\t},\n\t\tiniter: scr => {\n\t\t\tsetTimeout(() => scr.ready(), 1000);\n\t\t\tsetTimeout(() => scr.error(\"Error\", \"Just testing\"), 2000);\n\t\t}\n\t});\n\n\tscreens.add(\"-\", {\n\t\talias: \"not-found-screen\",\n\t\trenderer: () => {\n\t\t\treturn `404 NOT FOUND `;\n\t\t},\n\t\tiniter: scr => {\n\t\t\tscr.ready();\n\t\t}\n\t});\n\n\tscreens.add(\"/devices\", devices.list(sh_api));\n\tscreens.add(\"/devices/scanning\", devices.scanning(sh_api));\n}\n\nexport {\n\troutes\n}", "function template(id, title, footer) {\n\treturn `\n\t\t\n\t`;\n}\n\nfunction init(modal, onready) {\n\tmodal.show = function() {\n\t\tdocument.querySelector(\"body\").append(modal);\n\n\t\tsetTimeout(() => {\n\t\t\tthis.classList.add(\"a-show\");\n\t\t}, 10);\n\t}\n\n\tmodal.close = function() {\n\t\tthis.classList.add(\"a-hide\");\n\t\tsetTimeout(() => {\n\t\t\tthis.remove();\n\t\t}, 300);\n\t}\n\n\tmodal.querySelector(\".modal-close\").addEventListener(\"click\", e => {\n\t\tmodal.close();\n\t});\n\n\tif(typeof onready == \"function\") {\n\t\tonready(modal);\n\t}\n\n\treturn modal;\n}\n\n\t/**\n\t * Create new modal window;\n\t * @param {string} id Uniq id (selector)\n\t * @param {string} title Display title\n\t * @param {object} props { body: modal => {}, actions => modal => {} }\n\t * @return {object} DOM object\n\t */\nfunction create(id, props) {\n\tconst title = props.title || \"\";\n\tconst footer = props.footer || \"\";\n\n\tconst div = document.createElement(\"div\");\n\tdiv.innerHTML = template(id, title, footer);\n\tconst modal = div.childNodes[1];\n\n\tconst modalBody = modal.querySelector(\".modal-body\");\n\tconst modalFooter = modal.querySelector(\".modal-footer\");\n\n\tif(typeof props.actions == \"function\") {\n\t\tconst actionsResult = props.actions(modal);\n\n\t\tif(typeof actionsResult[0] == \"object\") {\n\t\t\tconst actions = document.createElement(\"div\");\n\t\t\tactions.classList.add(\"actions\");\n\t\t\tfor(let actionElement of actionsResult) {\n\t\t\t\tactions.append(actionElement);\n\t\t\t}\n\n\t\t\tmodalFooter.append(actions);\n\t\t}\n\t}\n\n\tif(typeof props.body == \"function\") {\n\t\tconst bodyResult = props.body(modal);\n\n\t\tif(typeof bodyResult == \"object\") {\n\t\t\tmodalBody.append(bodyResult);\n\t\t} else if(typeof bodyResult == \"string\") {\n\t\t\tmodalBody.innerHTML = bodyResult;\n\t\t}\n\t}\n\n\treturn init(modal, props?.onready);\n}\n\nexport default {\n\tcreate\n}", "export default function confirmPopup(text, confirmedCb, canceledCb) {\n\tModals.create(\"confirm-popup\", {\n\t\ttitle: `Requires confirmation`,\n\t\tbody: modal => {\n\t\t\treturn `\n\t\t\t\t${text}
\n\t\t\t`;\n\t\t},\n\t\tactions: modal => {\n\t\t\tconst buttonNO = Helper.template.createElement(\"button\", { class: \"btn btn-primary\" }, \"NO\");\n\t\t\tconst buttonYES = Helper.template.createElement(\"button\", { class: \"btn btn-warning\" }, \"YES\");\n\n\t\t\tbuttonNO.addEventListener(\"click\", e => {\n\t\t\t\tmodal.close();\n\t\t\t\tcanceledCb();\n\t\t\t});\n\n\t\t\tbuttonYES.addEventListener(\"click\", e => {\n\t\t\t\tmodal.close();\n\t\t\t\tconfirmedCb();\n\t\t\t});\n\n\t\t\treturn [ buttonNO, buttonYES ];\n\t\t}\n\t}).show();\n}", "import { hud, navigationShow, navigationHide } from \"./components/hud.js\";\nimport { Screens } from \"./components/Screens.js\";\nimport Toasts from \"./components/toasts.js\"\nimport Helper from \"./components/helper.js\"\nimport { SmartHomeApi } from \"./sh/SmartHomeApi.js\";\nimport { routes } from \"./routes.js\";\nimport Modals from \"./components/modals.js\";\nimport confirmPopup from \"./components/confirm-popup.js\";\n\ndocument.addEventListener(\"DOMContentLoaded\", e => {\n\tconsole.log(\"App init\");\n\n\twindow.Toasts = Toasts;\n\twindow.Helper = Helper;\n\twindow.Modals = Modals;\n\twindow.confirmPopup = confirmPopup;\n\n\thud();\n\tconst sh_api = new SmartHomeApi({\n\t base_url: \"http://shswebclient.local\",\n\t token: \"YOUR_TOKEN\",\n\t timeout_ms: 3000,\n\t on_unauthorized: ({ error }) => console.log(\"auth problem:\", error),\n\t proxy_path: \"/proxy.php\",\n\t});\n\n\t// api.scripts.actions_list((err, data, meta) => console.log(data));\n\t// api.scripts.scopes_list((err, data, meta) => console.log(data));\n\t// api.devices.info(4, (err, data, meta) => console.log(data));\n\n\tconst screens = new Screens(\".screens\", \".load-screen\", \".error-screen\");\n\t\n\troutes(screens, sh_api);\n\n\tconsole.log(screens.getScreens());\n\n\tscreens.onSwitch((scr, alias) => {\n\t\tnavigationHide();\n\t});\n\n\tscreens.routing();\n\n\twindow.Screens = screens;\n});"],
+ "mappings": "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",
+ "names": ["navToggleBtn", "navigation", "reloadScreenBtn", "navigationShow", "navigationHide", "hud", "e", "Screens", "screensContainerSelector", "loaderSelector", "errorScreenSelector", "route", "screen", "__spreadValues", "alias", "_a", "screenContainer", "title", "text", "cb", "handler", "template", "type", "icon", "title", "text", "init", "toast", "props", "i", "e", "scr", "alias", "lifetimeInterval", "create", "div", "createSuccess", "createInfo", "createWarning", "createError", "toasts_default", "sidebarNav", "items", "listItems", "item", "aOpen", "aClose", "table", "caption", "columns", "data", "tfoot", "head", "totalColumns", "key", "body", "column", "foot", "createElement", "type", "props", "content", "node", "value", "createAlert", "deviceFieldsUnification", "map", "dataObj", "field", "btnLoadingState", "btn", "isLoading", "helper_default", "ScriptsApi", "core", "cb", "filename", "safe", "payload", "alias", "name", "DevicesApi", "core", "cb", "payload", "id", "safe", "AreasApi", "core", "cb", "area_id", "safe", "payload", "build_query", "params", "usp", "k", "v", "s", "join_url", "base_url", "path", "b", "p", "safe_json_parse", "text", "SmartHomeApi", "opts", "ScriptsApi", "DevicesApi", "AreasApi", "token", "proxy_path", "extra_query", "q", "__spreadValues", "method", "body", "cb", "callback", "url", "controller", "timeout_ms", "t", "headers", "payload", "res", "__async", "meta", "parsed", "data", "err", "_", "st", "e", "api_path", "sidebarTemplate", "active", "deviceDetailsPopup", "device", "sh_api", "modal", "deviceProperties", "field", "buttonCancel", "buttonReboot", "buttonRemove", "e", "err", "data", "meta", "list", "sh_api", "sidebarTemplate", "scr", "err", "resp", "meta", "preparedData", "device", "connectionState", "btn", "e", "btnReboot", "deviceId", "deviceName", "deviceAlias", "data", "deviceDetailsPopup", "deviceSetupFormPopup", "device", "sh_api", "modal", "deviceProperties", "field", "buttonCancel", "e", "buttonSubmit", "inputs", "setupForm", "i", "inputElements", "textareaElement", "input", "err", "resp", "meta", "_a", "_b", "errFieldName", "alertContainer", "scanning", "sh_api", "sidebarTemplate", "scr", "err", "resp", "meta", "preparedData", "device", "btn", "e", "deviceSetupFormPopup", "devices_default", "list", "scanning", "routes", "screens", "sh_api", "scr", "devices_default", "template", "id", "title", "footer", "init", "modal", "onready", "e", "create", "props", "div", "modalBody", "modalFooter", "actionsResult", "actions", "actionElement", "bodyResult", "modals_default", "confirmPopup", "text", "confirmedCb", "canceledCb", "modal", "buttonNO", "buttonYES", "e", "e", "toasts_default", "helper_default", "modals_default", "confirmPopup", "hud", "sh_api", "SmartHomeApi", "error", "screens", "Screens", "routes", "scr", "alias", "navigationHide"]
}
diff --git a/webclient/src/js/components/screens/devices/devices-funcs.js b/webclient/src/js/components/screens/devices/devices-funcs.js
new file mode 100644
index 0000000..2fa740d
--- /dev/null
+++ b/webclient/src/js/components/screens/devices/devices-funcs.js
@@ -0,0 +1,18 @@
+function sidebarTemplate(active) {
+ return Helper.template.sidebarNav([
+ {
+ content: ` Devices `,
+ route: "/#!/devices",
+ is_active: active == "devices"
+ },
+ {
+ content: ` Scanning `,
+ route: "/#!/devices/scanning",
+ is_active: active == "scanning"
+ }
+ ]);
+}
+
+export {
+ sidebarTemplate
+}
\ No newline at end of file
diff --git a/webclient/src/js/components/screens/devices/devices-list-screen.js b/webclient/src/js/components/screens/devices/devices-list-screen.js
new file mode 100644
index 0000000..2c2f3bb
--- /dev/null
+++ b/webclient/src/js/components/screens/devices/devices-list-screen.js
@@ -0,0 +1,124 @@
+import { sidebarTemplate } from "./devices-funcs.js";
+import { deviceDetailsPopup } from "./device-details-popup.js";
+
+function list(sh_api) {
+ return {
+ alias: "devices",
+ renderer: () => {
+ const sidebar = sidebarTemplate("devices");
+
+ return `
+
+ `;
+ },
+
+ initer: scr => {
+ sh_api.devices.list((err, resp, meta) => {
+ console.log("sh_api.devices.list", err, resp, meta);
+
+ if(meta.status_code != 200) {
+ return scr.error("Server API ERROR", "");
+ }
+
+ const preparedData = [];
+ for(let device of resp.data.devices) {
+ device = Helper.unification.deviceFieldsUnification(device);
+
+ const connectionState = device.connection_state == "active"
+ ? `Online `
+ : `Offline `;
+
+ preparedData.push({
+ deviceName: device.name,
+ alias: device.alias,
+ status: connectionState,
+ ip: `${device.ip}`,
+ actions: `
+ Details
+
+ Reboot
+ `
+ });
+ }
+
+ scr.currentScreen.DOMObject.querySelector(".devices-container").innerHTML = Helper.template.table(
+ "Devices list",
+ {
+ deviceName: "Device name",
+ alias: "Device alias",
+ status: "Status",
+ ip: "IP",
+ actions: "Actions"
+ },
+ preparedData,
+ `Total: ${resp.data.total} devices `
+ );
+
+ scr.currentScreen.DOMObject.querySelectorAll(".reboot-btn").forEach(btn => {
+ btn.addEventListener("click", e => {
+ if(e.currentTarget.getAttribute("disabled")) {
+ return ;
+ }
+
+ const btnReboot = e.currentTarget;
+ Helper.states.btnLoadingState(btnReboot, true);
+ const deviceId = e.currentTarget.dataset.deviceId;
+ const deviceName = e.currentTarget.dataset.deviceName;
+ const deviceAlias = e.currentTarget.dataset.deviceAlias;
+ sh_api.devices.reboot(
+ deviceId,
+ (err, data, meta) => {
+ Helper.states.btnLoadingState(btnReboot, false);
+
+ console.log("Reboot done", err, data, meta);
+ if(data) {
+ Toasts.createSuccess(
+ "Reboot successful",
+ `Device: ${deviceName}
+ Alias: ${deviceAlias} `
+ ).show();
+ } else {
+ Toasts.createError(
+ "Reboot failed",
+ `Device: ${deviceName}
+ Alias: ${deviceAlias} `
+ ).show();
+ }
+ }
+ );
+ });
+ });
+
+ scr.currentScreen.DOMObject.querySelectorAll(".details-btn").forEach(btn => {
+ btn.addEventListener("click", e => {
+ const device = JSON.parse(e.currentTarget.dataset.device);
+ deviceDetailsPopup(device, sh_api).show();
+ });
+ });
+
+ scr.ready();
+ });
+ }
+ };
+}
+
+export {
+ list
+}
\ No newline at end of file
diff --git a/webclient/src/js/components/screens/devices/devices-scanning-screen.js b/webclient/src/js/components/screens/devices/devices-scanning-screen.js
new file mode 100644
index 0000000..bccd756
--- /dev/null
+++ b/webclient/src/js/components/screens/devices/devices-scanning-screen.js
@@ -0,0 +1,82 @@
+import { sidebarTemplate } from "./devices-funcs.js";
+import { deviceSetupFormPopup } from "./device-setup-form-popup.js";
+
+function scanning(sh_api) {
+ return {
+ alias: "devices-scanning",
+ renderer: () => {
+ const sidebar = sidebarTemplate("scanning");
+
+ return `
+
+ `;
+ },
+ initer: scr => {
+ sh_api.devices.scanning_all((err, resp, meta) => {
+ console.log("sh_api.devices.scanning_all", err, resp);
+
+ if(meta.status_code != 200) {
+ return scr.error("Server API ERROR", "");
+ }
+
+ const preparedData = [];
+ for(let device of resp.data.devices) {
+ device = Helper.unification.deviceFieldsUnification(device);
+
+ preparedData.push({
+ deviceId: device.device_id,
+ deviceName: device.name,
+ deviceType: device.type,
+ status: `${device.status} `,
+ ip: `${device.ip}`,
+ mac: `${device.mac}`,
+ wifiSignal: device.wifi_signal,
+ actions: device.status == "setup" ? `
+ Setup
+ ` : ""
+ });
+ }
+
+ scr.currentScreen.DOMObject.querySelector(".devices-container").innerHTML = Helper.template.table(
+ "Found devices",
+ {
+ deviceId: "Device ID",
+ deviceName: "Device name",
+ deviceType: "Type",
+ status: "Status",
+ ip: "IP",
+ mac: "Mac",
+ wifiSignal: "Signal",
+ actions: "Actions"
+ },
+ preparedData,
+ `Total: ${resp.data.devices.length} devices `
+ );
+
+ scr.currentScreen.DOMObject.querySelectorAll(".setup-btn").forEach(btn => {
+ btn.addEventListener("click", e => {
+ const device = JSON.parse(e.currentTarget.dataset.device);
+ deviceSetupFormPopup(device, sh_api).show();
+ });
+ });
+
+ scr.ready();
+ });
+ }
+ };
+}
+
+export {
+ scanning
+}
\ No newline at end of file
diff --git a/webclient/src/js/components/screens/devices/devices.js b/webclient/src/js/components/screens/devices/devices.js
index 7d7458b..5f5e5b4 100644
--- a/webclient/src/js/components/screens/devices/devices.js
+++ b/webclient/src/js/components/screens/devices/devices.js
@@ -1,215 +1,5 @@
-import { deviceDetailsPopup } from "./device-details-popup.js";
-import { deviceSetupFormPopup } from "./device-setup-form-popup.js";
-
-function sidebarTemplate(active) {
- return Helper.template.sidebarNav([
- {
- content: ` Devices `,
- route: "/#!/devices",
- is_active: active == "devices"
- },
- {
- content: ` Scanning `,
- route: "/#!/devices/scanning",
- is_active: active == "scanning"
- }
- ]);
-}
-
-
-function list(sh_api) {
- return {
- alias: "devices",
- renderer: () => {
- const sidebar = sidebarTemplate("devices");
-
- return `
-
- `;
- },
-
- initer: scr => {
- sh_api.devices.list((err, resp, meta) => {
- console.log("sh_api.devices.list", err, resp, meta);
-
- if(meta.status_code != 200) {
- return scr.error("Server API ERROR", "");
- }
-
- const preparedData = [];
- for(let device of resp.data.devices) {
- device = Helper.unification.deviceFieldsUnification(device);
-
- const connectionState = device.connection_state == "active"
- ? `Online `
- : `Offline `;
-
- preparedData.push({
- deviceName: device.name,
- alias: device.alias,
- status: connectionState,
- ip: `${device.ip}`,
- actions: `
- Details
-
- Reboot
- `
- });
- }
-
- scr.currentScreen.DOMObject.querySelector(".devices-container").innerHTML = Helper.template.table(
- "Devices list",
- {
- deviceName: "Device name",
- alias: "Device alias",
- status: "Status",
- ip: "IP",
- actions: "Actions"
- },
- preparedData,
- `Total: ${resp.data.total} devices `
- );
-
- scr.currentScreen.DOMObject.querySelectorAll(".reboot-btn").forEach(btn => {
- btn.addEventListener("click", e => {
- if(e.currentTarget.getAttribute("disabled")) {
- return ;
- }
-
- const btnReboot = e.currentTarget;
- Helper.states.btnLoadingState(btnReboot, true);
- const deviceId = e.currentTarget.dataset.deviceId;
- const deviceName = e.currentTarget.dataset.deviceName;
- const deviceAlias = e.currentTarget.dataset.deviceAlias;
- sh_api.devices.reboot(
- deviceId,
- (err, data, meta) => {
- Helper.states.btnLoadingState(btnReboot, false);
-
- console.log("Reboot done", err, data, meta);
- if(data) {
- Toasts.createSuccess(
- "Reboot successful",
- `Device: ${deviceName}
- Alias: ${deviceAlias} `
- ).show();
- } else {
- Toasts.createError(
- "Reboot failed",
- `Device: ${deviceName}
- Alias: ${deviceAlias} `
- ).show();
- }
- }
- );
- });
- });
-
- scr.currentScreen.DOMObject.querySelectorAll(".details-btn").forEach(btn => {
- btn.addEventListener("click", e => {
- const device = JSON.parse(e.currentTarget.dataset.device);
- deviceDetailsPopup(device, sh_api).show();
- });
- });
-
- scr.ready();
- });
- }
- };
-}
-
-function scanning(sh_api) {
- return {
- alias: "devices-scanning",
- renderer: () => {
- const sidebar = sidebarTemplate("scanning");
-
- return `
-
- `;
- },
- initer: scr => {
- sh_api.devices.scanning_all((err, resp, meta) => {
- console.log("sh_api.devices.scanning_all", err, resp);
-
- if(meta.status_code != 200) {
- return scr.error("Server API ERROR", "");
- }
-
- const preparedData = [];
- for(let device of resp.data.devices) {
- device = Helper.unification.deviceFieldsUnification(device);
-
- preparedData.push({
- deviceId: device.device_id,
- deviceName: device.name,
- deviceType: device.type,
- status: `${device.status} `,
- ip: `${device.ip}`,
- mac: `${device.mac}`,
- wifiSignal: device.wifi_signal,
- actions: device.status == "setup" ? `
- Setup
- ` : ""
- });
- }
-
- scr.currentScreen.DOMObject.querySelector(".devices-container").innerHTML = Helper.template.table(
- "Found devices",
- {
- deviceId: "Device ID",
- deviceName: "Device name",
- deviceType: "Type",
- status: "Status",
- ip: "IP",
- mac: "Mac",
- wifiSignal: "Signal",
- actions: "Actions"
- },
- preparedData,
- `Total: ${resp.data.devices.length} devices `
- );
-
- scr.currentScreen.DOMObject.querySelectorAll(".setup-btn").forEach(btn => {
- btn.addEventListener("click", e => {
- const device = JSON.parse(e.currentTarget.dataset.device);
- deviceSetupFormPopup(device, sh_api).show();
- });
- });
-
- scr.ready();
- });
- }
- };
-}
+import { list } from "./devices-list-screen.js";
+import { scanning } from "./devices-scanning-screen.js";
export default {
list,