From e3106d7b6014ced25f41e1ff622130766b9bb71d Mon Sep 17 00:00:00 2001 From: tajniak81 <13187254+tajniak81@users.noreply.github.com> Date: Mon, 13 Jul 2026 18:36:17 +0200 Subject: [PATCH] Show status latency at end of detail line in API panel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reorder the Status card meta() detail so HTTP status and URL come first and the latency (ms) reads last, e.g. "HTTP 200 · · 12ms". Rebuild the embedded panel assets. Co-Authored-By: Claude Opus 4.8 --- .../api/dist/assets/{index-DJSuRngH.js => index-BkFF389B.js} | 2 +- API Server/internal/api/dist/index.html | 2 +- API Server/panel/src/App.vue | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename API Server/internal/api/dist/assets/{index-DJSuRngH.js => index-BkFF389B.js} (99%) diff --git a/API Server/internal/api/dist/assets/index-DJSuRngH.js b/API Server/internal/api/dist/assets/index-BkFF389B.js similarity index 99% rename from API Server/internal/api/dist/assets/index-DJSuRngH.js rename to API Server/internal/api/dist/assets/index-BkFF389B.js index 3dcd126..f13ecdd 100644 --- a/API Server/internal/api/dist/assets/index-DJSuRngH.js +++ b/API Server/internal/api/dist/assets/index-BkFF389B.js @@ -14,4 +14,4 @@ * @vue/runtime-dom v3.5.39 * (c) 2018-present Yuxi (Evan) You and Vue contributors * @license MIT -**/let wn;const ho=typeof window<"u"&&window.trustedTypes;if(ho)try{wn=ho.createPolicy("vue",{createHTML:e=>e})}catch{}const Ui=wn?e=>wn.createHTML(e):e=>e,Vr="http://www.w3.org/2000/svg",Hr="http://www.w3.org/1998/Math/MathML",at=typeof document<"u"?document:null,go=at&&at.createElement("template"),Br={insert:(e,t,s)=>{t.insertBefore(e,s||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,s,n)=>{const o=t==="svg"?at.createElementNS(Vr,e):t==="mathml"?at.createElementNS(Hr,e):s?at.createElement(e,{is:s}):at.createElement(e);return e==="select"&&n&&n.multiple!=null&&o.setAttribute("multiple",n.multiple),o},createText:e=>at.createTextNode(e),createComment:e=>at.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>at.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,s,n,o,i){const l=s?s.previousSibling:t.lastChild;if(o&&(o===i||o.nextSibling))for(;t.insertBefore(o.cloneNode(!0),s),!(o===i||!(o=o.nextSibling)););else{go.innerHTML=Ui(n==="svg"?`${e}`:n==="mathml"?`${e}`:e);const r=go.content;if(n==="svg"||n==="mathml"){const c=r.firstChild;for(;c.firstChild;)r.appendChild(c.firstChild);r.removeChild(c)}t.insertBefore(r,s)}return[l?l.nextSibling:t.firstChild,s?s.previousSibling:t.lastChild]}},Kr=Symbol("_vtc");function zr(e,t,s){const n=e[Kr];n&&(t=(t?[t,...n]:[...n]).join(" ")),t==null?e.removeAttribute("class"):s?e.setAttribute("class",t):e.className=t}const Ls=Symbol("_vod"),$i=Symbol("_vsh"),Jt={name:"show",beforeMount(e,{value:t},{transition:s}){e[Ls]=e.style.display==="none"?"":e.style.display,s&&t?s.beforeEnter(e):Yt(e,t)},mounted(e,{value:t},{transition:s}){s&&t&&s.enter(e)},updated(e,{value:t,oldValue:s},{transition:n}){!t!=!s&&(n?t?(n.beforeEnter(e),Yt(e,!0),n.enter(e)):n.leave(e,()=>{Yt(e,!1)}):Yt(e,t))},beforeUnmount(e,{value:t}){Yt(e,t)}};function Yt(e,t){e.style.display=t?e[Ls]:"none",e[$i]=!t}const Wr=Symbol(""),Gr=/(?:^|;)\s*display\s*:/;function qr(e,t,s){const n=e.style,o=ce(s);let i=!1;if(s&&!o){if(t)if(ce(t))for(const l of t.split(";")){const r=l.slice(0,l.indexOf(":")).trim();s[r]==null&&Qt(n,r,"")}else for(const l in t)s[l]==null&&Qt(n,l,"");for(const l in s){l==="display"&&(i=!0);const r=s[l];r!=null?Yr(e,l,!ce(t)&&t?t[l]:void 0,r)||Qt(n,l,r):Qt(n,l,"")}}else if(o){if(t!==s){const l=n[Wr];l&&(s+=";"+l),n.cssText=s,i=Gr.test(s)}}else t&&e.removeAttribute("style");Ls in e&&(e[Ls]=i?n.display:"",e[$i]&&(n.display="none"))}const mo=/\s*!important$/;function Qt(e,t,s){if(F(s))s.forEach(n=>Qt(e,t,n));else if(s==null&&(s=""),t.startsWith("--"))e.setProperty(t,s);else{const n=Jr(e,t);mo.test(s)?e.setProperty(yt(n),s.replace(mo,""),"important"):e[n]=s}}const vo=["Webkit","Moz","ms"],an={};function Jr(e,t){const s=an[t];if(s)return s;let n=Be(t);if(n!=="filter"&&n in e)return an[t]=n;n=Uo(n);for(let o=0;ocn||(sa.then(()=>cn=0),cn=Date.now());function oa(e,t){const s=n=>{if(!n._vts)n._vts=Date.now();else if(n._vts<=s.attached)return;const o=s.value;if(F(o)){const i=n.stopImmediatePropagation;n.stopImmediatePropagation=()=>{i.call(n),n._stopped=!0};const l=o.slice(),r=[n];for(let c=0;ce.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,ia=(e,t,s,n,o,i)=>{const l=o==="svg";t==="class"?zr(e,n,l):t==="style"?qr(e,s,n):Fs(t)?Ns(t)||Zr(e,t,s,n,i):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):la(e,t,n,l))?(xo(e,t,n),!e.tagName.includes("-")&&(t==="value"||t==="checked"||t==="selected")&&yo(e,t,n,l,i,t!=="value")):e._isVueCE&&(ra(e,t)||e._def.__asyncLoader&&(/[A-Z]/.test(t)||!ce(n)))?xo(e,Be(t),n,i,t):(t==="true-value"?e._trueValue=n:t==="false-value"&&(e._falseValue=n),yo(e,t,n,l))};function la(e,t,s,n){if(n)return!!(t==="innerHTML"||t==="textContent"||t in e&&wo(t)&&H(s));if(t==="spellcheck"||t==="draggable"||t==="translate"||t==="autocorrect"||t==="sandbox"&&e.tagName==="IFRAME"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA")return!1;if(t==="width"||t==="height"){const o=e.tagName;if(o==="IMG"||o==="VIDEO"||o==="CANVAS"||o==="SOURCE")return!1}return wo(t)&&ce(s)?!1:t in e}function ra(e,t){const s=e._def.props;if(!s)return!1;const n=Be(t);return Array.isArray(s)?s.some(o=>Be(o)===n):Object.keys(s).some(o=>Be(o)===n)}const bt=e=>{const t=e.props["onUpdate:modelValue"]||!1;return F(t)?s=>Ts(t,s):t};function aa(e){e.target.composing=!0}function Co(e){const t=e.target;t.composing&&(t.composing=!1,t.dispatchEvent(new Event("input")))}const Le=Symbol("_assign");function So(e,t,s){return t&&(e=e.trim()),s&&(e=Hs(e)),e}const ye={created(e,{modifiers:{lazy:t,trim:s,number:n}},o){e[Le]=bt(o);const i=n||o.props&&o.props.type==="number";dt(e,t?"change":"input",l=>{l.target.composing||e[Le](So(e.value,s,i))}),(s||i)&&dt(e,"change",()=>{e.value=So(e.value,s,i)}),t||(dt(e,"compositionstart",aa),dt(e,"compositionend",Co),dt(e,"change",Co))},mounted(e,{value:t}){e.value=t??""},beforeUpdate(e,{value:t,oldValue:s,modifiers:{lazy:n,trim:o,number:i}},l){if(e[Le]=bt(l),e.composing)return;const r=(i||e.type==="number")&&!/^0\d/.test(e.value)?Hs(e.value):e.value,c=t??"";if(r===c)return;const g=e.getRootNode();(g instanceof Document||g instanceof ShadowRoot)&&g.activeElement===e&&e.type!=="range"&&(n&&t===s||o&&e.value.trim()===c)||(e.value=c)}},ji={deep:!0,created(e,t,s){e[Le]=bt(s),dt(e,"change",()=>{const n=e._modelValue,o=Kt(e),i=e.checked,l=e[Le];if(F(n)){const r=Tn(n,o),c=r!==-1;if(i&&!c)l(n.concat(o));else if(!i&&c){const g=[...n];g.splice(r,1),l(g)}}else if(zt(n)){const r=new Set(n);i?r.add(o):r.delete(o),l(r)}else l(Di(e,i))})},mounted:ko,beforeUpdate(e,t,s){e[Le]=bt(s),ko(e,t,s)}};function ko(e,{value:t,oldValue:s},n){e._modelValue=t;let o;if(F(t))o=Tn(t,n.props.value)>-1;else if(zt(t))o=t.has(n.props.value);else{if(t===s)return;o=mt(t,Di(e,!0))}e.checked!==o&&(e.checked=o)}const ca={created(e,{value:t},s){e.checked=mt(t,s.props.value),e[Le]=bt(s),dt(e,"change",()=>{e[Le](Kt(e))})},beforeUpdate(e,{value:t,oldValue:s},n){e[Le]=bt(n),t!==s&&(e.checked=mt(t,n.props.value))}},Dt={deep:!0,created(e,{value:t,modifiers:{number:s}},n){const o=zt(t);dt(e,"change",()=>{const i=Array.prototype.filter.call(e.options,l=>l.selected).map(l=>s?Hs(Kt(l)):Kt(l));e[Le](e.multiple?o?new Set(i):i:i[0]),e._assigning=!0,ti(()=>{e._assigning=!1})}),e[Le]=bt(n)},mounted(e,{value:t}){Eo(e,t)},beforeUpdate(e,t,s){e[Le]=bt(s)},updated(e,{value:t}){e._assigning||Eo(e,t)}};function Eo(e,t){const s=e.multiple,n=F(t);if(!(s&&!n&&!zt(t))){for(let o=0,i=e.options.length;oString(g)===String(r)):l.selected=Tn(t,r)>-1}else l.selected=t.has(r);else if(mt(Kt(l),t)){e.selectedIndex!==o&&(e.selectedIndex=o);return}}!s&&e.selectedIndex!==-1&&(e.selectedIndex=-1)}}function Kt(e){return"_value"in e?e._value:e.value}function Di(e,t){const s=t?"_trueValue":"_falseValue";return s in e?e[s]:t}const ua={created(e,t,s){ks(e,t,s,null,"created")},mounted(e,t,s){ks(e,t,s,null,"mounted")},beforeUpdate(e,t,s,n){ks(e,t,s,n,"beforeUpdate")},updated(e,t,s,n){ks(e,t,s,n,"updated")}};function fa(e,t){switch(e){case"SELECT":return Dt;case"TEXTAREA":return ye;default:switch(t){case"checkbox":return ji;case"radio":return ca;default:return ye}}}function ks(e,t,s,n,o){const l=fa(e.tagName,s.props&&s.props.type)[o];l&&l(e,t,s,n)}const da=["ctrl","shift","alt","meta"],pa={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,t)=>da.some(s=>e[`${s}Key`]&&!t.includes(s))},ha=(e,t)=>{if(!e)return e;const s=e._withMods||(e._withMods={}),n=t.join(".");return s[n]||(s[n]=((o,...i)=>{for(let l=0;l{const s=e._withKeys||(e._withKeys={}),n=t.join(".");return s[n]||(s[n]=(o=>{if(!("key"in o))return;const i=yt(o.key);if(t.some(l=>l===i||ga[l]===i))return e(o)}))},ma=ve({patchProp:ia},Br);let Po;function va(){return Po||(Po=xr(ma))}const ba=((...e)=>{const t=va().createApp(...e),{mount:s}=t;return t.mount=n=>{const o=xa(n);if(!o)return;const i=t._component;!H(i)&&!i.render&&!i.template&&(i.template=o.innerHTML),o.nodeType===1&&(o.textContent="");const l=s(o,!1,ya(o));return o instanceof Element&&(o.removeAttribute("v-cloak"),o.setAttribute("data-v-app","")),l},t});function ya(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function xa(e){return ce(e)?document.querySelector(e):e}const Li="pilotvault-theme";function _a(){try{return localStorage.getItem(Li)==="dark"?"dark":"light"}catch{return"light"}}const ds=L(_a());function Fi(e){ds.value=e,document.documentElement.setAttribute("data-theme",e);try{localStorage.setItem(Li,e)}catch{}}function Ao(){Fi(ds.value==="dark"?"light":"dark")}Fi(ds.value);const wa={class:"overflow-hidden rounded-lg border border-subtle bg-card shadow-xs"},Ca={class:"flex items-center justify-between border-b border-subtle px-5 py-4"},Sa={class:"text-base font-semibold text-primary"},ka={class:"pv-eyebrow"},Ea={class:"w-full text-left text-sm"},Ta={class:"border-t border-subtle px-5 py-2.5 font-mono text-xs whitespace-nowrap"},Pa={class:"text-primary"},Aa={class:"border-t border-subtle px-5 py-2.5 text-secondary"},un={__name:"EndpointTable",props:{title:String,auth:String,endpoints:Array},setup(e){const t={GET:"text-success",POST:"text-brand-text",PATCH:"text-warning",DELETE:"text-danger"};return(s,n)=>(P(),A("div",wa,[d("div",Ca,[d("div",Sa,O(e.title),1),d("span",ka,O(e.auth),1)]),d("table",Ea,[n[0]||(n[0]=d("thead",null,[d("tr",{class:"pv-eyebrow"},[d("th",{class:"px-5 py-2.5 font-medium"},"Endpoint"),d("th",{class:"px-5 py-2.5 font-medium"},"Description")])],-1)),d("tbody",null,[(P(!0),A(re,null,Ce(e.endpoints,o=>(P(),A("tr",{key:o.method+o.path,class:"transition-colors hover:bg-sunken"},[d("td",Ta,[d("span",{class:Pe(["font-semibold",t[o.method]])},O(o.method),3),d("span",Pa,O(o.path),1)]),d("td",Aa,O(o.desc),1)]))),128))])])]))}},Oa={class:"mx-auto flex max-w-5xl flex-col gap-6 px-6 pt-12 pb-16"},Ra={class:"flex items-center gap-3"},Ia={key:0,class:"pv-eyebrow hidden truncate sm:inline"},Ma=["title"],Ua={key:0,class:"h-4 w-4",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},$a={key:1,class:"h-4 w-4",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},ja={key:0,class:"rounded-lg border border-subtle bg-card px-5 py-10 text-center shadow-sm"},Da={key:1,class:"mx-auto w-full max-w-sm rounded-lg border border-subtle bg-card shadow-sm"},La={class:"flex flex-col gap-1"},Fa={class:"flex flex-col gap-1"},Na={key:0,class:"rounded-sm bg-danger-tint px-3 py-2 text-xs font-medium text-danger"},Va=["disabled"],Ha={class:"flex gap-1 self-start rounded-lg border border-subtle bg-card p-1 shadow-sm"},Ba=["onClick"],Ka={class:"flex flex-col gap-6"},za={class:"rounded-lg border border-subtle bg-card shadow-sm"},Wa={class:"flex items-center justify-between border-b border-subtle px-5 py-4"},Ga={class:"pv-eyebrow"},qa={class:"min-w-0"},Ja={class:"text-sm font-semibold text-primary"},Ya={key:0,class:"truncate font-mono text-xs text-secondary"},Xa={class:"flex items-center justify-between gap-3 border-t border-subtle px-5 py-3.5"},Za={class:"font-mono text-xs text-secondary"},Qa={class:"flex flex-col gap-6"},ec={class:"rounded-lg border border-subtle bg-card shadow-sm"},tc={class:"flex flex-col gap-3 px-5 py-5"},sc={class:"flex flex-col gap-3 sm:flex-row"},nc={class:"flex flex-1 flex-col gap-1"},oc={class:"flex flex-1 flex-col gap-1"},ic={class:"flex flex-col gap-3 sm:flex-row"},lc={class:"flex flex-1 flex-col gap-1"},rc=["value"],ac={class:"flex flex-1 flex-col gap-1"},cc=["value"],uc={key:0,class:"rounded-sm bg-danger-tint px-3 py-2 text-xs font-medium text-danger"},fc={key:1,class:"rounded-sm bg-success-tint px-3 py-2 text-xs font-medium text-success"},dc=["disabled"],pc={class:"rounded-lg border border-subtle bg-card shadow-sm"},hc={class:"flex items-center justify-between border-b border-subtle px-5 py-4"},gc={class:"pv-eyebrow"},mc={class:"flex flex-col"},vc={key:0,class:"px-5 py-3 text-xs font-medium text-danger"},bc={key:1,class:"border-b border-subtle bg-sunken px-5 py-2.5 font-mono text-xs text-secondary"},yc={key:2,class:"px-5 py-6 text-sm text-secondary"},xc={class:"flex flex-wrap items-center gap-x-3 gap-y-2"},_c={class:"min-w-0 flex-1"},wc={class:"flex flex-wrap items-center gap-2"},Cc={class:"truncate text-sm font-semibold text-primary"},Sc={key:0,class:"rounded-sm bg-brand/10 px-1.5 py-0.5 font-mono text-[10px] font-medium text-brand-text"},kc={key:1,class:"rounded-sm bg-warning-tint px-1.5 py-0.5 font-mono text-[10px] font-medium text-warning"},Ec={class:"mt-0.5 font-mono text-xs text-secondary"},Tc={class:"flex shrink-0 items-center gap-2"},Pc=["onClick"],Ac=["disabled","onClick"],Oc={key:0,class:"mt-3 flex flex-col gap-3 rounded-md border border-subtle bg-sunken px-4 py-4"},Rc={class:"flex flex-col gap-3 sm:flex-row"},Ic={class:"flex flex-1 flex-col gap-1"},Mc={class:"flex flex-1 flex-col gap-1"},Uc={class:"flex flex-col gap-3 sm:flex-row"},$c={class:"flex flex-1 flex-col gap-1"},jc=["disabled"],Dc=["value"],Lc={key:0,class:"text-[11px] text-muted"},Fc={class:"flex flex-1 flex-col gap-1"},Nc=["value"],Vc={class:"flex items-center gap-2"},Hc={class:"flex items-center gap-2"},Bc=["disabled","onClick"],Kc={class:"flex flex-col gap-6"},zc={class:"rounded-lg border border-subtle bg-card shadow-sm"},Wc={class:"flex flex-col gap-3 px-5 py-5"},Gc={class:"flex flex-col gap-2 sm:flex-row"},qc=["disabled"],Jc={key:0,class:"rounded-sm bg-danger-tint px-3 py-2 text-xs font-medium text-danger"},Yc={key:1,class:"rounded-sm bg-success-tint px-3 py-2 text-xs font-medium text-success"},Xc={class:"rounded-lg border border-subtle bg-card shadow-sm"},Zc={class:"flex items-center justify-between border-b border-subtle px-5 py-4"},Qc={class:"pv-eyebrow"},eu={class:"flex flex-col"},tu={key:0,class:"border-b border-subtle bg-sunken px-5 py-2.5 font-mono text-xs text-secondary"},su={key:1,class:"px-5 py-6 text-sm text-secondary"},nu={class:"flex flex-wrap items-center gap-x-3 gap-y-2"},ou={class:"min-w-0 flex-1"},iu={class:"truncate text-sm font-semibold text-primary"},lu={class:"mt-0.5 font-mono text-xs text-secondary"},ru={class:"flex shrink-0 items-center gap-2"},au=["onClick"],cu=["disabled","title","onClick"],uu={key:0,class:"mt-3 flex flex-col gap-2 rounded-md border border-subtle bg-sunken px-4 py-4 sm:flex-row sm:items-end"},fu={class:"flex flex-1 flex-col gap-1"},du=["onKeyup"],pu={class:"flex items-center gap-2"},hu=["disabled","onClick"],gu={class:"flex flex-col gap-6"},mu={class:"rounded-lg border border-subtle bg-card shadow-sm"},vu={class:"flex items-center justify-between border-b border-subtle px-5 py-4"},bu={class:"flex flex-col gap-3 px-5 py-5"},yu={class:"flex flex-col gap-1"},xu={class:"flex flex-col gap-1"},_u={class:"flex flex-col gap-1"},wu=["placeholder"],Cu={key:0,class:"font-mono text-[11px] text-muted"},Su={key:0},ku={key:1},Eu={key:1,class:"rounded-sm bg-danger-tint px-3 py-2 text-xs font-medium text-danger"},Tu={key:2,class:"rounded-sm bg-success-tint px-3 py-2 text-xs font-medium text-success"},Pu={class:"flex flex-wrap items-center gap-2"},Au=["disabled"],Ou=["disabled"],Ru={class:"flex flex-col gap-6"},Iu={class:"rounded-lg border border-subtle bg-card shadow-sm"},Mu={class:"flex flex-col"},Uu={key:0,class:"px-5 py-3 text-xs font-medium text-danger"},$u={key:1,class:"border-b border-subtle bg-sunken px-5 py-2.5 font-mono text-xs text-secondary"},ju={key:2,class:"px-5 py-6 text-sm text-secondary"},Du={key:3,class:"flex gap-1 overflow-x-auto overflow-y-hidden border-b border-subtle px-3 pt-1"},Lu=["onClick"],Fu={key:4,class:"px-5 py-6 text-sm text-secondary"},Nu={class:"flex flex-wrap items-center gap-x-3 gap-y-2"},Vu={class:"min-w-0 flex-1"},Hu={class:"flex flex-wrap items-center gap-2"},Bu={class:"text-sm font-semibold text-primary"},Ku=["title"],zu={key:0},Wu={class:"mt-0.5 font-mono text-xs text-secondary"},Gu={key:0,class:"mt-0.5 text-[11px] text-secondary"},qu={key:1,class:"mt-2 flex flex-col gap-1.5"},Ju={class:"rounded-sm bg-sunken px-1.5 py-0.5 font-mono text-[10px] text-secondary"},Yu={key:0,class:"font-mono text-[10px] text-muted"},Xu={key:1,class:"w-full text-[11px] text-secondary sm:w-auto"},Zu={key:2,class:"mt-1 truncate font-mono text-[11px] text-muted"},Qu={class:"flex shrink-0 items-center gap-2"},ef=["disabled","onClick"],tf=["onClick"],sf=["disabled","onClick"],nf=["disabled","onClick"],of={key:0,class:"mt-3 flex flex-col gap-2 rounded-md border border-subtle bg-sunken px-4 py-4"},lf={class:"pv-eyebrow"},rf={key:0,class:"text-danger"},af=["onUpdate:modelValue"],cf=["value"],uf=["onUpdate:modelValue","type","placeholder"],ff={key:2,class:"text-[11px] text-muted"},df={class:"flex items-center gap-2"},pf=["disabled","onClick"],hf={class:"border-t border-subtle px-5 py-4"},gf={class:"flex flex-col gap-2 sm:flex-row"},mf=["disabled"],vf={key:0,class:"mt-2 text-xs font-medium text-danger"},Es="pv_panel_token",bf={__name:"App",setup(e){const t=L(localStorage.getItem(Es)||""),s=L(null),n=L(!1),o=L(!0),i=L({email:"",password:""}),l=L(""),r=L(!1),c=L("overview"),g=[{id:"overview",label:"Overview"},{id:"users",label:"Users"},{id:"organizations",label:"Organizations"},{id:"pocketbase",label:"PocketBase"},{id:"plugins",label:"Plugins"}];async function h(v){try{const u=await fetch("/api/me",{headers:{Authorization:v}});if(!u.ok)return!1;const f=await u.json();return f.role!=="superadmin"?!1:(s.value={id:f.id,email:f.email,role:f.role},!0)}catch{return!1}}async function y(v){t.value=v,localStorage.setItem(Es,v),n.value=!0,Gn(),ke(),it(),Mt(),ie()}async function I(){l.value="";const v=i.value.email.trim().toLowerCase();if(!v||!i.value.password){l.value="Enter your email and password.";return}r.value=!0;try{const u=await fetch("/api/auth/login",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,password:i.value.password})}),f=await u.json().catch(()=>({}));if(!u.ok||!f.token){l.value="Invalid email or password.";return}if(!await h(f.token)){l.value="Access to this panel is restricted to superadmins.";return}i.value.password="",await y(f.token)}catch{l.value="Cannot reach the API server."}finally{r.value=!1}}function U(){qn(),localStorage.removeItem(Es),t.value="",s.value=null,n.value=!1}const q=L(null),$=L({url:"",adminEmail:"",adminPassword:""}),W=L(null),Y=L(""),V=L(""),X=L(!1),j=L(!1);function z(v){const u={Authorization:t.value};return v&&(u["Content-Type"]="application/json"),u}async function ke(){try{const v=await fetch("/api/admin/pb-config",{headers:z()});if(!v.ok)return;const u=await v.json();q.value=u,$.value={url:u.url||"",adminEmail:u.adminEmail||"",adminPassword:""},W.value=u.probe||null}catch{}}async function Re(){Y.value="",V.value="",j.value=!0;try{const v=await fetch("/api/admin/pb-config/test",{method:"POST",headers:z(!0),body:JSON.stringify($.value)});W.value=await v.json()}catch{V.value="Could not run the test."}finally{j.value=!1}}async function Ge(){var v;if(Y.value="",V.value="",!$.value.url.trim()){V.value="A PocketBase URL is required.";return}X.value=!0;try{const u=await fetch("/api/admin/pb-config",{method:"PUT",headers:z(!0),body:JSON.stringify($.value)}),f=await u.json().catch(()=>({}));if(!u.ok){V.value=f.error||"Could not save the connection.";return}q.value=f.config,W.value=((v=f.config)==null?void 0:v.probe)||null,$.value={url:f.config.url,adminEmail:f.config.adminEmail,adminPassword:""},Y.value=f.warning||"Connection saved."}catch{V.value="Could not reach the API server."}finally{X.value=!1}}const Ie=L([]),we=L(""),ue=L(""),qe=L(""),Fe=L({}),he=L(""),Ne=L({name:"",baseURL:"",provider:""}),ae=L(""),ee=L(!1),te=[{id:"apis-external",label:"APIs — External"},{id:"drives-external",label:"Drives — External"},{id:"drives-local",label:"Drives — Local"}],Ve=L("apis-external");function Rt(v){return v.category||"apis-external"}function ot(v){return Ie.value.filter(u=>Rt(u)===v)}const Ee=_n(()=>ot(Ve.value)),ms={builtin:"bg-success-tint text-success",external:"bg-warning-tint text-warning"},Ys={ok:"bg-success-tint text-success",degraded:"bg-warning-tint text-warning",down:"bg-danger-tint text-danger"};async function it(){we.value="";try{const v=await fetch("/api/admin/plugins",{headers:z()});if(!v.ok){we.value="Could not load plugins.";return}const u=await v.json();Ie.value=u.plugins||[];for(const f of Ie.value)f.enabled&&!f.health&&xt(f.name)}catch{we.value="Could not reach the API server."}}async function xt(v){try{const u=await fetch(`/api/admin/plugins/${encodeURIComponent(v)}/health`,{method:"POST",headers:z()}),f=await u.json().catch(()=>({}));if(u.ok&&f.health){const S=_t(v);S&&(S.health=f.health)}}catch{}}function _t(v){return Ie.value.find(u=>u.name===v)}async function Wt(v){he.value=v.name,ue.value="";try{const u=await fetch(`/api/admin/plugins/${encodeURIComponent(v.name)}`,{method:"PUT",headers:z(!0),body:JSON.stringify({enabled:!v.enabled})}),f=await u.json().catch(()=>({}));u.ok?f.warning&&(ue.value=`${v.name}: ${f.warning}`):ue.value=f.error||"Could not update the plugin.",await it()}finally{he.value=""}}function vs(v){qe.value=qe.value===v.name?"":v.name;const u={...v.config||{}};for(const f of v.configFields||[])(u[f.key]===void 0||u[f.key]==="")&&f.default&&(u[f.key]=f.default);Fe.value=u}async function wt(v){he.value=v.name,ue.value="";try{const u=await fetch(`/api/admin/plugins/${encodeURIComponent(v.name)}`,{method:"PUT",headers:z(!0),body:JSON.stringify({config:Fe.value})}),f=await u.json().catch(()=>({}));u.ok?(ue.value=f.warning?`${v.name}: ${f.warning}`:"Configuration saved.",qe.value=""):ue.value=f.error||"Could not save the configuration.",await it()}finally{he.value=""}}async function Vn(v){he.value=v.name,ue.value="";try{const u=await fetch(`/api/admin/plugins/${encodeURIComponent(v.name)}/health`,{method:"POST",headers:z()}),f=await u.json().catch(()=>({}));if(u.ok&&f.health){const S=_t(v.name);S&&(S.health=f.health)}else ue.value=f.error||"Health check failed."}finally{he.value=""}}async function a(v){if(v.kind==="external"){he.value=v.name;try{const u=await fetch(`/api/admin/plugins/${encodeURIComponent(v.name)}`,{method:"DELETE",headers:z()});if(!u.ok){const f=await u.json().catch(()=>({}));ue.value=f.error||"Could not remove the plugin."}await it()}finally{he.value=""}}}async function p(){if(ae.value="",!Ne.value.name.trim()||!Ne.value.baseURL.trim()){ae.value="Name and base URL are required.";return}ee.value=!0;try{const v=await fetch("/api/admin/plugins",{method:"POST",headers:z(!0),body:JSON.stringify(Ne.value)}),u=await v.json().catch(()=>({}));if(!v.ok){ae.value=u.error||"Could not register the plugin.";return}Ne.value={name:"",baseURL:"",provider:""},ue.value="External plugin registered.",await it()}catch{ae.value="Could not reach the API server."}finally{ee.value=!1}}const m=L([]),w=L([]),x=L(""),_=[{value:"user",label:"User"},{value:"admin",label:"Admin"},{value:"superadmin",label:"Superadmin"}],T={user:"User",admin:"Admin",superadmin:"Superadmin"},k={user:"bg-sunken text-secondary",admin:"bg-warning-tint text-warning",superadmin:"bg-success-tint text-success"},C=_n(()=>{const v={};for(const u of m.value)u.organization&&(v[u.organization]=(v[u.organization]||0)+1);return v});function b(v,u){if(!v)return u;if(v.error)return v.error;if(v.data&&typeof v.data=="object"){const f=[];for(const S in v.data)v.data[S]&&v.data[S].message&&f.push(`${S}: ${v.data[S].message}`);if(f.length)return f.join("; ")}return v.message||u}const R=L({email:"",password:"",role:"user",organization:""}),E=L(""),M=L(""),D=L(!1),N=L(""),B=L({}),G=L(""),J=L("");async function ie(){x.value="";try{const v=await fetch("/api/users",{headers:z()}),u=await v.json().catch(()=>({}));if(!v.ok){x.value=b(u,"Could not load users.");return}m.value=u.users||[]}catch{x.value="Could not reach the API server."}}async function Me(){E.value="",M.value="";const v=R.value.email.trim().toLowerCase();if(!v||!v.includes("@")){E.value="A valid email is required.";return}if(R.value.password.length<8){E.value="Password must be at least 8 characters.";return}D.value=!0;try{const u=await fetch("/api/users",{method:"POST",headers:z(!0),body:JSON.stringify({email:v,password:R.value.password,role:R.value.role,organization:R.value.organization})}),f=await u.json().catch(()=>({}));if(!u.ok){E.value=b(f,"Could not create the user.");return}R.value={email:"",password:"",role:"user",organization:""},M.value=`Created ${f.user?f.user.email:"user"}.`,await ie()}catch{E.value="Could not reach the API server."}finally{D.value=!1}}function Ue(v){J.value="",N.value=N.value===v.id?"":v.id,B.value={email:v.email,role:v.role,organization:v.organization||"",verified:!!v.verified,password:""}}async function Ct(v){J.value="",G.value=v.id;try{const u={},f=B.value;if(f.email.trim().toLowerCase()!==v.email&&(u.email=f.email.trim().toLowerCase()),f.role!==v.role&&(u.role=f.role),(f.organization||"")!==(v.organization||"")&&(u.organization=f.organization||""),f.verified!==!!v.verified&&(u.verified=f.verified),f.password&&(u.password=f.password),Object.keys(u).length===0){J.value="No changes to save.";return}const S=await fetch(`/api/users/${encodeURIComponent(v.id)}`,{method:"PATCH",headers:z(!0),body:JSON.stringify(u)}),He=await S.json().catch(()=>({}));if(!S.ok){J.value=b(He,"Could not update the user.");return}J.value=`Updated ${v.email}.`,N.value="",await ie()}catch{J.value="Could not reach the API server."}finally{G.value=""}}async function bs(v){if(v.id!==(s.value&&s.value.id)&&confirm(`Delete user ${v.email}? This cannot be undone.`)){J.value="",G.value=v.id;try{const u=await fetch(`/api/users/${encodeURIComponent(v.id)}`,{method:"DELETE",headers:z()}),f=await u.json().catch(()=>({}));if(!u.ok){J.value=b(f,"Could not delete the user.");return}J.value=`Deleted ${v.email}.`,N.value===v.id&&(N.value=""),await ie()}catch{J.value="Could not reach the API server."}finally{G.value=""}}}const fe=L(""),de=L(""),St=L(""),kt=L(!1),lt=L(""),ys=L(""),It=L(""),Te=L("");async function Mt(){try{const v=await fetch("/api/orgs",{headers:z()});if(!v.ok)return;const u=await v.json().catch(()=>({}));w.value=u.organizations||[]}catch{}}async function Hn(){de.value="",St.value="";const v=fe.value.trim();if(!v){de.value="An organization name is required.";return}kt.value=!0;try{const u=await fetch("/api/orgs",{method:"POST",headers:z(!0),body:JSON.stringify({name:v})}),f=await u.json().catch(()=>({}));if(!u.ok){de.value=b(f,"Could not create the organization.");return}fe.value="",St.value=`Created ${f.organization?f.organization.name:"organization"}.`,await Mt()}catch{de.value="Could not reach the API server."}finally{kt.value=!1}}function Ni(v){Te.value="",lt.value=lt.value===v.id?"":v.id,ys.value=v.name}async function Bn(v){Te.value="";const u=ys.value.trim();if(!u){Te.value="An organization name is required.";return}if(u===v.name){lt.value="";return}It.value=v.id;try{const f=await fetch(`/api/orgs/${encodeURIComponent(v.id)}`,{method:"PATCH",headers:z(!0),body:JSON.stringify({name:u})}),S=await f.json().catch(()=>({}));if(!f.ok){Te.value=b(S,"Could not rename the organization.");return}Te.value=`Renamed to ${u}.`,lt.value="",await Mt(),await ie()}catch{Te.value="Could not reach the API server."}finally{It.value=""}}async function Vi(v){const u=C.value[v.id]||0;if(u>0){Te.value=`${v.name} still has ${u} member${u===1?"":"s"}; reassign or remove them first.`;return}if(confirm(`Delete organization ${v.name}?`)){Te.value="",It.value=v.id;try{const f=await fetch(`/api/orgs/${encodeURIComponent(v.id)}`,{method:"DELETE",headers:z()}),S=await f.json().catch(()=>({}));if(!f.ok){Te.value=b(S,"Could not delete the organization.");return}Te.value=`Deleted ${v.name}.`,lt.value===v.id&&(lt.value=""),await Mt()}catch{Te.value="Could not reach the API server."}finally{It.value=""}}}const Xs=L(null),xs=L(null),Ut=L({apiServer:{status:"checking",detail:""},pocketBase:{status:"checking",detail:""},webApp:{status:"checking",detail:""}});let _s=null;const Hi=[{key:"apiServer",label:"API server"},{key:"pocketBase",label:"PocketBase"},{key:"webApp",label:"Web App"}],Kn={checking:{label:"checking",cls:"bg-sunken text-secondary"},ok:{label:"operational",cls:"bg-success-tint text-success"},down:{label:"unreachable",cls:"bg-danger-tint text-danger"},unreachable:{label:"unreachable",cls:"bg-danger-tint text-danger"}};function zn(v){const u=[];return typeof v.latencyMs=="number"&&u.push(v.latencyMs+"ms"),v.httpStatus&&u.push("HTTP "+v.httpStatus),v.url&&u.push(v.url),u.join(" · ")}async function Wn(){var v,u;try{const f=await fetch("/api/status");if(!f.ok)throw new Error("status "+f.status);const S=await f.json(),He=S.apiServer||{};xs.value=He.devices??0,Ut.value={apiServer:{status:"ok",detail:""},pocketBase:{status:((v=S.pocketBase)==null?void 0:v.status)==="ok"?"ok":"down",detail:zn(S.pocketBase||{})},webApp:{status:((u=S.webApp)==null?void 0:u.status)==="ok"?"ok":"down",detail:zn(S.webApp||{})}}}catch{xs.value=null,Ut.value={apiServer:{status:"unreachable",detail:""},pocketBase:{status:"unreachable",detail:""},webApp:{status:"unreachable",detail:""}}}Xs.value=new Date}function Gn(){Wn(),clearInterval(_s),_s=setInterval(Wn,1e4)}function qn(){clearInterval(_s),_s=null}fi(async()=>{t.value&&await h(t.value)?(n.value=!0,Gn(),ke(),it(),Mt(),ie()):t.value&&(localStorage.removeItem(Es),t.value=""),o.value=!1}),Ln(()=>qn());const Bi=[{method:"POST",path:"/api/auth/login",desc:"Exchange email + password for a session (via PocketBase)"},{method:"GET",path:"/api/auth/validate",desc:"Validate the current session token"},{method:"GET",path:"/api/me",desc:"Caller's id, email, role, and organization from their token"},{method:"GET",path:"/api/preferences",desc:"Read the caller's saved settings blob"},{method:"PUT",path:"/api/preferences",desc:"Persist the caller's settings onto their user record"},{method:"GET",path:"/api/devices",desc:"List connected devices and last-known state"},{method:"GET",path:"/api/devices/{id}/track",desc:"GPS track history for a device"},{method:"POST",path:"/api/devices/{id}/command",desc:"Send a command down to a device"},{method:"DELETE",path:"/api/devices/{id}",desc:"Forget a device's stored state"},{method:"GET",path:"/ws/ui",desc:"Live telemetry stream (WebSocket)"}],Ki=[{method:"GET",path:"/api/users",desc:"List users (admin: own org · superadmin: all)"},{method:"POST",path:"/api/users",desc:"Create a user {email, password, role, organization?}"},{method:"PATCH",path:"/api/users/{id}",desc:"Edit a user (role/org changes are scope-checked)"},{method:"DELETE",path:"/api/users/{id}",desc:"Delete a user (not self; admins in-org only)"},{method:"GET",path:"/api/orgs",desc:"List organizations (admin: own · superadmin: all)"},{method:"POST",path:"/api/orgs",desc:"Create an organization {name} (superadmin)"},{method:"PATCH",path:"/api/orgs/{id}",desc:"Rename an organization (superadmin)"},{method:"DELETE",path:"/api/orgs/{id}",desc:"Delete an empty organization (superadmin)"},{method:"GET",path:"/api/admin/pb-config",desc:"Read the PocketBase connection + live probe (superadmin)"},{method:"POST",path:"/api/admin/pb-config/test",desc:"Test a candidate connection without applying (superadmin)"},{method:"PUT",path:"/api/admin/pb-config",desc:"Update + persist the PocketBase connection (superadmin)"},{method:"GET",path:"/api/admin/plugins",desc:"List plugins + state + last health (superadmin)"},{method:"POST",path:"/api/admin/plugins",desc:"Register an external plugin {name, baseURL} (superadmin)"},{method:"PUT",path:"/api/admin/plugins/{name}",desc:"Enable/disable + configure a plugin (superadmin)"},{method:"DELETE",path:"/api/admin/plugins/{name}",desc:"Remove an external plugin (superadmin)"},{method:"POST",path:"/api/admin/plugins/{name}/health",desc:"Run a plugin health check (superadmin)"}],zi=[{method:"GET",path:"/ws/device?id={id}",desc:"Device telemetry uplink (WebSocket)"},{method:"POST",path:"/api/telemetry?id={id}",desc:"Push a single telemetry event over HTTP"},{method:"GET",path:"/healthz",desc:"Readiness probe"}];return(v,u)=>(P(),A("div",Oa,[d("div",Ra,[u[25]||(u[25]=Ar('
PilotVault
API server
',3)),n.value&&s.value?(P(),A("span",Ia,O(s.value.email),1)):K("",!0),n.value?(P(),A("button",{key:1,class:"pv-btn-sec pv-btn-sm",onClick:U},"Sign out")):K("",!0),d("button",{class:"pv-btn-sec pv-btn-sm",title:Xt(ds)==="dark"?"Switch to light theme":"Switch to dark theme",onClick:u[0]||(u[0]=(...f)=>Xt(Ao)&&Xt(Ao)(...f))},[Xt(ds)==="dark"?(P(),A("svg",Ua,[...u[22]||(u[22]=[d("circle",{cx:"12",cy:"12",r:"4"},null,-1),d("path",{d:"M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"},null,-1)])])):(P(),A("svg",$a,[...u[23]||(u[23]=[d("path",{d:"M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"},null,-1)])])),u[24]||(u[24]=$e(" Theme ",-1))],8,Ma)]),o.value?(P(),A("div",ja,[...u[26]||(u[26]=[d("span",{class:"pv-eyebrow"},"Checking session…",-1)])])):n.value?(P(),A(re,{key:2},[d("div",Ha,[(P(),A(re,null,Ce(g,f=>d("button",{key:f.id,class:Pe(["rounded-md px-3.5 py-1.5 text-sm font-semibold transition",c.value===f.id?"bg-brand text-on-brand":"text-secondary hover:text-primary"]),onClick:S=>c.value=f.id},O(f.label),11,Ba)),64))]),le(d("div",Ka,[d("div",za,[d("div",Wa,[u[30]||(u[30]=d("div",{class:"text-base font-semibold text-primary"},"Status",-1)),d("span",Ga,O(Xs.value?"checked "+Xs.value.toLocaleTimeString():"—"),1)]),d("div",null,[(P(),A(re,null,Ce(Hi,f=>d("div",{key:f.key,class:"flex items-center justify-between gap-3 border-t border-subtle px-5 py-3.5 first:border-t-0"},[d("div",qa,[d("div",Ja,O(f.label),1),Ut.value[f.key].detail?(P(),A("div",Ya,O(Ut.value[f.key].detail),1)):K("",!0)]),d("span",{class:Pe(["inline-flex shrink-0 items-center gap-1.5 rounded-sm px-2.5 py-1 font-mono text-xs font-medium",Kn[Ut.value[f.key].status].cls])},[u[31]||(u[31]=d("span",{class:"h-1.5 w-1.5 rounded-full bg-current"},null,-1)),$e(" "+O(Kn[Ut.value[f.key].status].label),1)],2)])),64)),d("div",Xa,[u[32]||(u[32]=d("div",{class:"text-sm font-semibold text-primary"},"Devices",-1)),d("span",Za,O(xs.value===null?"—":xs.value+" online"),1)])])]),Oe(un,{title:"Client API",auth:"PocketBase session",endpoints:Bi}),Oe(un,{title:"Management API",auth:"Admin · superadmin",endpoints:Ki}),Oe(un,{title:"Device API",auth:"Device uplink",endpoints:zi})],512),[[Jt,c.value==="overview"]]),le(d("div",Qa,[d("div",ec,[u[38]||(u[38]=d("div",{class:"border-b border-subtle px-5 py-4"},[d("div",{class:"text-base font-semibold text-primary"},"Add user"),d("span",{class:"pv-eyebrow"},"Create an account")],-1)),d("div",tc,[d("div",sc,[d("label",nc,[u[33]||(u[33]=d("span",{class:"pv-eyebrow"},"Email",-1)),le(d("input",{"onUpdate:modelValue":u[3]||(u[3]=f=>R.value.email=f),type:"email",class:"pv-input",placeholder:"pilot@pilotvault.local",autocomplete:"off",spellcheck:"false"},null,512),[[ye,R.value.email]])]),d("label",oc,[u[34]||(u[34]=d("span",{class:"pv-eyebrow"},"Password",-1)),le(d("input",{"onUpdate:modelValue":u[4]||(u[4]=f=>R.value.password=f),type:"password",class:"pv-input",placeholder:"min. 8 characters",autocomplete:"new-password"},null,512),[[ye,R.value.password]])])]),d("div",ic,[d("label",lc,[u[35]||(u[35]=d("span",{class:"pv-eyebrow"},"Role",-1)),le(d("select",{"onUpdate:modelValue":u[5]||(u[5]=f=>R.value.role=f),class:"pv-input"},[(P(),A(re,null,Ce(_,f=>d("option",{key:f.value,value:f.value},O(f.label),9,rc)),64))],512),[[Dt,R.value.role]])]),d("label",ac,[u[37]||(u[37]=d("span",{class:"pv-eyebrow"},"Organization",-1)),le(d("select",{"onUpdate:modelValue":u[6]||(u[6]=f=>R.value.organization=f),class:"pv-input"},[u[36]||(u[36]=d("option",{value:""},"— none —",-1)),(P(!0),A(re,null,Ce(w.value,f=>(P(),A("option",{key:f.id,value:f.id},O(f.name),9,cc))),128))],512),[[Dt,R.value.organization]])])]),E.value?(P(),A("p",uc,O(E.value),1)):M.value?(P(),A("p",fc,O(M.value),1)):K("",!0),d("div",null,[d("button",{class:"pv-btn",disabled:D.value,onClick:Me},O(D.value?"Creating…":"Create user"),9,dc)])])]),d("div",pc,[d("div",hc,[d("div",null,[u[39]||(u[39]=d("div",{class:"text-base font-semibold text-primary"},"Users",-1)),d("span",gc,O(m.value.length)+" total",1)]),d("button",{class:"pv-btn-sec pv-btn-sm",onClick:ie},"Refresh")]),d("div",mc,[x.value?(P(),A("p",vc,O(x.value),1)):K("",!0),J.value?(P(),A("p",bc,O(J.value),1)):K("",!0),!m.value.length&&!x.value?(P(),A("p",yc,"No users yet.")):K("",!0),(P(!0),A(re,null,Ce(m.value,f=>(P(),A("div",{key:f.id,class:"border-t border-subtle px-5 py-4 first:border-t-0"},[d("div",xc,[d("div",_c,[d("div",wc,[d("span",Cc,O(f.email),1),d("span",{class:Pe(["rounded-sm px-1.5 py-0.5 font-mono text-[10px] font-medium uppercase tracking-wider",k[f.role]])},O(T[f.role]||f.role),3),f.id===(s.value&&s.value.id)?(P(),A("span",Sc,"you")):K("",!0),f.verified?K("",!0):(P(),A("span",kc,"unverified"))]),d("div",Ec,O(f.organizationName||(f.organization?f.organization:"no organization")),1)]),d("div",Tc,[d("button",{class:"pv-btn-sec pv-btn-sm",onClick:S=>Ue(f)},O(N.value===f.id?"Close":"Edit"),9,Pc),f.id!==(s.value&&s.value.id)?(P(),A("button",{key:0,class:"pv-btn-sec pv-btn-sm !text-danger",disabled:G.value===f.id,onClick:S=>bs(f)}," Delete ",8,Ac)):K("",!0)])]),N.value===f.id?(P(),A("div",Oc,[d("div",Rc,[d("label",Ic,[u[40]||(u[40]=d("span",{class:"pv-eyebrow"},"Email",-1)),le(d("input",{"onUpdate:modelValue":u[7]||(u[7]=S=>B.value.email=S),type:"email",class:"pv-input",autocomplete:"off",spellcheck:"false"},null,512),[[ye,B.value.email]])]),d("label",Mc,[u[41]||(u[41]=d("span",{class:"pv-eyebrow"},"New password",-1)),le(d("input",{"onUpdate:modelValue":u[8]||(u[8]=S=>B.value.password=S),type:"password",class:"pv-input",placeholder:"leave blank to keep current",autocomplete:"new-password"},null,512),[[ye,B.value.password]])])]),d("div",Uc,[d("label",$c,[u[42]||(u[42]=d("span",{class:"pv-eyebrow"},"Role",-1)),le(d("select",{"onUpdate:modelValue":u[9]||(u[9]=S=>B.value.role=S),class:"pv-input",disabled:f.id===(s.value&&s.value.id)},[(P(),A(re,null,Ce(_,S=>d("option",{key:S.value,value:S.value},O(S.label),9,Dc)),64))],8,jc),[[Dt,B.value.role]]),f.id===(s.value&&s.value.id)?(P(),A("span",Lc,"You cannot change your own role.")):K("",!0)]),d("label",Fc,[u[44]||(u[44]=d("span",{class:"pv-eyebrow"},"Organization",-1)),le(d("select",{"onUpdate:modelValue":u[10]||(u[10]=S=>B.value.organization=S),class:"pv-input"},[u[43]||(u[43]=d("option",{value:""},"— none —",-1)),(P(!0),A(re,null,Ce(w.value,S=>(P(),A("option",{key:S.id,value:S.id},O(S.name),9,Nc))),128))],512),[[Dt,B.value.organization]])])]),d("label",Vc,[le(d("input",{"onUpdate:modelValue":u[11]||(u[11]=S=>B.value.verified=S),type:"checkbox",class:"h-4 w-4"},null,512),[[ji,B.value.verified]]),u[45]||(u[45]=d("span",{class:"text-sm text-primary"},"Verified",-1))]),d("div",Hc,[d("button",{class:"pv-btn pv-btn-sm",disabled:G.value===f.id,onClick:S=>Ct(f)},"Save changes",8,Bc),d("button",{class:"pv-btn-sec pv-btn-sm",onClick:u[12]||(u[12]=S=>N.value="")},"Cancel")])])):K("",!0)]))),128))])])],512),[[Jt,c.value==="users"]]),le(d("div",Kc,[d("div",zc,[u[46]||(u[46]=d("div",{class:"border-b border-subtle px-5 py-4"},[d("div",{class:"text-base font-semibold text-primary"},"Add organization"),d("span",{class:"pv-eyebrow"},"Create a tenant")],-1)),d("div",Wc,[d("div",Gc,[le(d("input",{"onUpdate:modelValue":u[13]||(u[13]=f=>fe.value=f),class:"pv-input flex-1",placeholder:"Acme Aerial Ltd.",autocomplete:"off",spellcheck:"false",onKeyup:To(Hn,["enter"])},null,544),[[ye,fe.value]]),d("button",{class:"pv-btn",disabled:kt.value,onClick:Hn},O(kt.value?"Creating…":"Create"),9,qc)]),de.value?(P(),A("p",Jc,O(de.value),1)):St.value?(P(),A("p",Yc,O(St.value),1)):K("",!0)])]),d("div",Xc,[d("div",Zc,[d("div",null,[u[47]||(u[47]=d("div",{class:"text-base font-semibold text-primary"},"Organizations",-1)),d("span",Qc,O(w.value.length)+" total",1)]),d("button",{class:"pv-btn-sec pv-btn-sm",onClick:Mt},"Refresh")]),d("div",eu,[Te.value?(P(),A("p",tu,O(Te.value),1)):K("",!0),w.value.length?K("",!0):(P(),A("p",su,"No organizations yet.")),(P(!0),A(re,null,Ce(w.value,f=>(P(),A("div",{key:f.id,class:"border-t border-subtle px-5 py-4 first:border-t-0"},[d("div",nu,[d("div",ou,[d("div",iu,O(f.name),1),d("div",lu,O(C.value[f.id]||0)+" member"+O((C.value[f.id]||0)===1?"":"s"),1)]),d("div",ru,[d("button",{class:"pv-btn-sec pv-btn-sm",onClick:S=>Ni(f)},O(lt.value===f.id?"Close":"Rename"),9,au),d("button",{class:"pv-btn-sec pv-btn-sm !text-danger",disabled:It.value===f.id||(C.value[f.id]||0)>0,title:(C.value[f.id]||0)>0?"Reassign or remove members first":"Delete organization",onClick:S=>Vi(f)}," Delete ",8,cu)])]),lt.value===f.id?(P(),A("div",uu,[d("label",fu,[u[48]||(u[48]=d("span",{class:"pv-eyebrow"},"Name",-1)),le(d("input",{"onUpdate:modelValue":u[14]||(u[14]=S=>ys.value=S),class:"pv-input",autocomplete:"off",spellcheck:"false",onKeyup:To(S=>Bn(f),["enter"])},null,40,du),[[ye,ys.value]])]),d("div",pu,[d("button",{class:"pv-btn pv-btn-sm",disabled:It.value===f.id,onClick:S=>Bn(f)},"Save",8,hu),d("button",{class:"pv-btn-sec pv-btn-sm",onClick:u[15]||(u[15]=S=>lt.value="")},"Cancel")])])):K("",!0)]))),128))])])],512),[[Jt,c.value==="organizations"]]),le(d("div",gu,[d("div",mu,[d("div",vu,[u[50]||(u[50]=d("div",null,[d("div",{class:"text-base font-semibold text-primary"},"PocketBase connection"),d("span",{class:"pv-eyebrow"},"Settings")],-1)),W.value?(P(),A("span",{key:0,class:Pe(["inline-flex shrink-0 items-center gap-1.5 rounded-sm px-2.5 py-1 font-mono text-xs font-medium",W.value.reachable?W.value.superuser?"bg-success-tint text-success":"bg-warning-tint text-warning":"bg-danger-tint text-danger"])},[u[49]||(u[49]=d("span",{class:"h-1.5 w-1.5 rounded-full bg-current"},null,-1)),$e(" "+O(W.value.reachable?W.value.superuser?"connected":"reachable":"unreachable"),1)],2)):K("",!0)]),d("div",bu,[d("label",yu,[u[51]||(u[51]=d("span",{class:"pv-eyebrow"},"PocketBase URL",-1)),le(d("input",{"onUpdate:modelValue":u[16]||(u[16]=f=>$.value.url=f),class:"pv-input",placeholder:"http://10.2.1.10:8026",spellcheck:"false"},null,512),[[ye,$.value.url]])]),d("label",xu,[u[52]||(u[52]=d("span",{class:"pv-eyebrow"},"Service account email",-1)),le(d("input",{"onUpdate:modelValue":u[17]||(u[17]=f=>$.value.adminEmail=f),class:"pv-input",placeholder:"admin@pilotvault.local",autocomplete:"off",spellcheck:"false"},null,512),[[ye,$.value.adminEmail]])]),d("label",_u,[u[53]||(u[53]=d("span",{class:"pv-eyebrow"},"Service account password",-1)),le(d("input",{"onUpdate:modelValue":u[18]||(u[18]=f=>$.value.adminPassword=f),type:"password",class:"pv-input",autocomplete:"new-password",placeholder:q.value&&q.value.adminConfigured?"leave blank to keep current":"set a password"},null,8,wu),[[ye,$.value.adminPassword]])]),W.value?(P(),A("div",Cu,[$e(" health: "+O(W.value.reachable?"ok":"down"),1),W.value.latencyMs?(P(),A("span",Su," · "+O(W.value.latencyMs)+"ms",1)):K("",!0),$e(" · superuser auth: "+O(W.value.superuser?"ok":"—"),1),W.value.detail?(P(),A("span",ku," · "+O(W.value.detail),1)):K("",!0)])):K("",!0),V.value?(P(),A("p",Eu,O(V.value),1)):Y.value?(P(),A("p",Tu,O(Y.value),1)):K("",!0),d("div",Pu,[d("button",{class:"pv-btn",disabled:X.value,onClick:Ge},O(X.value?"Saving…":"Save connection"),9,Au),d("button",{class:"pv-btn-sec",disabled:j.value,onClick:Re},O(j.value?"Testing…":"Test connection"),9,Ou)]),u[54]||(u[54]=d("p",{class:"text-[11px] text-muted"}," The service account is used only for user & organization management. Changing the URL repoints the whole API Server at a new PocketBase and may sign you out. ",-1))])])],512),[[Jt,c.value==="pocketbase"]]),le(d("div",Ru,[d("div",Iu,[d("div",{class:"flex items-center justify-between border-b border-subtle px-5 py-4"},[u[55]||(u[55]=d("div",null,[d("div",{class:"text-base font-semibold text-primary"},"Plugins"),d("span",{class:"pv-eyebrow"},"External integrations")],-1)),d("button",{class:"pv-btn-sec pv-btn-sm",onClick:it},"Refresh")]),d("div",Mu,[we.value?(P(),A("p",Uu,O(we.value),1)):K("",!0),ue.value?(P(),A("p",$u,O(ue.value),1)):K("",!0),!Ie.value.length&&!we.value?(P(),A("p",ju,"No plugins registered yet.")):K("",!0),Ie.value.length?(P(),A("div",Du,[(P(),A(re,null,Ce(te,f=>d("button",{key:f.id,class:Pe(["-mb-px whitespace-nowrap border-b-2 px-3 py-2 text-sm font-semibold transition",Ve.value===f.id?"border-brand text-primary":"border-transparent text-secondary hover:text-primary"]),onClick:S=>Ve.value=f.id},O(f.label),11,Lu)),64))])):K("",!0),Ie.value.length&&!Ee.value.length?(P(),A("p",Fu,"No plugins in this category.")):K("",!0),(P(!0),A(re,null,Ce(Ee.value,f=>(P(),A("div",{key:f.name,class:"border-t border-subtle px-5 py-4 first:border-t-0"},[d("div",Nu,[d("div",Vu,[d("div",Hu,[d("span",Bu,O(f.name),1),d("span",{class:Pe(["rounded-sm px-1.5 py-0.5 font-mono text-[10px] font-medium uppercase tracking-wider",ms[f.kind]])},O(f.kind),3),f.health?(P(),A("span",{key:0,class:Pe(["inline-flex items-center gap-1 rounded-sm px-1.5 py-0.5 font-mono text-[10px] font-medium",Ys[f.health.status]]),title:f.health.detail||""},[u[56]||(u[56]=d("span",{class:"h-1 w-1 rounded-full bg-current"},null,-1)),$e(O(f.health.status),1),f.health.latencyMs?(P(),A("span",zu," · "+O(f.health.latencyMs)+"ms",1)):K("",!0)],10,Ku)):K("",!0)]),d("div",Wu,O(f.provider)+" · v"+O(f.version)+" · "+O(f.authType),1),f.health&&f.health.detail?(P(),A("div",Gu,O(f.health.detail),1)):K("",!0),f.capabilities&&f.capabilities.length?(P(),A("div",qu,[u[57]||(u[57]=d("div",{class:"pv-eyebrow"},"Capabilities",-1)),(P(!0),A(re,null,Ce(f.capabilities,S=>(P(),A("div",{key:S.id,class:"flex flex-wrap items-baseline gap-x-2 gap-y-0.5"},[d("span",Ju,O(S.id),1),S.method||S.endpoint?(P(),A("span",Yu,O(S.method)+" "+O(S.endpoint),1)):K("",!0),S.description?(P(),A("span",Xu,O(S.description),1)):K("",!0)]))),128))])):K("",!0),f.baseURL?(P(),A("div",Zu,O(f.baseURL),1)):K("",!0)]),d("div",Qu,[d("button",{class:Pe(["pv-btn-sec pv-btn-sm",f.enabled?"!border-transparent !bg-success-tint !text-success":""]),disabled:he.value===f.name,onClick:S=>Wt(f)},[d("span",{class:Pe(["h-1.5 w-1.5 rounded-full",f.enabled?"bg-success":"bg-muted"])},null,2),$e(" "+O(f.enabled?"Enabled":"Disabled"),1)],10,ef),f.configFields&&f.configFields.length?(P(),A("button",{key:0,class:"pv-btn-sec pv-btn-sm",onClick:S=>vs(f)},"Configure",8,tf)):K("",!0),d("button",{class:"pv-btn-sec pv-btn-sm",disabled:he.value===f.name,onClick:S=>Vn(f)},"Check",8,sf),f.kind==="external"?(P(),A("button",{key:1,class:"pv-btn-sec pv-btn-sm !text-danger",disabled:he.value===f.name,onClick:S=>a(f)},"Remove",8,nf)):K("",!0)])]),qe.value===f.name?(P(),A("div",of,[(P(!0),A(re,null,Ce(f.configFields,S=>(P(),A("label",{key:S.key,class:"flex flex-col gap-1"},[d("span",lf,[$e(O(S.label),1),S.required?(P(),A("span",rf," *")):K("",!0)]),S.type==="select"?le((P(),A("select",{key:0,"onUpdate:modelValue":He=>Fe.value[S.key]=He,class:"pv-input"},[(P(!0),A(re,null,Ce(S.options,He=>(P(),A("option",{key:He.value,value:He.value},O(He.label),9,cf))),128))],8,af)),[[Dt,Fe.value[S.key]]]):le((P(),A("input",{key:1,"onUpdate:modelValue":He=>Fe.value[S.key]=He,type:S.secret||S.type==="password"?"password":S.type==="number"?"number":"text",class:"pv-input",autocomplete:"off",placeholder:S.help||""},null,8,uf)),[[ua,Fe.value[S.key]]]),S.help?(P(),A("span",ff,O(S.help),1)):K("",!0)]))),128)),d("div",df,[d("button",{class:"pv-btn pv-btn-sm",disabled:he.value===f.name,onClick:S=>wt(f)},"Save configuration",8,pf),d("button",{class:"pv-btn-sec pv-btn-sm",onClick:u[19]||(u[19]=S=>qe.value="")},"Cancel")])])):K("",!0)]))),128)),d("div",hf,[u[58]||(u[58]=d("div",{class:"pv-eyebrow mb-2"},"Register external plugin",-1)),d("div",gf,[le(d("input",{"onUpdate:modelValue":u[20]||(u[20]=f=>Ne.value.name=f),class:"pv-input sm:w-40",placeholder:"name",autocomplete:"off",spellcheck:"false"},null,512),[[ye,Ne.value.name]]),le(d("input",{"onUpdate:modelValue":u[21]||(u[21]=f=>Ne.value.baseURL=f),class:"pv-input flex-1",placeholder:"https://plugin.example.com",autocomplete:"off",spellcheck:"false"},null,512),[[ye,Ne.value.baseURL]]),d("button",{class:"pv-btn",disabled:ee.value,onClick:p},O(ee.value?"Adding…":"Add"),9,mf)]),ae.value?(P(),A("p",vf,O(ae.value),1)):K("",!0),u[59]||(u[59]=d("p",{class:"mt-2 text-[11px] text-muted"},[$e(" A remote service that answers "),d("span",{class:"font-mono"},"GET /health"),$e(" and "),d("span",{class:"font-mono"},"GET /manifest"),$e(" — added at runtime, no rebuild. ")],-1))])])])],512),[[Jt,c.value==="plugins"]])],64)):(P(),A("div",Da,[u[29]||(u[29]=d("div",{class:"border-b border-subtle px-5 py-4"},[d("div",{class:"text-base font-semibold text-primary"},"Sign in"),d("span",{class:"pv-eyebrow"},"Superadmin access only")],-1)),d("form",{class:"flex flex-col gap-3 px-5 py-5",onSubmit:ha(I,["prevent"])},[d("label",La,[u[27]||(u[27]=d("span",{class:"pv-eyebrow"},"Email",-1)),le(d("input",{"onUpdate:modelValue":u[1]||(u[1]=f=>i.value.email=f),type:"email",autocomplete:"username",class:"pv-input",placeholder:"superadmin@pilotvault.local"},null,512),[[ye,i.value.email]])]),d("label",Fa,[u[28]||(u[28]=d("span",{class:"pv-eyebrow"},"Password",-1)),le(d("input",{"onUpdate:modelValue":u[2]||(u[2]=f=>i.value.password=f),type:"password",autocomplete:"current-password",class:"pv-input",placeholder:"••••••••"},null,512),[[ye,i.value.password]])]),l.value?(P(),A("p",Na,O(l.value),1)):K("",!0),d("button",{type:"submit",class:"pv-btn mt-1",disabled:r.value},O(r.value?"Signing in…":"Sign in"),9,Va)],32)])),u[60]||(u[60]=d("p",{class:"text-center font-mono text-[11px] text-muted"}," PilotVault — live drone telemetry, command & control. ",-1))]))}};ba(bf).mount("#app"); +**/let wn;const ho=typeof window<"u"&&window.trustedTypes;if(ho)try{wn=ho.createPolicy("vue",{createHTML:e=>e})}catch{}const Ui=wn?e=>wn.createHTML(e):e=>e,Vr="http://www.w3.org/2000/svg",Hr="http://www.w3.org/1998/Math/MathML",at=typeof document<"u"?document:null,go=at&&at.createElement("template"),Br={insert:(e,t,s)=>{t.insertBefore(e,s||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,s,n)=>{const o=t==="svg"?at.createElementNS(Vr,e):t==="mathml"?at.createElementNS(Hr,e):s?at.createElement(e,{is:s}):at.createElement(e);return e==="select"&&n&&n.multiple!=null&&o.setAttribute("multiple",n.multiple),o},createText:e=>at.createTextNode(e),createComment:e=>at.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>at.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,s,n,o,i){const l=s?s.previousSibling:t.lastChild;if(o&&(o===i||o.nextSibling))for(;t.insertBefore(o.cloneNode(!0),s),!(o===i||!(o=o.nextSibling)););else{go.innerHTML=Ui(n==="svg"?`${e}`:n==="mathml"?`${e}`:e);const r=go.content;if(n==="svg"||n==="mathml"){const c=r.firstChild;for(;c.firstChild;)r.appendChild(c.firstChild);r.removeChild(c)}t.insertBefore(r,s)}return[l?l.nextSibling:t.firstChild,s?s.previousSibling:t.lastChild]}},Kr=Symbol("_vtc");function zr(e,t,s){const n=e[Kr];n&&(t=(t?[t,...n]:[...n]).join(" ")),t==null?e.removeAttribute("class"):s?e.setAttribute("class",t):e.className=t}const Ls=Symbol("_vod"),$i=Symbol("_vsh"),Jt={name:"show",beforeMount(e,{value:t},{transition:s}){e[Ls]=e.style.display==="none"?"":e.style.display,s&&t?s.beforeEnter(e):Yt(e,t)},mounted(e,{value:t},{transition:s}){s&&t&&s.enter(e)},updated(e,{value:t,oldValue:s},{transition:n}){!t!=!s&&(n?t?(n.beforeEnter(e),Yt(e,!0),n.enter(e)):n.leave(e,()=>{Yt(e,!1)}):Yt(e,t))},beforeUnmount(e,{value:t}){Yt(e,t)}};function Yt(e,t){e.style.display=t?e[Ls]:"none",e[$i]=!t}const Wr=Symbol(""),Gr=/(?:^|;)\s*display\s*:/;function qr(e,t,s){const n=e.style,o=ce(s);let i=!1;if(s&&!o){if(t)if(ce(t))for(const l of t.split(";")){const r=l.slice(0,l.indexOf(":")).trim();s[r]==null&&Qt(n,r,"")}else for(const l in t)s[l]==null&&Qt(n,l,"");for(const l in s){l==="display"&&(i=!0);const r=s[l];r!=null?Yr(e,l,!ce(t)&&t?t[l]:void 0,r)||Qt(n,l,r):Qt(n,l,"")}}else if(o){if(t!==s){const l=n[Wr];l&&(s+=";"+l),n.cssText=s,i=Gr.test(s)}}else t&&e.removeAttribute("style");Ls in e&&(e[Ls]=i?n.display:"",e[$i]&&(n.display="none"))}const mo=/\s*!important$/;function Qt(e,t,s){if(F(s))s.forEach(n=>Qt(e,t,n));else if(s==null&&(s=""),t.startsWith("--"))e.setProperty(t,s);else{const n=Jr(e,t);mo.test(s)?e.setProperty(yt(n),s.replace(mo,""),"important"):e[n]=s}}const vo=["Webkit","Moz","ms"],an={};function Jr(e,t){const s=an[t];if(s)return s;let n=Be(t);if(n!=="filter"&&n in e)return an[t]=n;n=Uo(n);for(let o=0;ocn||(sa.then(()=>cn=0),cn=Date.now());function oa(e,t){const s=n=>{if(!n._vts)n._vts=Date.now();else if(n._vts<=s.attached)return;const o=s.value;if(F(o)){const i=n.stopImmediatePropagation;n.stopImmediatePropagation=()=>{i.call(n),n._stopped=!0};const l=o.slice(),r=[n];for(let c=0;ce.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,ia=(e,t,s,n,o,i)=>{const l=o==="svg";t==="class"?zr(e,n,l):t==="style"?qr(e,s,n):Fs(t)?Ns(t)||Zr(e,t,s,n,i):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):la(e,t,n,l))?(xo(e,t,n),!e.tagName.includes("-")&&(t==="value"||t==="checked"||t==="selected")&&yo(e,t,n,l,i,t!=="value")):e._isVueCE&&(ra(e,t)||e._def.__asyncLoader&&(/[A-Z]/.test(t)||!ce(n)))?xo(e,Be(t),n,i,t):(t==="true-value"?e._trueValue=n:t==="false-value"&&(e._falseValue=n),yo(e,t,n,l))};function la(e,t,s,n){if(n)return!!(t==="innerHTML"||t==="textContent"||t in e&&wo(t)&&H(s));if(t==="spellcheck"||t==="draggable"||t==="translate"||t==="autocorrect"||t==="sandbox"&&e.tagName==="IFRAME"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA")return!1;if(t==="width"||t==="height"){const o=e.tagName;if(o==="IMG"||o==="VIDEO"||o==="CANVAS"||o==="SOURCE")return!1}return wo(t)&&ce(s)?!1:t in e}function ra(e,t){const s=e._def.props;if(!s)return!1;const n=Be(t);return Array.isArray(s)?s.some(o=>Be(o)===n):Object.keys(s).some(o=>Be(o)===n)}const bt=e=>{const t=e.props["onUpdate:modelValue"]||!1;return F(t)?s=>Ts(t,s):t};function aa(e){e.target.composing=!0}function Co(e){const t=e.target;t.composing&&(t.composing=!1,t.dispatchEvent(new Event("input")))}const Le=Symbol("_assign");function So(e,t,s){return t&&(e=e.trim()),s&&(e=Hs(e)),e}const ye={created(e,{modifiers:{lazy:t,trim:s,number:n}},o){e[Le]=bt(o);const i=n||o.props&&o.props.type==="number";dt(e,t?"change":"input",l=>{l.target.composing||e[Le](So(e.value,s,i))}),(s||i)&&dt(e,"change",()=>{e.value=So(e.value,s,i)}),t||(dt(e,"compositionstart",aa),dt(e,"compositionend",Co),dt(e,"change",Co))},mounted(e,{value:t}){e.value=t??""},beforeUpdate(e,{value:t,oldValue:s,modifiers:{lazy:n,trim:o,number:i}},l){if(e[Le]=bt(l),e.composing)return;const r=(i||e.type==="number")&&!/^0\d/.test(e.value)?Hs(e.value):e.value,c=t??"";if(r===c)return;const g=e.getRootNode();(g instanceof Document||g instanceof ShadowRoot)&&g.activeElement===e&&e.type!=="range"&&(n&&t===s||o&&e.value.trim()===c)||(e.value=c)}},ji={deep:!0,created(e,t,s){e[Le]=bt(s),dt(e,"change",()=>{const n=e._modelValue,o=Kt(e),i=e.checked,l=e[Le];if(F(n)){const r=Tn(n,o),c=r!==-1;if(i&&!c)l(n.concat(o));else if(!i&&c){const g=[...n];g.splice(r,1),l(g)}}else if(zt(n)){const r=new Set(n);i?r.add(o):r.delete(o),l(r)}else l(Di(e,i))})},mounted:ko,beforeUpdate(e,t,s){e[Le]=bt(s),ko(e,t,s)}};function ko(e,{value:t,oldValue:s},n){e._modelValue=t;let o;if(F(t))o=Tn(t,n.props.value)>-1;else if(zt(t))o=t.has(n.props.value);else{if(t===s)return;o=mt(t,Di(e,!0))}e.checked!==o&&(e.checked=o)}const ca={created(e,{value:t},s){e.checked=mt(t,s.props.value),e[Le]=bt(s),dt(e,"change",()=>{e[Le](Kt(e))})},beforeUpdate(e,{value:t,oldValue:s},n){e[Le]=bt(n),t!==s&&(e.checked=mt(t,n.props.value))}},Dt={deep:!0,created(e,{value:t,modifiers:{number:s}},n){const o=zt(t);dt(e,"change",()=>{const i=Array.prototype.filter.call(e.options,l=>l.selected).map(l=>s?Hs(Kt(l)):Kt(l));e[Le](e.multiple?o?new Set(i):i:i[0]),e._assigning=!0,ti(()=>{e._assigning=!1})}),e[Le]=bt(n)},mounted(e,{value:t}){Eo(e,t)},beforeUpdate(e,t,s){e[Le]=bt(s)},updated(e,{value:t}){e._assigning||Eo(e,t)}};function Eo(e,t){const s=e.multiple,n=F(t);if(!(s&&!n&&!zt(t))){for(let o=0,i=e.options.length;oString(g)===String(r)):l.selected=Tn(t,r)>-1}else l.selected=t.has(r);else if(mt(Kt(l),t)){e.selectedIndex!==o&&(e.selectedIndex=o);return}}!s&&e.selectedIndex!==-1&&(e.selectedIndex=-1)}}function Kt(e){return"_value"in e?e._value:e.value}function Di(e,t){const s=t?"_trueValue":"_falseValue";return s in e?e[s]:t}const ua={created(e,t,s){ks(e,t,s,null,"created")},mounted(e,t,s){ks(e,t,s,null,"mounted")},beforeUpdate(e,t,s,n){ks(e,t,s,n,"beforeUpdate")},updated(e,t,s,n){ks(e,t,s,n,"updated")}};function fa(e,t){switch(e){case"SELECT":return Dt;case"TEXTAREA":return ye;default:switch(t){case"checkbox":return ji;case"radio":return ca;default:return ye}}}function ks(e,t,s,n,o){const l=fa(e.tagName,s.props&&s.props.type)[o];l&&l(e,t,s,n)}const da=["ctrl","shift","alt","meta"],pa={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,t)=>da.some(s=>e[`${s}Key`]&&!t.includes(s))},ha=(e,t)=>{if(!e)return e;const s=e._withMods||(e._withMods={}),n=t.join(".");return s[n]||(s[n]=((o,...i)=>{for(let l=0;l{const s=e._withKeys||(e._withKeys={}),n=t.join(".");return s[n]||(s[n]=(o=>{if(!("key"in o))return;const i=yt(o.key);if(t.some(l=>l===i||ga[l]===i))return e(o)}))},ma=ve({patchProp:ia},Br);let Po;function va(){return Po||(Po=xr(ma))}const ba=((...e)=>{const t=va().createApp(...e),{mount:s}=t;return t.mount=n=>{const o=xa(n);if(!o)return;const i=t._component;!H(i)&&!i.render&&!i.template&&(i.template=o.innerHTML),o.nodeType===1&&(o.textContent="");const l=s(o,!1,ya(o));return o instanceof Element&&(o.removeAttribute("v-cloak"),o.setAttribute("data-v-app","")),l},t});function ya(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function xa(e){return ce(e)?document.querySelector(e):e}const Li="pilotvault-theme";function _a(){try{return localStorage.getItem(Li)==="dark"?"dark":"light"}catch{return"light"}}const ds=L(_a());function Fi(e){ds.value=e,document.documentElement.setAttribute("data-theme",e);try{localStorage.setItem(Li,e)}catch{}}function Ao(){Fi(ds.value==="dark"?"light":"dark")}Fi(ds.value);const wa={class:"overflow-hidden rounded-lg border border-subtle bg-card shadow-xs"},Ca={class:"flex items-center justify-between border-b border-subtle px-5 py-4"},Sa={class:"text-base font-semibold text-primary"},ka={class:"pv-eyebrow"},Ea={class:"w-full text-left text-sm"},Ta={class:"border-t border-subtle px-5 py-2.5 font-mono text-xs whitespace-nowrap"},Pa={class:"text-primary"},Aa={class:"border-t border-subtle px-5 py-2.5 text-secondary"},un={__name:"EndpointTable",props:{title:String,auth:String,endpoints:Array},setup(e){const t={GET:"text-success",POST:"text-brand-text",PATCH:"text-warning",DELETE:"text-danger"};return(s,n)=>(P(),A("div",wa,[d("div",Ca,[d("div",Sa,O(e.title),1),d("span",ka,O(e.auth),1)]),d("table",Ea,[n[0]||(n[0]=d("thead",null,[d("tr",{class:"pv-eyebrow"},[d("th",{class:"px-5 py-2.5 font-medium"},"Endpoint"),d("th",{class:"px-5 py-2.5 font-medium"},"Description")])],-1)),d("tbody",null,[(P(!0),A(re,null,Ce(e.endpoints,o=>(P(),A("tr",{key:o.method+o.path,class:"transition-colors hover:bg-sunken"},[d("td",Ta,[d("span",{class:Pe(["font-semibold",t[o.method]])},O(o.method),3),d("span",Pa,O(o.path),1)]),d("td",Aa,O(o.desc),1)]))),128))])])]))}},Oa={class:"mx-auto flex max-w-5xl flex-col gap-6 px-6 pt-12 pb-16"},Ra={class:"flex items-center gap-3"},Ia={key:0,class:"pv-eyebrow hidden truncate sm:inline"},Ma=["title"],Ua={key:0,class:"h-4 w-4",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},$a={key:1,class:"h-4 w-4",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},ja={key:0,class:"rounded-lg border border-subtle bg-card px-5 py-10 text-center shadow-sm"},Da={key:1,class:"mx-auto w-full max-w-sm rounded-lg border border-subtle bg-card shadow-sm"},La={class:"flex flex-col gap-1"},Fa={class:"flex flex-col gap-1"},Na={key:0,class:"rounded-sm bg-danger-tint px-3 py-2 text-xs font-medium text-danger"},Va=["disabled"],Ha={class:"flex gap-1 self-start rounded-lg border border-subtle bg-card p-1 shadow-sm"},Ba=["onClick"],Ka={class:"flex flex-col gap-6"},za={class:"rounded-lg border border-subtle bg-card shadow-sm"},Wa={class:"flex items-center justify-between border-b border-subtle px-5 py-4"},Ga={class:"pv-eyebrow"},qa={class:"min-w-0"},Ja={class:"text-sm font-semibold text-primary"},Ya={key:0,class:"truncate font-mono text-xs text-secondary"},Xa={class:"flex items-center justify-between gap-3 border-t border-subtle px-5 py-3.5"},Za={class:"font-mono text-xs text-secondary"},Qa={class:"flex flex-col gap-6"},ec={class:"rounded-lg border border-subtle bg-card shadow-sm"},tc={class:"flex flex-col gap-3 px-5 py-5"},sc={class:"flex flex-col gap-3 sm:flex-row"},nc={class:"flex flex-1 flex-col gap-1"},oc={class:"flex flex-1 flex-col gap-1"},ic={class:"flex flex-col gap-3 sm:flex-row"},lc={class:"flex flex-1 flex-col gap-1"},rc=["value"],ac={class:"flex flex-1 flex-col gap-1"},cc=["value"],uc={key:0,class:"rounded-sm bg-danger-tint px-3 py-2 text-xs font-medium text-danger"},fc={key:1,class:"rounded-sm bg-success-tint px-3 py-2 text-xs font-medium text-success"},dc=["disabled"],pc={class:"rounded-lg border border-subtle bg-card shadow-sm"},hc={class:"flex items-center justify-between border-b border-subtle px-5 py-4"},gc={class:"pv-eyebrow"},mc={class:"flex flex-col"},vc={key:0,class:"px-5 py-3 text-xs font-medium text-danger"},bc={key:1,class:"border-b border-subtle bg-sunken px-5 py-2.5 font-mono text-xs text-secondary"},yc={key:2,class:"px-5 py-6 text-sm text-secondary"},xc={class:"flex flex-wrap items-center gap-x-3 gap-y-2"},_c={class:"min-w-0 flex-1"},wc={class:"flex flex-wrap items-center gap-2"},Cc={class:"truncate text-sm font-semibold text-primary"},Sc={key:0,class:"rounded-sm bg-brand/10 px-1.5 py-0.5 font-mono text-[10px] font-medium text-brand-text"},kc={key:1,class:"rounded-sm bg-warning-tint px-1.5 py-0.5 font-mono text-[10px] font-medium text-warning"},Ec={class:"mt-0.5 font-mono text-xs text-secondary"},Tc={class:"flex shrink-0 items-center gap-2"},Pc=["onClick"],Ac=["disabled","onClick"],Oc={key:0,class:"mt-3 flex flex-col gap-3 rounded-md border border-subtle bg-sunken px-4 py-4"},Rc={class:"flex flex-col gap-3 sm:flex-row"},Ic={class:"flex flex-1 flex-col gap-1"},Mc={class:"flex flex-1 flex-col gap-1"},Uc={class:"flex flex-col gap-3 sm:flex-row"},$c={class:"flex flex-1 flex-col gap-1"},jc=["disabled"],Dc=["value"],Lc={key:0,class:"text-[11px] text-muted"},Fc={class:"flex flex-1 flex-col gap-1"},Nc=["value"],Vc={class:"flex items-center gap-2"},Hc={class:"flex items-center gap-2"},Bc=["disabled","onClick"],Kc={class:"flex flex-col gap-6"},zc={class:"rounded-lg border border-subtle bg-card shadow-sm"},Wc={class:"flex flex-col gap-3 px-5 py-5"},Gc={class:"flex flex-col gap-2 sm:flex-row"},qc=["disabled"],Jc={key:0,class:"rounded-sm bg-danger-tint px-3 py-2 text-xs font-medium text-danger"},Yc={key:1,class:"rounded-sm bg-success-tint px-3 py-2 text-xs font-medium text-success"},Xc={class:"rounded-lg border border-subtle bg-card shadow-sm"},Zc={class:"flex items-center justify-between border-b border-subtle px-5 py-4"},Qc={class:"pv-eyebrow"},eu={class:"flex flex-col"},tu={key:0,class:"border-b border-subtle bg-sunken px-5 py-2.5 font-mono text-xs text-secondary"},su={key:1,class:"px-5 py-6 text-sm text-secondary"},nu={class:"flex flex-wrap items-center gap-x-3 gap-y-2"},ou={class:"min-w-0 flex-1"},iu={class:"truncate text-sm font-semibold text-primary"},lu={class:"mt-0.5 font-mono text-xs text-secondary"},ru={class:"flex shrink-0 items-center gap-2"},au=["onClick"],cu=["disabled","title","onClick"],uu={key:0,class:"mt-3 flex flex-col gap-2 rounded-md border border-subtle bg-sunken px-4 py-4 sm:flex-row sm:items-end"},fu={class:"flex flex-1 flex-col gap-1"},du=["onKeyup"],pu={class:"flex items-center gap-2"},hu=["disabled","onClick"],gu={class:"flex flex-col gap-6"},mu={class:"rounded-lg border border-subtle bg-card shadow-sm"},vu={class:"flex items-center justify-between border-b border-subtle px-5 py-4"},bu={class:"flex flex-col gap-3 px-5 py-5"},yu={class:"flex flex-col gap-1"},xu={class:"flex flex-col gap-1"},_u={class:"flex flex-col gap-1"},wu=["placeholder"],Cu={key:0,class:"font-mono text-[11px] text-muted"},Su={key:0},ku={key:1},Eu={key:1,class:"rounded-sm bg-danger-tint px-3 py-2 text-xs font-medium text-danger"},Tu={key:2,class:"rounded-sm bg-success-tint px-3 py-2 text-xs font-medium text-success"},Pu={class:"flex flex-wrap items-center gap-2"},Au=["disabled"],Ou=["disabled"],Ru={class:"flex flex-col gap-6"},Iu={class:"rounded-lg border border-subtle bg-card shadow-sm"},Mu={class:"flex flex-col"},Uu={key:0,class:"px-5 py-3 text-xs font-medium text-danger"},$u={key:1,class:"border-b border-subtle bg-sunken px-5 py-2.5 font-mono text-xs text-secondary"},ju={key:2,class:"px-5 py-6 text-sm text-secondary"},Du={key:3,class:"flex gap-1 overflow-x-auto overflow-y-hidden border-b border-subtle px-3 pt-1"},Lu=["onClick"],Fu={key:4,class:"px-5 py-6 text-sm text-secondary"},Nu={class:"flex flex-wrap items-center gap-x-3 gap-y-2"},Vu={class:"min-w-0 flex-1"},Hu={class:"flex flex-wrap items-center gap-2"},Bu={class:"text-sm font-semibold text-primary"},Ku=["title"],zu={key:0},Wu={class:"mt-0.5 font-mono text-xs text-secondary"},Gu={key:0,class:"mt-0.5 text-[11px] text-secondary"},qu={key:1,class:"mt-2 flex flex-col gap-1.5"},Ju={class:"rounded-sm bg-sunken px-1.5 py-0.5 font-mono text-[10px] text-secondary"},Yu={key:0,class:"font-mono text-[10px] text-muted"},Xu={key:1,class:"w-full text-[11px] text-secondary sm:w-auto"},Zu={key:2,class:"mt-1 truncate font-mono text-[11px] text-muted"},Qu={class:"flex shrink-0 items-center gap-2"},ef=["disabled","onClick"],tf=["onClick"],sf=["disabled","onClick"],nf=["disabled","onClick"],of={key:0,class:"mt-3 flex flex-col gap-2 rounded-md border border-subtle bg-sunken px-4 py-4"},lf={class:"pv-eyebrow"},rf={key:0,class:"text-danger"},af=["onUpdate:modelValue"],cf=["value"],uf=["onUpdate:modelValue","type","placeholder"],ff={key:2,class:"text-[11px] text-muted"},df={class:"flex items-center gap-2"},pf=["disabled","onClick"],hf={class:"border-t border-subtle px-5 py-4"},gf={class:"flex flex-col gap-2 sm:flex-row"},mf=["disabled"],vf={key:0,class:"mt-2 text-xs font-medium text-danger"},Es="pv_panel_token",bf={__name:"App",setup(e){const t=L(localStorage.getItem(Es)||""),s=L(null),n=L(!1),o=L(!0),i=L({email:"",password:""}),l=L(""),r=L(!1),c=L("overview"),g=[{id:"overview",label:"Overview"},{id:"users",label:"Users"},{id:"organizations",label:"Organizations"},{id:"pocketbase",label:"PocketBase"},{id:"plugins",label:"Plugins"}];async function h(v){try{const u=await fetch("/api/me",{headers:{Authorization:v}});if(!u.ok)return!1;const f=await u.json();return f.role!=="superadmin"?!1:(s.value={id:f.id,email:f.email,role:f.role},!0)}catch{return!1}}async function y(v){t.value=v,localStorage.setItem(Es,v),n.value=!0,Gn(),ke(),it(),Mt(),ie()}async function I(){l.value="";const v=i.value.email.trim().toLowerCase();if(!v||!i.value.password){l.value="Enter your email and password.";return}r.value=!0;try{const u=await fetch("/api/auth/login",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,password:i.value.password})}),f=await u.json().catch(()=>({}));if(!u.ok||!f.token){l.value="Invalid email or password.";return}if(!await h(f.token)){l.value="Access to this panel is restricted to superadmins.";return}i.value.password="",await y(f.token)}catch{l.value="Cannot reach the API server."}finally{r.value=!1}}function U(){qn(),localStorage.removeItem(Es),t.value="",s.value=null,n.value=!1}const q=L(null),$=L({url:"",adminEmail:"",adminPassword:""}),W=L(null),Y=L(""),V=L(""),X=L(!1),j=L(!1);function z(v){const u={Authorization:t.value};return v&&(u["Content-Type"]="application/json"),u}async function ke(){try{const v=await fetch("/api/admin/pb-config",{headers:z()});if(!v.ok)return;const u=await v.json();q.value=u,$.value={url:u.url||"",adminEmail:u.adminEmail||"",adminPassword:""},W.value=u.probe||null}catch{}}async function Re(){Y.value="",V.value="",j.value=!0;try{const v=await fetch("/api/admin/pb-config/test",{method:"POST",headers:z(!0),body:JSON.stringify($.value)});W.value=await v.json()}catch{V.value="Could not run the test."}finally{j.value=!1}}async function Ge(){var v;if(Y.value="",V.value="",!$.value.url.trim()){V.value="A PocketBase URL is required.";return}X.value=!0;try{const u=await fetch("/api/admin/pb-config",{method:"PUT",headers:z(!0),body:JSON.stringify($.value)}),f=await u.json().catch(()=>({}));if(!u.ok){V.value=f.error||"Could not save the connection.";return}q.value=f.config,W.value=((v=f.config)==null?void 0:v.probe)||null,$.value={url:f.config.url,adminEmail:f.config.adminEmail,adminPassword:""},Y.value=f.warning||"Connection saved."}catch{V.value="Could not reach the API server."}finally{X.value=!1}}const Ie=L([]),we=L(""),ue=L(""),qe=L(""),Fe=L({}),he=L(""),Ne=L({name:"",baseURL:"",provider:""}),ae=L(""),ee=L(!1),te=[{id:"apis-external",label:"APIs — External"},{id:"drives-external",label:"Drives — External"},{id:"drives-local",label:"Drives — Local"}],Ve=L("apis-external");function Rt(v){return v.category||"apis-external"}function ot(v){return Ie.value.filter(u=>Rt(u)===v)}const Ee=_n(()=>ot(Ve.value)),ms={builtin:"bg-success-tint text-success",external:"bg-warning-tint text-warning"},Ys={ok:"bg-success-tint text-success",degraded:"bg-warning-tint text-warning",down:"bg-danger-tint text-danger"};async function it(){we.value="";try{const v=await fetch("/api/admin/plugins",{headers:z()});if(!v.ok){we.value="Could not load plugins.";return}const u=await v.json();Ie.value=u.plugins||[];for(const f of Ie.value)f.enabled&&!f.health&&xt(f.name)}catch{we.value="Could not reach the API server."}}async function xt(v){try{const u=await fetch(`/api/admin/plugins/${encodeURIComponent(v)}/health`,{method:"POST",headers:z()}),f=await u.json().catch(()=>({}));if(u.ok&&f.health){const S=_t(v);S&&(S.health=f.health)}}catch{}}function _t(v){return Ie.value.find(u=>u.name===v)}async function Wt(v){he.value=v.name,ue.value="";try{const u=await fetch(`/api/admin/plugins/${encodeURIComponent(v.name)}`,{method:"PUT",headers:z(!0),body:JSON.stringify({enabled:!v.enabled})}),f=await u.json().catch(()=>({}));u.ok?f.warning&&(ue.value=`${v.name}: ${f.warning}`):ue.value=f.error||"Could not update the plugin.",await it()}finally{he.value=""}}function vs(v){qe.value=qe.value===v.name?"":v.name;const u={...v.config||{}};for(const f of v.configFields||[])(u[f.key]===void 0||u[f.key]==="")&&f.default&&(u[f.key]=f.default);Fe.value=u}async function wt(v){he.value=v.name,ue.value="";try{const u=await fetch(`/api/admin/plugins/${encodeURIComponent(v.name)}`,{method:"PUT",headers:z(!0),body:JSON.stringify({config:Fe.value})}),f=await u.json().catch(()=>({}));u.ok?(ue.value=f.warning?`${v.name}: ${f.warning}`:"Configuration saved.",qe.value=""):ue.value=f.error||"Could not save the configuration.",await it()}finally{he.value=""}}async function Vn(v){he.value=v.name,ue.value="";try{const u=await fetch(`/api/admin/plugins/${encodeURIComponent(v.name)}/health`,{method:"POST",headers:z()}),f=await u.json().catch(()=>({}));if(u.ok&&f.health){const S=_t(v.name);S&&(S.health=f.health)}else ue.value=f.error||"Health check failed."}finally{he.value=""}}async function a(v){if(v.kind==="external"){he.value=v.name;try{const u=await fetch(`/api/admin/plugins/${encodeURIComponent(v.name)}`,{method:"DELETE",headers:z()});if(!u.ok){const f=await u.json().catch(()=>({}));ue.value=f.error||"Could not remove the plugin."}await it()}finally{he.value=""}}}async function p(){if(ae.value="",!Ne.value.name.trim()||!Ne.value.baseURL.trim()){ae.value="Name and base URL are required.";return}ee.value=!0;try{const v=await fetch("/api/admin/plugins",{method:"POST",headers:z(!0),body:JSON.stringify(Ne.value)}),u=await v.json().catch(()=>({}));if(!v.ok){ae.value=u.error||"Could not register the plugin.";return}Ne.value={name:"",baseURL:"",provider:""},ue.value="External plugin registered.",await it()}catch{ae.value="Could not reach the API server."}finally{ee.value=!1}}const m=L([]),w=L([]),x=L(""),_=[{value:"user",label:"User"},{value:"admin",label:"Admin"},{value:"superadmin",label:"Superadmin"}],T={user:"User",admin:"Admin",superadmin:"Superadmin"},k={user:"bg-sunken text-secondary",admin:"bg-warning-tint text-warning",superadmin:"bg-success-tint text-success"},C=_n(()=>{const v={};for(const u of m.value)u.organization&&(v[u.organization]=(v[u.organization]||0)+1);return v});function b(v,u){if(!v)return u;if(v.error)return v.error;if(v.data&&typeof v.data=="object"){const f=[];for(const S in v.data)v.data[S]&&v.data[S].message&&f.push(`${S}: ${v.data[S].message}`);if(f.length)return f.join("; ")}return v.message||u}const R=L({email:"",password:"",role:"user",organization:""}),E=L(""),M=L(""),D=L(!1),N=L(""),B=L({}),G=L(""),J=L("");async function ie(){x.value="";try{const v=await fetch("/api/users",{headers:z()}),u=await v.json().catch(()=>({}));if(!v.ok){x.value=b(u,"Could not load users.");return}m.value=u.users||[]}catch{x.value="Could not reach the API server."}}async function Me(){E.value="",M.value="";const v=R.value.email.trim().toLowerCase();if(!v||!v.includes("@")){E.value="A valid email is required.";return}if(R.value.password.length<8){E.value="Password must be at least 8 characters.";return}D.value=!0;try{const u=await fetch("/api/users",{method:"POST",headers:z(!0),body:JSON.stringify({email:v,password:R.value.password,role:R.value.role,organization:R.value.organization})}),f=await u.json().catch(()=>({}));if(!u.ok){E.value=b(f,"Could not create the user.");return}R.value={email:"",password:"",role:"user",organization:""},M.value=`Created ${f.user?f.user.email:"user"}.`,await ie()}catch{E.value="Could not reach the API server."}finally{D.value=!1}}function Ue(v){J.value="",N.value=N.value===v.id?"":v.id,B.value={email:v.email,role:v.role,organization:v.organization||"",verified:!!v.verified,password:""}}async function Ct(v){J.value="",G.value=v.id;try{const u={},f=B.value;if(f.email.trim().toLowerCase()!==v.email&&(u.email=f.email.trim().toLowerCase()),f.role!==v.role&&(u.role=f.role),(f.organization||"")!==(v.organization||"")&&(u.organization=f.organization||""),f.verified!==!!v.verified&&(u.verified=f.verified),f.password&&(u.password=f.password),Object.keys(u).length===0){J.value="No changes to save.";return}const S=await fetch(`/api/users/${encodeURIComponent(v.id)}`,{method:"PATCH",headers:z(!0),body:JSON.stringify(u)}),He=await S.json().catch(()=>({}));if(!S.ok){J.value=b(He,"Could not update the user.");return}J.value=`Updated ${v.email}.`,N.value="",await ie()}catch{J.value="Could not reach the API server."}finally{G.value=""}}async function bs(v){if(v.id!==(s.value&&s.value.id)&&confirm(`Delete user ${v.email}? This cannot be undone.`)){J.value="",G.value=v.id;try{const u=await fetch(`/api/users/${encodeURIComponent(v.id)}`,{method:"DELETE",headers:z()}),f=await u.json().catch(()=>({}));if(!u.ok){J.value=b(f,"Could not delete the user.");return}J.value=`Deleted ${v.email}.`,N.value===v.id&&(N.value=""),await ie()}catch{J.value="Could not reach the API server."}finally{G.value=""}}}const fe=L(""),de=L(""),St=L(""),kt=L(!1),lt=L(""),ys=L(""),It=L(""),Te=L("");async function Mt(){try{const v=await fetch("/api/orgs",{headers:z()});if(!v.ok)return;const u=await v.json().catch(()=>({}));w.value=u.organizations||[]}catch{}}async function Hn(){de.value="",St.value="";const v=fe.value.trim();if(!v){de.value="An organization name is required.";return}kt.value=!0;try{const u=await fetch("/api/orgs",{method:"POST",headers:z(!0),body:JSON.stringify({name:v})}),f=await u.json().catch(()=>({}));if(!u.ok){de.value=b(f,"Could not create the organization.");return}fe.value="",St.value=`Created ${f.organization?f.organization.name:"organization"}.`,await Mt()}catch{de.value="Could not reach the API server."}finally{kt.value=!1}}function Ni(v){Te.value="",lt.value=lt.value===v.id?"":v.id,ys.value=v.name}async function Bn(v){Te.value="";const u=ys.value.trim();if(!u){Te.value="An organization name is required.";return}if(u===v.name){lt.value="";return}It.value=v.id;try{const f=await fetch(`/api/orgs/${encodeURIComponent(v.id)}`,{method:"PATCH",headers:z(!0),body:JSON.stringify({name:u})}),S=await f.json().catch(()=>({}));if(!f.ok){Te.value=b(S,"Could not rename the organization.");return}Te.value=`Renamed to ${u}.`,lt.value="",await Mt(),await ie()}catch{Te.value="Could not reach the API server."}finally{It.value=""}}async function Vi(v){const u=C.value[v.id]||0;if(u>0){Te.value=`${v.name} still has ${u} member${u===1?"":"s"}; reassign or remove them first.`;return}if(confirm(`Delete organization ${v.name}?`)){Te.value="",It.value=v.id;try{const f=await fetch(`/api/orgs/${encodeURIComponent(v.id)}`,{method:"DELETE",headers:z()}),S=await f.json().catch(()=>({}));if(!f.ok){Te.value=b(S,"Could not delete the organization.");return}Te.value=`Deleted ${v.name}.`,lt.value===v.id&&(lt.value=""),await Mt()}catch{Te.value="Could not reach the API server."}finally{It.value=""}}}const Xs=L(null),xs=L(null),Ut=L({apiServer:{status:"checking",detail:""},pocketBase:{status:"checking",detail:""},webApp:{status:"checking",detail:""}});let _s=null;const Hi=[{key:"apiServer",label:"API server"},{key:"pocketBase",label:"PocketBase"},{key:"webApp",label:"Web App"}],Kn={checking:{label:"checking",cls:"bg-sunken text-secondary"},ok:{label:"operational",cls:"bg-success-tint text-success"},down:{label:"unreachable",cls:"bg-danger-tint text-danger"},unreachable:{label:"unreachable",cls:"bg-danger-tint text-danger"}};function zn(v){const u=[];return v.httpStatus&&u.push("HTTP "+v.httpStatus),v.url&&u.push(v.url),typeof v.latencyMs=="number"&&u.push(v.latencyMs+"ms"),u.join(" · ")}async function Wn(){var v,u;try{const f=await fetch("/api/status");if(!f.ok)throw new Error("status "+f.status);const S=await f.json(),He=S.apiServer||{};xs.value=He.devices??0,Ut.value={apiServer:{status:"ok",detail:""},pocketBase:{status:((v=S.pocketBase)==null?void 0:v.status)==="ok"?"ok":"down",detail:zn(S.pocketBase||{})},webApp:{status:((u=S.webApp)==null?void 0:u.status)==="ok"?"ok":"down",detail:zn(S.webApp||{})}}}catch{xs.value=null,Ut.value={apiServer:{status:"unreachable",detail:""},pocketBase:{status:"unreachable",detail:""},webApp:{status:"unreachable",detail:""}}}Xs.value=new Date}function Gn(){Wn(),clearInterval(_s),_s=setInterval(Wn,1e4)}function qn(){clearInterval(_s),_s=null}fi(async()=>{t.value&&await h(t.value)?(n.value=!0,Gn(),ke(),it(),Mt(),ie()):t.value&&(localStorage.removeItem(Es),t.value=""),o.value=!1}),Ln(()=>qn());const Bi=[{method:"POST",path:"/api/auth/login",desc:"Exchange email + password for a session (via PocketBase)"},{method:"GET",path:"/api/auth/validate",desc:"Validate the current session token"},{method:"GET",path:"/api/me",desc:"Caller's id, email, role, and organization from their token"},{method:"GET",path:"/api/preferences",desc:"Read the caller's saved settings blob"},{method:"PUT",path:"/api/preferences",desc:"Persist the caller's settings onto their user record"},{method:"GET",path:"/api/devices",desc:"List connected devices and last-known state"},{method:"GET",path:"/api/devices/{id}/track",desc:"GPS track history for a device"},{method:"POST",path:"/api/devices/{id}/command",desc:"Send a command down to a device"},{method:"DELETE",path:"/api/devices/{id}",desc:"Forget a device's stored state"},{method:"GET",path:"/ws/ui",desc:"Live telemetry stream (WebSocket)"}],Ki=[{method:"GET",path:"/api/users",desc:"List users (admin: own org · superadmin: all)"},{method:"POST",path:"/api/users",desc:"Create a user {email, password, role, organization?}"},{method:"PATCH",path:"/api/users/{id}",desc:"Edit a user (role/org changes are scope-checked)"},{method:"DELETE",path:"/api/users/{id}",desc:"Delete a user (not self; admins in-org only)"},{method:"GET",path:"/api/orgs",desc:"List organizations (admin: own · superadmin: all)"},{method:"POST",path:"/api/orgs",desc:"Create an organization {name} (superadmin)"},{method:"PATCH",path:"/api/orgs/{id}",desc:"Rename an organization (superadmin)"},{method:"DELETE",path:"/api/orgs/{id}",desc:"Delete an empty organization (superadmin)"},{method:"GET",path:"/api/admin/pb-config",desc:"Read the PocketBase connection + live probe (superadmin)"},{method:"POST",path:"/api/admin/pb-config/test",desc:"Test a candidate connection without applying (superadmin)"},{method:"PUT",path:"/api/admin/pb-config",desc:"Update + persist the PocketBase connection (superadmin)"},{method:"GET",path:"/api/admin/plugins",desc:"List plugins + state + last health (superadmin)"},{method:"POST",path:"/api/admin/plugins",desc:"Register an external plugin {name, baseURL} (superadmin)"},{method:"PUT",path:"/api/admin/plugins/{name}",desc:"Enable/disable + configure a plugin (superadmin)"},{method:"DELETE",path:"/api/admin/plugins/{name}",desc:"Remove an external plugin (superadmin)"},{method:"POST",path:"/api/admin/plugins/{name}/health",desc:"Run a plugin health check (superadmin)"}],zi=[{method:"GET",path:"/ws/device?id={id}",desc:"Device telemetry uplink (WebSocket)"},{method:"POST",path:"/api/telemetry?id={id}",desc:"Push a single telemetry event over HTTP"},{method:"GET",path:"/healthz",desc:"Readiness probe"}];return(v,u)=>(P(),A("div",Oa,[d("div",Ra,[u[25]||(u[25]=Ar('
PilotVault
API server
',3)),n.value&&s.value?(P(),A("span",Ia,O(s.value.email),1)):K("",!0),n.value?(P(),A("button",{key:1,class:"pv-btn-sec pv-btn-sm",onClick:U},"Sign out")):K("",!0),d("button",{class:"pv-btn-sec pv-btn-sm",title:Xt(ds)==="dark"?"Switch to light theme":"Switch to dark theme",onClick:u[0]||(u[0]=(...f)=>Xt(Ao)&&Xt(Ao)(...f))},[Xt(ds)==="dark"?(P(),A("svg",Ua,[...u[22]||(u[22]=[d("circle",{cx:"12",cy:"12",r:"4"},null,-1),d("path",{d:"M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"},null,-1)])])):(P(),A("svg",$a,[...u[23]||(u[23]=[d("path",{d:"M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"},null,-1)])])),u[24]||(u[24]=$e(" Theme ",-1))],8,Ma)]),o.value?(P(),A("div",ja,[...u[26]||(u[26]=[d("span",{class:"pv-eyebrow"},"Checking session…",-1)])])):n.value?(P(),A(re,{key:2},[d("div",Ha,[(P(),A(re,null,Ce(g,f=>d("button",{key:f.id,class:Pe(["rounded-md px-3.5 py-1.5 text-sm font-semibold transition",c.value===f.id?"bg-brand text-on-brand":"text-secondary hover:text-primary"]),onClick:S=>c.value=f.id},O(f.label),11,Ba)),64))]),le(d("div",Ka,[d("div",za,[d("div",Wa,[u[30]||(u[30]=d("div",{class:"text-base font-semibold text-primary"},"Status",-1)),d("span",Ga,O(Xs.value?"checked "+Xs.value.toLocaleTimeString():"—"),1)]),d("div",null,[(P(),A(re,null,Ce(Hi,f=>d("div",{key:f.key,class:"flex items-center justify-between gap-3 border-t border-subtle px-5 py-3.5 first:border-t-0"},[d("div",qa,[d("div",Ja,O(f.label),1),Ut.value[f.key].detail?(P(),A("div",Ya,O(Ut.value[f.key].detail),1)):K("",!0)]),d("span",{class:Pe(["inline-flex shrink-0 items-center gap-1.5 rounded-sm px-2.5 py-1 font-mono text-xs font-medium",Kn[Ut.value[f.key].status].cls])},[u[31]||(u[31]=d("span",{class:"h-1.5 w-1.5 rounded-full bg-current"},null,-1)),$e(" "+O(Kn[Ut.value[f.key].status].label),1)],2)])),64)),d("div",Xa,[u[32]||(u[32]=d("div",{class:"text-sm font-semibold text-primary"},"Devices",-1)),d("span",Za,O(xs.value===null?"—":xs.value+" online"),1)])])]),Oe(un,{title:"Client API",auth:"PocketBase session",endpoints:Bi}),Oe(un,{title:"Management API",auth:"Admin · superadmin",endpoints:Ki}),Oe(un,{title:"Device API",auth:"Device uplink",endpoints:zi})],512),[[Jt,c.value==="overview"]]),le(d("div",Qa,[d("div",ec,[u[38]||(u[38]=d("div",{class:"border-b border-subtle px-5 py-4"},[d("div",{class:"text-base font-semibold text-primary"},"Add user"),d("span",{class:"pv-eyebrow"},"Create an account")],-1)),d("div",tc,[d("div",sc,[d("label",nc,[u[33]||(u[33]=d("span",{class:"pv-eyebrow"},"Email",-1)),le(d("input",{"onUpdate:modelValue":u[3]||(u[3]=f=>R.value.email=f),type:"email",class:"pv-input",placeholder:"pilot@pilotvault.local",autocomplete:"off",spellcheck:"false"},null,512),[[ye,R.value.email]])]),d("label",oc,[u[34]||(u[34]=d("span",{class:"pv-eyebrow"},"Password",-1)),le(d("input",{"onUpdate:modelValue":u[4]||(u[4]=f=>R.value.password=f),type:"password",class:"pv-input",placeholder:"min. 8 characters",autocomplete:"new-password"},null,512),[[ye,R.value.password]])])]),d("div",ic,[d("label",lc,[u[35]||(u[35]=d("span",{class:"pv-eyebrow"},"Role",-1)),le(d("select",{"onUpdate:modelValue":u[5]||(u[5]=f=>R.value.role=f),class:"pv-input"},[(P(),A(re,null,Ce(_,f=>d("option",{key:f.value,value:f.value},O(f.label),9,rc)),64))],512),[[Dt,R.value.role]])]),d("label",ac,[u[37]||(u[37]=d("span",{class:"pv-eyebrow"},"Organization",-1)),le(d("select",{"onUpdate:modelValue":u[6]||(u[6]=f=>R.value.organization=f),class:"pv-input"},[u[36]||(u[36]=d("option",{value:""},"— none —",-1)),(P(!0),A(re,null,Ce(w.value,f=>(P(),A("option",{key:f.id,value:f.id},O(f.name),9,cc))),128))],512),[[Dt,R.value.organization]])])]),E.value?(P(),A("p",uc,O(E.value),1)):M.value?(P(),A("p",fc,O(M.value),1)):K("",!0),d("div",null,[d("button",{class:"pv-btn",disabled:D.value,onClick:Me},O(D.value?"Creating…":"Create user"),9,dc)])])]),d("div",pc,[d("div",hc,[d("div",null,[u[39]||(u[39]=d("div",{class:"text-base font-semibold text-primary"},"Users",-1)),d("span",gc,O(m.value.length)+" total",1)]),d("button",{class:"pv-btn-sec pv-btn-sm",onClick:ie},"Refresh")]),d("div",mc,[x.value?(P(),A("p",vc,O(x.value),1)):K("",!0),J.value?(P(),A("p",bc,O(J.value),1)):K("",!0),!m.value.length&&!x.value?(P(),A("p",yc,"No users yet.")):K("",!0),(P(!0),A(re,null,Ce(m.value,f=>(P(),A("div",{key:f.id,class:"border-t border-subtle px-5 py-4 first:border-t-0"},[d("div",xc,[d("div",_c,[d("div",wc,[d("span",Cc,O(f.email),1),d("span",{class:Pe(["rounded-sm px-1.5 py-0.5 font-mono text-[10px] font-medium uppercase tracking-wider",k[f.role]])},O(T[f.role]||f.role),3),f.id===(s.value&&s.value.id)?(P(),A("span",Sc,"you")):K("",!0),f.verified?K("",!0):(P(),A("span",kc,"unverified"))]),d("div",Ec,O(f.organizationName||(f.organization?f.organization:"no organization")),1)]),d("div",Tc,[d("button",{class:"pv-btn-sec pv-btn-sm",onClick:S=>Ue(f)},O(N.value===f.id?"Close":"Edit"),9,Pc),f.id!==(s.value&&s.value.id)?(P(),A("button",{key:0,class:"pv-btn-sec pv-btn-sm !text-danger",disabled:G.value===f.id,onClick:S=>bs(f)}," Delete ",8,Ac)):K("",!0)])]),N.value===f.id?(P(),A("div",Oc,[d("div",Rc,[d("label",Ic,[u[40]||(u[40]=d("span",{class:"pv-eyebrow"},"Email",-1)),le(d("input",{"onUpdate:modelValue":u[7]||(u[7]=S=>B.value.email=S),type:"email",class:"pv-input",autocomplete:"off",spellcheck:"false"},null,512),[[ye,B.value.email]])]),d("label",Mc,[u[41]||(u[41]=d("span",{class:"pv-eyebrow"},"New password",-1)),le(d("input",{"onUpdate:modelValue":u[8]||(u[8]=S=>B.value.password=S),type:"password",class:"pv-input",placeholder:"leave blank to keep current",autocomplete:"new-password"},null,512),[[ye,B.value.password]])])]),d("div",Uc,[d("label",$c,[u[42]||(u[42]=d("span",{class:"pv-eyebrow"},"Role",-1)),le(d("select",{"onUpdate:modelValue":u[9]||(u[9]=S=>B.value.role=S),class:"pv-input",disabled:f.id===(s.value&&s.value.id)},[(P(),A(re,null,Ce(_,S=>d("option",{key:S.value,value:S.value},O(S.label),9,Dc)),64))],8,jc),[[Dt,B.value.role]]),f.id===(s.value&&s.value.id)?(P(),A("span",Lc,"You cannot change your own role.")):K("",!0)]),d("label",Fc,[u[44]||(u[44]=d("span",{class:"pv-eyebrow"},"Organization",-1)),le(d("select",{"onUpdate:modelValue":u[10]||(u[10]=S=>B.value.organization=S),class:"pv-input"},[u[43]||(u[43]=d("option",{value:""},"— none —",-1)),(P(!0),A(re,null,Ce(w.value,S=>(P(),A("option",{key:S.id,value:S.id},O(S.name),9,Nc))),128))],512),[[Dt,B.value.organization]])])]),d("label",Vc,[le(d("input",{"onUpdate:modelValue":u[11]||(u[11]=S=>B.value.verified=S),type:"checkbox",class:"h-4 w-4"},null,512),[[ji,B.value.verified]]),u[45]||(u[45]=d("span",{class:"text-sm text-primary"},"Verified",-1))]),d("div",Hc,[d("button",{class:"pv-btn pv-btn-sm",disabled:G.value===f.id,onClick:S=>Ct(f)},"Save changes",8,Bc),d("button",{class:"pv-btn-sec pv-btn-sm",onClick:u[12]||(u[12]=S=>N.value="")},"Cancel")])])):K("",!0)]))),128))])])],512),[[Jt,c.value==="users"]]),le(d("div",Kc,[d("div",zc,[u[46]||(u[46]=d("div",{class:"border-b border-subtle px-5 py-4"},[d("div",{class:"text-base font-semibold text-primary"},"Add organization"),d("span",{class:"pv-eyebrow"},"Create a tenant")],-1)),d("div",Wc,[d("div",Gc,[le(d("input",{"onUpdate:modelValue":u[13]||(u[13]=f=>fe.value=f),class:"pv-input flex-1",placeholder:"Acme Aerial Ltd.",autocomplete:"off",spellcheck:"false",onKeyup:To(Hn,["enter"])},null,544),[[ye,fe.value]]),d("button",{class:"pv-btn",disabled:kt.value,onClick:Hn},O(kt.value?"Creating…":"Create"),9,qc)]),de.value?(P(),A("p",Jc,O(de.value),1)):St.value?(P(),A("p",Yc,O(St.value),1)):K("",!0)])]),d("div",Xc,[d("div",Zc,[d("div",null,[u[47]||(u[47]=d("div",{class:"text-base font-semibold text-primary"},"Organizations",-1)),d("span",Qc,O(w.value.length)+" total",1)]),d("button",{class:"pv-btn-sec pv-btn-sm",onClick:Mt},"Refresh")]),d("div",eu,[Te.value?(P(),A("p",tu,O(Te.value),1)):K("",!0),w.value.length?K("",!0):(P(),A("p",su,"No organizations yet.")),(P(!0),A(re,null,Ce(w.value,f=>(P(),A("div",{key:f.id,class:"border-t border-subtle px-5 py-4 first:border-t-0"},[d("div",nu,[d("div",ou,[d("div",iu,O(f.name),1),d("div",lu,O(C.value[f.id]||0)+" member"+O((C.value[f.id]||0)===1?"":"s"),1)]),d("div",ru,[d("button",{class:"pv-btn-sec pv-btn-sm",onClick:S=>Ni(f)},O(lt.value===f.id?"Close":"Rename"),9,au),d("button",{class:"pv-btn-sec pv-btn-sm !text-danger",disabled:It.value===f.id||(C.value[f.id]||0)>0,title:(C.value[f.id]||0)>0?"Reassign or remove members first":"Delete organization",onClick:S=>Vi(f)}," Delete ",8,cu)])]),lt.value===f.id?(P(),A("div",uu,[d("label",fu,[u[48]||(u[48]=d("span",{class:"pv-eyebrow"},"Name",-1)),le(d("input",{"onUpdate:modelValue":u[14]||(u[14]=S=>ys.value=S),class:"pv-input",autocomplete:"off",spellcheck:"false",onKeyup:To(S=>Bn(f),["enter"])},null,40,du),[[ye,ys.value]])]),d("div",pu,[d("button",{class:"pv-btn pv-btn-sm",disabled:It.value===f.id,onClick:S=>Bn(f)},"Save",8,hu),d("button",{class:"pv-btn-sec pv-btn-sm",onClick:u[15]||(u[15]=S=>lt.value="")},"Cancel")])])):K("",!0)]))),128))])])],512),[[Jt,c.value==="organizations"]]),le(d("div",gu,[d("div",mu,[d("div",vu,[u[50]||(u[50]=d("div",null,[d("div",{class:"text-base font-semibold text-primary"},"PocketBase connection"),d("span",{class:"pv-eyebrow"},"Settings")],-1)),W.value?(P(),A("span",{key:0,class:Pe(["inline-flex shrink-0 items-center gap-1.5 rounded-sm px-2.5 py-1 font-mono text-xs font-medium",W.value.reachable?W.value.superuser?"bg-success-tint text-success":"bg-warning-tint text-warning":"bg-danger-tint text-danger"])},[u[49]||(u[49]=d("span",{class:"h-1.5 w-1.5 rounded-full bg-current"},null,-1)),$e(" "+O(W.value.reachable?W.value.superuser?"connected":"reachable":"unreachable"),1)],2)):K("",!0)]),d("div",bu,[d("label",yu,[u[51]||(u[51]=d("span",{class:"pv-eyebrow"},"PocketBase URL",-1)),le(d("input",{"onUpdate:modelValue":u[16]||(u[16]=f=>$.value.url=f),class:"pv-input",placeholder:"http://10.2.1.10:8026",spellcheck:"false"},null,512),[[ye,$.value.url]])]),d("label",xu,[u[52]||(u[52]=d("span",{class:"pv-eyebrow"},"Service account email",-1)),le(d("input",{"onUpdate:modelValue":u[17]||(u[17]=f=>$.value.adminEmail=f),class:"pv-input",placeholder:"admin@pilotvault.local",autocomplete:"off",spellcheck:"false"},null,512),[[ye,$.value.adminEmail]])]),d("label",_u,[u[53]||(u[53]=d("span",{class:"pv-eyebrow"},"Service account password",-1)),le(d("input",{"onUpdate:modelValue":u[18]||(u[18]=f=>$.value.adminPassword=f),type:"password",class:"pv-input",autocomplete:"new-password",placeholder:q.value&&q.value.adminConfigured?"leave blank to keep current":"set a password"},null,8,wu),[[ye,$.value.adminPassword]])]),W.value?(P(),A("div",Cu,[$e(" health: "+O(W.value.reachable?"ok":"down"),1),W.value.latencyMs?(P(),A("span",Su," · "+O(W.value.latencyMs)+"ms",1)):K("",!0),$e(" · superuser auth: "+O(W.value.superuser?"ok":"—"),1),W.value.detail?(P(),A("span",ku," · "+O(W.value.detail),1)):K("",!0)])):K("",!0),V.value?(P(),A("p",Eu,O(V.value),1)):Y.value?(P(),A("p",Tu,O(Y.value),1)):K("",!0),d("div",Pu,[d("button",{class:"pv-btn",disabled:X.value,onClick:Ge},O(X.value?"Saving…":"Save connection"),9,Au),d("button",{class:"pv-btn-sec",disabled:j.value,onClick:Re},O(j.value?"Testing…":"Test connection"),9,Ou)]),u[54]||(u[54]=d("p",{class:"text-[11px] text-muted"}," The service account is used only for user & organization management. Changing the URL repoints the whole API Server at a new PocketBase and may sign you out. ",-1))])])],512),[[Jt,c.value==="pocketbase"]]),le(d("div",Ru,[d("div",Iu,[d("div",{class:"flex items-center justify-between border-b border-subtle px-5 py-4"},[u[55]||(u[55]=d("div",null,[d("div",{class:"text-base font-semibold text-primary"},"Plugins"),d("span",{class:"pv-eyebrow"},"External integrations")],-1)),d("button",{class:"pv-btn-sec pv-btn-sm",onClick:it},"Refresh")]),d("div",Mu,[we.value?(P(),A("p",Uu,O(we.value),1)):K("",!0),ue.value?(P(),A("p",$u,O(ue.value),1)):K("",!0),!Ie.value.length&&!we.value?(P(),A("p",ju,"No plugins registered yet.")):K("",!0),Ie.value.length?(P(),A("div",Du,[(P(),A(re,null,Ce(te,f=>d("button",{key:f.id,class:Pe(["-mb-px whitespace-nowrap border-b-2 px-3 py-2 text-sm font-semibold transition",Ve.value===f.id?"border-brand text-primary":"border-transparent text-secondary hover:text-primary"]),onClick:S=>Ve.value=f.id},O(f.label),11,Lu)),64))])):K("",!0),Ie.value.length&&!Ee.value.length?(P(),A("p",Fu,"No plugins in this category.")):K("",!0),(P(!0),A(re,null,Ce(Ee.value,f=>(P(),A("div",{key:f.name,class:"border-t border-subtle px-5 py-4 first:border-t-0"},[d("div",Nu,[d("div",Vu,[d("div",Hu,[d("span",Bu,O(f.name),1),d("span",{class:Pe(["rounded-sm px-1.5 py-0.5 font-mono text-[10px] font-medium uppercase tracking-wider",ms[f.kind]])},O(f.kind),3),f.health?(P(),A("span",{key:0,class:Pe(["inline-flex items-center gap-1 rounded-sm px-1.5 py-0.5 font-mono text-[10px] font-medium",Ys[f.health.status]]),title:f.health.detail||""},[u[56]||(u[56]=d("span",{class:"h-1 w-1 rounded-full bg-current"},null,-1)),$e(O(f.health.status),1),f.health.latencyMs?(P(),A("span",zu," · "+O(f.health.latencyMs)+"ms",1)):K("",!0)],10,Ku)):K("",!0)]),d("div",Wu,O(f.provider)+" · v"+O(f.version)+" · "+O(f.authType),1),f.health&&f.health.detail?(P(),A("div",Gu,O(f.health.detail),1)):K("",!0),f.capabilities&&f.capabilities.length?(P(),A("div",qu,[u[57]||(u[57]=d("div",{class:"pv-eyebrow"},"Capabilities",-1)),(P(!0),A(re,null,Ce(f.capabilities,S=>(P(),A("div",{key:S.id,class:"flex flex-wrap items-baseline gap-x-2 gap-y-0.5"},[d("span",Ju,O(S.id),1),S.method||S.endpoint?(P(),A("span",Yu,O(S.method)+" "+O(S.endpoint),1)):K("",!0),S.description?(P(),A("span",Xu,O(S.description),1)):K("",!0)]))),128))])):K("",!0),f.baseURL?(P(),A("div",Zu,O(f.baseURL),1)):K("",!0)]),d("div",Qu,[d("button",{class:Pe(["pv-btn-sec pv-btn-sm",f.enabled?"!border-transparent !bg-success-tint !text-success":""]),disabled:he.value===f.name,onClick:S=>Wt(f)},[d("span",{class:Pe(["h-1.5 w-1.5 rounded-full",f.enabled?"bg-success":"bg-muted"])},null,2),$e(" "+O(f.enabled?"Enabled":"Disabled"),1)],10,ef),f.configFields&&f.configFields.length?(P(),A("button",{key:0,class:"pv-btn-sec pv-btn-sm",onClick:S=>vs(f)},"Configure",8,tf)):K("",!0),d("button",{class:"pv-btn-sec pv-btn-sm",disabled:he.value===f.name,onClick:S=>Vn(f)},"Check",8,sf),f.kind==="external"?(P(),A("button",{key:1,class:"pv-btn-sec pv-btn-sm !text-danger",disabled:he.value===f.name,onClick:S=>a(f)},"Remove",8,nf)):K("",!0)])]),qe.value===f.name?(P(),A("div",of,[(P(!0),A(re,null,Ce(f.configFields,S=>(P(),A("label",{key:S.key,class:"flex flex-col gap-1"},[d("span",lf,[$e(O(S.label),1),S.required?(P(),A("span",rf," *")):K("",!0)]),S.type==="select"?le((P(),A("select",{key:0,"onUpdate:modelValue":He=>Fe.value[S.key]=He,class:"pv-input"},[(P(!0),A(re,null,Ce(S.options,He=>(P(),A("option",{key:He.value,value:He.value},O(He.label),9,cf))),128))],8,af)),[[Dt,Fe.value[S.key]]]):le((P(),A("input",{key:1,"onUpdate:modelValue":He=>Fe.value[S.key]=He,type:S.secret||S.type==="password"?"password":S.type==="number"?"number":"text",class:"pv-input",autocomplete:"off",placeholder:S.help||""},null,8,uf)),[[ua,Fe.value[S.key]]]),S.help?(P(),A("span",ff,O(S.help),1)):K("",!0)]))),128)),d("div",df,[d("button",{class:"pv-btn pv-btn-sm",disabled:he.value===f.name,onClick:S=>wt(f)},"Save configuration",8,pf),d("button",{class:"pv-btn-sec pv-btn-sm",onClick:u[19]||(u[19]=S=>qe.value="")},"Cancel")])])):K("",!0)]))),128)),d("div",hf,[u[58]||(u[58]=d("div",{class:"pv-eyebrow mb-2"},"Register external plugin",-1)),d("div",gf,[le(d("input",{"onUpdate:modelValue":u[20]||(u[20]=f=>Ne.value.name=f),class:"pv-input sm:w-40",placeholder:"name",autocomplete:"off",spellcheck:"false"},null,512),[[ye,Ne.value.name]]),le(d("input",{"onUpdate:modelValue":u[21]||(u[21]=f=>Ne.value.baseURL=f),class:"pv-input flex-1",placeholder:"https://plugin.example.com",autocomplete:"off",spellcheck:"false"},null,512),[[ye,Ne.value.baseURL]]),d("button",{class:"pv-btn",disabled:ee.value,onClick:p},O(ee.value?"Adding…":"Add"),9,mf)]),ae.value?(P(),A("p",vf,O(ae.value),1)):K("",!0),u[59]||(u[59]=d("p",{class:"mt-2 text-[11px] text-muted"},[$e(" A remote service that answers "),d("span",{class:"font-mono"},"GET /health"),$e(" and "),d("span",{class:"font-mono"},"GET /manifest"),$e(" — added at runtime, no rebuild. ")],-1))])])])],512),[[Jt,c.value==="plugins"]])],64)):(P(),A("div",Da,[u[29]||(u[29]=d("div",{class:"border-b border-subtle px-5 py-4"},[d("div",{class:"text-base font-semibold text-primary"},"Sign in"),d("span",{class:"pv-eyebrow"},"Superadmin access only")],-1)),d("form",{class:"flex flex-col gap-3 px-5 py-5",onSubmit:ha(I,["prevent"])},[d("label",La,[u[27]||(u[27]=d("span",{class:"pv-eyebrow"},"Email",-1)),le(d("input",{"onUpdate:modelValue":u[1]||(u[1]=f=>i.value.email=f),type:"email",autocomplete:"username",class:"pv-input",placeholder:"superadmin@pilotvault.local"},null,512),[[ye,i.value.email]])]),d("label",Fa,[u[28]||(u[28]=d("span",{class:"pv-eyebrow"},"Password",-1)),le(d("input",{"onUpdate:modelValue":u[2]||(u[2]=f=>i.value.password=f),type:"password",autocomplete:"current-password",class:"pv-input",placeholder:"••••••••"},null,512),[[ye,i.value.password]])]),l.value?(P(),A("p",Na,O(l.value),1)):K("",!0),d("button",{type:"submit",class:"pv-btn mt-1",disabled:r.value},O(r.value?"Signing in…":"Sign in"),9,Va)],32)])),u[60]||(u[60]=d("p",{class:"text-center font-mono text-[11px] text-muted"}," PilotVault — live drone telemetry, command & control. ",-1))]))}};ba(bf).mount("#app"); diff --git a/API Server/internal/api/dist/index.html b/API Server/internal/api/dist/index.html index 7494b8e..88857b7 100644 --- a/API Server/internal/api/dist/index.html +++ b/API Server/internal/api/dist/index.html @@ -6,7 +6,7 @@ PilotVault · API Server - + diff --git a/API Server/panel/src/App.vue b/API Server/panel/src/App.vue index 951862b..e4a0cc8 100644 --- a/API Server/panel/src/App.vue +++ b/API Server/panel/src/App.vue @@ -701,9 +701,9 @@ const badge = { function meta(h) { const bits = []; - if (typeof h.latencyMs === "number") bits.push(h.latencyMs + "ms"); if (h.httpStatus) bits.push("HTTP " + h.httpStatus); if (h.url) bits.push(h.url); + if (typeof h.latencyMs === "number") bits.push(h.latencyMs + "ms"); return bits.join(" · "); }