Newer
Older
smart-home-server / webclient / dist / js / main.js
(()=>{var de=Object.defineProperty,ue=Object.defineProperties;var pe=Object.getOwnPropertyDescriptors;var C=Object.getOwnPropertySymbols;var me=Object.prototype.hasOwnProperty,fe=Object.prototype.propertyIsEnumerable;var x=(a,e,t)=>e in a?de(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t,v=(a,e)=>{for(var t in e||(e={}))me.call(e,t)&&x(a,t,e[t]);if(C)for(var t of C(e))fe.call(e,t)&&x(a,t,e[t]);return a},j=(a,e)=>ue(a,pe(e));var P=(a,e,t)=>new Promise((r,s)=>{var n=o=>{try{c(t.next(o))}catch(u){s(u)}},i=o=>{try{c(t.throw(o))}catch(u){s(u)}},c=o=>o.done?r(o.value):Promise.resolve(o.value).then(n,i);c((t=t.apply(a,e)).next())});var g,w,U;function be(){g.dataset.navState="displayed",g.classList.remove("state-off"),g.classList.add("state-on"),w.classList.add("a-show")}function k(){g.dataset.navState="hidden",g.classList.remove("state-on"),g.classList.add("state-off"),w.classList.add("a-hide"),w.classList.remove("a-show"),setTimeout(()=>{w.classList.remove("a-hide")},300)}function F(){console.log("HUD init"),g=document.querySelector(".hud .nav-toggle"),w=document.querySelector(".hud .navigation"),U=document.querySelector(".hud .reload-screen"),g.addEventListener("click",a=>{a.currentTarget.dataset.navState!="displayed"?be():k()}),U.addEventListener("click",a=>{Screens.reload()})}var $=class{constructor(e,t,r){this.screens={},this.routesMap={},this.currentScreen=null,this.eventsHandlers={switch:[],reload:[],reinit:[]},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]=v({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))}reinit(){this.currentScreen&&(this.currentScreen.initer(this),this.runReinitHandlers())}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)}onReinit(e){this.eventsHandlers.reinit.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)}runReinitHandlers(){for(let e of this.eventsHandlers.reinit)e(this)}};function he(a,e,t,r){return`
		<div class="toast toast-${a}" role="alert">
	    <div class="toast-content">
	      <h4 class="toast-title">${e} ${t}</h4>
	      <p class="toast-text">${r}</p>
	    </div>
	    <button class="btn-icon toast-close" type="button" aria-label="Close">\u2715</button>
	  </div>
	`}function ve(a,e){if(e!=null&&e.alone&&document.querySelectorAll(".toast").forEach(t=>t.close()),a.close=function(){this.classList.add("a-hide"),setTimeout(()=>{this.remove()},300)},a.querySelector(".toast-close").addEventListener("click",t=>{a.close()}),a.show=function(){document.querySelector("body").append(a),setTimeout(()=>{a.classList.add("a-show")},10)},Screens.onSwitch((t,r)=>{setTimeout(()=>{a==null||a.close()},1e4)}),a.addEventListener("mouseover",t=>a.ishovered=!0),a.addEventListener("mouseout",t=>a.ishovered=!1),e!=null&&e.lifetime){console.log(e);let t=setInterval(()=>{a.ishovered||(a.close(),clearInterval(t))},e==null?void 0:e.lifetime)}return a}function T(a,e,t,r,s){let n=document.createElement("div");return n.innerHTML=he(a,e,t,r),ve(n.childNodes[1],s)}function ge(a,e,t){return typeof t=="undefined"&&(t={}),typeof t.lifetime=="undefined"&&(t.lifetime=4e3),typeof t.alone=="undefined"&&(t.alone=!0),T("success",'<i class="ph ph-check-circle"></i>',a,e,t)}function Se(a,e,t){return T("info",'<i class="ph ph-info"></i>',a,e,t)}function ye(a,e,t){return T("warning",'<i class="ph ph-warning"></i>',a,e,t)}function B(a,e,t){return T("danger",'<i class="ph ph-warning-octagon"></i>',a,e,t)}var z={create:T,createInfo:Se,createSuccess:ge,createWarning:ye,createError:B,createDanger:B};function _e(a){let e="";for(let t of a){let r="",s="";t.route&&(r=`<a class="list-action" href="${t.route}">`,s="</a>"),e+=`
			<li class="list-item ${t.is_active?"list-item-active":""}">
				${r}${t.content}${s}
			</li>
		`}return`
		<div class="sidebar block">
			<ul class="list list-nav">
				${e} 
			</ul>
		</div>
	`}function we(a,e,t,r){let s='<tr class="table-row">',n=0;for(let p in e)s+=`<th scope="col">${e[p]}</th>`,n++;s+="</tr>";let i="";for(let p of t){i+='<tr class="table-row">';for(let m in e)i+=`<td>${p[m]}</td>`;i+="</tr>"}let c="";typeof r!="undefined"&&(c=`
			<tfoot class="table-foot">
				<tr class="table-row">
					<td colspan="${n}">
						${r}
					</td>
				</tr>
			</tfoot>
		`);let o=a?`<caption class="table-caption">${a}</caption>`:"",u=t.length?`<thead class="table-head">${s}</thead>`:"";return i=t.length?i:'<tr><td class="is-empty">Empty</td></tr>',`
		<table class="table devices-lists ${t.length?"":"table-empty"}">
			${o}
			${u}
			<tbody class="table-body">${i}</tbody>
			${c}
		</table>
	`}function J(a,e,t){let r=document.createElement(a);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 Te(a,e){return["primary","success","secondary","info","warning","error","danger"].indexOf(a)<0?console.error("createAlert()","Error of type: "+a):J("div",{class:`alert alert-${a}`},e)}function $e(a){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 a){if(typeof e[r]!="undefined"){t[e[r]]=a[r];continue}t[r]=a[r]}return t}function Ee(a,e){if((a==null?void 0:a.isLoading)==e)return!1;if(e)a.isLoading=!0,a.originalContent=a.innerHTML,a.classList.contains("with-icon")?a.originalWithIcon=!0:a.classList.add("with-icon"),a.classList.add("loading-state"),a.setAttribute("disabled","disabled"),a.innerHTML='<i class="ph-bold ph-spinner"></i> Loading';else{if(a.isLoading=!1,!a.originalContent)return!1;a.removeAttribute("disabled"),a.classList.remove("loading-state"),a.originalWithIcon||a.classList.remove("with-icon"),a.innerHTML=a.originalContent}return a}function Le(a,e){if((a==null?void 0:a.isLoading)==e)return!1;let t=a.querySelector(".device-icon");if(e)a.isLoading=!0,a.originalContent=t.innerHTML,a.classList.add("loading-state"),a.setAttribute("disabled","disabled"),t.innerHTML='<i class="ph-bold ph-spinner"></i>';else{if(a.isLoading=!1,!a.originalContent)return!1;a.removeAttribute("disabled"),a.classList.remove("loading-state"),t.innerHTML=a.originalContent}return a}function He(a,e){return e=e!=null?e:"",`
		<div class="container">
			<div class="row g-6">
				<div class="col sidebar-container">
					${a}
				</div>
				<div class="col main-container w-100">
					${e}
				</div>
			</div>
		</div>
	`}function Ae(a){return a=="active"?'<span class="badge badge-success">Online</span>':'<span class="badge badge-warning">Offline</span>'}function De(a){return a=="enabled"?'<span class="badge badge-success">Enabled</span>':'<span class="badge badge-primary">Disabled</span>'}var W={template:{sidebarNav:_e,table:we,createElement:J,createAlert:Te,mainTemplate:He,connectionStatusBadge:Ae,toogleStateBadge:De},unification:{deviceFieldsUnification:$e},states:{btnLoadingState:Ee,cardScriptActionLoadingState:Le}};var E=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/regular/alias/${r}/enable`,t)}regular_disable(e,t){let r=encodeURIComponent(String(e||""));return this.core.api_get(`/api/v1/scripts/regular/alias/${r}/disable`,t)}scope_enable(e,t){let r=encodeURIComponent(String(e||""));return this.core.api_get(`/api/v1/scripts/scopes/name/${r}/enable`,t)}scope_disable(e,t){let r=encodeURIComponent(String(e||""));return this.core.api_get(`/api/v1/scripts/scopes/name/${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 H=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 Y(a){if(!a||typeof a!="object")return"";let e=new URLSearchParams;Object.entries(a).forEach(([r,s])=>{s!=null&&e.append(r,String(s))});let t=e.toString();return t?`?${t}`:""}function Oe(a,e){let t=String(a||"").replace(/\/+$/,""),r=String(e||"").replace(/^\/+/,"");return`${t}/${r}`}function Me(a){try{return{ok:!0,data:JSON.parse(a)}}catch(e){return{ok:!1,error:e}}}var A=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 E(this),this.devices=new L(this),this.areas=new H(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}${Y(t)}`:e;let r=v({path:e},t||{});return`${this.proxy_path}${Y(r)}`}request(e,t,r,s,n){let i=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,l=setTimeout(()=>o.abort(),u),p=v(v({},this.default_headers),(n==null?void 0:n.headers)||{});this.token&&(p.Authorization=`Bearer ${this.token}`);let m;r!=null&&(p["Content-Type"]="application/json",m=JSON.stringify(r)),fetch(c,{method:e,headers:p,body:m,signal:o.signal}).then(d=>P(this,null,function*(){clearTimeout(l);let b={url:c,method:e,status_code:d.status,headers:d.headers},f=yield d.text(),R=Me(f),h=R.ok?R.data:f;if(!d.ok){let _={type:"http_error",message:`HTTP ${d.status}`,status_code:d.status,raw:h};if((d.status===401||d.status===403)&&this.on_unauthorized)try{this.on_unauthorized({error:_,meta:b})}catch(I){}return i(_,null,b)}if(R.ok&&h&&typeof h=="object"){let _=h.status;if(_===!1||_==="error"){let I={type:"api_error",message:h.message||"API error",status_code:d.status,raw:h,field:h.field};return i(I,null,b)}}return i(null,h,b)})).catch(d=>{clearTimeout(l);let f=d&&(d.name==="AbortError"||String(d).includes("AbortError"))?{type:"timeout",message:`Timeout after ${u}ms`}:{type:"network_error",message:(d==null?void 0:d.message)||"Network error",details:d};return i(f,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 D(a){return Helper.template.sidebarNav([{content:'<span class="list-label"><i class="ph ph-cpu"></i> Devices</span>',route:"/#!/devices",is_active:a=="devices"},{content:'<span class="list-label"><i class="ph ph-magnifying-glass"></i> Scanning</span>',route:"/#!/devices/scanning",is_active:a=="scanning"},{content:'<span class="list-label"><i class="ph ph-play"></i> Actions</span>',route:"/#!/devices/actions",is_active:a=="actions"}])}function S(a,e,t){Helper.states.btnLoadingState(e,!0);let r=e.dataset.deviceId,s=e.dataset.deviceName,n=e.dataset.deviceAlias;a.devices.reboot(r,(i,c,o)=>{Helper.states.btnLoadingState(e,!1),console.log("Reboot done",i,c,o),t==null||t.close(),c?(setTimeout(()=>Screens.reinit(),8e3),Toasts.createSuccess("Reboot successful",`Device: ${s}<br>
					Alias: <b>${n}</b>`).show()):Toasts.createError("Reboot failed",`Device: ${s}<br>
					Alias: <b>${n}</b>`).show()})}function G(a,e){return console.log(a),Modals.create("device-popup",{title:`Device ${a.name}`,body:t=>{let r="";for(let s in a)r+=`
					<tr class="table-row">
						<th>${s}: </th>
						<td>${a[s]}</td>
					</tr>
				`;return`
				<div class="block">
					<table class="table" style="border: 0">
						<tbody class="table-body">
							${r}
						</tbody>
					</table>
				</div>
			`},actions:t=>{let r=Helper.template.createElement("button",{class:"btn btn-primary"},"Close"),s=Helper.template.createElement("button",{class:"btn btn-warning with-icon"},'<i class="ph ph-arrow-clockwise"></i> Reboot'),n=Helper.template.createElement("button",{class:"btn btn-danger with-icon"},'<i class="ph ph-trash"></i> Remove');return r.addEventListener("click",i=>{t.close()}),s.dataset.deviceId=a.id,s.dataset.deviceName=a.name,s.dataset.deviceAlias=a.alias,s.addEventListener("click",i=>{s.getAttribute("disabled")||S(e,i.currentTarget,t)}),n.addEventListener("click",i=>{n.getAttribute("disabled")||(Helper.states.btnLoadingState(n,!0),confirmPopup("Are you sure you want to remove this device?",()=>{e.devices.remove(a.id,(c,o,u)=>{Helper.states.btnLoadingState(n,!1),console.log("Was removed"),t.close(),Screens.reinit(),setTimeout(()=>{Toasts.createSuccess("Removed",`
										Device: ${a.name}<br>
										Alias: <b>${a.alias}</b><br>
										IP: <b>${a.ip}</b>
										`).show()},300)})},()=>{Helper.states.btnLoadingState(n,!1),console.log("CANCELED")}))}),[r,s,n]}})}function Re(a){let e=[];for(let t of a.devices)t=Helper.unification.deviceFieldsUnification(t),e.push({deviceName:t.name,alias:t.alias,status:Helper.template.connectionStatusBadge(t.connection_state),ip:`<code class="code">${t.ip}</code>`,actions:`
				<button 
					class="btn btn-secondary btn-small details-btn" 
					data-device='${JSON.stringify(t)}'
					type="button"
				>Details</button>

				<button 
					class="btn btn-warning btn-small reboot-btn" 
					data-device-id="${t.id}" 
					data-device-name="${t.name}" 
					data-device-alias="${t.alias}" 
					type="button"
				>Reboot</button>
			`});return e}function ke(a,e,t){a.currentScreen.DOMObject.querySelector(".main-container").innerHTML=Helper.template.table("Devices list",{deviceName:"Device name",alias:"Device alias",status:"Status",ip:"IP",actions:"Actions"},e,`<span class="table-meta">Total: <span class="total">${t}</span> devices</span>`)}function qe(a,e){a.currentScreen.DOMObject.querySelectorAll(".reboot-btn").forEach(t=>{t.addEventListener("click",r=>{r.currentTarget.getAttribute("disabled")||S(e,r.currentTarget)})}),a.currentScreen.DOMObject.querySelectorAll(".details-btn").forEach(t=>{t.addEventListener("click",r=>{let s=JSON.parse(r.currentTarget.dataset.device);G(s,e).show()})})}function K(a){return{alias:"devices",renderer:()=>Helper.template.mainTemplate(D("devices")),initer:e=>{a.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","");ke(e,Re(r.data),r.data.total),qe(e,a),e.ready()})}}}function Q(a,e){return a=Helper.unification.deviceFieldsUnification(a),Modals.create("device-setup",{title:`Setup new device ${a.ip}`,body:t=>{let r="";for(let n in a)n[0]!="_"&&(r+=`
					<tr class="table-row">
						<th>${n}: </th>
						<td>${a[n]}</td>
					</tr>
				`);return`
				<div class="row g-6">
					<div class="col device-info">
						${`
				<div class="block">
					<table class="table" style="border: 0">
						<tbody class="table-body">
							${r}
						</tbody>
					</table>
				</div>
			`}
					</div>

					<div class="col setup-form w-100">
						<div class="block form-group">
							<label class="label">
								Device alias
								<i class="ph ph-asterisk"></i>
								<input type="text" name="alias" class="input" placeholder="Input alias">
							</label>
						</div>

						<div class="block form-group">
							<label class="label">
								Device name
								<i class="ph ph-asterisk"></i>
								<input type="text" name="name" class="input" placeholder="Input name">
							</label>
						</div>

						<div class="block form-group">
							<label class="label">
								About device
								<i class="ph ph-note-pencil"></i>
								<textarea class="input" name="description" placeholder="Input description"></textarea>
							</label>
						</div>

						<div class="alert-container"></div>
					</div>
				</div>
			`},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"},'<i class="ph ph-gear"></i> Setup');return s.addEventListener("click",n=>{if(n.currentTarget.getAttribute("disabled"))return!1;let i={device_ip:a.ip},c=document.querySelector("#device-setup .setup-form");if(c.querySelectorAll("input[type='text']").forEach(l=>{l.dispatchEvent(new Event("input",{bubbles:!0}))}),c.querySelectorAll(".label.error").length)return!1;let o=c.querySelectorAll("input"),u=c.querySelector("textarea");for(let l of o)i[l.getAttribute("name")]=l.value;i[u.getAttribute("name")]=u.value,Helper.states.btnLoadingState(s,!0),e.devices.setup_new_device(i,(l,p,m)=>{var d,b;if(Helper.states.btnLoadingState(s,!1),(l==null?void 0:l.type)=="api_error"){if(console.error("ERR! sh_api.devices.setup_new_device",l.raw),(d=l.raw)!=null&&d.failed_fields)for(let f of l.raw.failed_fields)t.querySelector(`[name="${f}"]`).parentNode.classList.add("error");if((b=l.raw)!=null&&b.msg){let f=t.querySelector(".setup-form .alert-container");f.innerHTML="",f==null||f.append(Helper.template.createAlert("error",l.raw.msg))}return!1}if(!p)return!1;o.forEach(f=>f.value=""),u.value="",t.close(),Screens.reinit(),setTimeout(()=>{Toasts.createSuccess("Setup successful",`Added new device <b>ID ${a.device_id}</b>`).show()},300)})}),[r,s]},onready:t=>{t.querySelector(".setup-form").querySelectorAll("input").forEach(s=>{s.addEventListener("input",n=>{var i;n.currentTarget.value.length?(n.currentTarget.parentNode.classList.remove("error"),(i=n.currentTarget.parentNode.parentNode.querySelector(".input-info.error"))==null||i.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"},'<i class="ph ph-warning-circle"></i> Field cannot be empty')))})})}})}function Ne(a){let e=[];for(let t of a.devices)t=Helper.unification.deviceFieldsUnification(t),e.push({deviceId:t.device_id,deviceName:t.name,deviceType:t.type,status:`<span class="badge badge-primary">${t.status}</span>`,ip:`<code class="code">${t.ip}</code>`,mac:`<code class="code">${t.mac}</code>`,wifiSignal:t.wifi_signal,actions:t.status=="setup"?`
				<button 
					class="btn btn-secondary btn-small setup-btn" 
					data-device='${JSON.stringify(t)}'
					type="button"
				>Setup</button>
			`:""});return e}function Ie(a,e,t){a.currentScreen.DOMObject.querySelector(".main-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"},e,`<span class="table-meta">Total: <span class="total">${t}</span> devices</span>`)}function Ce(a,e){a.currentScreen.DOMObject.querySelectorAll(".setup-btn").forEach(t=>{t.addEventListener("click",r=>{let s=JSON.parse(r.currentTarget.dataset.device);Q(s,e).show()})})}function V(a){return{alias:"devices-scanning",renderer:()=>Helper.template.mainTemplate(D("scanning")),initer:e=>{a.devices.scanning_all((t,r,s)=>{if(console.log("sh_api.devices.scanning_all",t,r),s.status_code!=200)return e.error("Server API ERROR","");Ie(e,Ne(r.data),r.data.devices.length),Ce(e,a),e.ready()})}}}var q={list:K,scanning:V};function y(a){return Helper.template.sidebarNav([{content:'<span class="list-label"><i class="ph ph-cpu"></i> Scopes</span>',route:"/#!/scripts/scopes",is_active:a=="scopes"},{content:'<span class="list-label"><i class="ph ph-play"></i> Actions</span>',route:"/#!/scripts/actions",is_active:a=="actions"},{content:'<span class="list-label"><i class="ph ph-magnifying-glass"></i> Regular</span>',route:"/#!/scripts/regular",is_active:a=="regular"}])}function O(a,e,t){a.scripts.run({alias:e,params:{}},(r,s,n)=>{s?(t(!0),setTimeout(()=>Screens.reinit(),1e3),setTimeout(()=>Toasts.createSuccess(`${e} running`,`<b>${e}</b> running success`).show(),300)):(t(!1),setTimeout(()=>Toasts.createError(`${e} failed`,`<b>${e}</b> running failed`).show(),300))})}function xe(a){let e=[];for(let t of a.scopes){let r=t.state=="disabled"?`<button 
					class="btn btn-success btn-small change-state-btn" 
					data-scope='${JSON.stringify(t)}'
					type="button"
					data-value="enable"
				>Enable</button>`:`<button 
					class="btn btn-warning btn-small change-state-btn" 
					data-scope='${JSON.stringify(t)}'
					type="button"
					data-value="disable"
				>Disable</button>`;e.push({name:t.name,filename:`${t.filename}<br><code><small>${t.path}</small></code>`,state:Helper.template.toogleStateBadge(t.state),actions:`
				${r}
			`})}return e}function je(a,e,t){a.currentScreen.DOMObject.querySelector(".main-container").innerHTML=Helper.template.table("Scopes list",{name:"Scope name",filename:"Filename",state:"State",actions:"Actions"},e,`<span class="table-meta">Total: <span class="total">${t}</span> scopes</span>`)}function Pe(a,e){a.currentScreen.DOMObject.querySelectorAll(".change-state-btn").forEach(t=>{t.addEventListener("click",r=>{let s=r.currentTarget;if(s.getAttribute("disabled"))return;let n=s.dataset.value=="enable"?"scope_enable":"scope_disable",i=JSON.parse(s.dataset.scope);Helper.states.btnLoadingState(s,!0),e.scripts[n](i.name,(c,o,u)=>{Helper.states.btnLoadingState(s,!1),o?(setTimeout(()=>Screens.reinit(),250),Toasts.createSuccess("Request Success",`State of <b>${i.name}</b> was changed`).show()):Toasts.createError("Request failed","Scope state not changed").show()})})})}function X(a){return{title:"Scripts Scopes",alias:"scripts-scopes",renderer:()=>Helper.template.mainTemplate(y("scopes")),initer:e=>{a.scripts.scopes_list((t,r,s)=>{if(console.log("sh_api.scripts.scopes_list",t,r,s),s.status_code!=200)return e.error("Server API ERROR","");je(e,xe(r.data),r.data.total),Pe(e,a),e.ready()})}}}function Ue(a){let e=[];for(let t of a.scripts){let r=t.state=="disabled"?`<button 
					class="btn btn-success btn-small change-state-btn" 
					data-alias='${t.alias}'
					type="button"
					data-value="enable"
				>Enable</button>`:`<button 
					class="btn btn-warning btn-small change-state-btn" 
					data-alias='${t.alias}'
					type="button"
					data-value="disable"
				>Disable</button>`;e.push({alias:`${t.alias}<br><small class="text-muted">by ${t.created_by}</small>`,name:`${t.name}<div class="mt-1"><small>${t.description}</small></div>`,filename:`${t.filename}<br><code><small>${t.path}</small></code>`,state:Helper.template.toogleStateBadge(t.state),actions:`
				${r}
			`})}return e}function Fe(a,e,t){let r={};for(let s in e)r[e[s].alias]=e[s],e[s].code="";a.currentScreen.DOMObject.provideSciptsData=r,a.currentScreen.DOMObject.querySelector(".main-container").innerHTML=Helper.template.table("Regular scripts list",{alias:"Alias",name:"Script name",filename:"Filename",state:"State",actions:"Actions"},e,`<span class="table-meta">Total: <span class="total">${t}</span> scripts</span>`)}function Be(a,e){a.currentScreen.DOMObject.querySelectorAll(".change-state-btn").forEach(t=>{t.addEventListener("click",r=>{var c;let s=r.currentTarget;if(s.getAttribute("disabled"))return;let n=s.dataset.value=="enable"?"regular_enable":"regular_disable",i=(c=a.currentScreen.DOMObject.provideSciptsData[s.dataset.alias])!=null?c:{};Helper.states.btnLoadingState(s,!0),e.scripts[n](i.alias,(o,u,l)=>{Helper.states.btnLoadingState(s,!1),u?(setTimeout(()=>Screens.reinit(),250),Toasts.createSuccess("Request Success",`State of <b>${i.alias}</b> was changed`).show()):Toasts.createError("Request failed","Regular script state not changed").show()})})})}function Z(a){return{title:"Scripts Regular",alias:"scripts-regular",renderer:()=>Helper.template.mainTemplate(y("regular")),initer:e=>{a.scripts.regular_list((t,r,s)=>{if(console.log("sh_api.scripts.regular_list",t,r,s),s.status_code!=200)return e.error("Server API ERROR","");Fe(e,Ue(r.data),r.data.total),Be(e,a),e.ready()})}}}function ee(a,e){return console.log("actionDetailsPopup",a),Modals.create("action-script-popup",{title:`${a.name}`,body:t=>`
				<div class="block">
					<div class="row g-4">
						<div class="col script-info w-100">
							<h4 class="alias"><i class="ph ph-link-simple-break normalize"></i> <code>${a.alias}</code></h4>
							<div class="description mt-3">${a.description}</div>
							<div class="state mt-10">${Helper.template.toogleStateBadge(a.state)}</div>
							<div class="filename mt-4"><i class="ph ph-file-code normalize"></i> ${a.filename}</div>
							<div class="author mt-4 text-muted"><i class="ph ph-user normalize"></i> By ${a.author}</div>
						</div>
						<div class="col script-code w-200">
							<div class="script-code-view">
								<pre><code class="language-php code-viewer fs-xs">${a.code}</code></pre>
							</div>
						</div>
					</div>
				</div>
			`,actions:t=>{let r=Helper.template.createElement("button",{class:"btn btn-primary"},"Close"),s=Helper.template.createElement("button",{class:a.state=="enabled"?"btn btn-warning":"btn btn-success","data-value":a.state=="enabled"?"disable":"enable"},a.state=="enabled"?"Disable":"Enable"),n=Helper.template.createElement("button",{class:"btn btn-secondary with-icon"},'<i class="ph ph-play"></i> Run');return r.addEventListener("click",i=>{t.close()}),s.addEventListener("click",i=>{let c=i.currentTarget;if(c.getAttribute("disabled"))return;let o=c.dataset.value=="enable"?"action_enable":"action_disable";Helper.states.btnLoadingState(c,!0),e.scripts[o](a.alias,(u,l,p)=>{Helper.states.btnLoadingState(c,!1),t.close(),l?(setTimeout(()=>Screens.reinit(),250),Toasts.createSuccess("Request Success",`State of <b>${a.alias}</b> was changed`).show()):Toasts.createError("Request failed","Regular script state not changed").show()})}),n.addEventListener("click",i=>{let c=i.currentTarget;Helper.states.btnLoadingState(c,!0),O(e,a.alias,o=>{Helper.states.btnLoadingState(c,!1),o&&t.close()})}),[r,s,n]},onready:t=>{hljs.highlightElement(t.querySelector(".code-viewer"))}})}function ze(a){var t;let e=[];for(let r of a.scripts)e.push({alias:r.alias,author:r.created_by,name:r.name,icon:(t=r.icon)!=null?t:'<i class="ph ph-play"></i>',description:r.description,filename:`${r.filename}<br><code><small>${r.path}</small></code>`,state:r.state,code:r.code});return e}function Je(a,e,t){let r='<div class="f-grid g-5 w-100">',s={};for(let i of e){s[i.alias]=i;let c=i.state=="enabled"?"primary":"warning";r+=`
			<div 
				class="card device-action card-${c} script-action" 
				data-alias="${i.alias}"
			>
				<span class="card-title">${i.name} 
					<button 
						class="btn-icon without-hover action-details-btn" 
						data-alias='${i.alias}'
					>
						<i class="ph ph-dots-three-vertical"></i>
					</button>
				</span>

				<div class="card-content">
					<div class="device-icon-container">
						<div class="device-icon">
							${i.icon}
						</div>
					</div>

					<div class="device-name mb-2">${i.description}</div>
				</div>
			</div>
		`}r+="</div>";let n=a.currentScreen.DOMObject.querySelector(".main-container");n.innerHTML=r,a.currentScreen.DOMObject.provideSciptsData=s}function We(a,e){a.currentScreen.DOMObject.querySelectorAll(".script-action .card-content").forEach(t=>{t.addEventListener("click",r=>{let s=r.currentTarget.parentNode;if(s.getAttribute("disabled"))return;Helper.states.cardScriptActionLoadingState(s,!0);let n=s.dataset.alias;O(e,n,i=>{Helper.states.cardScriptActionLoadingState(s,!1),i&&(s.classList.add("card-success"),setTimeout(()=>s.classList.remove("card-success"),1e3))})})}),a.currentScreen.DOMObject.querySelectorAll(".action-details-btn").forEach(t=>{t.addEventListener("click",r=>{var i;let s=r.currentTarget,n=(i=a.currentScreen.DOMObject.provideSciptsData[s.dataset.alias])!=null?i:{};console.log("SCRIPT",n),ee(n,e).show()})})}function te(a){return{title:"Scripts Actions",alias:"scripts-actions",renderer:()=>Helper.template.mainTemplate(y("actions")),initer:e=>{a.scripts.actions_list((t,r,s)=>{if(console.log("sh_api.scripts.regular_list",t,r,s),s.status_code!=200)return e.error("Server API ERROR","");Je(e,ze(r.data),r.data.total),We(e,a),e.ready()})}}}var M={scopes:X,regular:Z,actions:te};function ae(a){return Helper.template.sidebarNav([{content:'<span class="list-label"><i class="ph ph-tree-structure"></i> Areas Tree</span>',route:"/#!/areas/tree",is_active:a=="areas-tree"},{content:'<span class="list-label"><i class="ph ph-play"></i> Actions</span>',route:"/#!/scripts/actions",is_active:a=="actions"}])}function re(a,e){return console.log("areaDevicesModal",a),Modals.create("area-devices-modal",{title:`<i class="ph ph-map-trifold normalize"></i> ${a.name}`,body:t=>`
				<div class="loader"></div>
				<div class="devices-container"></div>
			`,actions:t=>{let r=Helper.template.createElement("button",{class:"btn btn-primary"},"Close");return r.addEventListener("click",s=>{t.close()}),[r]},onready:t=>{let r=t.querySelector(".devices-container"),s=t.querySelector(".loader");e.areas.devices(a.id,(n,i,c)=>{console.log("sh_api.areas.devices",i);function o(l){if(!l)return[];let p=[];for(let m of l.devices)m=Helper.unification.deviceFieldsUnification(m),p.push({deviceName:m.name,alias:m.alias,status:Helper.template.connectionStatusBadge(m.connection_state),ip:`<code class="code">${m.ip}</code>`,actions:`
								<button 
									class="btn btn-warning btn-small reboot-btn" 
									data-device-id="${m.id}" 
									data-device-name="${m.name}" 
									data-device-alias="${m.alias}" 
									type="button"
								>Reboot</button>
							`});return p}let u=o(i==null?void 0:i.data);r.innerHTML=Helper.template.table("",{deviceName:"Device name",alias:"Device alias",status:"Status",ip:"IP",actions:"Actions"},u,`<span class="table-meta">Total: <span class="total">${u.length}</span> devices</span>`),r.querySelectorAll(".reboot-btn").forEach(l=>{l.addEventListener("click",p=>{l.getAttribute("disabled")||S(e,p.currentTarget,t)})}),s.remove(),console.log("devices",u)})}})}function se(a){return console.log("createNewAreaModal"),Modals.create("create-area-modal",{title:'<i class="ph ph-plus normalize"></i> Create new Area',body:e=>`
				<div class="create-area-form">
					<div class="block form-group">
						<label class="label">
							Type
							<input type="text" class="input" name="type" placeholder="Input Area Type">
						</label>
					</div>

					<div class="block form-group">
						<label class="label">
							Alias
							<i class="ph ph-link-simple-break"></i>
							<input type="text" class="input" name="alias" placeholder="Input Area Alias">
						</label>
					</div>

					<div class="block form-group">
						<label class="label">
							Display Name
							<i class="ph ph-tag"></i>
							<input type="text" class="input" name="display_name" placeholder="Input Display Name">
						</label>
					</div>

					<div class="alert-container"></div>
				</div>
			`,actions:e=>{let t=Helper.template.createElement("button",{class:"btn btn-primary"},"Close"),r=Helper.template.createElement("button",{class:"btn btn-success with-icon"},'<i class="ph ph-plus"></i> Create');return t.addEventListener("click",s=>{e.close()}),r.addEventListener("click",s=>{let n=e.querySelector(".create-area-form");if(n.querySelectorAll("input[type='text']").forEach(o=>{o.dispatchEvent(new Event("input",{bubbles:!0}))}),n.querySelectorAll(".label.error").length)return!1;let i=n.querySelectorAll("input"),c={};for(let o of i)c[o.getAttribute("name")]=o.value;Helper.states.btnLoadingState(r,!0),a.areas.new_area(c,(o,u,l)=>{var p,m;if(Helper.states.btnLoadingState(r,!1),(o==null?void 0:o.type)=="api_error"){if(console.error("ERR! sh_api.areas.new_area",o.raw),(p=o.raw)!=null&&p.failed_fields)for(let d of o.raw.failed_fields)e.querySelector(`[name="${d}"]`).parentNode.classList.add("error");if((m=o.raw)!=null&&m.msg){let d=e.querySelector(".alert-container");d.innerHTML="",d==null||d.append(Helper.template.createAlert("error",o.raw.msg))}return!1}if(!u)return!1;i.forEach(d=>d.value=""),e.close(),Screens.reinit(),setTimeout(()=>{Toasts.createSuccess("Setup successful",`Added new area <b>ID ${c.alias}</b>`).show()},300)})}),[t,r]},onready:e=>{e.querySelector(".create-area-form").querySelectorAll(".input").forEach(r=>{r.addEventListener("input",s=>{var n;s.currentTarget.value.length?(s.currentTarget.parentNode.classList.remove("error"),(n=s.currentTarget.parentNode.parentNode.querySelector(".input-info.error"))==null||n.remove()):(s.currentTarget.parentNode.classList.add("error"),s.currentTarget.parentNode.parentNode.querySelector(".input-info.error")||s.currentTarget.parentNode.parentNode.append(Helper.template.createElement("div",{class:"input-info error"},'<i class="ph ph-warning-circle"></i> Field cannot be empty')))})})}})}function Ye(a){let e=a.areas,t={},r=[];for(let s of e)t[s.id]=j(v({},s),{children:[]});for(let s of e){let n=t[s.id];s.parent_id&&t[s.parent_id]?t[s.parent_id].children.push(n):r.push(n)}return r}function Ge(a){return Ye(a)}function ne(a){var t;let e='<div class="branch">';if(e+=`
		<div class="branch">
			<div class="branch-container">
				<div class="branch-info">
					<span class="title"><i class="ph ph-map-trifold normalize"></i> ${a.display_name}</span>
					[
					<span class="text-muted area-type">${a.type}</span>
					<span><i class="ph ph-link-simple-break normalize"></i> ${a.alias}</span>
					]
				</div>

				<div class="row g-4">
					<button 
						class="btn btn-accent btn-small with-icon"
						data-area-id="${a.id}"
						data-area-name="${a.display_name}"
					><i class="ph ph-brackets-curly"></i> Scripts</button>
					<button 
						class="btn btn-accent btn-small with-icon devices" 
						data-area-id="${a.id}"
						data-area-name="${a.display_name}"
					><i class="ph ph-cpu"></i> Devices</button>
					<button 
						class="btn btn-small btn-primary"
					>Details</button>
				</div>
			</div>
		</div>
	`,(t=a.children)!=null&&t.length)for(let r of a.children)e+=ne(r);return e+="</div>",e}function Ke(a,e){console.log("TREE",e);let t='<div class="tree">';for(let r of e)t+=ne(r);t+="</div>",a.currentScreen.DOMObject.querySelector(".main-container .tree-container").innerHTML=t}function Qe(a,e){a.currentScreen.DOMObject.querySelectorAll(".btn.devices").forEach(t=>{t.addEventListener("click",r=>{let s=r.currentTarget,n=s.dataset.areaId,i=s.dataset.areaName;re({id:n,name:i},e).show()})}),a.ready()}function ie(a){return{title:"Areas Tree",alias:"areas-tree",renderer:()=>Helper.template.mainTemplate(ae("areas-tree"),`<div class="top-bar">
					<div class="row g-4">
						<div class="col">
							<h3 class="title">Areas Tree</h3>
						</div>
						<div class="col">
							<button class="btn btn-primary with-icon create-new-area-modal">
								<i class="ph ph-plus"></i>
								Create
							</button>
						</div>
					</div>
				</div>
				<div class="mt-6 tree-container"></div>
				`),initer:e=>{a.areas.list((t,r,s)=>{if(console.log("sh_api.areas.list",t,r,s),s.status_code!=200)return e.error("Server API ERROR","");Ke(e,Ge(r.data)),Qe(e,a),e.currentScreen.DOMObject.querySelector(".create-new-area-modal").addEventListener("click",n=>{se(a).show()}),e.ready()})}}}var oe={areasTree:ie};function ce(a,e){a.add("/",{alias:"home",renderer:()=>'<h2 class="mt-4">Hello world</h2>',initer:t=>{setTimeout(()=>t.ready(),1e3),setTimeout(()=>t.error("Error","Just testing"),2e3)}}),a.add("-",{alias:"not-found-screen",renderer:()=>'<h2 class="mt-4">404 NOT FOUND</h2>',initer:t=>{t.ready()}}),a.add("/devices",q.list(e)),a.add("/devices/scanning",q.scanning(e)),a.add("/scripts/scopes",M.scopes(e)),a.add("/scripts/regular",M.regular(e)),a.add("/scripts/actions",M.actions(e)),a.add("/areas/tree",oe.areasTree(e))}function Ve(a,e,t){return`
		<div class="modal" aria-hidden="true" id="${a}">
      <div class="modal-backdrop"></div>

      <div class="modal-panel" role="dialog" aria-modal="true" aria-labelledby="modal-title-basic">
        <header class="modal-header">
          <h4 class="modal-title" id="modal-title-basic">${e}</h4>
          <button class="btn-icon modal-close" type="button" aria-label="Close">\u2715</button>
        </header>

        <div class="modal-body"></div>
        <footer class="modal-footer">${t}</footer>
      </div>
    </div>
	`}function Xe(a,e){return a.show=function(){document.querySelector("body").append(a),setTimeout(()=>{this.classList.add("a-show")},10)},a.close=function(){this.classList.add("a-hide"),setTimeout(()=>{this.remove()},300)},a.querySelector(".modal-close").addEventListener("click",t=>{a.close()}),typeof e=="function"&&e(a),a}function Ze(a,e){let t=e.title||"",r=e.footer||"",s=document.createElement("div");s.innerHTML=Ve(a,t,r);let n=s.childNodes[1],i=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 l of o)u.append(l);c.append(u)}}if(typeof e.body=="function"){let o=e.body(n);typeof o=="object"?i.append(o):typeof o=="string"&&(i.innerHTML=o)}return Xe(n,e==null?void 0:e.onready)}var le={create:Ze};function N(a,e,t){Modals.create("confirm-popup",{title:"Requires confirmation",body:r=>`
				<p>${a}</p>
			`,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",i=>{r.close(),t()}),n.addEventListener("click",i=>{r.close(),e()}),[s,n]}}).show()}document.addEventListener("DOMContentLoaded",a=>{console.log("App init"),window.Toasts=z,window.Helper=W,window.Modals=le,window.confirmPopup=N,F();let e=new A({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 $(".screens",".load-screen",".error-screen");ce(t,e),console.log(t.getScreens()),t.onSwitch((r,s)=>{k()}),t.routing(),window.Screens=t});})();
//# sourceMappingURL=main.js.map