livedesk 0.1.697 → 0.1.700
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -3
- package/bin/livedesk.js +16 -8
- package/client/package.json +5 -5
- package/diagnostics/vuvodesk-linux-desktop.mjs +188 -0
- package/electron/entitlements.mac.plist +12 -12
- package/electron/recurring-update-owner.mjs +2 -2
- package/electron/update-manager.mjs +59 -16
- package/hub/src/plan-device-access.test.mjs +8 -8
- package/hub/src/server.js +1 -1
- package/package.json +7 -7
- package/web/dist/app.html +1 -1
- package/web/dist/app.webmanifest +1 -1
- package/web/dist/assets/{AgentSettingsTab-DRWDCG0o.js → AgentSettingsTab-CvKCM1zo.js} +1 -1
- package/web/dist/assets/{AgentsPage-BnF3p9G1.js → AgentsPage-C0yd93rX.js} +1 -1
- package/web/dist/assets/{CaptureGallery-8lr9Ct1i.js → CaptureGallery-CDp1NX62.js} +1 -1
- package/web/dist/assets/DesktopUpdatePanel-BaRZzRao.js +1 -0
- package/web/dist/assets/HubApp-BoHzIvar.js +182 -0
- package/web/dist/assets/HubApp-C-E5cpCr.css +1 -0
- package/web/dist/assets/{MonitorStackIcon-led0pnag.js → MonitorStackIcon-BLNbbRNY.js} +5 -5
- package/web/dist/assets/{SettingsPage-k202bRU1.js → SettingsPage-D-7mFs9n.js} +1 -1
- package/web/dist/assets/SettingsTabs-C_xNvq7v.js +1 -0
- package/web/dist/assets/{ShareFilesPage-DRW1qS1Z.js → ShareFilesPage-CKdD-FK5.js} +1 -1
- package/web/dist/assets/{SupportPage-DXkBQh_W.js → SupportPage-LJUVsA1x.js} +1 -1
- package/web/dist/assets/{VuvoDeskApp-BHcF72r3.js → VuvoDeskApp-nDShkdzM.js} +1 -1
- package/web/dist/assets/{app-DcrmhmnT.js → app-CUaudslO.js} +2 -2
- package/web/dist/assets/{client-D-D35ghV.js → client-DV0v4wud.js} +1 -1
- package/web/dist/assets/frame-lifecycle-CNz8ou2A.js +1 -0
- package/web/dist/assets/{icons-ChMazCZR.js → icons-BwhnWKHR.js} +1 -1
- package/web/dist/assets/main-DNiaJr76.js +2 -0
- package/web/dist/assets/{pwa-startup-BiuYh5eN.js → pwa-startup-C8kDd3Vd.js} +1 -1
- package/web/dist/assets/{react-CnkEM7Rb.js → react-Dm67yaJf.js} +1 -1
- package/web/dist/index.html +6 -6
- package/web/dist/sw.js +2 -2
- package/web/dist/vuvodesk-build-evidence.json +57 -57
- package/web/dist/assets/DesktopUpdatePanel-DopP2EeD.js +0 -1
- package/web/dist/assets/HubApp-CqNxUVJD.js +0 -182
- package/web/dist/assets/HubApp-DdHHVOM0.css +0 -1
- package/web/dist/assets/SettingsTabs-v57M-CCZ.js +0 -1
- package/web/dist/assets/frame-lifecycle-D91nchvm.js +0 -1
- package/web/dist/assets/main-BXBJt96-.js +0 -2
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{j as e}from"./pwa-startup-BiuYh5eN.js";import{r as c,z as X,S as T,R as xe,a1 as Ke,a2 as ye,X as G,a3 as be,y as ee,a4 as je,L as V,a5 as Xe,a6 as et,a7 as ve,a8 as _e,a9 as tt,D as st,m as at,aa as it,ab as nt,ac as rt,ad as ot}from"./icons-ChMazCZR.js";import{s as u}from"./HubApp-CqNxUVJD.js";import"./pwa-bootstrap-ljOQTt2e.js";import"./public-site-routing-pddZbLCj.js";import"./MonitorStackIcon-led0pnag.js";import"./supabase-C7qjtLN3.js";import"./frame-lifecycle-D91nchvm.js";const ct=new Set(["browserLanguage","platform","online","viewport","timezone","screen"]),lt={id:"browser-safe-v1",collect(){if(typeof navigator>"u")return{};const s={browserLanguage:navigator.language||"",platform:navigator.platform||"",online:navigator.onLine,timezone:typeof Intl>"u"?"":Intl.DateTimeFormat().resolvedOptions().timeZone||"",viewport:typeof window>"u"?void 0:{width:window.innerWidth,height:window.innerHeight},screen:typeof window>"u"?void 0:{width:window.screen.width,height:window.screen.height}};return Object.fromEntries(Object.entries(s).filter(([i,n])=>ct.has(i)&&n!==void 0))}};function dt(s,i="Support request failed."){if(s&&typeof s=="object"&&"message"in s){const n=String(s.message||"").trim();if(n)return n.replace(/^.*Support request failed:\s*/i,"")}return s instanceof Error?s.message:i}function pt(s=lt){return s.collect()}async function ut(s,i="livedesk"){const{data:n,error:d}=await u.from("app_admins").select("role").eq("user_id",s).limit(1);if(d)throw d;const o=n?.[0]?.role||"user";if(o!=="owner"){const{error:x}=await u.rpc("register_product_access",{p_product_key:i,p_access_type:"free"});if(x)throw x}const[y,m,P]=await Promise.all([u.from("products").select("id, product_key, name, description, sort_order").order("sort_order"),u.from("product_admins").select("product_id, role").eq("user_id",s),u.from("user_products").select("product_id").eq("user_id",s).eq("is_active",!0)]);if(y.error)throw y.error;if(m.error)throw m.error;if(P.error)throw P.error;const j=y.data||[],z=(m.data||[]).map(x=>String(x.product_id)),L=(P.data||[]).map(x=>String(x.product_id)),S=o==="owner",k=S?j.map(x=>x.id):[...new Set([...z,...L])];return{products:j,access:{userId:s,globalRole:o,accessibleProductIds:k,managedProductIds:S?j.map(x=>x.id):z,canViewAllProducts:S,canViewAllPrivatePosts:S,canManageAllProducts:S,canCreateAnnouncements:S||z.length>0}}}async function ht(s=""){const{data:i,error:n}=await u.rpc("search_support_posts",{p_query:s.trim()||null,p_limit:250});if(n)throw n;return i||[]}async function mt(s){const{data:i,error:n}=await u.from("support_attachments").select("*").eq("post_id",s).order("created_at");if(n)throw n;const d=i||[];return Promise.all(d.map(async o=>{const y=await u.storage.from("support-attachments").createSignedUrl(o.storage_path,3600);return{...o,signed_url:y.data?.signedUrl||void 0}}))}async function ft(){const{data:s,error:i}=await u.from("support_notifications").select("*").order("created_at",{ascending:!1}).limit(30);if(i)throw i;return s||[]}async function xt(s){const{error:i}=await u.rpc("mark_support_notification_read",{p_notification_id:s});if(i)throw i}async function ge(s){const{data:i,error:n}=await u.from("support_comments").select("*").eq("post_id",s).order("created_at");if(n)throw n;return i||[]}async function yt(s){const{data:i,error:n}=await u.from("support_votes").select("post_id").eq("user_id",s);if(n)throw n;return new Set((i||[]).map(d=>String(d.post_id)))}async function bt(s){const{data:i,error:n}=await u.rpc("create_support_post",{p_product_id:s.productId,p_post_type:s.postType,p_title:s.title,p_body:s.body,p_visibility:s.visibility,p_app_version:s.appVersion||null,p_platform:typeof navigator>"u"?null:navigator.platform||null,p_os_version:typeof navigator>"u"?null:navigator.platform||null,p_environment:s.includeEnvironment?pt():{}});if(n)throw n;const d=Array.isArray(i)?i[0]?.post_id:i?.post_id;if(!d)throw new Error("Support post was not created.");return String(d)}const jt=new Set(["image/png","image/jpeg","image/webp","text/plain","text/markdown","application/json","application/pdf"]);async function vt(s,i){if(!jt.has(i.type))throw new Error("This file type is not allowed.");if(i.size<=0||i.size>10*1024*1024)throw new Error("Attachments must be smaller than 10 MB.");const n=i.name.replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"attachment",d=typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():`${Date.now()}-${Math.random().toString(16).slice(2)}`,o=`${s}/${d}-${n}`,y=await u.storage.from("support-attachments").upload(o,i,{contentType:i.type,upsert:!1});if(y.error)throw y.error;const{data:m,error:P}=await u.rpc("add_support_attachment",{p_post_id:s,p_storage_path:o,p_file_name:n,p_mime_type:i.type,p_size_bytes:i.size});if(P)throw await u.storage.from("support-attachments").remove([o]),P;const j=Array.isArray(m)?m[0]?.attachment_id:m?.attachment_id;if(!j)throw new Error("Attachment metadata was not created.");return String(j)}async function _t(s,i,n,d){const{error:o}=await u.rpc("update_support_post",{p_post_id:s,p_title:i,p_body:n,p_visibility:d});if(o)throw o}async function gt(s,i){const{error:n}=await u.rpc("add_support_comment",{p_post_id:s,p_body:i});if(n)throw n}async function wt(s){const{data:i,error:n}=await u.rpc("toggle_support_vote",{p_post_id:s});if(n)throw n;const d=Array.isArray(i)?i[0]:i;return{voted:!!d?.voted,totalVotes:Number(d?.total_votes||0)}}async function St(s,i){const{error:n}=await u.rpc("change_support_post_status",{p_post_id:s,p_target_status:i});if(n)throw n}async function Nt(s){const{error:i}=await u.rpc("set_support_post_hidden",{p_post_id:s,p_hidden:!0});if(i)throw i}async function Pt(s,i){const{error:n}=await u.rpc("set_support_post_locked",{p_post_id:s,p_locked:i});if(n)throw n}async function kt(s,i){const{error:n}=await u.rpc("set_support_post_pinned",{p_post_id:s,p_pinned:i});if(n)throw n}async function Ct(s,i){const{error:n}=await u.rpc("mark_support_duplicate",{p_post_id:s,p_duplicate_of_post_id:i});if(n)throw n}async function At(s,i){const{error:n}=await u.rpc("accept_support_answer",{p_post_id:s,p_comment_id:i});if(n)throw n}async function qt(s,i=!0){const{error:n}=await u.rpc("hide_support_comment",{p_comment_id:s,p_hidden:i});if(n)throw n}const ae=[{id:"question",label:"Questions",shortLabel:"Question"},{id:"issue",label:"Issues",shortLabel:"Issue"},{id:"feature",label:"Feature Requests",shortLabel:"Feature"},{id:"announcement",label:"Announcements",shortLabel:"Announcement"}],zt=[{id:"all",label:"All statuses"},{id:"needs-response",label:"Needs response"},{id:"open",label:"Open"},{id:"needs-info",label:"Needs more information"},{id:"in-progress",label:"In progress"},{id:"planned",label:"Planned"},{id:"released",label:"Released"},{id:"closed",label:"Closed"}],Et={question:["open","answered","resolved","closed"],issue:["open","needs-info","confirmed","in-progress","fixed","closed"],feature:["under-review","planned","in-progress","released","declined","closed"],announcement:["published","archived"]},Tt={type:"all",product:"",status:"all",visibility:"all",sort:"recent",query:""};function te(){if(typeof window>"u")return Tt;const s=new URLSearchParams(window.location.search),i=window.location.pathname.match(/^\/support\/(questions|issues|features|announcements)$/)?.[1],n=s.get("type")||i||"",d=n==="questions"||n==="question"?"question":n==="issues"||n==="issue"?"issue":n==="features"||n==="feature"?"feature":n==="announcements"||n==="announcement"?"announcement":"all",o=s.get("visibility"),y=s.get("sort");return{type:d,product:s.get("product")||"",status:s.get("status")||"all",visibility:o==="public"||o==="private"?o:"all",sort:y==="votes"||y==="newest"?y:"recent",query:s.get("q")||""}}function Dt(s){return s==="all"?"":s==="question"?"questions":s==="issue"?"issues":s==="feature"?"features":"announcements"}function It(s,i){const n={...s,...i},d=new URLSearchParams;n.product&&d.set("product",n.product),n.status!=="all"&&d.set("status",n.status),n.visibility!=="all"&&d.set("visibility",n.visibility),n.sort!=="recent"&&d.set("sort",n.sort),n.query&&d.set("q",n.query);const o=Dt(n.type),y=d.toString();return`/support${o?`/${o}`:""}${y?`?${y}`:""}`}function Q(s){const i=new Date(s);return Number.isFinite(i.getTime())?i.toLocaleString(void 0,{dateStyle:"medium",timeStyle:"short"}):s}function se(s){return s.replaceAll("-"," ").replace(/\b\w/g,i=>i.toUpperCase())}function we(s){return s==="question"?it:s==="issue"?nt:s==="feature"?rt:ot}function Se(s){return ae.find(i=>i.id===s)?.shortLabel||s}function b(s){const i=dt(s);return/relation .* does not exist|function .* does not exist|schema cache/i.test(i)?"Support Board database is not installed yet. Apply the latest Supabase migration first.":/not-authenticated|jwt/i.test(i)?"Sign in again to use Support.":/product-access-denied|product-not-found/i.test(i)?"You do not have access to this product.":i}function Ht({session:s,currentProductKey:i="livedesk",appVersion:n="",onSignIn:d}){const[o,y]=c.useState(()=>te()),[m,P]=c.useState(null),[j,z]=c.useState([]),[L,S]=c.useState([]),[k,x]=c.useState(""),[R,U]=c.useState([]),[$,ie]=c.useState([]),[M,W]=c.useState([]),[ne,re]=c.useState(()=>new Set),[Z,J]=c.useState(!0),[v,f]=c.useState(""),[oe,p]=c.useState(""),[Ne,B]=c.useState(!1),[Pe,F]=c.useState(!1),[O,ce]=c.useState(""),[le,K]=c.useState(()=>te().query),[ke,de]=c.useState(!1),[Ce,Ae]=c.useState(!1),[qe,ze]=c.useState(""),[pe,Ee]=c.useState(""),[Te,De]=c.useState("free"),[Ie,Ve]=c.useState(""),[ue,Le]=c.useState(""),[Re,Ue]=c.useState("admin"),[D,he]=c.useState(""),[me,Vt]=c.useState(""),[H,fe]=c.useState([]),[h,A]=c.useState({productId:"",postType:"question",title:"",body:"",visibility:"public",includeEnvironment:!0,files:[]}),N=c.useCallback(t=>{const r={...o,...t};y(r),typeof window<"u"&&window.history.pushState({},"",It(o,t))},[o]);c.useEffect(()=>{const t=()=>y(te());return window.addEventListener("popstate",t),()=>window.removeEventListener("popstate",t)},[]);const _=c.useCallback(async()=>{const t=await ht(o.query);return S(t),s?.user.id&&re(await yt(s.user.id)),t},[o.query,s?.user.id]),Y=c.useCallback(async()=>{if(!s?.user.id){P(null),z([]),S([]),x(""),W([]),J(!1);return}J(!0),p("");try{const t=await ut(s.user.id,i);P(t.access),z(t.products),await _(),W(await ft())}catch(t){p(b(t))}finally{J(!1)}},[i,_,s?.user.id]);c.useEffect(()=>{Y()},[Y]);const g=c.useMemo(()=>{if(!m)return[];const t=j.find(r=>r.product_key===i);return t?m.canViewAllProducts||m.accessibleProductIds.includes(t.id)?[t]:[]:[]},[m,i,j]),I=g[0]?.id||"",q=c.useMemo(()=>{const t=new Map(j.map(l=>[l.id,l.product_key]));return[...L.filter(l=>o.type!=="all"&&l.post_type!==o.type||!I||l.product_id!==I||o.status==="needs-response"&&!["open","needs-info"].includes(l.status)||o.status!=="all"&&o.status!=="needs-response"&&l.status!==o.status||o.visibility!=="all"&&l.visibility!==o.visibility?!1:t.has(l.product_id))].sort((l,w)=>o.sort==="votes"?w.vote_count-l.vote_count||w.updated_at.localeCompare(l.updated_at):o.sort==="newest"?w.created_at.localeCompare(l.created_at):Number(w.is_pinned)-Number(l.is_pinned)||w.updated_at.localeCompare(l.updated_at))},[L,j,o.sort,o.status,o.type,o.visibility,I]),a=q.find(t=>t.id===k)||q[0]||null,E=!!(a&&m&&(m.canViewAllProducts||m.managedProductIds.includes(a.product_id))),$e=!!(a&&s?.user.id===a.author_id)||E;c.useEffect(()=>{if(!a){x(""),U([]),F(!1);return}a.id!==k&&x(a.id)},[a,k]),c.useEffect(()=>{let t=!0;return k?(ge(k).then(r=>{t&&U(r)}).catch(r=>{t&&p(b(r))}),mt(k).then(r=>{t&&ie(r)}).catch(r=>{t&&p(b(r))}),()=>{t=!1}):(U([]),ie([]),()=>{t=!1})},[k]),c.useEffect(()=>{!h.productId&&g[0]&&A(t=>({...t,productId:I||g[0].id}))},[g,h.productId,I]),c.useEffect(()=>{K(o.query)},[o.query]),c.useEffect(()=>{!pe&&g[0]&&Ee(g[0].id),!ue&&g[0]&&Le(g[0].id)},[g,pe,ue]);const C=t=>{a&&S(r=>r.map(l=>l.id===a.id?{...l,...t}:l))},Me=async t=>{if(t.preventDefault(),!(!s||!h.productId)){f("create"),p("");try{const r=await bt({productId:h.productId,postType:h.postType,title:h.title,body:h.body,visibility:h.postType==="announcement"?"public":h.visibility,appVersion:n,includeEnvironment:h.postType==="issue"&&h.includeEnvironment});for(const w of H)await vt(r,w);const l=await _();B(!1),fe([]),A(w=>({...w,title:"",body:"",files:[]})),x(r),l.some(w=>w.id===r)||await Y()}catch(r){p(b(r))}finally{f("")}}},Be=async t=>{if(t.preventDefault(),!!a){f("edit"),p("");try{await _t(a.id,a.title,a.body,a.visibility),F(!1),await _()}catch(r){p(b(r))}finally{f("")}}},Fe=async t=>{if(t.preventDefault(),!(!a||!O.trim())){f("comment"),p("");try{await gt(a.id,O),ce(""),U(await ge(a.id)),await _()}catch(r){p(b(r))}finally{f("")}}},Oe=async()=>{if(!(!a||a.post_type!=="feature")){f("vote"),p("");try{const t=await wt(a.id);re(r=>{const l=new Set(r);return t.voted?l.add(a.id):l.delete(a.id),l}),C({vote_count:t.totalVotes})}catch(t){p(b(t))}finally{f("")}}},He=async t=>{if(a){f("status"),p("");try{await St(a.id,t),C({status:t}),await _()}catch(r){p(b(r))}finally{f("")}}},Ye=async()=>{if(!(!a||!window.confirm("Hide this Support post from the board?"))){f("hide"),p("");try{await Nt(a.id),x(""),await _()}catch(t){p(b(t))}finally{f("")}}},Ge=async()=>{if(a){f("lock"),p("");try{await Pt(a.id,!a.is_locked),C({is_locked:!a.is_locked}),await _()}catch(t){p(b(t))}finally{f("")}}},Qe=async()=>{if(a){f("pin"),p("");try{await kt(a.id,!a.is_pinned),C({is_pinned:!a.is_pinned}),await _()}catch(t){p(b(t))}finally{f("")}}},We=async t=>{if(a){f(`accept-${t}`),p("");try{await At(a.id,t),C({accepted_comment_id:t,status:a.post_type==="question"?"answered":a.status}),await _()}catch(r){p(b(r))}finally{f("")}}},Ze=async()=>{if(!(!a||!D||D===a.id)){f("duplicate"),p("");try{await Ct(a.id,D),x(""),he(""),await _()}catch(t){p(b(t))}finally{f("")}}},Je=async t=>{if(!t.read_at)try{await xt(t.id),W(r=>r.map(l=>l.id===t.id?{...l,read_at:new Date().toISOString()}:l))}catch(r){p(b(r))}t.post_id&&x(t.post_id),de(!1)};return s?Z&&!m?e.jsxs("section",{className:"support-page support-loading",children:[e.jsx(xe,{className:"support-spin",size:23})," Loading Support Board..."]}):e.jsxs("section",{className:"support-page",children:[e.jsx("header",{className:"support-page-header support-page-actions-only",children:e.jsxs("div",{className:"support-header-actions",children:[e.jsxs("div",{className:"support-notification-wrap",children:[e.jsxs("button",{className:"support-secondary-button",type:"button",onClick:()=>de(t=>!t),title:"Notifications",children:[e.jsx(Ke,{size:16})," ",M.filter(t=>!t.read_at).length>0&&e.jsx("b",{children:M.filter(t=>!t.read_at).length})]}),ke&&e.jsxs("div",{className:"support-notification-popover",children:[e.jsx("strong",{children:"Notifications"}),M.length===0?e.jsx("span",{className:"support-muted",children:"No notifications yet."}):M.map(t=>e.jsxs("button",{type:"button",className:t.read_at?"":"unread",onClick:()=>{Je(t)},children:[e.jsx("b",{children:t.title}),e.jsx("span",{children:t.body}),e.jsx("small",{children:Q(t.created_at)})]},t.id))]})]}),m?.canViewAllProducts&&e.jsxs("button",{className:"support-secondary-button",type:"button",onClick:()=>Ae(t=>!t),children:[e.jsx(T,{size:16})," Admin"]}),e.jsxs("button",{className:"support-secondary-button",type:"button",onClick:()=>{Y()},disabled:Z,children:[e.jsx(xe,{size:16,className:Z?"support-spin":""})," Refresh"]}),e.jsxs("button",{className:"support-primary-button",type:"button",onClick:()=>B(!0),disabled:g.length===0,children:[e.jsx(ye,{size:17})," New request"]})]})}),oe&&e.jsxs("div",{className:"support-error",role:"alert",children:[e.jsx(G,{size:17})," ",e.jsx("span",{children:oe}),e.jsx("button",{type:"button",onClick:()=>p(""),"aria-label":"Dismiss error",children:e.jsx(G,{size:15})})]}),Ne&&e.jsxs("form",{className:"support-composer",onSubmit:t=>{Me(t)},children:[e.jsxs("div",{className:"support-section-heading",children:[e.jsxs("div",{children:[e.jsx("span",{children:"New Support request"}),e.jsx("strong",{children:"Describe one actionable problem or idea."})]}),e.jsx("button",{className:"support-icon-button",type:"button",onClick:()=>B(!1),"aria-label":"Close composer",children:e.jsx(G,{size:18})})]}),e.jsxs("div",{className:"support-form-grid",children:[e.jsxs("label",{children:[e.jsx("span",{children:"Type"}),e.jsx("select",{value:h.postType,onChange:t=>A(r=>({...r,postType:t.target.value})),children:ae.filter(t=>t.id!=="announcement"||m?.canCreateAnnouncements).map(t=>e.jsx("option",{value:t.id,children:t.label},t.id))})]}),e.jsxs("label",{className:"support-form-wide",children:[e.jsx("span",{children:"Title"}),e.jsx("input",{required:!0,minLength:3,maxLength:180,value:h.title,onChange:t=>A(r=>({...r,title:t.target.value})),placeholder:"A short, searchable summary"})]}),e.jsxs("label",{className:"support-form-wide",children:[e.jsx("span",{children:h.postType==="issue"?"What happened?":h.postType==="feature"?"Describe the desired behavior":h.postType==="announcement"?"Announcement":"Question"}),e.jsx("textarea",{required:!0,value:h.body,onChange:t=>A(r=>({...r,body:t.target.value})),placeholder:"Include the context another person needs to respond.",rows:6})]}),e.jsxs("label",{children:[e.jsx("span",{children:"Visibility"}),e.jsxs("select",{value:h.visibility,disabled:h.postType==="announcement",onChange:t=>A(r=>({...r,visibility:t.target.value})),children:[e.jsx("option",{value:"public",children:"Public"}),e.jsx("option",{value:"private",children:"Private"})]})]}),h.postType==="issue"&&e.jsxs("label",{className:"support-checkbox",children:[e.jsx("input",{type:"checkbox",checked:h.includeEnvironment,onChange:t=>A(r=>({...r,includeEnvironment:t.target.checked}))}),e.jsx("span",{children:"Attach safe browser/runtime details"})]}),e.jsxs("label",{className:"support-form-wide",children:[e.jsx("span",{children:"Attachments"}),e.jsx("input",{type:"file",multiple:!0,accept:"image/png,image/jpeg,image/webp,text/plain,text/markdown,application/json,application/pdf",onChange:t=>fe(Array.from(t.target.files||[]).slice(0,5))}),e.jsx("small",{className:"support-muted",children:"Up to 5 files, 10 MB each. Images, text, JSON, Markdown, and PDF."})]})]}),e.jsxs("div",{className:"support-composer-footer",children:[e.jsx("span",{children:H.length>0?`${H.length} attachment${H.length===1?"":"s"} selected.`:"Private posts are visible only to you and VuvoDesk Support."}),e.jsxs("button",{className:"support-primary-button",type:"submit",disabled:v==="create",children:[e.jsx(be,{size:16})," ",v==="create"?"Submitting...":"Submit request"]})]})]}),e.jsxs("div",{className:"support-tabs",role:"tablist","aria-label":"Support post type",children:[e.jsx("button",{className:o.type==="all"?"active":"",type:"button",onClick:()=>N({type:"all"}),children:"All"}),ae.map(t=>{const r=we(t.id);return e.jsxs("button",{className:o.type===t.id?"active":"",type:"button",onClick:()=>N({type:t.id}),children:[e.jsx(r,{size:15})," ",t.label]},t.id)})]}),Ce&&m?.canViewAllProducts&&e.jsxs("section",{className:"support-admin-panel",children:[e.jsxs("div",{className:"support-section-heading",children:[e.jsxs("div",{children:[e.jsx("span",{children:"VuvoDesk owner controls"}),e.jsx("strong",{children:"Manage VuvoDesk support access and staff roles by email."})]}),e.jsx(T,{size:19})]}),e.jsxs("div",{className:"support-admin-grid",children:[e.jsxs("form",{onSubmit:t=>{},children:[e.jsx("strong",{children:"Grant VuvoDesk access"}),e.jsx("input",{type:"email",required:!0,placeholder:"User email",value:qe,onChange:t=>ze(t.target.value)}),e.jsxs("select",{value:Te,onChange:t=>De(t.target.value),children:[e.jsx("option",{value:"free",children:"Free"}),e.jsx("option",{value:"user",children:"User"}),e.jsx("option",{value:"paid",children:"Paid"}),e.jsx("option",{value:"beta",children:"Beta"}),e.jsx("option",{value:"staff",children:"Staff"})]}),e.jsxs("button",{className:"support-secondary-button",type:"submit",disabled:me==="access",children:[e.jsx(ee,{size:15})," Grant access"]})]}),e.jsxs("form",{onSubmit:t=>{},children:[e.jsx("strong",{children:"Assign VuvoDesk staff"}),e.jsx("input",{type:"email",required:!0,placeholder:"Staff email",value:Ie,onChange:t=>Ve(t.target.value)}),e.jsxs("select",{value:Re,onChange:t=>Ue(t.target.value),children:[e.jsx("option",{value:"admin",children:"Admin"}),e.jsx("option",{value:"support",children:"Support"}),e.jsx("option",{value:"moderator",children:"Moderator"})]}),e.jsxs("button",{className:"support-secondary-button",type:"submit",disabled:me==="product-admin",children:[e.jsx(T,{size:15})," Assign staff"]})]})]})]}),e.jsxs("form",{className:"support-search-bar",onSubmit:t=>{t.preventDefault(),N({query:le.trim()})},children:[e.jsxs("label",{children:[e.jsx("span",{children:"Search Support"}),e.jsx("input",{value:le,onChange:t=>K(t.target.value),placeholder:"Search titles and request details"})]}),e.jsxs("button",{className:"support-secondary-button",type:"submit",children:[e.jsx(je,{size:15})," Search"]}),o.query&&e.jsx("button",{className:"support-icon-button",type:"button",onClick:()=>{K(""),N({query:""})},"aria-label":"Clear search",children:e.jsx(G,{size:16})})]}),e.jsxs("div",{className:"support-filter-bar",children:[e.jsxs("div",{className:"support-filter-title",children:[e.jsx(je,{size:16}),e.jsx("span",{children:"Filter"})]}),e.jsxs("label",{children:[e.jsx("span",{children:"Status"}),e.jsx("select",{value:o.status,onChange:t=>N({status:t.target.value}),children:zt.map(t=>e.jsx("option",{value:t.id,children:t.label},t.id))})]}),e.jsxs("label",{children:[e.jsx("span",{children:"Visibility"}),e.jsxs("select",{value:o.visibility,onChange:t=>N({visibility:t.target.value}),children:[e.jsx("option",{value:"all",children:"All visibility"}),e.jsx("option",{value:"public",children:"Public"}),e.jsx("option",{value:"private",children:"Private"})]})]}),e.jsxs("label",{children:[e.jsx("span",{children:"Sort"}),e.jsxs("select",{value:o.sort,onChange:t=>N({sort:t.target.value}),children:[e.jsx("option",{value:"recent",children:"Recently updated"}),e.jsx("option",{value:"newest",children:"Newest"}),e.jsx("option",{value:"votes",children:"Most votes"})]})]})]}),m?.canViewAllProducts&&e.jsxs("div",{className:"support-admin-shortcuts",children:[e.jsxs("span",{children:[e.jsx(T,{size:15})," VuvoDesk owner"]}),e.jsx("button",{type:"button",onClick:()=>N({status:"needs-response"}),children:"Needs response"}),e.jsx("button",{type:"button",onClick:()=>N({visibility:"private"}),children:"Private requests"}),e.jsx("button",{type:"button",onClick:()=>N({type:"feature",status:"all",sort:"votes"}),children:"High-vote features"})]}),e.jsxs("div",{className:"support-board-layout",children:[e.jsxs("section",{className:"support-post-list","aria-label":"Support posts",children:[e.jsxs("div",{className:"support-list-heading",children:[e.jsxs("span",{children:[q.length," request",q.length===1?"":"s"]}),e.jsx("small",{children:"VuvoDesk"})]}),q.length===0?e.jsxs("div",{className:"support-list-empty",children:[e.jsx(X,{size:25}),e.jsx("strong",{children:"No posts match these filters."}),e.jsx("span",{children:"Start with a focused question, issue report, or feature request."}),g.length>0&&e.jsxs("button",{className:"support-secondary-button",type:"button",onClick:()=>B(!0),children:[e.jsx(ye,{size:16})," Create the first request"]})]}):q.map(t=>{const r=we(t.post_type);return e.jsxs("button",{type:"button",className:`support-post-row ${t.id===a?.id?"active":""}`,onClick:()=>{x(t.id),F(!1)},children:[e.jsx("span",{className:"support-post-row-icon",children:e.jsx(r,{size:17})}),e.jsxs("span",{className:"support-post-row-copy",children:[e.jsxs("span",{className:"support-post-row-meta",children:[e.jsx("em",{children:Se(t.post_type)}),t.visibility==="private"&&e.jsx(V,{size:13})]}),e.jsx("strong",{children:t.title}),e.jsxs("small",{children:[se(t.status)," · ",Q(t.updated_at)," · ",t.comment_count," comments"]})]}),t.post_type==="feature"&&e.jsxs("span",{className:"support-vote-count",children:[e.jsx(Xe,{size:14})," ",t.vote_count]})]},t.id)})]}),e.jsx("section",{className:"support-post-detail","aria-label":"Support post detail",children:a?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"support-detail-head",children:[e.jsxs("div",{className:"support-detail-badges",children:[e.jsx("span",{className:"support-type-badge",children:Se(a.post_type)}),e.jsx("span",{className:`support-status-badge status-${a.status}`,children:se(a.status)}),a.visibility==="private"&&e.jsxs("span",{className:"support-private-badge",children:[e.jsx(V,{size:13})," Private"]})]}),e.jsxs("div",{className:"support-detail-actions",children:[$e&&e.jsx("button",{className:"support-icon-button",type:"button",onClick:()=>F(t=>!t),title:"Edit post",children:e.jsx(et,{size:16})}),E&&e.jsxs(e.Fragment,{children:[e.jsx("button",{className:"support-icon-button",type:"button",onClick:()=>{Qe()},disabled:v==="pin",title:a.is_pinned?"Unpin post":"Pin post",children:e.jsx(ve,{size:16})}),e.jsx("button",{className:"support-icon-button",type:"button",onClick:()=>{Ge()},disabled:v==="lock",title:a.is_locked?"Unlock post":"Lock post",children:e.jsx(V,{size:16})}),e.jsx("button",{className:"support-icon-button danger",type:"button",onClick:()=>{Ye()},disabled:v==="hide",title:"Hide post",children:e.jsx(_e,{size:16})})]})]})]}),Pe?e.jsxs("form",{className:"support-edit-form",onSubmit:t=>{Be(t)},children:[e.jsx("input",{value:a.title,onChange:t=>C({title:t.target.value}),minLength:3,maxLength:180,required:!0}),e.jsx("textarea",{value:a.body,onChange:t=>C({body:t.target.value}),rows:9,required:!0}),e.jsxs("div",{className:"support-edit-actions",children:[e.jsxs("select",{value:a.visibility,onChange:t=>C({visibility:t.target.value}),children:[e.jsx("option",{value:"public",children:"Public"}),e.jsx("option",{value:"private",children:"Private"})]}),e.jsxs("button",{className:"support-primary-button",type:"submit",disabled:v==="edit",children:[e.jsx(ee,{size:16})," Save changes"]})]})]}):e.jsxs(e.Fragment,{children:[e.jsx("h3",{children:a.title}),e.jsx("div",{className:"support-detail-body",children:a.body.split(`
|
|
1
|
+
import{j as e}from"./pwa-startup-C8kDd3Vd.js";import{r as c,z as X,S as T,R as xe,a1 as Ke,a2 as ye,X as G,a3 as be,y as ee,a4 as je,L as V,a5 as Xe,a6 as et,a7 as ve,a8 as _e,a9 as tt,D as st,m as at,aa as it,ab as nt,ac as rt,ad as ot}from"./icons-BwhnWKHR.js";import{s as u}from"./HubApp-BoHzIvar.js";import"./pwa-bootstrap-ljOQTt2e.js";import"./public-site-routing-pddZbLCj.js";import"./MonitorStackIcon-BLNbbRNY.js";import"./supabase-C7qjtLN3.js";import"./frame-lifecycle-CNz8ou2A.js";const ct=new Set(["browserLanguage","platform","online","viewport","timezone","screen"]),lt={id:"browser-safe-v1",collect(){if(typeof navigator>"u")return{};const s={browserLanguage:navigator.language||"",platform:navigator.platform||"",online:navigator.onLine,timezone:typeof Intl>"u"?"":Intl.DateTimeFormat().resolvedOptions().timeZone||"",viewport:typeof window>"u"?void 0:{width:window.innerWidth,height:window.innerHeight},screen:typeof window>"u"?void 0:{width:window.screen.width,height:window.screen.height}};return Object.fromEntries(Object.entries(s).filter(([i,n])=>ct.has(i)&&n!==void 0))}};function dt(s,i="Support request failed."){if(s&&typeof s=="object"&&"message"in s){const n=String(s.message||"").trim();if(n)return n.replace(/^.*Support request failed:\s*/i,"")}return s instanceof Error?s.message:i}function pt(s=lt){return s.collect()}async function ut(s,i="livedesk"){const{data:n,error:d}=await u.from("app_admins").select("role").eq("user_id",s).limit(1);if(d)throw d;const o=n?.[0]?.role||"user";if(o!=="owner"){const{error:x}=await u.rpc("register_product_access",{p_product_key:i,p_access_type:"free"});if(x)throw x}const[y,m,P]=await Promise.all([u.from("products").select("id, product_key, name, description, sort_order").order("sort_order"),u.from("product_admins").select("product_id, role").eq("user_id",s),u.from("user_products").select("product_id").eq("user_id",s).eq("is_active",!0)]);if(y.error)throw y.error;if(m.error)throw m.error;if(P.error)throw P.error;const j=y.data||[],z=(m.data||[]).map(x=>String(x.product_id)),L=(P.data||[]).map(x=>String(x.product_id)),S=o==="owner",k=S?j.map(x=>x.id):[...new Set([...z,...L])];return{products:j,access:{userId:s,globalRole:o,accessibleProductIds:k,managedProductIds:S?j.map(x=>x.id):z,canViewAllProducts:S,canViewAllPrivatePosts:S,canManageAllProducts:S,canCreateAnnouncements:S||z.length>0}}}async function ht(s=""){const{data:i,error:n}=await u.rpc("search_support_posts",{p_query:s.trim()||null,p_limit:250});if(n)throw n;return i||[]}async function mt(s){const{data:i,error:n}=await u.from("support_attachments").select("*").eq("post_id",s).order("created_at");if(n)throw n;const d=i||[];return Promise.all(d.map(async o=>{const y=await u.storage.from("support-attachments").createSignedUrl(o.storage_path,3600);return{...o,signed_url:y.data?.signedUrl||void 0}}))}async function ft(){const{data:s,error:i}=await u.from("support_notifications").select("*").order("created_at",{ascending:!1}).limit(30);if(i)throw i;return s||[]}async function xt(s){const{error:i}=await u.rpc("mark_support_notification_read",{p_notification_id:s});if(i)throw i}async function ge(s){const{data:i,error:n}=await u.from("support_comments").select("*").eq("post_id",s).order("created_at");if(n)throw n;return i||[]}async function yt(s){const{data:i,error:n}=await u.from("support_votes").select("post_id").eq("user_id",s);if(n)throw n;return new Set((i||[]).map(d=>String(d.post_id)))}async function bt(s){const{data:i,error:n}=await u.rpc("create_support_post",{p_product_id:s.productId,p_post_type:s.postType,p_title:s.title,p_body:s.body,p_visibility:s.visibility,p_app_version:s.appVersion||null,p_platform:typeof navigator>"u"?null:navigator.platform||null,p_os_version:typeof navigator>"u"?null:navigator.platform||null,p_environment:s.includeEnvironment?pt():{}});if(n)throw n;const d=Array.isArray(i)?i[0]?.post_id:i?.post_id;if(!d)throw new Error("Support post was not created.");return String(d)}const jt=new Set(["image/png","image/jpeg","image/webp","text/plain","text/markdown","application/json","application/pdf"]);async function vt(s,i){if(!jt.has(i.type))throw new Error("This file type is not allowed.");if(i.size<=0||i.size>10*1024*1024)throw new Error("Attachments must be smaller than 10 MB.");const n=i.name.replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"attachment",d=typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():`${Date.now()}-${Math.random().toString(16).slice(2)}`,o=`${s}/${d}-${n}`,y=await u.storage.from("support-attachments").upload(o,i,{contentType:i.type,upsert:!1});if(y.error)throw y.error;const{data:m,error:P}=await u.rpc("add_support_attachment",{p_post_id:s,p_storage_path:o,p_file_name:n,p_mime_type:i.type,p_size_bytes:i.size});if(P)throw await u.storage.from("support-attachments").remove([o]),P;const j=Array.isArray(m)?m[0]?.attachment_id:m?.attachment_id;if(!j)throw new Error("Attachment metadata was not created.");return String(j)}async function _t(s,i,n,d){const{error:o}=await u.rpc("update_support_post",{p_post_id:s,p_title:i,p_body:n,p_visibility:d});if(o)throw o}async function gt(s,i){const{error:n}=await u.rpc("add_support_comment",{p_post_id:s,p_body:i});if(n)throw n}async function wt(s){const{data:i,error:n}=await u.rpc("toggle_support_vote",{p_post_id:s});if(n)throw n;const d=Array.isArray(i)?i[0]:i;return{voted:!!d?.voted,totalVotes:Number(d?.total_votes||0)}}async function St(s,i){const{error:n}=await u.rpc("change_support_post_status",{p_post_id:s,p_target_status:i});if(n)throw n}async function Nt(s){const{error:i}=await u.rpc("set_support_post_hidden",{p_post_id:s,p_hidden:!0});if(i)throw i}async function Pt(s,i){const{error:n}=await u.rpc("set_support_post_locked",{p_post_id:s,p_locked:i});if(n)throw n}async function kt(s,i){const{error:n}=await u.rpc("set_support_post_pinned",{p_post_id:s,p_pinned:i});if(n)throw n}async function Ct(s,i){const{error:n}=await u.rpc("mark_support_duplicate",{p_post_id:s,p_duplicate_of_post_id:i});if(n)throw n}async function At(s,i){const{error:n}=await u.rpc("accept_support_answer",{p_post_id:s,p_comment_id:i});if(n)throw n}async function qt(s,i=!0){const{error:n}=await u.rpc("hide_support_comment",{p_comment_id:s,p_hidden:i});if(n)throw n}const ae=[{id:"question",label:"Questions",shortLabel:"Question"},{id:"issue",label:"Issues",shortLabel:"Issue"},{id:"feature",label:"Feature Requests",shortLabel:"Feature"},{id:"announcement",label:"Announcements",shortLabel:"Announcement"}],zt=[{id:"all",label:"All statuses"},{id:"needs-response",label:"Needs response"},{id:"open",label:"Open"},{id:"needs-info",label:"Needs more information"},{id:"in-progress",label:"In progress"},{id:"planned",label:"Planned"},{id:"released",label:"Released"},{id:"closed",label:"Closed"}],Et={question:["open","answered","resolved","closed"],issue:["open","needs-info","confirmed","in-progress","fixed","closed"],feature:["under-review","planned","in-progress","released","declined","closed"],announcement:["published","archived"]},Tt={type:"all",product:"",status:"all",visibility:"all",sort:"recent",query:""};function te(){if(typeof window>"u")return Tt;const s=new URLSearchParams(window.location.search),i=window.location.pathname.match(/^\/support\/(questions|issues|features|announcements)$/)?.[1],n=s.get("type")||i||"",d=n==="questions"||n==="question"?"question":n==="issues"||n==="issue"?"issue":n==="features"||n==="feature"?"feature":n==="announcements"||n==="announcement"?"announcement":"all",o=s.get("visibility"),y=s.get("sort");return{type:d,product:s.get("product")||"",status:s.get("status")||"all",visibility:o==="public"||o==="private"?o:"all",sort:y==="votes"||y==="newest"?y:"recent",query:s.get("q")||""}}function Dt(s){return s==="all"?"":s==="question"?"questions":s==="issue"?"issues":s==="feature"?"features":"announcements"}function It(s,i){const n={...s,...i},d=new URLSearchParams;n.product&&d.set("product",n.product),n.status!=="all"&&d.set("status",n.status),n.visibility!=="all"&&d.set("visibility",n.visibility),n.sort!=="recent"&&d.set("sort",n.sort),n.query&&d.set("q",n.query);const o=Dt(n.type),y=d.toString();return`/support${o?`/${o}`:""}${y?`?${y}`:""}`}function Q(s){const i=new Date(s);return Number.isFinite(i.getTime())?i.toLocaleString(void 0,{dateStyle:"medium",timeStyle:"short"}):s}function se(s){return s.replaceAll("-"," ").replace(/\b\w/g,i=>i.toUpperCase())}function we(s){return s==="question"?it:s==="issue"?nt:s==="feature"?rt:ot}function Se(s){return ae.find(i=>i.id===s)?.shortLabel||s}function b(s){const i=dt(s);return/relation .* does not exist|function .* does not exist|schema cache/i.test(i)?"Support Board database is not installed yet. Apply the latest Supabase migration first.":/not-authenticated|jwt/i.test(i)?"Sign in again to use Support.":/product-access-denied|product-not-found/i.test(i)?"You do not have access to this product.":i}function Ht({session:s,currentProductKey:i="livedesk",appVersion:n="",onSignIn:d}){const[o,y]=c.useState(()=>te()),[m,P]=c.useState(null),[j,z]=c.useState([]),[L,S]=c.useState([]),[k,x]=c.useState(""),[R,U]=c.useState([]),[$,ie]=c.useState([]),[M,W]=c.useState([]),[ne,re]=c.useState(()=>new Set),[Z,J]=c.useState(!0),[v,f]=c.useState(""),[oe,p]=c.useState(""),[Ne,B]=c.useState(!1),[Pe,F]=c.useState(!1),[O,ce]=c.useState(""),[le,K]=c.useState(()=>te().query),[ke,de]=c.useState(!1),[Ce,Ae]=c.useState(!1),[qe,ze]=c.useState(""),[pe,Ee]=c.useState(""),[Te,De]=c.useState("free"),[Ie,Ve]=c.useState(""),[ue,Le]=c.useState(""),[Re,Ue]=c.useState("admin"),[D,he]=c.useState(""),[me,Vt]=c.useState(""),[H,fe]=c.useState([]),[h,A]=c.useState({productId:"",postType:"question",title:"",body:"",visibility:"public",includeEnvironment:!0,files:[]}),N=c.useCallback(t=>{const r={...o,...t};y(r),typeof window<"u"&&window.history.pushState({},"",It(o,t))},[o]);c.useEffect(()=>{const t=()=>y(te());return window.addEventListener("popstate",t),()=>window.removeEventListener("popstate",t)},[]);const _=c.useCallback(async()=>{const t=await ht(o.query);return S(t),s?.user.id&&re(await yt(s.user.id)),t},[o.query,s?.user.id]),Y=c.useCallback(async()=>{if(!s?.user.id){P(null),z([]),S([]),x(""),W([]),J(!1);return}J(!0),p("");try{const t=await ut(s.user.id,i);P(t.access),z(t.products),await _(),W(await ft())}catch(t){p(b(t))}finally{J(!1)}},[i,_,s?.user.id]);c.useEffect(()=>{Y()},[Y]);const g=c.useMemo(()=>{if(!m)return[];const t=j.find(r=>r.product_key===i);return t?m.canViewAllProducts||m.accessibleProductIds.includes(t.id)?[t]:[]:[]},[m,i,j]),I=g[0]?.id||"",q=c.useMemo(()=>{const t=new Map(j.map(l=>[l.id,l.product_key]));return[...L.filter(l=>o.type!=="all"&&l.post_type!==o.type||!I||l.product_id!==I||o.status==="needs-response"&&!["open","needs-info"].includes(l.status)||o.status!=="all"&&o.status!=="needs-response"&&l.status!==o.status||o.visibility!=="all"&&l.visibility!==o.visibility?!1:t.has(l.product_id))].sort((l,w)=>o.sort==="votes"?w.vote_count-l.vote_count||w.updated_at.localeCompare(l.updated_at):o.sort==="newest"?w.created_at.localeCompare(l.created_at):Number(w.is_pinned)-Number(l.is_pinned)||w.updated_at.localeCompare(l.updated_at))},[L,j,o.sort,o.status,o.type,o.visibility,I]),a=q.find(t=>t.id===k)||q[0]||null,E=!!(a&&m&&(m.canViewAllProducts||m.managedProductIds.includes(a.product_id))),$e=!!(a&&s?.user.id===a.author_id)||E;c.useEffect(()=>{if(!a){x(""),U([]),F(!1);return}a.id!==k&&x(a.id)},[a,k]),c.useEffect(()=>{let t=!0;return k?(ge(k).then(r=>{t&&U(r)}).catch(r=>{t&&p(b(r))}),mt(k).then(r=>{t&&ie(r)}).catch(r=>{t&&p(b(r))}),()=>{t=!1}):(U([]),ie([]),()=>{t=!1})},[k]),c.useEffect(()=>{!h.productId&&g[0]&&A(t=>({...t,productId:I||g[0].id}))},[g,h.productId,I]),c.useEffect(()=>{K(o.query)},[o.query]),c.useEffect(()=>{!pe&&g[0]&&Ee(g[0].id),!ue&&g[0]&&Le(g[0].id)},[g,pe,ue]);const C=t=>{a&&S(r=>r.map(l=>l.id===a.id?{...l,...t}:l))},Me=async t=>{if(t.preventDefault(),!(!s||!h.productId)){f("create"),p("");try{const r=await bt({productId:h.productId,postType:h.postType,title:h.title,body:h.body,visibility:h.postType==="announcement"?"public":h.visibility,appVersion:n,includeEnvironment:h.postType==="issue"&&h.includeEnvironment});for(const w of H)await vt(r,w);const l=await _();B(!1),fe([]),A(w=>({...w,title:"",body:"",files:[]})),x(r),l.some(w=>w.id===r)||await Y()}catch(r){p(b(r))}finally{f("")}}},Be=async t=>{if(t.preventDefault(),!!a){f("edit"),p("");try{await _t(a.id,a.title,a.body,a.visibility),F(!1),await _()}catch(r){p(b(r))}finally{f("")}}},Fe=async t=>{if(t.preventDefault(),!(!a||!O.trim())){f("comment"),p("");try{await gt(a.id,O),ce(""),U(await ge(a.id)),await _()}catch(r){p(b(r))}finally{f("")}}},Oe=async()=>{if(!(!a||a.post_type!=="feature")){f("vote"),p("");try{const t=await wt(a.id);re(r=>{const l=new Set(r);return t.voted?l.add(a.id):l.delete(a.id),l}),C({vote_count:t.totalVotes})}catch(t){p(b(t))}finally{f("")}}},He=async t=>{if(a){f("status"),p("");try{await St(a.id,t),C({status:t}),await _()}catch(r){p(b(r))}finally{f("")}}},Ye=async()=>{if(!(!a||!window.confirm("Hide this Support post from the board?"))){f("hide"),p("");try{await Nt(a.id),x(""),await _()}catch(t){p(b(t))}finally{f("")}}},Ge=async()=>{if(a){f("lock"),p("");try{await Pt(a.id,!a.is_locked),C({is_locked:!a.is_locked}),await _()}catch(t){p(b(t))}finally{f("")}}},Qe=async()=>{if(a){f("pin"),p("");try{await kt(a.id,!a.is_pinned),C({is_pinned:!a.is_pinned}),await _()}catch(t){p(b(t))}finally{f("")}}},We=async t=>{if(a){f(`accept-${t}`),p("");try{await At(a.id,t),C({accepted_comment_id:t,status:a.post_type==="question"?"answered":a.status}),await _()}catch(r){p(b(r))}finally{f("")}}},Ze=async()=>{if(!(!a||!D||D===a.id)){f("duplicate"),p("");try{await Ct(a.id,D),x(""),he(""),await _()}catch(t){p(b(t))}finally{f("")}}},Je=async t=>{if(!t.read_at)try{await xt(t.id),W(r=>r.map(l=>l.id===t.id?{...l,read_at:new Date().toISOString()}:l))}catch(r){p(b(r))}t.post_id&&x(t.post_id),de(!1)};return s?Z&&!m?e.jsxs("section",{className:"support-page support-loading",children:[e.jsx(xe,{className:"support-spin",size:23})," Loading Support Board..."]}):e.jsxs("section",{className:"support-page",children:[e.jsx("header",{className:"support-page-header support-page-actions-only",children:e.jsxs("div",{className:"support-header-actions",children:[e.jsxs("div",{className:"support-notification-wrap",children:[e.jsxs("button",{className:"support-secondary-button",type:"button",onClick:()=>de(t=>!t),title:"Notifications",children:[e.jsx(Ke,{size:16})," ",M.filter(t=>!t.read_at).length>0&&e.jsx("b",{children:M.filter(t=>!t.read_at).length})]}),ke&&e.jsxs("div",{className:"support-notification-popover",children:[e.jsx("strong",{children:"Notifications"}),M.length===0?e.jsx("span",{className:"support-muted",children:"No notifications yet."}):M.map(t=>e.jsxs("button",{type:"button",className:t.read_at?"":"unread",onClick:()=>{Je(t)},children:[e.jsx("b",{children:t.title}),e.jsx("span",{children:t.body}),e.jsx("small",{children:Q(t.created_at)})]},t.id))]})]}),m?.canViewAllProducts&&e.jsxs("button",{className:"support-secondary-button",type:"button",onClick:()=>Ae(t=>!t),children:[e.jsx(T,{size:16})," Admin"]}),e.jsxs("button",{className:"support-secondary-button",type:"button",onClick:()=>{Y()},disabled:Z,children:[e.jsx(xe,{size:16,className:Z?"support-spin":""})," Refresh"]}),e.jsxs("button",{className:"support-primary-button",type:"button",onClick:()=>B(!0),disabled:g.length===0,children:[e.jsx(ye,{size:17})," New request"]})]})}),oe&&e.jsxs("div",{className:"support-error",role:"alert",children:[e.jsx(G,{size:17})," ",e.jsx("span",{children:oe}),e.jsx("button",{type:"button",onClick:()=>p(""),"aria-label":"Dismiss error",children:e.jsx(G,{size:15})})]}),Ne&&e.jsxs("form",{className:"support-composer",onSubmit:t=>{Me(t)},children:[e.jsxs("div",{className:"support-section-heading",children:[e.jsxs("div",{children:[e.jsx("span",{children:"New Support request"}),e.jsx("strong",{children:"Describe one actionable problem or idea."})]}),e.jsx("button",{className:"support-icon-button",type:"button",onClick:()=>B(!1),"aria-label":"Close composer",children:e.jsx(G,{size:18})})]}),e.jsxs("div",{className:"support-form-grid",children:[e.jsxs("label",{children:[e.jsx("span",{children:"Type"}),e.jsx("select",{value:h.postType,onChange:t=>A(r=>({...r,postType:t.target.value})),children:ae.filter(t=>t.id!=="announcement"||m?.canCreateAnnouncements).map(t=>e.jsx("option",{value:t.id,children:t.label},t.id))})]}),e.jsxs("label",{className:"support-form-wide",children:[e.jsx("span",{children:"Title"}),e.jsx("input",{required:!0,minLength:3,maxLength:180,value:h.title,onChange:t=>A(r=>({...r,title:t.target.value})),placeholder:"A short, searchable summary"})]}),e.jsxs("label",{className:"support-form-wide",children:[e.jsx("span",{children:h.postType==="issue"?"What happened?":h.postType==="feature"?"Describe the desired behavior":h.postType==="announcement"?"Announcement":"Question"}),e.jsx("textarea",{required:!0,value:h.body,onChange:t=>A(r=>({...r,body:t.target.value})),placeholder:"Include the context another person needs to respond.",rows:6})]}),e.jsxs("label",{children:[e.jsx("span",{children:"Visibility"}),e.jsxs("select",{value:h.visibility,disabled:h.postType==="announcement",onChange:t=>A(r=>({...r,visibility:t.target.value})),children:[e.jsx("option",{value:"public",children:"Public"}),e.jsx("option",{value:"private",children:"Private"})]})]}),h.postType==="issue"&&e.jsxs("label",{className:"support-checkbox",children:[e.jsx("input",{type:"checkbox",checked:h.includeEnvironment,onChange:t=>A(r=>({...r,includeEnvironment:t.target.checked}))}),e.jsx("span",{children:"Attach safe browser/runtime details"})]}),e.jsxs("label",{className:"support-form-wide",children:[e.jsx("span",{children:"Attachments"}),e.jsx("input",{type:"file",multiple:!0,accept:"image/png,image/jpeg,image/webp,text/plain,text/markdown,application/json,application/pdf",onChange:t=>fe(Array.from(t.target.files||[]).slice(0,5))}),e.jsx("small",{className:"support-muted",children:"Up to 5 files, 10 MB each. Images, text, JSON, Markdown, and PDF."})]})]}),e.jsxs("div",{className:"support-composer-footer",children:[e.jsx("span",{children:H.length>0?`${H.length} attachment${H.length===1?"":"s"} selected.`:"Private posts are visible only to you and VuvoDesk Support."}),e.jsxs("button",{className:"support-primary-button",type:"submit",disabled:v==="create",children:[e.jsx(be,{size:16})," ",v==="create"?"Submitting...":"Submit request"]})]})]}),e.jsxs("div",{className:"support-tabs",role:"tablist","aria-label":"Support post type",children:[e.jsx("button",{className:o.type==="all"?"active":"",type:"button",onClick:()=>N({type:"all"}),children:"All"}),ae.map(t=>{const r=we(t.id);return e.jsxs("button",{className:o.type===t.id?"active":"",type:"button",onClick:()=>N({type:t.id}),children:[e.jsx(r,{size:15})," ",t.label]},t.id)})]}),Ce&&m?.canViewAllProducts&&e.jsxs("section",{className:"support-admin-panel",children:[e.jsxs("div",{className:"support-section-heading",children:[e.jsxs("div",{children:[e.jsx("span",{children:"VuvoDesk owner controls"}),e.jsx("strong",{children:"Manage VuvoDesk support access and staff roles by email."})]}),e.jsx(T,{size:19})]}),e.jsxs("div",{className:"support-admin-grid",children:[e.jsxs("form",{onSubmit:t=>{},children:[e.jsx("strong",{children:"Grant VuvoDesk access"}),e.jsx("input",{type:"email",required:!0,placeholder:"User email",value:qe,onChange:t=>ze(t.target.value)}),e.jsxs("select",{value:Te,onChange:t=>De(t.target.value),children:[e.jsx("option",{value:"free",children:"Free"}),e.jsx("option",{value:"user",children:"User"}),e.jsx("option",{value:"paid",children:"Paid"}),e.jsx("option",{value:"beta",children:"Beta"}),e.jsx("option",{value:"staff",children:"Staff"})]}),e.jsxs("button",{className:"support-secondary-button",type:"submit",disabled:me==="access",children:[e.jsx(ee,{size:15})," Grant access"]})]}),e.jsxs("form",{onSubmit:t=>{},children:[e.jsx("strong",{children:"Assign VuvoDesk staff"}),e.jsx("input",{type:"email",required:!0,placeholder:"Staff email",value:Ie,onChange:t=>Ve(t.target.value)}),e.jsxs("select",{value:Re,onChange:t=>Ue(t.target.value),children:[e.jsx("option",{value:"admin",children:"Admin"}),e.jsx("option",{value:"support",children:"Support"}),e.jsx("option",{value:"moderator",children:"Moderator"})]}),e.jsxs("button",{className:"support-secondary-button",type:"submit",disabled:me==="product-admin",children:[e.jsx(T,{size:15})," Assign staff"]})]})]})]}),e.jsxs("form",{className:"support-search-bar",onSubmit:t=>{t.preventDefault(),N({query:le.trim()})},children:[e.jsxs("label",{children:[e.jsx("span",{children:"Search Support"}),e.jsx("input",{value:le,onChange:t=>K(t.target.value),placeholder:"Search titles and request details"})]}),e.jsxs("button",{className:"support-secondary-button",type:"submit",children:[e.jsx(je,{size:15})," Search"]}),o.query&&e.jsx("button",{className:"support-icon-button",type:"button",onClick:()=>{K(""),N({query:""})},"aria-label":"Clear search",children:e.jsx(G,{size:16})})]}),e.jsxs("div",{className:"support-filter-bar",children:[e.jsxs("div",{className:"support-filter-title",children:[e.jsx(je,{size:16}),e.jsx("span",{children:"Filter"})]}),e.jsxs("label",{children:[e.jsx("span",{children:"Status"}),e.jsx("select",{value:o.status,onChange:t=>N({status:t.target.value}),children:zt.map(t=>e.jsx("option",{value:t.id,children:t.label},t.id))})]}),e.jsxs("label",{children:[e.jsx("span",{children:"Visibility"}),e.jsxs("select",{value:o.visibility,onChange:t=>N({visibility:t.target.value}),children:[e.jsx("option",{value:"all",children:"All visibility"}),e.jsx("option",{value:"public",children:"Public"}),e.jsx("option",{value:"private",children:"Private"})]})]}),e.jsxs("label",{children:[e.jsx("span",{children:"Sort"}),e.jsxs("select",{value:o.sort,onChange:t=>N({sort:t.target.value}),children:[e.jsx("option",{value:"recent",children:"Recently updated"}),e.jsx("option",{value:"newest",children:"Newest"}),e.jsx("option",{value:"votes",children:"Most votes"})]})]})]}),m?.canViewAllProducts&&e.jsxs("div",{className:"support-admin-shortcuts",children:[e.jsxs("span",{children:[e.jsx(T,{size:15})," VuvoDesk owner"]}),e.jsx("button",{type:"button",onClick:()=>N({status:"needs-response"}),children:"Needs response"}),e.jsx("button",{type:"button",onClick:()=>N({visibility:"private"}),children:"Private requests"}),e.jsx("button",{type:"button",onClick:()=>N({type:"feature",status:"all",sort:"votes"}),children:"High-vote features"})]}),e.jsxs("div",{className:"support-board-layout",children:[e.jsxs("section",{className:"support-post-list","aria-label":"Support posts",children:[e.jsxs("div",{className:"support-list-heading",children:[e.jsxs("span",{children:[q.length," request",q.length===1?"":"s"]}),e.jsx("small",{children:"VuvoDesk"})]}),q.length===0?e.jsxs("div",{className:"support-list-empty",children:[e.jsx(X,{size:25}),e.jsx("strong",{children:"No posts match these filters."}),e.jsx("span",{children:"Start with a focused question, issue report, or feature request."}),g.length>0&&e.jsxs("button",{className:"support-secondary-button",type:"button",onClick:()=>B(!0),children:[e.jsx(ye,{size:16})," Create the first request"]})]}):q.map(t=>{const r=we(t.post_type);return e.jsxs("button",{type:"button",className:`support-post-row ${t.id===a?.id?"active":""}`,onClick:()=>{x(t.id),F(!1)},children:[e.jsx("span",{className:"support-post-row-icon",children:e.jsx(r,{size:17})}),e.jsxs("span",{className:"support-post-row-copy",children:[e.jsxs("span",{className:"support-post-row-meta",children:[e.jsx("em",{children:Se(t.post_type)}),t.visibility==="private"&&e.jsx(V,{size:13})]}),e.jsx("strong",{children:t.title}),e.jsxs("small",{children:[se(t.status)," · ",Q(t.updated_at)," · ",t.comment_count," comments"]})]}),t.post_type==="feature"&&e.jsxs("span",{className:"support-vote-count",children:[e.jsx(Xe,{size:14})," ",t.vote_count]})]},t.id)})]}),e.jsx("section",{className:"support-post-detail","aria-label":"Support post detail",children:a?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"support-detail-head",children:[e.jsxs("div",{className:"support-detail-badges",children:[e.jsx("span",{className:"support-type-badge",children:Se(a.post_type)}),e.jsx("span",{className:`support-status-badge status-${a.status}`,children:se(a.status)}),a.visibility==="private"&&e.jsxs("span",{className:"support-private-badge",children:[e.jsx(V,{size:13})," Private"]})]}),e.jsxs("div",{className:"support-detail-actions",children:[$e&&e.jsx("button",{className:"support-icon-button",type:"button",onClick:()=>F(t=>!t),title:"Edit post",children:e.jsx(et,{size:16})}),E&&e.jsxs(e.Fragment,{children:[e.jsx("button",{className:"support-icon-button",type:"button",onClick:()=>{Qe()},disabled:v==="pin",title:a.is_pinned?"Unpin post":"Pin post",children:e.jsx(ve,{size:16})}),e.jsx("button",{className:"support-icon-button",type:"button",onClick:()=>{Ge()},disabled:v==="lock",title:a.is_locked?"Unlock post":"Lock post",children:e.jsx(V,{size:16})}),e.jsx("button",{className:"support-icon-button danger",type:"button",onClick:()=>{Ye()},disabled:v==="hide",title:"Hide post",children:e.jsx(_e,{size:16})})]})]})]}),Pe?e.jsxs("form",{className:"support-edit-form",onSubmit:t=>{Be(t)},children:[e.jsx("input",{value:a.title,onChange:t=>C({title:t.target.value}),minLength:3,maxLength:180,required:!0}),e.jsx("textarea",{value:a.body,onChange:t=>C({body:t.target.value}),rows:9,required:!0}),e.jsxs("div",{className:"support-edit-actions",children:[e.jsxs("select",{value:a.visibility,onChange:t=>C({visibility:t.target.value}),children:[e.jsx("option",{value:"public",children:"Public"}),e.jsx("option",{value:"private",children:"Private"})]}),e.jsxs("button",{className:"support-primary-button",type:"submit",disabled:v==="edit",children:[e.jsx(ee,{size:16})," Save changes"]})]})]}):e.jsxs(e.Fragment,{children:[e.jsx("h3",{children:a.title}),e.jsx("div",{className:"support-detail-body",children:a.body.split(`
|
|
2
2
|
`).map((t,r)=>e.jsx("p",{children:t||" "},`${a.id}-body-${r}`))})]}),e.jsxs("div",{className:"support-detail-meta",children:[e.jsxs("span",{children:["Opened ",Q(a.created_at)]}),a.app_version&&e.jsxs("span",{children:["Version ",a.app_version]}),a.platform&&e.jsx("span",{children:a.platform}),a.is_locked&&e.jsxs("span",{children:[e.jsx(V,{size:13})," Locked"]}),a.is_pinned&&e.jsxs("span",{children:[e.jsx(ve,{size:13})," Pinned"]})]}),e.jsxs("div",{className:"support-detail-controls",children:[a.post_type==="feature"&&e.jsxs("button",{className:`support-vote-button ${ne.has(a.id)?"voted":""}`,type:"button",onClick:()=>{Oe()},disabled:v==="vote",children:[e.jsx(tt,{size:16})," ",ne.has(a.id)?"Voted":"Vote"," ",e.jsx("b",{children:a.vote_count})]}),E&&e.jsxs("label",{className:"support-status-control",children:[e.jsx("span",{children:"Change status"}),e.jsx("select",{value:a.status,onChange:t=>{He(t.target.value)},disabled:v==="status",children:(Et[a.post_type]||[]).map(t=>e.jsx("option",{value:t,children:se(t)},t))})]}),E&&e.jsxs(e.Fragment,{children:[e.jsxs("select",{className:"support-status-control",value:D,onChange:t=>he(t.target.value),children:[e.jsx("option",{value:"",children:"Duplicate of..."}),q.filter(t=>t.id!==a.id&&t.product_id===a.product_id).map(t=>e.jsx("option",{value:t.id,children:t.title.slice(0,55)},t.id))]}),e.jsx("button",{className:"support-secondary-button",type:"button",onClick:()=>{Ze()},disabled:!D||v==="duplicate",children:"Merge duplicate"})]})]}),$.length>0&&e.jsxs("div",{className:"support-attachments",children:[e.jsx("div",{className:"support-section-heading",children:e.jsxs("div",{children:[e.jsx("span",{children:"Attachments"}),e.jsxs("strong",{children:[$.length," file",$.length===1?"":"s"]})]})}),$.map(t=>e.jsxs("a",{href:t.signed_url,target:"_blank",rel:"noreferrer",children:[e.jsx(st,{size:14})," ",t.file_name,e.jsxs("small",{children:[Math.ceil(t.size_bytes/1024)," KB"]})]},t.id))]}),e.jsxs("div",{className:"support-comments",children:[e.jsxs("div",{className:"support-section-heading",children:[e.jsxs("div",{children:[e.jsx("span",{children:"Discussion"}),e.jsxs("strong",{children:[R.length," comment",R.length===1?"":"s"]})]}),a.is_locked&&e.jsxs("span",{className:"support-locked-label",children:[e.jsx(V,{size:14})," Locked"]})]}),R.length===0?e.jsx("p",{className:"support-muted",children:"No response yet. Keep the conversation focused on this request."}):e.jsx("div",{className:"support-comment-list",children:R.map(t=>e.jsxs("article",{className:`support-comment ${t.is_staff_answer?"staff":""} ${a.accepted_comment_id===t.id?"accepted":""}`,children:[e.jsxs("div",{className:"support-comment-head",children:[e.jsx("strong",{children:t.is_staff_answer?"VuvoDesk Support":t.author_id===s.user.id?"You":"Support user"}),t.is_staff_answer&&e.jsxs("span",{children:[e.jsx(T,{size:13})," Staff answer"]}),a.accepted_comment_id===t.id&&e.jsxs("span",{children:[e.jsx(at,{size:13})," Accepted"]}),e.jsx("time",{children:Q(t.created_at)})]}),e.jsx("p",{children:t.body}),e.jsxs("div",{className:"support-comment-actions",children:[(s.user.id===a.author_id||E)&&a.post_type==="question"&&a.accepted_comment_id!==t.id&&e.jsxs("button",{className:"support-secondary-button",type:"button",onClick:()=>{We(t.id)},disabled:v===`accept-${t.id}`,children:[e.jsx(ee,{size:14})," Accept answer"]}),E&&e.jsx("button",{className:"support-icon-button danger",type:"button",onClick:()=>{qt(t.id)},title:"Hide comment",children:e.jsx(_e,{size:14})})]})]},t.id))}),!a.is_locked&&e.jsxs("form",{className:"support-comment-form",onSubmit:t=>{Fe(t)},children:[e.jsx("textarea",{value:O,onChange:t=>ce(t.target.value),placeholder:"Add a focused reply...",rows:3}),e.jsxs("button",{className:"support-primary-button",type:"submit",disabled:v==="comment"||!O.trim(),children:[e.jsx(be,{size:15})," Reply"]})]})]})]}):e.jsxs("div",{className:"support-detail-empty",children:[e.jsx(X,{size:28}),e.jsx("strong",{children:"Select a Support request"}),e.jsx("span",{children:"Its discussion and staff actions will appear here."})]})})]})]}):e.jsx("section",{className:"support-page support-auth-page",children:e.jsxs("div",{className:"support-empty-hero",children:[e.jsx("span",{className:"support-hero-icon",children:e.jsx(X,{size:28})}),e.jsx("p",{className:"support-eyebrow",children:"VuvoDesk Support"}),e.jsx("h2",{children:"Get help, report issues, and shape the product."}),e.jsx("p",{children:"Sign in to view VuvoDesk support and submit a private or public request."}),e.jsxs("button",{className:"support-primary-button",type:"button",onClick:d,children:[e.jsx(T,{size:17})," Sign in with Google"]})]})})}export{Ht as SupportPage};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as e}from"./pwa-startup-BiuYh5eN.js";import{r,u as te,M as ce,B as Ye,z as qe,H as Qe,I as De,J as Ie,X as Se,S as $e,K as Ze,m as Fe,O as et,Q as ke,U as tt,V as nt,Y as Ne,W as st,Z as it,_ as rt,$ as at,A as ot,a0 as ct}from"./icons-ChMazCZR.js";import{SupportPage as lt}from"./SupportPage-DXkBQh_W.js";import{s as V,g as Ce,n as ut,r as dt,a as Ee,b as ht,f as Te,A as mt,H as ft}from"./HubApp-CqNxUVJD.js";import{DesktopUpdatePanel as pt}from"./DesktopUpdatePanel-DopP2EeD.js";import{M as gt,w as bt,i as wt,D as ne,r as vt,h as xt}from"./MonitorStackIcon-led0pnag.js";import"./pwa-bootstrap-ljOQTt2e.js";import"./public-site-routing-pddZbLCj.js";import"./supabase-C7qjtLN3.js";import"./frame-lifecycle-D91nchvm.js";function yt(i=[]){return[...new Set(i.filter(t=>typeof t=="string").map(t=>t.trim()).filter(Boolean))]}function jt(i=[],t=new Set){return i.find(c=>!t.has(c))||""}function St(i=[],t=new Set){const c=new Set(i);return new Set([...t].filter(o=>c.has(o)))}const kt="client-runtime-connection-unavailable",Nt="VuvoDesk Client is reconnecting to the service on this computer.",Ct=/failed to fetch|fetch failed|network request failed|networkerror when attempting to fetch resource|load failed|signal timed out|operation was aborted due to timeout|the operation timed out/i;function Oe(i,t){if(!i||typeof i!="object")return"";const c=i[t];return typeof c=="string"?c.trim():""}function le(i){return typeof i=="string"?i.trim():Oe(i,"message")||String(i??"").trim()}function Re(i){return/supabase-user-verification-failed:(401|403)/i.test(i)?"Saved sign-in needs refresh. VuvoDesk will retry it automatically.":i}function Ae(i){const t=le(i)||"Client status could not be refreshed.",c=Oe(i,"name").toLowerCase();return c==="timeouterror"||c==="aborterror"||Ct.test(t)?{key:kt,message:Nt}:{key:`client-status-poll:${t}`,message:t}}function Et({actionError:i="",discoveryWakeError:t=null,statusPollError:c=null,runtimeError:o=""}={}){const u=le(i);if(u)return{key:`client-action:${u}`,message:Re(u)};if(t?.key&&t?.message)return t;if(c?.key&&c?.message)return c;const p=le(o);return p?{key:`client-runtime:${p}`,message:Re(p)}:null}function Tt(i,t){if(!t?.message)return{nextKey:"",message:null};const c=String(t.key||t.message).trim();return String(i||"")===c?{nextKey:c,message:null}:{nextKey:c,message:t.message}}const Rt=[{id:"docs",label:"Doc",icon:Ye},{id:"support",label:"Support",icon:qe},{id:"pricing",label:"Pricing",icon:Qe},{id:"settings",label:"Settings",icon:De}],Pe=[0,1e3,2e3,5e3,1e4,2e4,3e4],At=15e3;function Pt(i=""){const t=i.trim().replace(/\/+$/,"");return t||(typeof window>"u"?"":window.location.port==="5179"?window.location.origin:"http://127.0.0.1:5179")}async function U(i,t=!1){const c=t?"":sessionStorage.getItem("livedesk.client.csrf");if(c)return c;const o=await fetch(`${i}/api/runtime/status`,{cache:"no-store"}),u=await o.json().catch(()=>({}));if(!o.ok)throw new Error(u.error||`Client runtime returned HTTP ${o.status}.`);const p=String(u.csrfToken||"");return p&&sessionStorage.setItem("livedesk.client.csrf",p),p}function ue(i){return`${Math.max(0,Math.min(100,Number(i||0))).toFixed(0)}%`}function oe(i){return Number.isFinite(i)?`${Math.max(0,Math.min(100,Number(i))).toFixed(0)}%`:"—"}function Me(i){return Number.isFinite(i)?ue(Number(i)):"0%"}function H(i){const t=Number(i);return!Number.isFinite(t)||t<0?"—":t>=1024**4?`${(t/1024**4).toFixed(t>=10*1024**4?0:1)} TB`:t>=1024**3?`${(t/1024**3).toFixed(t>=10*1024**3?0:1)} GB`:`${(t/1024**2).toFixed(0)} MB`}function Le(i){const t=Math.max(0,Number(i||0));return t>=1024**3?`${(t/1024**3).toFixed(1)} GB/s`:t>=1024**2?`${(t/1024**2).toFixed(1)} MB/s`:t>=1024?`${(t/1024).toFixed(1)} KB/s`:`${t.toFixed(0)} B/s`}function Lt(i,t){const c=Number(i||0)/1073741824,o=Number(t||0)/1024**3;return o>0?`${c.toFixed(1)} / ${o.toFixed(1)} GB`:"Checking..."}function Dt(i,t){return!Number.isFinite(t)||Number(t)<=0?"Dedicated memory unavailable":Number.isFinite(i)?`${H(i)} / ${H(t)}`:`${H(t)} available`}function It(i){const t=Math.max(0,Math.floor(Number(i||0)/60)),c=Math.floor(t/1440),o=Math.floor(t%1440/60),u=t%60;return c>0?`${c}d ${o}h`:o>0?`${o}h ${u}m`:`${u}m`}function ee({icon:i,label:t,value:c,detail:o,percent:u}){return e.jsxs("article",{className:"client-resource-metric",children:[e.jsxs("div",{className:"client-resource-metric-head",children:[e.jsx(i,{size:17}),e.jsx("span",{children:t}),e.jsx("strong",{children:c})]}),e.jsx("small",{title:o,children:o}),e.jsx("i",{"aria-hidden":"true",children:e.jsx("b",{style:{width:Me(u)}})})]})}function $t(i,t){const c=i?.user.user_metadata||{},o=c.full_name||c.name||c.preferred_username||i?.user.email||i?.user.id||t?.userName||t?.auth?.name||t?.userEmail||t?.userId||"Account";return String(o).trim()||"Account"}function Ft(i,t){const c=i?.user.user_metadata||{};return yt([c.avatar_url,c.picture,t?.userAvatarUrl,t?.auth?.avatarUrl])}function Ot({page:i,status:t}){const o={docs:{label:"DOC",title:"Using this computer",body:"This computer connects to its assigned Hub automatically. Keep VuvoDesk running and manage screens, files, and remote control from the Hub."},pricing:{label:"PRICING",title:"VuvoDesk plans",body:"Plans are based on how many computers the Hub manages. This Client computer does not need a separate subscription or setup."},settings:{label:"SETTINGS",title:"Computer preferences",body:"VuvoDesk keeps the verified sign-in on this computer and reconnects to the assigned Hub automatically."}}[i];return e.jsxs("section",{className:"client-service-page",children:[e.jsx("span",{className:"client-unified-section-label",children:o.label}),e.jsx("h2",{children:o.title}),e.jsx("p",{children:o.body}),e.jsxs("div",{className:"client-service-page-card",children:[i==="docs"&&e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"Automatic connection"}),e.jsx("span",{children:"Start VuvoDesk. This computer signs in, finds the Hub, and becomes available without another action."})]}),i==="pricing"&&e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"One plan, managed at the Hub"}),e.jsx("span",{children:"Computer access follows the account and plan used by the Hub."})]}),i==="settings"&&e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"Saved sign-in"}),e.jsx("span",{children:t?.auth?.persisted?"Enabled on this computer":"Sign in once to enable automatic reconnection"})]})]}),i==="settings"&&e.jsx(pt,{})]})}function Mt({session:i,status:t,pin:c,roleChangeMessage:o,videoAccelerationBusy:u,slotInput:p,slotBusy:v,onSignIn:R,onPinChange:_,onSubmitPin:C,onSlotInputChange:d,onSaveSlot:A,onEnableVideoAcceleration:k}){const j=t?.connectionState==="connected",g=t?.videoAcceleration,$=u||g?.busy||g?.state==="installing",b=g?.ready?`${g.encoder||"H.264"} · ${g.driver||"VAAPI"}`:$?"Setting up…":g?.message||"Setup available",y=t?.system?.memoryTotalBytes?Number(t.system.memoryUsedBytes||0)/t.system.memoryTotalBytes*100:0,P=t?.system?.gpus||[],w=P.find(h=>Number.isFinite(h.usagePercent)||Number.isFinite(h.memoryTotalBytes))||P[0],z=Number.isFinite(w?.usagePercent)?Number(w?.usagePercent):null,G=Number.isFinite(w?.memoryTotalBytes)&&Number(w?.memoryTotalBytes)>0&&Number.isFinite(w?.memoryUsedBytes)?Number(w?.memoryUsedBytes)/Number(w?.memoryTotalBytes)*100:null,E=t?.system?.disks||[],T=t?.system?.network,B=!!T?.sampledAt,N=T?.interfaces||[],S=[...new Set(N.map(h=>h.name).filter(Boolean))],L=N.map(h=>h.address).filter(Boolean);return e.jsxs("section",{className:"client-home-page",children:[e.jsxs("header",{className:"client-home-heading",children:[e.jsxs("div",{children:[e.jsx("p",{className:"client-unified-eyebrow",children:"THIS COMPUTER"}),e.jsx("h2",{children:t?.deviceName||"This Computer"})]}),e.jsxs("span",{className:`client-unified-role-chip ${j?"connected":""}`,children:[e.jsx(ce,{size:15})," ",j?"Online":"Connecting"]})]}),e.jsxs("div",{className:"client-home-layout",children:[e.jsxs("section",{className:"client-main-surface","aria-label":"Client computer",children:[e.jsxs("div",{className:"client-main-surface-head",children:[e.jsxs("div",{children:[e.jsx("span",{className:"client-unified-section-label",children:"SYSTEM STATUS"}),e.jsx("strong",{children:"Hardware at a glance"})]}),e.jsxs("small",{children:[e.jsx(et,{size:14})," Uptime ",It(t?.system?.uptimeSeconds)]})]}),e.jsxs("div",{className:"client-system-dashboard",children:[e.jsxs("section",{className:"client-performance-panel","aria-label":"Performance",children:[e.jsxs("div",{className:"client-system-subhead",children:[e.jsxs("div",{children:[e.jsx("span",{className:"client-unified-section-label",children:"PERFORMANCE"}),e.jsx("strong",{children:"Live resources"})]}),e.jsx("small",{children:"Live updates"})]}),e.jsxs("div",{className:"client-live-metrics",children:[e.jsx(ee,{icon:ke,label:"CPU",value:ue(t?.system?.cpuUsagePercent),detail:t?.system?.cpuLogicalCores?`${t.system.cpuLogicalCores} logical cores · Current processor usage`:"Current processor usage",percent:t?.system?.cpuUsagePercent}),e.jsx(ee,{icon:tt,label:"Memory",value:ue(y),detail:Lt(t?.system?.memoryUsedBytes,t?.system?.memoryTotalBytes),percent:y}),e.jsx(ee,{icon:nt,label:"GPU",value:oe(z),detail:w?.name||(t?.system?.hardwareCollecting?"Detecting graphics hardware…":"Graphics usage unavailable"),percent:z}),e.jsx(ee,{icon:te,label:"VRAM",value:oe(G),detail:Dt(w?.memoryUsedBytes,w?.memoryTotalBytes),percent:G})]})]}),e.jsxs("section",{className:"client-storage-panel","aria-label":"Local storage",children:[e.jsxs("div",{className:"client-system-subhead",children:[e.jsxs("div",{children:[e.jsx("span",{className:"client-unified-section-label",children:"STORAGE"}),e.jsx("strong",{children:"Local drives"})]}),e.jsx("small",{children:E.length>0?`${E.length} ${E.length===1?"drive":"drives"}`:t?.system?.hardwareCollecting?"Detecting…":"Unavailable"})]}),e.jsxs("div",{className:"client-disk-list",children:[E.map(h=>e.jsxs("article",{className:"client-disk-row",children:[e.jsxs("div",{className:"client-disk-row-head",children:[e.jsxs("span",{children:[e.jsx(Ne,{size:16}),e.jsx("strong",{children:h.mount||"Disk"}),e.jsx("small",{children:h.name||"Local disk"})]}),e.jsx("strong",{children:oe(h.usedPercent)})]}),e.jsxs("small",{children:[H(h.freeBytes)," free · ",H(h.totalBytes)," total"]}),e.jsx("i",{"aria-hidden":"true",children:e.jsx("b",{style:{width:Me(h.usedPercent)}})})]},`${h.mount}-${h.name||""}`)),E.length===0&&e.jsxs("div",{className:"client-disk-empty",children:[e.jsx(Ne,{size:18}),e.jsx("span",{children:t?.system?.hardwareCollecting?"Detecting local drives…":"Storage information is not available."})]})]})]}),e.jsxs("section",{className:"client-network-panel","aria-label":"Network activity",children:[e.jsxs("div",{className:"client-system-subhead",children:[e.jsxs("div",{children:[e.jsx("span",{className:"client-unified-section-label",children:"NETWORK"}),e.jsx("strong",{children:"Live traffic"})]}),e.jsx("small",{children:S.length>0?S.join(", "):"Detecting adapter"})]}),e.jsxs("div",{className:"client-network-live",children:[e.jsxs("div",{className:"client-network-adapter",children:[e.jsx(st,{size:18}),e.jsxs("span",{children:[e.jsx("strong",{children:S.join(", ")||"Network"}),e.jsx("small",{children:L.join(" / ")||"Checking active connection"})]})]}),e.jsxs("div",{className:"client-network-rate download",children:[e.jsx(it,{size:17}),e.jsxs("span",{children:[e.jsx("small",{children:"Receive"}),e.jsx("strong",{children:Le(B?T?.receiveBytesPerSecond:void 0)})]})]}),e.jsxs("div",{className:"client-network-rate upload",children:[e.jsx(rt,{size:17}),e.jsxs("span",{children:[e.jsx("small",{children:"Send"}),e.jsx("strong",{children:Le(B?T?.sendBytesPerSecond:void 0)})]})]}),e.jsx("small",{className:"client-network-total",children:B?`Total ${H(T?.receivedBytes)} received / ${H(T?.sentBytes)} sent`:"Traffic has not been measured yet."})]})]})]})]}),e.jsxs("aside",{className:"client-connection-panel",children:[e.jsx("span",{className:"client-unified-section-label",children:"VUVODESK SERVICES"}),e.jsx("h3",{children:j?"Connected to the Hub":t?.authenticated?"Finding the Hub":"Connect this computer"}),j?e.jsxs(e.Fragment,{children:[e.jsx("p",{className:"client-unified-copy",children:"This computer is available from the VuvoDesk Hub."}),e.jsxs("div",{className:"client-service-status-list",children:[e.jsxs("div",{children:[e.jsx(ce,{size:17}),e.jsxs("span",{children:[e.jsx("strong",{children:"Screen sharing"}),e.jsx("small",{children:t?.permissions?.screenCapture?"Active":"Waiting"})]})]}),e.jsxs("div",{children:[e.jsx($e,{size:17}),e.jsxs("span",{children:[e.jsx("strong",{children:"Remote control"}),e.jsx("small",{children:t?.permissions?.remoteInput?"Available":"Unavailable"})]})]}),e.jsxs("div",{children:[e.jsx(at,{size:17}),e.jsxs("span",{children:[e.jsx("strong",{children:"File delivery"}),e.jsx("small",{children:t?.permissions?.files?"Ready to receive":"Unavailable"})]})]}),e.jsxs("div",{children:[e.jsx(ot,{size:17}),e.jsxs("span",{children:[e.jsx("strong",{children:"Computer audio"}),e.jsx("small",{children:t?.permissions?.audio?"Available":"Unavailable"})]})]})]})]}):e.jsxs(e.Fragment,{children:[e.jsx("p",{className:"client-unified-copy",children:t?.authenticated?"VuvoDesk is checking the registered Hub endpoints. A temporary Hub PIN can be used as a fallback.":"Sign in once on this computer. VuvoDesk saves the verified session, finds the Hub, and starts screen sharing automatically."}),!i&&!t?.authenticated?e.jsxs("button",{className:"client-unified-primary",type:"button",onClick:R,children:[e.jsx(Ie,{size:16})," Sign in with Google"]}):e.jsxs("p",{className:"client-unified-success",children:[e.jsx(Fe,{size:16})," Signed in as ",i?.user.email||i?.user.id||t?.userEmail||t?.userId||"saved account"]}),e.jsxs("div",{className:"client-unified-pin-row",children:[e.jsx(ct,{size:16}),e.jsx("input",{value:c,onChange:h=>_(h.target.value),placeholder:"6-digit Hub PIN",inputMode:"numeric","aria-label":"6-digit Hub PIN"}),e.jsx("button",{className:"client-unified-secondary",type:"button",onClick:C,disabled:c.length!==6,children:"Connect"})]})]}),g?.supported&&e.jsxs("div",{className:`client-video-acceleration state-${g.ready?"ready":g.state||"setup-required"}`,children:[e.jsx(ke,{size:17}),e.jsxs("span",{children:[e.jsx("strong",{children:"Hardware video"}),e.jsx("small",{children:b})]}),!g.ready&&g.canInstall&&e.jsx("button",{type:"button",onClick:k,disabled:$,title:"Install and verify Linux FFmpeg hardware video support",children:$?"Setting up":"Enable"})]}),o&&e.jsx("p",{className:"client-unified-success",children:o}),e.jsxs("div",{className:"client-slot-setting",children:[e.jsxs("label",{htmlFor:"client-slot-number",children:[e.jsx("span",{children:"Slot"}),e.jsx("input",{id:"client-slot-number",value:p,onChange:h=>d(h.target.value),inputMode:"numeric",pattern:"[0-9]*",placeholder:"1-999","aria-label":"Wall slot number",disabled:!j||v})]}),e.jsxs("button",{type:"button",onClick:A,disabled:!j||v||!p,"aria-label":"Save slot number",title:"Save slot number",children:[e.jsx(De,{size:17}),e.jsx("span",{children:v?"Saving":"Set"})]})]})]})]})]})}function Ut({runtimeBaseUrl:i=""}){const[t,c]=r.useState(null),[o,u]=r.useState(null),[p,v]=r.useState(!1),[R,_]=r.useState(""),[C,d]=r.useState(""),[A,k]=r.useState(null),[j,g]=r.useState(null),[$,b]=r.useState(""),[y,P]=r.useState(!1),[w,z]=r.useState(!1),[G,E]=r.useState(""),[T,B]=r.useState(!1),[N,S]=r.useState(null),[L,h]=r.useState(!1),[D,de]=r.useState("computer"),[he,Y]=r.useState(!1),me=r.useRef(null),fe=r.useRef(null),se=r.useRef(!1),q=r.useRef(null),Q=r.useRef(null),pe=r.useRef(!1),K=r.useRef(!1),ge=r.useRef(0),ie=r.useRef(!1),be=r.useRef(""),m=r.useMemo(()=>Pt(i),[i]),re=r.useMemo(()=>$t(o,t),[o,t]),ae=r.useMemo(()=>Ft(o,t),[o,t]),Ue=JSON.stringify(ae),[He,we]=r.useState(()=>new Set),W=jt(ae,He),ve=re.slice(0,1).toUpperCase()||"L";r.useEffect(()=>{we(n=>St(ae,n))},[Ue]);const _e=r.useCallback(n=>{we(s=>{if(!n||s.has(n))return s;const a=new Set(s);return a.add(n),a})},[]),F=r.useCallback(async()=>{if(d(""),window.liveDesk?.auth?.signInWithGoogle){const n=await window.liveDesk.auth.signInWithGoogle();return n?.ok===!1?(d(n.error||"VuvoDesk could not open the system browser for Google sign-in."),!1):!0}return window.location.assign(`${m}/auth/google`),!0},[m]),xe=r.useCallback(async()=>{K.current||(K.current=!0,d("Your saved Google sign-in is incomplete. VuvoDesk is reopening sign-in once to repair it."),await V.auth.signOut({scope:"local"}).catch(()=>{}),u(null),await F()||(K.current=!1))},[F]),ye=r.useCallback(async n=>{const s=Ce(n);if(s)throw new Error(s);if(se.current)return!1;se.current=!0;try{if(window.liveDesk?.auth?.persistSession){const a=await window.liveDesk.auth.persistSession(n);if(a?.ok===!1)throw new Error(a.error||"VuvoDesk could not validate the desktop session.");return d(""),!0}for(let a=0;a<2;a+=1){const l=await U(m,a>0),f=await fetch(`${m}/api/auth/session`,{method:"POST",headers:{"Content-Type":"application/json","X-LiveDesk-CSRF":l},signal:AbortSignal.timeout(1e4),body:JSON.stringify({accessToken:n.access_token,refreshToken:n.refresh_token,expiresAt:n.expires_at,user:{id:n.user.id,email:n.user.email}})}),M=await f.json().catch(()=>({}));if(f.status===403&&a===0){sessionStorage.removeItem("livedesk.client.csrf");continue}if(!f.ok)throw new Error(M.error||`Client runtime returned HTTP ${f.status}.`);return d(""),!0}throw new Error("Client runtime rejected the session transfer.")}finally{se.current=!1}},[m]),x=r.useCallback(()=>{const n=q.current;if(n)return n;const s=(async()=>{try{const a=await fetch(`${m}/api/client/status`,{cache:"no-store",signal:AbortSignal.timeout(1500)}),l=await a.json().catch(()=>({}));if(!a.ok)throw new Error(l.error||`Client runtime returned HTTP ${a.status}.`);if(l.csrfToken&&sessionStorage.setItem("livedesk.client.csrf",l.csrfToken),String(l.role||"").toLowerCase()==="hub")throw new Error("This computer is assigned to the Hub role.");c(l),k(null),g(null)}catch(a){k(Ae(a))}})();return q.current=s,s.finally(()=>{q.current===s&&(q.current=null)}),s},[m]),je=r.useCallback(()=>{const n=Q.current;if(n)return n;const s=(async()=>{const a=await fetch(`${m}/api/client/diagnostics`,{cache:"no-store",signal:AbortSignal.timeout(8e3)}),l=await a.json().catch(()=>({}));if(!a.ok)throw new Error(l.error||`Client diagnostics returned HTTP ${a.status}.`);if(String(l.role||"").toLowerCase()==="hub")throw new Error("This computer is assigned to the Hub role.");c(l)})();return Q.current=s,s.finally(()=>{Q.current===s&&(Q.current=null)}),s},[m]);r.useEffect(()=>{let n=!1,s=null;const a=async()=>{await x(),n||(s=window.setTimeout(()=>{a()},2e3))};return a(),()=>{n=!0,s!==null&&window.clearTimeout(s)}},[x]),r.useEffect(()=>{if(D!=="computer")return;let n=!1,s=null;const a=()=>{n||(s=window.setTimeout(()=>{l()},At))},l=async()=>{document.visibilityState==="visible"&&await je().catch(()=>{}),a()},f=()=>{document.visibilityState==="visible"&&(s!==null&&(window.clearTimeout(s),s=null),l())};return document.addEventListener("visibilitychange",f),l(),()=>{n=!0,document.removeEventListener("visibilitychange",f),s!==null&&window.clearTimeout(s)}},[D,je]),r.useEffect(()=>{if(ie.current)return;const n=Number(t?.slotNumber||0);E(n>0?String(n):"")},[t?.slotNumber]),r.useEffect(()=>{if(!N)return;const n=window.setTimeout(()=>S(null),5e3);return()=>window.clearTimeout(n)},[N]),r.useEffect(()=>{const n=Et({actionError:C,discoveryWakeError:j,statusPollError:A,runtimeError:t?.lastError}),s=Tt(be.current,n);be.current=s.nextKey,s.message&&S({kind:"error",message:s.message})},[j,C,A,t?.lastError]);const Z=r.useCallback(async()=>{const n=Date.now();if(!(!t?.authenticated||t.connectionState==="connected"||!["waiting","reconnecting"].includes(String(t.agent?.state||""))||n-ge.current<4e3)){ge.current=n;try{const s=await fetch(`${m}/api/client/reconnect`,{method:"POST",headers:{"Content-Type":"application/json","X-LiveDesk-CSRF":await U(m)},body:JSON.stringify({onlyIfWaiting:!0,reason:"app-active"})});if(!s.ok)throw new Error(`Client reconnect returned HTTP ${s.status}.`);g(null),await x()}catch(s){g(Ae(s))}}},[m,x,t]);r.useEffect(()=>{const n=()=>{Z()},s=()=>{Z()},a=()=>{document.visibilityState==="visible"&&Z()};return window.addEventListener("online",n),window.addEventListener("focus",s),document.addEventListener("visibilitychange",a),()=>{window.removeEventListener("online",n),window.removeEventListener("focus",s),document.removeEventListener("visibilitychange",a)}},[Z]),r.useEffect(()=>{if(!p||!t||!o?.access_token||t.authenticated)return;if(Ce(o)==="refresh-token-required"){xe().catch(f=>{K.current=!1,d(f instanceof Error?f.message:String(f))});return}let n=!1,s,a=0;const l=async()=>{if(n)return;try{const M=await ye(o);if(await x(),M)return}catch(M){d(M instanceof Error?M.message:String(M))}if(n)return;const f=Pe[Math.min(a,Pe.length-1)];a+=1,s=window.setTimeout(()=>{l()},f)};return l(),()=>{n=!0,s!==void 0&&window.clearTimeout(s)}},[p,x,xe,o,t,ye]),r.useEffect(()=>{const n=new URLSearchParams(window.location.search),s=n.get("auth_error");if(!s)return;d(s),n.delete("auth_error");const a=n.toString();window.history.replaceState(window.history.state,"",`${window.location.pathname}${a?`?${a}`:""}${window.location.hash}`)},[]),r.useEffect(()=>{let n=!0;if(!window.liveDesk?.auth)return u(null),v(!0),x(),()=>{n=!1};const s=window.liveDesk?.auth?.onComplete?.(l=>{l.ok&&l.session?V.auth.setSession(l.session).catch(f=>d(f instanceof Error?f.message:String(f))):l.ok&&l.signedOut?(u(null),v(!0),V.auth.signOut({scope:"local"})):l.error&&d(l.error)});(async()=>{try{const l=window.liveDesk?.auth?.getSession?await window.liveDesk.auth.getSession():await V.auth.getSession();if(!n)return;const f=ut(l);u(f),x()}catch(l){n&&d(l instanceof Error?l.message:String(l))}finally{n&&v(!0)}})();const{data:a}=V.auth.onAuthStateChange((l,f)=>{if(n){if(!f&&window.liveDesk?.auth){v(!0);return}u(f),v(!0),x()}});return()=>{n=!1,s?.(),a.subscription.unsubscribe()}},[x]),r.useEffect(()=>{if(!p||!t||pe.current||K.current||o||t.authenticated)return;const n=new URLSearchParams(window.location.search);if(!n.has("livedesk_launch"))return;pe.current=!0,n.delete("livedesk_launch");const s=n.toString();window.history.replaceState(window.history.state,"",`${window.location.pathname}${s?`?${s}`:""}${window.location.hash}`),F().catch(a=>d(a instanceof Error?a.message:String(a)))},[p,o,F,t]);const Be=async()=>{Y(!1),window.liveDesk?.auth?.signOut?(await V.auth.signOut({scope:"local"}),(await window.liveDesk.auth.signOut())?.runtimeCleared===!1&&d("Signed out locally. The VuvoDesk runtime could not be reached to clear its session.")):await fetch(`${m}/api/auth/session`,{method:"DELETE",headers:{"X-LiveDesk-CSRF":await U(m)}}).catch(()=>{}),u(null),await x()},X=r.useCallback((n=!0)=>{y||(h(!1),n&&window.requestAnimationFrame(()=>fe.current?.focus()))},[y]),Ve=r.useCallback(()=>{y||!t?.authenticated||(fe.current=document.activeElement instanceof HTMLElement?document.activeElement:null,b(""),h(!0))},[y,t?.authenticated]);r.useEffect(()=>{if(!L)return;const n=window.requestAnimationFrame(()=>me.current?.focus()),s=l=>{l.target instanceof Element&&l.target.closest(".client-hub-switch-popover, .client-hub-switch-trigger")||X(!1)},a=l=>{l.key==="Escape"&&X()};return window.addEventListener("pointerdown",s),window.addEventListener("keydown",a),()=>{window.cancelAnimationFrame(n),window.removeEventListener("pointerdown",s),window.removeEventListener("keydown",a)}},[X,L]);const ze=async()=>{d("");try{const n=await fetch(`${m}/api/client/pin`,{method:"POST",headers:{"Content-Type":"application/json","X-LiveDesk-CSRF":await U(m)},body:JSON.stringify({pin:R})}),s=await n.json().catch(()=>({}));if(!n.ok||s?.ok===!1)throw new Error(s?.error||"PIN could not be accepted.");_(""),await x()}catch(n){d(n instanceof Error?n.message:String(n))}},Ge=async()=>{h(!1),P(!0),b(""),d("");try{const n=await fetch(`${m}/api/runtime/switch-role`,{method:"POST",headers:{"Content-Type":"application/json","X-LiveDesk-CSRF":await U(m)},body:JSON.stringify({role:"hub"})}),s=await n.json().catch(()=>({}));if(!n.ok||s?.ok===!1)throw new Error(s?.error||`Role change failed with HTTP ${n.status}.`);b("Hub role accepted. VuvoDesk is restarting this computer with the Hub Wall.");const a=Number(t?.runtimePid||0);await bt({baseUrl:m,targetRole:"hub",previousRuntimePid:a,allowedStates:["running"]}),window.location.reload()}catch(n){d(n instanceof Error?n.message:String(n)),P(!1)}},Ke=async()=>{if(T)return;const n=Number(G);if(!Number.isInteger(n)||n<1||n>999){S({kind:"error",message:"Enter a slot number from 1 to 999."});return}B(!0),S(null);try{const s=await fetch(`${m}/api/client/slot`,{method:"POST",headers:{"Content-Type":"application/json","X-LiveDesk-CSRF":await U(m)},body:JSON.stringify({slotNumber:n})}),a=await s.json().catch(()=>({}));if(!s.ok||a.ok===!1){if(a.error==="slot-taken"){const l=a.conflict?.deviceName||a.conflict?.hostname||a.conflict?.deviceId||"another computer";throw new Error(`Slot ${String(n).padStart(3,"0")} is already used by ${l}.`)}throw new Error(a.error||`Slot update failed with HTTP ${s.status}.`)}ie.current=!1,E(String(n)),c(a),S({kind:"success",message:`Slot ${String(n).padStart(3,"0")} saved. VuvoDesk is reconnecting this Client.`})}catch(s){S({kind:"error",message:s instanceof Error?s.message:String(s)})}finally{B(!1),await x()}},We=async()=>{if(!w){z(!0),d("");try{const n=await fetch(`${m}/api/client/video-acceleration/install`,{method:"POST",headers:{"Content-Type":"application/json","X-LiveDesk-CSRF":await U(m)},body:JSON.stringify({confirm:!0})}),s=await n.json().catch(()=>({}));if(c(s),!n.ok||s.videoAcceleration?.ready!==!0)throw new Error(s.videoAcceleration?.error||s.error||"Linux hardware video setup did not complete.")}catch(n){d(n instanceof Error?n.message:String(n))}finally{z(!1),await x()}}},I=!!(t?.authenticated||o),J=r.useMemo(()=>dt(),[]),Xe=Ee("switch-to-hub",J),Je=Ee("client",J),O=ht(J);return e.jsxs("main",{className:"app-shell client-unified-shell",children:[e.jsxs("aside",{className:"tool-rail","aria-label":"VuvoDesk Client tools",children:[e.jsx("div",{className:"rail-brand",title:"VuvoDesk",children:e.jsx(gt,{size:25})}),e.jsx("nav",{className:"rail-tools","aria-label":"Client navigation",children:e.jsxs("div",{className:"client-main-tool-slot",children:[e.jsxs("button",{className:"rail-tool client-main-tool client-hub-tool client-hub-switch-trigger accent-blue",type:"button",onClick:Ve,disabled:y||!t?.authenticated,"aria-busy":y,"aria-expanded":L,"aria-haspopup":"dialog","aria-controls":L?"client-hub-switch-popover":void 0,"aria-label":`Hub. ${Xe}`,"data-tooltip":L?void 0:Te("Hub","switch-to-hub",J),children:[e.jsx(te,{size:19}),e.jsx("span",{children:y?"Switching…":"Hub"})]}),e.jsxs("button",{className:`rail-tool client-main-tool accent-blue ${D==="computer"?"active":""}`,type:"button",onClick:()=>de("computer"),"aria-current":D==="computer"?"page":void 0,"aria-label":`Client. ${Je}`,"data-tooltip":Te("Client","client",J),children:[e.jsx(ce,{size:19}),e.jsx("span",{children:"Client"})]})]})}),e.jsxs("div",{className:"rail-footer",children:[Rt.map(n=>{const s=n.icon;return e.jsxs("button",{className:`rail-tool compact ${D===n.id?"active":""}`,type:"button",onClick:()=>de(n.id),title:n.label,children:[e.jsx(s,{size:18}),e.jsx("span",{children:n.label})]},n.id)}),e.jsxs("button",{className:`rail-account ${I?"signed-in":""}`,type:"button",onClick:()=>Y(n=>!n),"aria-expanded":he,"aria-haspopup":"dialog","aria-controls":"vuvodesk-account-dialog",title:I?"Account":"Sign in",children:[I&&W?e.jsx("img",{src:W,alt:re,referrerPolicy:"no-referrer",onError:()=>_e(W)},W):I?e.jsx("span",{className:"avatar-fallback",children:ve}):e.jsx(Ie,{size:18}),e.jsx("span",{children:I?"Account":"Sign in"})]})]})]}),L&&e.jsxs("section",{id:"client-hub-switch-popover",className:"client-hub-switch-popover",role:"dialog","aria-modal":"false","aria-labelledby":"client-hub-switch-title","aria-describedby":"client-hub-switch-description client-hub-switch-restart",children:[e.jsxs("header",{className:"client-hub-switch-head",children:[e.jsx("span",{className:"client-hub-switch-mark","aria-hidden":"true",children:e.jsx(te,{size:19})}),e.jsx("span",{className:"client-hub-switch-eyebrow",children:O.eyebrow}),e.jsx("button",{className:"client-hub-switch-close",type:"button",onClick:()=>X(),"aria-label":O.closeLabel,children:e.jsx(Se,{size:17})})]}),e.jsx("h2",{id:"client-hub-switch-title",children:O.title}),e.jsx("p",{id:"client-hub-switch-description",children:O.description}),e.jsxs("p",{id:"client-hub-switch-restart",className:"client-hub-switch-notice",children:[e.jsx($e,{size:16,"aria-hidden":"true"}),e.jsx("span",{children:O.restartNotice})]}),e.jsxs("div",{className:"client-hub-switch-actions",children:[e.jsx("button",{type:"button",onClick:()=>X(),children:O.cancel}),e.jsxs("button",{ref:me,className:"primary",type:"button",onClick:()=>{Ge()},disabled:y||!t?.authenticated,children:[e.jsx(te,{size:16}),O.confirm]})]})]}),e.jsx(mt,{open:he,signedIn:I,accountName:I?re:"Account",accountEmail:o?.user.email||t?.userEmail||t?.userId||"",accountInitial:ve,avatarUrl:W,currentPlan:"free",currentPlanKnown:!1,deviceCount:t?1:0,deviceLimit:Number.POSITIVE_INFINITY,licenseLabel:"Plan is managed at the Hub. This Client does not choose or change billing.",networkLabel:t?.connectionState==="connected"?"Connected to Hub":t?"Finding Hub":"Checking local app",accessLabel:t?.auth?.persisted?"Saved sign-in on this computer":I?"Active for this run":"Not signed in",authBusy:!p,checkoutBusy:!1,ltdCheckoutEnabled:!1,monthlyCheckoutEnabled:!1,teamCheckoutEnabled:!1,planChangesEnabled:!1,planManagementLabel:"Plan is managed at the Hub",showWorkspaceSwitcher:!1,workspaces:[],activeWorkspaceId:"",onClose:()=>Y(!1),onSignIn:async()=>{Y(!1),await F()},onSignOut:Be,onSelectPlan:()=>{}}),e.jsx("section",{className:"desk-stage client-unified-stage",children:D==="support"?e.jsx("section",{className:"client-unified-page",children:e.jsx(lt,{session:o,currentProductKey:"livedesk",appVersion:t?.appVersion||"",onSignIn:()=>{F()}})}):D!=="computer"?e.jsx("section",{className:"client-unified-page",children:e.jsx(Ot,{page:D,status:t})}):e.jsx(Mt,{session:o,status:t,pin:R,roleChangeMessage:$,videoAccelerationBusy:w,slotInput:G,slotBusy:T,onSignIn:()=>{F()},onPinChange:n=>_(n.replace(/\D/g,"").slice(0,6)),onSubmitPin:()=>{ze()},onSlotInputChange:n=>{ie.current=!0,E(n.replace(/\D/g,"").slice(0,3))},onSaveSlot:()=>{Ke()},onEnableVideoAcceleration:()=>{We()}})}),N&&e.jsxs("div",{className:`client-side-toast ${N.kind}`,role:N.kind==="error"?"alert":"status",children:[N.kind==="error"?e.jsx(Ze,{size:18}):e.jsx(Fe,{size:18}),e.jsx("span",{children:N.message}),e.jsx("button",{type:"button",onClick:()=>S(null),"aria-label":"Dismiss notification",children:e.jsx(Se,{size:16})})]})]})}const Ht=1e3,_t=5e3;function Bt(){return typeof window>"u"?!1:(!!window.navigator.standalone||window.matchMedia("(display-mode: standalone), (display-mode: fullscreen)").matches)&&window.matchMedia("(pointer: coarse)").matches}function Vt(){return typeof window>"u"?[]:[...new Set([window.location.origin,ne].filter(Boolean))]}function en(){const t=wt(),c=Bt(),o=t||c,u=t||typeof window>"u"?ne:window.location.origin,p=o?{role:"hub",baseUrl:u}:null,[v,R]=r.useState(p),_=r.useRef(null);return r.useEffect(()=>{if(o){R(b=>b?.role==="hub"&&b.baseUrl===u?b:{role:"hub",baseUrl:u});return}let C=!1,d=!1,A=null;const k=new AbortController,j=async()=>{for(const b of Vt()){if(k.signal.aborted)return;try{const P=(await xt("/api/runtime/status",{signal:k.signal,timeoutMs:900},b)).role==="hub"?"hub":"client";d=!0,C||R(w=>w?.role===P&&w.baseUrl===b?w:{role:P,baseUrl:b});return}catch{if(k.signal.aborted)return}}},g=()=>{vt(_,j).finally(()=>{!C&&!k.signal.aborted&&(A=window.setTimeout(g,d?_t:Ht))}).catch(()=>{})};g();const $=window.setTimeout(()=>{!C&&!d&&R(b=>b?.role==="client"&&b.baseUrl===ne?b:{role:"client",baseUrl:ne})},2500);return()=>{C=!0,k.abort(new Error("VuvoDesk runtime role probe stopped.")),A!==null&&window.clearTimeout(A),window.clearTimeout($)}},[null,o,u]),v?v.role==="client"?e.jsx(Ut,{runtimeBaseUrl:v.baseUrl}):e.jsx(ft,{runtimeBaseUrl:v.baseUrl}):e.jsxs("main",{className:"runtime-role-boot","aria-busy":"true","aria-label":"Starting VuvoDesk",children:[e.jsx("span",{className:"runtime-role-boot-mark","aria-hidden":"true"}),e.jsx("strong",{children:"Starting VuvoDesk"}),e.jsx("p",{children:"Loading this computer's assigned role..."})]})}export{en as VuvoDeskApp};
|
|
1
|
+
import{j as e}from"./pwa-startup-C8kDd3Vd.js";import{r,u as te,M as ce,B as Ye,z as qe,H as Qe,I as De,J as Ie,X as Se,S as $e,K as Ze,m as Fe,O as et,Q as ke,U as tt,V as nt,Y as Ne,W as st,Z as it,_ as rt,$ as at,A as ot,a0 as ct}from"./icons-BwhnWKHR.js";import{SupportPage as lt}from"./SupportPage-LJUVsA1x.js";import{s as V,g as Ce,n as ut,r as dt,a as Ee,b as ht,f as Te,A as mt,H as ft}from"./HubApp-BoHzIvar.js";import{DesktopUpdatePanel as pt}from"./DesktopUpdatePanel-BaRZzRao.js";import{M as gt,w as bt,i as wt,D as ne,r as vt,h as xt}from"./MonitorStackIcon-BLNbbRNY.js";import"./pwa-bootstrap-ljOQTt2e.js";import"./public-site-routing-pddZbLCj.js";import"./supabase-C7qjtLN3.js";import"./frame-lifecycle-CNz8ou2A.js";function yt(i=[]){return[...new Set(i.filter(t=>typeof t=="string").map(t=>t.trim()).filter(Boolean))]}function jt(i=[],t=new Set){return i.find(c=>!t.has(c))||""}function St(i=[],t=new Set){const c=new Set(i);return new Set([...t].filter(o=>c.has(o)))}const kt="client-runtime-connection-unavailable",Nt="VuvoDesk Client is reconnecting to the service on this computer.",Ct=/failed to fetch|fetch failed|network request failed|networkerror when attempting to fetch resource|load failed|signal timed out|operation was aborted due to timeout|the operation timed out/i;function Oe(i,t){if(!i||typeof i!="object")return"";const c=i[t];return typeof c=="string"?c.trim():""}function le(i){return typeof i=="string"?i.trim():Oe(i,"message")||String(i??"").trim()}function Re(i){return/supabase-user-verification-failed:(401|403)/i.test(i)?"Saved sign-in needs refresh. VuvoDesk will retry it automatically.":i}function Ae(i){const t=le(i)||"Client status could not be refreshed.",c=Oe(i,"name").toLowerCase();return c==="timeouterror"||c==="aborterror"||Ct.test(t)?{key:kt,message:Nt}:{key:`client-status-poll:${t}`,message:t}}function Et({actionError:i="",discoveryWakeError:t=null,statusPollError:c=null,runtimeError:o=""}={}){const u=le(i);if(u)return{key:`client-action:${u}`,message:Re(u)};if(t?.key&&t?.message)return t;if(c?.key&&c?.message)return c;const p=le(o);return p?{key:`client-runtime:${p}`,message:Re(p)}:null}function Tt(i,t){if(!t?.message)return{nextKey:"",message:null};const c=String(t.key||t.message).trim();return String(i||"")===c?{nextKey:c,message:null}:{nextKey:c,message:t.message}}const Rt=[{id:"docs",label:"Doc",icon:Ye},{id:"support",label:"Support",icon:qe},{id:"pricing",label:"Pricing",icon:Qe},{id:"settings",label:"Settings",icon:De}],Pe=[0,1e3,2e3,5e3,1e4,2e4,3e4],At=15e3;function Pt(i=""){const t=i.trim().replace(/\/+$/,"");return t||(typeof window>"u"?"":window.location.port==="5179"?window.location.origin:"http://127.0.0.1:5179")}async function U(i,t=!1){const c=t?"":sessionStorage.getItem("livedesk.client.csrf");if(c)return c;const o=await fetch(`${i}/api/runtime/status`,{cache:"no-store"}),u=await o.json().catch(()=>({}));if(!o.ok)throw new Error(u.error||`Client runtime returned HTTP ${o.status}.`);const p=String(u.csrfToken||"");return p&&sessionStorage.setItem("livedesk.client.csrf",p),p}function ue(i){return`${Math.max(0,Math.min(100,Number(i||0))).toFixed(0)}%`}function oe(i){return Number.isFinite(i)?`${Math.max(0,Math.min(100,Number(i))).toFixed(0)}%`:"—"}function Me(i){return Number.isFinite(i)?ue(Number(i)):"0%"}function H(i){const t=Number(i);return!Number.isFinite(t)||t<0?"—":t>=1024**4?`${(t/1024**4).toFixed(t>=10*1024**4?0:1)} TB`:t>=1024**3?`${(t/1024**3).toFixed(t>=10*1024**3?0:1)} GB`:`${(t/1024**2).toFixed(0)} MB`}function Le(i){const t=Math.max(0,Number(i||0));return t>=1024**3?`${(t/1024**3).toFixed(1)} GB/s`:t>=1024**2?`${(t/1024**2).toFixed(1)} MB/s`:t>=1024?`${(t/1024).toFixed(1)} KB/s`:`${t.toFixed(0)} B/s`}function Lt(i,t){const c=Number(i||0)/1073741824,o=Number(t||0)/1024**3;return o>0?`${c.toFixed(1)} / ${o.toFixed(1)} GB`:"Checking..."}function Dt(i,t){return!Number.isFinite(t)||Number(t)<=0?"Dedicated memory unavailable":Number.isFinite(i)?`${H(i)} / ${H(t)}`:`${H(t)} available`}function It(i){const t=Math.max(0,Math.floor(Number(i||0)/60)),c=Math.floor(t/1440),o=Math.floor(t%1440/60),u=t%60;return c>0?`${c}d ${o}h`:o>0?`${o}h ${u}m`:`${u}m`}function ee({icon:i,label:t,value:c,detail:o,percent:u}){return e.jsxs("article",{className:"client-resource-metric",children:[e.jsxs("div",{className:"client-resource-metric-head",children:[e.jsx(i,{size:17}),e.jsx("span",{children:t}),e.jsx("strong",{children:c})]}),e.jsx("small",{title:o,children:o}),e.jsx("i",{"aria-hidden":"true",children:e.jsx("b",{style:{width:Me(u)}})})]})}function $t(i,t){const c=i?.user.user_metadata||{},o=c.full_name||c.name||c.preferred_username||i?.user.email||i?.user.id||t?.userName||t?.auth?.name||t?.userEmail||t?.userId||"Account";return String(o).trim()||"Account"}function Ft(i,t){const c=i?.user.user_metadata||{};return yt([c.avatar_url,c.picture,t?.userAvatarUrl,t?.auth?.avatarUrl])}function Ot({page:i,status:t}){const o={docs:{label:"DOC",title:"Using this computer",body:"This computer connects to its assigned Hub automatically. Keep VuvoDesk running and manage screens, files, and remote control from the Hub."},pricing:{label:"PRICING",title:"VuvoDesk plans",body:"Plans are based on how many computers the Hub manages. This Client computer does not need a separate subscription or setup."},settings:{label:"SETTINGS",title:"Computer preferences",body:"VuvoDesk keeps the verified sign-in on this computer and reconnects to the assigned Hub automatically."}}[i];return e.jsxs("section",{className:"client-service-page",children:[e.jsx("span",{className:"client-unified-section-label",children:o.label}),e.jsx("h2",{children:o.title}),e.jsx("p",{children:o.body}),e.jsxs("div",{className:"client-service-page-card",children:[i==="docs"&&e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"Automatic connection"}),e.jsx("span",{children:"Start VuvoDesk. This computer signs in, finds the Hub, and becomes available without another action."})]}),i==="pricing"&&e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"One plan, managed at the Hub"}),e.jsx("span",{children:"Computer access follows the account and plan used by the Hub."})]}),i==="settings"&&e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"Saved sign-in"}),e.jsx("span",{children:t?.auth?.persisted?"Enabled on this computer":"Sign in once to enable automatic reconnection"})]})]}),i==="settings"&&e.jsx(pt,{})]})}function Mt({session:i,status:t,pin:c,roleChangeMessage:o,videoAccelerationBusy:u,slotInput:p,slotBusy:v,onSignIn:R,onPinChange:_,onSubmitPin:C,onSlotInputChange:d,onSaveSlot:A,onEnableVideoAcceleration:k}){const j=t?.connectionState==="connected",g=t?.videoAcceleration,$=u||g?.busy||g?.state==="installing",b=g?.ready?`${g.encoder||"H.264"} · ${g.driver||"VAAPI"}`:$?"Setting up…":g?.message||"Setup available",y=t?.system?.memoryTotalBytes?Number(t.system.memoryUsedBytes||0)/t.system.memoryTotalBytes*100:0,P=t?.system?.gpus||[],w=P.find(h=>Number.isFinite(h.usagePercent)||Number.isFinite(h.memoryTotalBytes))||P[0],z=Number.isFinite(w?.usagePercent)?Number(w?.usagePercent):null,G=Number.isFinite(w?.memoryTotalBytes)&&Number(w?.memoryTotalBytes)>0&&Number.isFinite(w?.memoryUsedBytes)?Number(w?.memoryUsedBytes)/Number(w?.memoryTotalBytes)*100:null,E=t?.system?.disks||[],T=t?.system?.network,B=!!T?.sampledAt,N=T?.interfaces||[],S=[...new Set(N.map(h=>h.name).filter(Boolean))],L=N.map(h=>h.address).filter(Boolean);return e.jsxs("section",{className:"client-home-page",children:[e.jsxs("header",{className:"client-home-heading",children:[e.jsxs("div",{children:[e.jsx("p",{className:"client-unified-eyebrow",children:"THIS COMPUTER"}),e.jsx("h2",{children:t?.deviceName||"This Computer"})]}),e.jsxs("span",{className:`client-unified-role-chip ${j?"connected":""}`,children:[e.jsx(ce,{size:15})," ",j?"Online":"Connecting"]})]}),e.jsxs("div",{className:"client-home-layout",children:[e.jsxs("section",{className:"client-main-surface","aria-label":"Client computer",children:[e.jsxs("div",{className:"client-main-surface-head",children:[e.jsxs("div",{children:[e.jsx("span",{className:"client-unified-section-label",children:"SYSTEM STATUS"}),e.jsx("strong",{children:"Hardware at a glance"})]}),e.jsxs("small",{children:[e.jsx(et,{size:14})," Uptime ",It(t?.system?.uptimeSeconds)]})]}),e.jsxs("div",{className:"client-system-dashboard",children:[e.jsxs("section",{className:"client-performance-panel","aria-label":"Performance",children:[e.jsxs("div",{className:"client-system-subhead",children:[e.jsxs("div",{children:[e.jsx("span",{className:"client-unified-section-label",children:"PERFORMANCE"}),e.jsx("strong",{children:"Live resources"})]}),e.jsx("small",{children:"Live updates"})]}),e.jsxs("div",{className:"client-live-metrics",children:[e.jsx(ee,{icon:ke,label:"CPU",value:ue(t?.system?.cpuUsagePercent),detail:t?.system?.cpuLogicalCores?`${t.system.cpuLogicalCores} logical cores · Current processor usage`:"Current processor usage",percent:t?.system?.cpuUsagePercent}),e.jsx(ee,{icon:tt,label:"Memory",value:ue(y),detail:Lt(t?.system?.memoryUsedBytes,t?.system?.memoryTotalBytes),percent:y}),e.jsx(ee,{icon:nt,label:"GPU",value:oe(z),detail:w?.name||(t?.system?.hardwareCollecting?"Detecting graphics hardware…":"Graphics usage unavailable"),percent:z}),e.jsx(ee,{icon:te,label:"VRAM",value:oe(G),detail:Dt(w?.memoryUsedBytes,w?.memoryTotalBytes),percent:G})]})]}),e.jsxs("section",{className:"client-storage-panel","aria-label":"Local storage",children:[e.jsxs("div",{className:"client-system-subhead",children:[e.jsxs("div",{children:[e.jsx("span",{className:"client-unified-section-label",children:"STORAGE"}),e.jsx("strong",{children:"Local drives"})]}),e.jsx("small",{children:E.length>0?`${E.length} ${E.length===1?"drive":"drives"}`:t?.system?.hardwareCollecting?"Detecting…":"Unavailable"})]}),e.jsxs("div",{className:"client-disk-list",children:[E.map(h=>e.jsxs("article",{className:"client-disk-row",children:[e.jsxs("div",{className:"client-disk-row-head",children:[e.jsxs("span",{children:[e.jsx(Ne,{size:16}),e.jsx("strong",{children:h.mount||"Disk"}),e.jsx("small",{children:h.name||"Local disk"})]}),e.jsx("strong",{children:oe(h.usedPercent)})]}),e.jsxs("small",{children:[H(h.freeBytes)," free · ",H(h.totalBytes)," total"]}),e.jsx("i",{"aria-hidden":"true",children:e.jsx("b",{style:{width:Me(h.usedPercent)}})})]},`${h.mount}-${h.name||""}`)),E.length===0&&e.jsxs("div",{className:"client-disk-empty",children:[e.jsx(Ne,{size:18}),e.jsx("span",{children:t?.system?.hardwareCollecting?"Detecting local drives…":"Storage information is not available."})]})]})]}),e.jsxs("section",{className:"client-network-panel","aria-label":"Network activity",children:[e.jsxs("div",{className:"client-system-subhead",children:[e.jsxs("div",{children:[e.jsx("span",{className:"client-unified-section-label",children:"NETWORK"}),e.jsx("strong",{children:"Live traffic"})]}),e.jsx("small",{children:S.length>0?S.join(", "):"Detecting adapter"})]}),e.jsxs("div",{className:"client-network-live",children:[e.jsxs("div",{className:"client-network-adapter",children:[e.jsx(st,{size:18}),e.jsxs("span",{children:[e.jsx("strong",{children:S.join(", ")||"Network"}),e.jsx("small",{children:L.join(" / ")||"Checking active connection"})]})]}),e.jsxs("div",{className:"client-network-rate download",children:[e.jsx(it,{size:17}),e.jsxs("span",{children:[e.jsx("small",{children:"Receive"}),e.jsx("strong",{children:Le(B?T?.receiveBytesPerSecond:void 0)})]})]}),e.jsxs("div",{className:"client-network-rate upload",children:[e.jsx(rt,{size:17}),e.jsxs("span",{children:[e.jsx("small",{children:"Send"}),e.jsx("strong",{children:Le(B?T?.sendBytesPerSecond:void 0)})]})]}),e.jsx("small",{className:"client-network-total",children:B?`Total ${H(T?.receivedBytes)} received / ${H(T?.sentBytes)} sent`:"Traffic has not been measured yet."})]})]})]})]}),e.jsxs("aside",{className:"client-connection-panel",children:[e.jsx("span",{className:"client-unified-section-label",children:"VUVODESK SERVICES"}),e.jsx("h3",{children:j?"Connected to the Hub":t?.authenticated?"Finding the Hub":"Connect this computer"}),j?e.jsxs(e.Fragment,{children:[e.jsx("p",{className:"client-unified-copy",children:"This computer is available from the VuvoDesk Hub."}),e.jsxs("div",{className:"client-service-status-list",children:[e.jsxs("div",{children:[e.jsx(ce,{size:17}),e.jsxs("span",{children:[e.jsx("strong",{children:"Screen sharing"}),e.jsx("small",{children:t?.permissions?.screenCapture?"Active":"Waiting"})]})]}),e.jsxs("div",{children:[e.jsx($e,{size:17}),e.jsxs("span",{children:[e.jsx("strong",{children:"Remote control"}),e.jsx("small",{children:t?.permissions?.remoteInput?"Available":"Unavailable"})]})]}),e.jsxs("div",{children:[e.jsx(at,{size:17}),e.jsxs("span",{children:[e.jsx("strong",{children:"File delivery"}),e.jsx("small",{children:t?.permissions?.files?"Ready to receive":"Unavailable"})]})]}),e.jsxs("div",{children:[e.jsx(ot,{size:17}),e.jsxs("span",{children:[e.jsx("strong",{children:"Computer audio"}),e.jsx("small",{children:t?.permissions?.audio?"Available":"Unavailable"})]})]})]})]}):e.jsxs(e.Fragment,{children:[e.jsx("p",{className:"client-unified-copy",children:t?.authenticated?"VuvoDesk is checking the registered Hub endpoints. A temporary Hub PIN can be used as a fallback.":"Sign in once on this computer. VuvoDesk saves the verified session, finds the Hub, and starts screen sharing automatically."}),!i&&!t?.authenticated?e.jsxs("button",{className:"client-unified-primary",type:"button",onClick:R,children:[e.jsx(Ie,{size:16})," Sign in with Google"]}):e.jsxs("p",{className:"client-unified-success",children:[e.jsx(Fe,{size:16})," Signed in as ",i?.user.email||i?.user.id||t?.userEmail||t?.userId||"saved account"]}),e.jsxs("div",{className:"client-unified-pin-row",children:[e.jsx(ct,{size:16}),e.jsx("input",{value:c,onChange:h=>_(h.target.value),placeholder:"6-digit Hub PIN",inputMode:"numeric","aria-label":"6-digit Hub PIN"}),e.jsx("button",{className:"client-unified-secondary",type:"button",onClick:C,disabled:c.length!==6,children:"Connect"})]})]}),g?.supported&&e.jsxs("div",{className:`client-video-acceleration state-${g.ready?"ready":g.state||"setup-required"}`,children:[e.jsx(ke,{size:17}),e.jsxs("span",{children:[e.jsx("strong",{children:"Hardware video"}),e.jsx("small",{children:b})]}),!g.ready&&g.canInstall&&e.jsx("button",{type:"button",onClick:k,disabled:$,title:"Install and verify Linux FFmpeg hardware video support",children:$?"Setting up":"Enable"})]}),o&&e.jsx("p",{className:"client-unified-success",children:o}),e.jsxs("div",{className:"client-slot-setting",children:[e.jsxs("label",{htmlFor:"client-slot-number",children:[e.jsx("span",{children:"Slot"}),e.jsx("input",{id:"client-slot-number",value:p,onChange:h=>d(h.target.value),inputMode:"numeric",pattern:"[0-9]*",placeholder:"1-999","aria-label":"Wall slot number",disabled:!j||v})]}),e.jsxs("button",{type:"button",onClick:A,disabled:!j||v||!p,"aria-label":"Save slot number",title:"Save slot number",children:[e.jsx(De,{size:17}),e.jsx("span",{children:v?"Saving":"Set"})]})]})]})]})]})}function Ut({runtimeBaseUrl:i=""}){const[t,c]=r.useState(null),[o,u]=r.useState(null),[p,v]=r.useState(!1),[R,_]=r.useState(""),[C,d]=r.useState(""),[A,k]=r.useState(null),[j,g]=r.useState(null),[$,b]=r.useState(""),[y,P]=r.useState(!1),[w,z]=r.useState(!1),[G,E]=r.useState(""),[T,B]=r.useState(!1),[N,S]=r.useState(null),[L,h]=r.useState(!1),[D,de]=r.useState("computer"),[he,Y]=r.useState(!1),me=r.useRef(null),fe=r.useRef(null),se=r.useRef(!1),q=r.useRef(null),Q=r.useRef(null),pe=r.useRef(!1),K=r.useRef(!1),ge=r.useRef(0),ie=r.useRef(!1),be=r.useRef(""),m=r.useMemo(()=>Pt(i),[i]),re=r.useMemo(()=>$t(o,t),[o,t]),ae=r.useMemo(()=>Ft(o,t),[o,t]),Ue=JSON.stringify(ae),[He,we]=r.useState(()=>new Set),W=jt(ae,He),ve=re.slice(0,1).toUpperCase()||"L";r.useEffect(()=>{we(n=>St(ae,n))},[Ue]);const _e=r.useCallback(n=>{we(s=>{if(!n||s.has(n))return s;const a=new Set(s);return a.add(n),a})},[]),F=r.useCallback(async()=>{if(d(""),window.liveDesk?.auth?.signInWithGoogle){const n=await window.liveDesk.auth.signInWithGoogle();return n?.ok===!1?(d(n.error||"VuvoDesk could not open the system browser for Google sign-in."),!1):!0}return window.location.assign(`${m}/auth/google`),!0},[m]),xe=r.useCallback(async()=>{K.current||(K.current=!0,d("Your saved Google sign-in is incomplete. VuvoDesk is reopening sign-in once to repair it."),await V.auth.signOut({scope:"local"}).catch(()=>{}),u(null),await F()||(K.current=!1))},[F]),ye=r.useCallback(async n=>{const s=Ce(n);if(s)throw new Error(s);if(se.current)return!1;se.current=!0;try{if(window.liveDesk?.auth?.persistSession){const a=await window.liveDesk.auth.persistSession(n);if(a?.ok===!1)throw new Error(a.error||"VuvoDesk could not validate the desktop session.");return d(""),!0}for(let a=0;a<2;a+=1){const l=await U(m,a>0),f=await fetch(`${m}/api/auth/session`,{method:"POST",headers:{"Content-Type":"application/json","X-LiveDesk-CSRF":l},signal:AbortSignal.timeout(1e4),body:JSON.stringify({accessToken:n.access_token,refreshToken:n.refresh_token,expiresAt:n.expires_at,user:{id:n.user.id,email:n.user.email}})}),M=await f.json().catch(()=>({}));if(f.status===403&&a===0){sessionStorage.removeItem("livedesk.client.csrf");continue}if(!f.ok)throw new Error(M.error||`Client runtime returned HTTP ${f.status}.`);return d(""),!0}throw new Error("Client runtime rejected the session transfer.")}finally{se.current=!1}},[m]),x=r.useCallback(()=>{const n=q.current;if(n)return n;const s=(async()=>{try{const a=await fetch(`${m}/api/client/status`,{cache:"no-store",signal:AbortSignal.timeout(1500)}),l=await a.json().catch(()=>({}));if(!a.ok)throw new Error(l.error||`Client runtime returned HTTP ${a.status}.`);if(l.csrfToken&&sessionStorage.setItem("livedesk.client.csrf",l.csrfToken),String(l.role||"").toLowerCase()==="hub")throw new Error("This computer is assigned to the Hub role.");c(l),k(null),g(null)}catch(a){k(Ae(a))}})();return q.current=s,s.finally(()=>{q.current===s&&(q.current=null)}),s},[m]),je=r.useCallback(()=>{const n=Q.current;if(n)return n;const s=(async()=>{const a=await fetch(`${m}/api/client/diagnostics`,{cache:"no-store",signal:AbortSignal.timeout(8e3)}),l=await a.json().catch(()=>({}));if(!a.ok)throw new Error(l.error||`Client diagnostics returned HTTP ${a.status}.`);if(String(l.role||"").toLowerCase()==="hub")throw new Error("This computer is assigned to the Hub role.");c(l)})();return Q.current=s,s.finally(()=>{Q.current===s&&(Q.current=null)}),s},[m]);r.useEffect(()=>{let n=!1,s=null;const a=async()=>{await x(),n||(s=window.setTimeout(()=>{a()},2e3))};return a(),()=>{n=!0,s!==null&&window.clearTimeout(s)}},[x]),r.useEffect(()=>{if(D!=="computer")return;let n=!1,s=null;const a=()=>{n||(s=window.setTimeout(()=>{l()},At))},l=async()=>{document.visibilityState==="visible"&&await je().catch(()=>{}),a()},f=()=>{document.visibilityState==="visible"&&(s!==null&&(window.clearTimeout(s),s=null),l())};return document.addEventListener("visibilitychange",f),l(),()=>{n=!0,document.removeEventListener("visibilitychange",f),s!==null&&window.clearTimeout(s)}},[D,je]),r.useEffect(()=>{if(ie.current)return;const n=Number(t?.slotNumber||0);E(n>0?String(n):"")},[t?.slotNumber]),r.useEffect(()=>{if(!N)return;const n=window.setTimeout(()=>S(null),5e3);return()=>window.clearTimeout(n)},[N]),r.useEffect(()=>{const n=Et({actionError:C,discoveryWakeError:j,statusPollError:A,runtimeError:t?.lastError}),s=Tt(be.current,n);be.current=s.nextKey,s.message&&S({kind:"error",message:s.message})},[j,C,A,t?.lastError]);const Z=r.useCallback(async()=>{const n=Date.now();if(!(!t?.authenticated||t.connectionState==="connected"||!["waiting","reconnecting"].includes(String(t.agent?.state||""))||n-ge.current<4e3)){ge.current=n;try{const s=await fetch(`${m}/api/client/reconnect`,{method:"POST",headers:{"Content-Type":"application/json","X-LiveDesk-CSRF":await U(m)},body:JSON.stringify({onlyIfWaiting:!0,reason:"app-active"})});if(!s.ok)throw new Error(`Client reconnect returned HTTP ${s.status}.`);g(null),await x()}catch(s){g(Ae(s))}}},[m,x,t]);r.useEffect(()=>{const n=()=>{Z()},s=()=>{Z()},a=()=>{document.visibilityState==="visible"&&Z()};return window.addEventListener("online",n),window.addEventListener("focus",s),document.addEventListener("visibilitychange",a),()=>{window.removeEventListener("online",n),window.removeEventListener("focus",s),document.removeEventListener("visibilitychange",a)}},[Z]),r.useEffect(()=>{if(!p||!t||!o?.access_token||t.authenticated)return;if(Ce(o)==="refresh-token-required"){xe().catch(f=>{K.current=!1,d(f instanceof Error?f.message:String(f))});return}let n=!1,s,a=0;const l=async()=>{if(n)return;try{const M=await ye(o);if(await x(),M)return}catch(M){d(M instanceof Error?M.message:String(M))}if(n)return;const f=Pe[Math.min(a,Pe.length-1)];a+=1,s=window.setTimeout(()=>{l()},f)};return l(),()=>{n=!0,s!==void 0&&window.clearTimeout(s)}},[p,x,xe,o,t,ye]),r.useEffect(()=>{const n=new URLSearchParams(window.location.search),s=n.get("auth_error");if(!s)return;d(s),n.delete("auth_error");const a=n.toString();window.history.replaceState(window.history.state,"",`${window.location.pathname}${a?`?${a}`:""}${window.location.hash}`)},[]),r.useEffect(()=>{let n=!0;if(!window.liveDesk?.auth)return u(null),v(!0),x(),()=>{n=!1};const s=window.liveDesk?.auth?.onComplete?.(l=>{l.ok&&l.session?V.auth.setSession(l.session).catch(f=>d(f instanceof Error?f.message:String(f))):l.ok&&l.signedOut?(u(null),v(!0),V.auth.signOut({scope:"local"})):l.error&&d(l.error)});(async()=>{try{const l=window.liveDesk?.auth?.getSession?await window.liveDesk.auth.getSession():await V.auth.getSession();if(!n)return;const f=ut(l);u(f),x()}catch(l){n&&d(l instanceof Error?l.message:String(l))}finally{n&&v(!0)}})();const{data:a}=V.auth.onAuthStateChange((l,f)=>{if(n){if(!f&&window.liveDesk?.auth){v(!0);return}u(f),v(!0),x()}});return()=>{n=!1,s?.(),a.subscription.unsubscribe()}},[x]),r.useEffect(()=>{if(!p||!t||pe.current||K.current||o||t.authenticated)return;const n=new URLSearchParams(window.location.search);if(!n.has("livedesk_launch"))return;pe.current=!0,n.delete("livedesk_launch");const s=n.toString();window.history.replaceState(window.history.state,"",`${window.location.pathname}${s?`?${s}`:""}${window.location.hash}`),F().catch(a=>d(a instanceof Error?a.message:String(a)))},[p,o,F,t]);const Be=async()=>{Y(!1),window.liveDesk?.auth?.signOut?(await V.auth.signOut({scope:"local"}),(await window.liveDesk.auth.signOut())?.runtimeCleared===!1&&d("Signed out locally. The VuvoDesk runtime could not be reached to clear its session.")):await fetch(`${m}/api/auth/session`,{method:"DELETE",headers:{"X-LiveDesk-CSRF":await U(m)}}).catch(()=>{}),u(null),await x()},X=r.useCallback((n=!0)=>{y||(h(!1),n&&window.requestAnimationFrame(()=>fe.current?.focus()))},[y]),Ve=r.useCallback(()=>{y||!t?.authenticated||(fe.current=document.activeElement instanceof HTMLElement?document.activeElement:null,b(""),h(!0))},[y,t?.authenticated]);r.useEffect(()=>{if(!L)return;const n=window.requestAnimationFrame(()=>me.current?.focus()),s=l=>{l.target instanceof Element&&l.target.closest(".client-hub-switch-popover, .client-hub-switch-trigger")||X(!1)},a=l=>{l.key==="Escape"&&X()};return window.addEventListener("pointerdown",s),window.addEventListener("keydown",a),()=>{window.cancelAnimationFrame(n),window.removeEventListener("pointerdown",s),window.removeEventListener("keydown",a)}},[X,L]);const ze=async()=>{d("");try{const n=await fetch(`${m}/api/client/pin`,{method:"POST",headers:{"Content-Type":"application/json","X-LiveDesk-CSRF":await U(m)},body:JSON.stringify({pin:R})}),s=await n.json().catch(()=>({}));if(!n.ok||s?.ok===!1)throw new Error(s?.error||"PIN could not be accepted.");_(""),await x()}catch(n){d(n instanceof Error?n.message:String(n))}},Ge=async()=>{h(!1),P(!0),b(""),d("");try{const n=await fetch(`${m}/api/runtime/switch-role`,{method:"POST",headers:{"Content-Type":"application/json","X-LiveDesk-CSRF":await U(m)},body:JSON.stringify({role:"hub"})}),s=await n.json().catch(()=>({}));if(!n.ok||s?.ok===!1)throw new Error(s?.error||`Role change failed with HTTP ${n.status}.`);b("Hub role accepted. VuvoDesk is restarting this computer with the Hub Wall.");const a=Number(t?.runtimePid||0);await bt({baseUrl:m,targetRole:"hub",previousRuntimePid:a,allowedStates:["running"]}),window.location.reload()}catch(n){d(n instanceof Error?n.message:String(n)),P(!1)}},Ke=async()=>{if(T)return;const n=Number(G);if(!Number.isInteger(n)||n<1||n>999){S({kind:"error",message:"Enter a slot number from 1 to 999."});return}B(!0),S(null);try{const s=await fetch(`${m}/api/client/slot`,{method:"POST",headers:{"Content-Type":"application/json","X-LiveDesk-CSRF":await U(m)},body:JSON.stringify({slotNumber:n})}),a=await s.json().catch(()=>({}));if(!s.ok||a.ok===!1){if(a.error==="slot-taken"){const l=a.conflict?.deviceName||a.conflict?.hostname||a.conflict?.deviceId||"another computer";throw new Error(`Slot ${String(n).padStart(3,"0")} is already used by ${l}.`)}throw new Error(a.error||`Slot update failed with HTTP ${s.status}.`)}ie.current=!1,E(String(n)),c(a),S({kind:"success",message:`Slot ${String(n).padStart(3,"0")} saved. VuvoDesk is reconnecting this Client.`})}catch(s){S({kind:"error",message:s instanceof Error?s.message:String(s)})}finally{B(!1),await x()}},We=async()=>{if(!w){z(!0),d("");try{const n=await fetch(`${m}/api/client/video-acceleration/install`,{method:"POST",headers:{"Content-Type":"application/json","X-LiveDesk-CSRF":await U(m)},body:JSON.stringify({confirm:!0})}),s=await n.json().catch(()=>({}));if(c(s),!n.ok||s.videoAcceleration?.ready!==!0)throw new Error(s.videoAcceleration?.error||s.error||"Linux hardware video setup did not complete.")}catch(n){d(n instanceof Error?n.message:String(n))}finally{z(!1),await x()}}},I=!!(t?.authenticated||o),J=r.useMemo(()=>dt(),[]),Xe=Ee("switch-to-hub",J),Je=Ee("client",J),O=ht(J);return e.jsxs("main",{className:"app-shell client-unified-shell",children:[e.jsxs("aside",{className:"tool-rail","aria-label":"VuvoDesk Client tools",children:[e.jsx("div",{className:"rail-brand",title:"VuvoDesk",children:e.jsx(gt,{size:25})}),e.jsx("nav",{className:"rail-tools","aria-label":"Client navigation",children:e.jsxs("div",{className:"client-main-tool-slot",children:[e.jsxs("button",{className:"rail-tool client-main-tool client-hub-tool client-hub-switch-trigger accent-blue",type:"button",onClick:Ve,disabled:y||!t?.authenticated,"aria-busy":y,"aria-expanded":L,"aria-haspopup":"dialog","aria-controls":L?"client-hub-switch-popover":void 0,"aria-label":`Hub. ${Xe}`,"data-tooltip":L?void 0:Te("Hub","switch-to-hub",J),children:[e.jsx(te,{size:19}),e.jsx("span",{children:y?"Switching…":"Hub"})]}),e.jsxs("button",{className:`rail-tool client-main-tool accent-blue ${D==="computer"?"active":""}`,type:"button",onClick:()=>de("computer"),"aria-current":D==="computer"?"page":void 0,"aria-label":`Client. ${Je}`,"data-tooltip":Te("Client","client",J),children:[e.jsx(ce,{size:19}),e.jsx("span",{children:"Client"})]})]})}),e.jsxs("div",{className:"rail-footer",children:[Rt.map(n=>{const s=n.icon;return e.jsxs("button",{className:`rail-tool compact ${D===n.id?"active":""}`,type:"button",onClick:()=>de(n.id),title:n.label,children:[e.jsx(s,{size:18}),e.jsx("span",{children:n.label})]},n.id)}),e.jsxs("button",{className:`rail-account ${I?"signed-in":""}`,type:"button",onClick:()=>Y(n=>!n),"aria-expanded":he,"aria-haspopup":"dialog","aria-controls":"vuvodesk-account-dialog",title:I?"Account":"Sign in",children:[I&&W?e.jsx("img",{src:W,alt:re,referrerPolicy:"no-referrer",onError:()=>_e(W)},W):I?e.jsx("span",{className:"avatar-fallback",children:ve}):e.jsx(Ie,{size:18}),e.jsx("span",{children:I?"Account":"Sign in"})]})]})]}),L&&e.jsxs("section",{id:"client-hub-switch-popover",className:"client-hub-switch-popover",role:"dialog","aria-modal":"false","aria-labelledby":"client-hub-switch-title","aria-describedby":"client-hub-switch-description client-hub-switch-restart",children:[e.jsxs("header",{className:"client-hub-switch-head",children:[e.jsx("span",{className:"client-hub-switch-mark","aria-hidden":"true",children:e.jsx(te,{size:19})}),e.jsx("span",{className:"client-hub-switch-eyebrow",children:O.eyebrow}),e.jsx("button",{className:"client-hub-switch-close",type:"button",onClick:()=>X(),"aria-label":O.closeLabel,children:e.jsx(Se,{size:17})})]}),e.jsx("h2",{id:"client-hub-switch-title",children:O.title}),e.jsx("p",{id:"client-hub-switch-description",children:O.description}),e.jsxs("p",{id:"client-hub-switch-restart",className:"client-hub-switch-notice",children:[e.jsx($e,{size:16,"aria-hidden":"true"}),e.jsx("span",{children:O.restartNotice})]}),e.jsxs("div",{className:"client-hub-switch-actions",children:[e.jsx("button",{type:"button",onClick:()=>X(),children:O.cancel}),e.jsxs("button",{ref:me,className:"primary",type:"button",onClick:()=>{Ge()},disabled:y||!t?.authenticated,children:[e.jsx(te,{size:16}),O.confirm]})]})]}),e.jsx(mt,{open:he,signedIn:I,accountName:I?re:"Account",accountEmail:o?.user.email||t?.userEmail||t?.userId||"",accountInitial:ve,avatarUrl:W,currentPlan:"free",currentPlanKnown:!1,deviceCount:t?1:0,deviceLimit:Number.POSITIVE_INFINITY,licenseLabel:"Plan is managed at the Hub. This Client does not choose or change billing.",networkLabel:t?.connectionState==="connected"?"Connected to Hub":t?"Finding Hub":"Checking local app",accessLabel:t?.auth?.persisted?"Saved sign-in on this computer":I?"Active for this run":"Not signed in",authBusy:!p,checkoutBusy:!1,ltdCheckoutEnabled:!1,monthlyCheckoutEnabled:!1,teamCheckoutEnabled:!1,planChangesEnabled:!1,planManagementLabel:"Plan is managed at the Hub",showWorkspaceSwitcher:!1,workspaces:[],activeWorkspaceId:"",onClose:()=>Y(!1),onSignIn:async()=>{Y(!1),await F()},onSignOut:Be,onSelectPlan:()=>{}}),e.jsx("section",{className:"desk-stage client-unified-stage",children:D==="support"?e.jsx("section",{className:"client-unified-page",children:e.jsx(lt,{session:o,currentProductKey:"livedesk",appVersion:t?.appVersion||"",onSignIn:()=>{F()}})}):D!=="computer"?e.jsx("section",{className:"client-unified-page",children:e.jsx(Ot,{page:D,status:t})}):e.jsx(Mt,{session:o,status:t,pin:R,roleChangeMessage:$,videoAccelerationBusy:w,slotInput:G,slotBusy:T,onSignIn:()=>{F()},onPinChange:n=>_(n.replace(/\D/g,"").slice(0,6)),onSubmitPin:()=>{ze()},onSlotInputChange:n=>{ie.current=!0,E(n.replace(/\D/g,"").slice(0,3))},onSaveSlot:()=>{Ke()},onEnableVideoAcceleration:()=>{We()}})}),N&&e.jsxs("div",{className:`client-side-toast ${N.kind}`,role:N.kind==="error"?"alert":"status",children:[N.kind==="error"?e.jsx(Ze,{size:18}):e.jsx(Fe,{size:18}),e.jsx("span",{children:N.message}),e.jsx("button",{type:"button",onClick:()=>S(null),"aria-label":"Dismiss notification",children:e.jsx(Se,{size:16})})]})]})}const Ht=1e3,_t=5e3;function Bt(){return typeof window>"u"?!1:(!!window.navigator.standalone||window.matchMedia("(display-mode: standalone), (display-mode: fullscreen)").matches)&&window.matchMedia("(pointer: coarse)").matches}function Vt(){return typeof window>"u"?[]:[...new Set([window.location.origin,ne].filter(Boolean))]}function en(){const t=wt(),c=Bt(),o=t||c,u=t||typeof window>"u"?ne:window.location.origin,p=o?{role:"hub",baseUrl:u}:null,[v,R]=r.useState(p),_=r.useRef(null);return r.useEffect(()=>{if(o){R(b=>b?.role==="hub"&&b.baseUrl===u?b:{role:"hub",baseUrl:u});return}let C=!1,d=!1,A=null;const k=new AbortController,j=async()=>{for(const b of Vt()){if(k.signal.aborted)return;try{const P=(await xt("/api/runtime/status",{signal:k.signal,timeoutMs:900},b)).role==="hub"?"hub":"client";d=!0,C||R(w=>w?.role===P&&w.baseUrl===b?w:{role:P,baseUrl:b});return}catch{if(k.signal.aborted)return}}},g=()=>{vt(_,j).finally(()=>{!C&&!k.signal.aborted&&(A=window.setTimeout(g,d?_t:Ht))}).catch(()=>{})};g();const $=window.setTimeout(()=>{!C&&!d&&R(b=>b?.role==="client"&&b.baseUrl===ne?b:{role:"client",baseUrl:ne})},2500);return()=>{C=!0,k.abort(new Error("VuvoDesk runtime role probe stopped.")),A!==null&&window.clearTimeout(A),window.clearTimeout($)}},[null,o,u]),v?v.role==="client"?e.jsx(Ut,{runtimeBaseUrl:v.baseUrl}):e.jsx(ft,{runtimeBaseUrl:v.baseUrl}):e.jsxs("main",{className:"runtime-role-boot","aria-busy":"true","aria-label":"Starting VuvoDesk",children:[e.jsx("span",{className:"runtime-role-boot-mark","aria-hidden":"true"}),e.jsx("strong",{children:"Starting VuvoDesk"}),e.jsx("p",{children:"Loading this computer's assigned role..."})]})}export{en as VuvoDeskApp};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/client-
|
|
2
|
-
import{r as d,i as u,_ as r}from"./public-site-routing-pddZbLCj.js";import{m as w,t as _,s as m,r as v}from"./pwa-bootstrap-ljOQTt2e.js";const h=8e3,f="http://127.0.0.1:5179".replace(/\/+$/,"");function E(a){const e=document.querySelector("[data-vuvodesk-static-boot]");if(!e?.isConnected)return;e.setAttribute("aria-busy","false"),e.querySelector(".vuvodesk-static-boot-mark")?.remove();const n=e.querySelector("[data-vuvodesk-static-boot-title]"),t=e.querySelector("[data-vuvodesk-static-boot-detail]"),i=e.querySelector("[data-vuvodesk-static-boot-retry]");n&&(n.textContent="VuvoDesk could not start",n.hidden=!1),t&&(t.textContent=a,t.hidden=!1),i&&(i.hidden=!1)}async function P(){let a=!1;const e=async t=>{if(a)return;a=!0,window.clearTimeout(n),await v("load-error",!0)||E(t)},n=window.setTimeout(()=>{e("The console files took too long to load. Check the connection, then try again.")},h);try{const[t,i,l,c]=await Promise.all([r(()=>import("./icons-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/client-DV0v4wud.js","assets/icons-BwhnWKHR.js","assets/react-Dm67yaJf.js","assets/HubApp-BoHzIvar.js","assets/public-site-routing-pddZbLCj.js","assets/pwa-startup-C8kDd3Vd.js","assets/pwa-bootstrap-ljOQTt2e.js","assets/MonitorStackIcon-BLNbbRNY.js","assets/supabase-C7qjtLN3.js","assets/frame-lifecycle-CNz8ou2A.js","assets/HubApp-C-E5cpCr.css","assets/styles-CQz52HHV.css"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{r as d,i as u,_ as r}from"./public-site-routing-pddZbLCj.js";import{m as w,t as _,s as m,r as v}from"./pwa-bootstrap-ljOQTt2e.js";const h=8e3,f="http://127.0.0.1:5179".replace(/\/+$/,"");function E(a){const e=document.querySelector("[data-vuvodesk-static-boot]");if(!e?.isConnected)return;e.setAttribute("aria-busy","false"),e.querySelector(".vuvodesk-static-boot-mark")?.remove();const n=e.querySelector("[data-vuvodesk-static-boot-title]"),t=e.querySelector("[data-vuvodesk-static-boot-detail]"),i=e.querySelector("[data-vuvodesk-static-boot-retry]");n&&(n.textContent="VuvoDesk could not start",n.hidden=!1),t&&(t.textContent=a,t.hidden=!1),i&&(i.hidden=!1)}async function P(){let a=!1;const e=async t=>{if(a)return;a=!0,window.clearTimeout(n),await v("load-error",!0)||E(t)},n=window.setTimeout(()=>{e("The console files took too long to load. Check the connection, then try again.")},h);try{const[t,i,l,c]=await Promise.all([r(()=>import("./icons-BwhnWKHR.js").then(o=>o.i),[]),r(()=>import("./client-DV0v4wud.js").then(o=>o.c),__vite__mapDeps([0,1,2])),r(()=>import("./HubApp-BoHzIvar.js").then(o=>o.e),__vite__mapDeps([3,4,5,1,6,7,8,9,10])),r(()=>import("./pwa-startup-C8kDd3Vd.js").then(o=>o.p),__vite__mapDeps([5,1,6])),r(()=>Promise.resolve({}),__vite__mapDeps([11]))]);if(a)return;a=!0,window.clearTimeout(n),i.createRoot(document.getElementById("root")).render(t.createElement(t.StrictMode,null,t.createElement(c.PwaStartupBoundary,{automaticRetry:!0,children:t.createElement(l.HubApp,{runtimeBaseUrl:f})}))),c.takeOverStaticBoot()}catch(t){console.warn("[VuvoDesk] PWA console load failed.",t),await e(window.navigator.onLine?"The latest console file could not be loaded.":"Reconnect to the internet, then try again.")}}w();const s=d({publicOrigin:u(window.location),electron:!!window.liveDesk,pathname:window.location.pathname,search:window.location.search,hash:window.location.hash,hostname:window.location.hostname,userAgent:window.navigator.userAgent,maxTouchPoints:window.navigator.maxTouchPoints});s.kind==="site"?window.location.replace(s.redirectPath||"/download"):(_(),m(),P());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{g as c}from"./icons-
|
|
1
|
+
import{g as c}from"./icons-BwhnWKHR.js";import{r as s}from"./react-Dm67yaJf.js";function f(r,a){for(var o=0;o<a.length;o++){const e=a[o];if(typeof e!="string"&&!Array.isArray(e)){for(const t in e)if(t!=="default"&&!(t in r)){const n=Object.getOwnPropertyDescriptor(e,t);n&&Object.defineProperty(r,t,n.get?n:{enumerable:!0,get:()=>e[t]})}}}return Object.freeze(Object.defineProperty(r,Symbol.toStringTag,{value:"Module"}))}var i=s();const l=c(i),g=f({__proto__:null,default:l},[i]);export{i as a,g as c};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function p(e,t=void 0){if(!e||e.disposed===!0||t!==void 0&&e.workspaceOwnerKey!==t)return!1;const n=Number(e.socket?.readyState);return n===0||n===1}function M(e,t,n){return p(e,n)?Number(e.socket.readyState)===0||e.reconnectRevision!==t||!!(e.handoffFrom&&!e.handoffCompleted):!1}function v(e){const t=e.handoffFrom;return e.handoffFrom=void 0,t}function T(e,t,n=void 0){return typeof e?.payloadKey=="string"&&e.restartMayHaveApplied!==!0&&!e.sentForceRestartToken&&e.payloadKey===t?.payloadKey&&p(t,n)}function y(e,t){if(!e||!t)return!1;const n=String(t.deviceId||"").trim(),s=String(t.connectionSessionId||"").trim(),r=Number(t.monitorIndex),c=t.streamPurpose==="control"?"control":"wall",a=e.streamPurpose===c,i=c==="wall"&&t.allowReadOnlyControlBorrow===!0&&e.streamPurpose==="control"&&e.readOnlyControlBorrow===!0&&e.presentationPurpose==="wall";return!!n&&e.deviceId===n&&(!s||e.sessionId===s)&&Number.isSafeInteger(r)&&r>=0&&e.monitorIndex===r&&(a||i)}function R(e,t,n){const s=e?.sentForceRestartToken,r=!!s&&n?.get?.(t)===s;return r&&n.delete(t),e&&(e.sentForceRestartToken=void 0),r}function _(e,t,n,s=void 0){const r=[],c=new Set;for(const a of Array.isArray(e)?e:[]){const i=String(a||"").trim();!i||c.has(i)||(c.add(i),!p(t?.get?.(i),s)&&(n?.has?.(i)||r.push(i)))}return r}function x(e={}){const t=Math.max(10,Math.min(1e4,Number(e.closeDeadlineMs)||1500)),n=typeof e.setTimeout=="function"?e.setTimeout:setTimeout,s=typeof e.clearTimeout=="function"?e.clearTimeout:clearTimeout,r=new Set,c=new WeakMap;let a=0,i=0;const f=(d,I)=>{if(!d||d.settled)return!1;d.settled=!0,d.timer!==null&&(s(d.timer),d.timer=null);try{d.socket.removeEventListener?.("close",d.handleClose)}catch{}return r.delete(d),c.delete(d.entry),I&&(a+=1),!0};return Object.freeze({beginClosing(d,I="livedesk-frame-socket-release"){if(!d?.socket||c.has(d))return!1;const u=d.socket;if(Number(u.readyState)===3)return!1;const m={entry:d,socket:u,timer:null,settled:!1,handleClose:null};m.handleClose=()=>f(m,!1),c.set(d,m),r.add(m),i=Math.max(i,r.size);try{u.addEventListener?.("close",m.handleClose)}catch{}m.timer=n(()=>{if(!m.settled){try{u.close()}catch{}f(m,Number(u.readyState)!==3)}},t);try{Number(u.readyState)===0||Number(u.readyState)===1?u.close(1e3,I):u.close()}catch{try{u.close()}catch{}}return Number(u.readyState)===3&&f(m,!1),!0},snapshot(){return{closingSocketCount:r.size,closingSocketTimerCount:[...r].filter(d=>d.timer!==null).length,closingSocketTimeoutCount:a,maximumClosingSocketCount:i}}})}function b(e,t="livedesk-frame-socket-release",n=null){if(!e)return 0;const s=[e],r=new Set;let c=0;for(;s.length>0;){const a=s.pop();if(!a||r.has(a))continue;r.add(a);const i=a.handoffFrom;a.handoffFrom=void 0,i&&!r.has(i)&&s.push(i);const f=a.disposed===!0;a.disposed=!0,a.handoffCompleted=!0;const d=a.detachListeners;a.detachListeners=void 0;try{d?.()}catch{}const I=a.releaseOwnedState;a.releaseOwnedState=void 0;try{I?.()}catch{}if(!f){if(n?.beginClosing)n.beginClosing(a,t);else try{a.socket.readyState===0||a.socket.readyState===1?a.socket.close(1e3,t):a.socket.close()}catch{try{a.socket.close()}catch{}}c+=1}}return c}const C=new Set(["not-connected","device-not-connected"]);function F(e,t=!1){const n=String(e||"").trim().toLowerCase();return n==="capture_transition_in_progress".toLowerCase()?t===!0:C.has(n)}function A({restartAttempts:e,healthySinceAt:t,previousPaintAt:n,paintedAt:s,maximumHealthyGapMs:r,stableForMs:c}={}){const a=Math.max(0,Math.floor(Number(e)||0)),i=Math.max(0,Number(s)||0),f=Math.max(0,Number(n)||0),d=Math.max(1,Number(r)||1),I=Math.max(1,Number(c)||1);if(a<=0||i<=0)return{healthySinceAt:0,resetAttempts:!1};const u=Math.max(0,Number(t)||0),m=f>0&&i>=f&&i-f<=d,N=m?u>0?u:f:i;return{healthySinceAt:N,resetAttempts:m&&i-N>=I}}function l(e){const t=Number(e);return Number.isSafeInteger(t)&&t>0?t:0}function o(e){return String(e||"").trim()}function G(e,t,n={}){return{deviceId:o(e),transitionGeneration:l(t),sessionId:o(n.sessionId),streamId:o(n.streamId),commandId:o(n.commandId),captureGeneration:l(n.captureGeneration),monitorIndex:Math.max(0,Math.floor(Number(n.monitorIndex)||0))}}function h(e,t){return!!e&&!!t&&o(e.deviceId)===o(t.deviceId)&&l(e.transitionGeneration)===l(t.transitionGeneration)}function S(e){return!!e&&!!o(e.deviceId)&&l(e.transitionGeneration)>0&&!!o(e.sessionId)&&!!o(e.streamId)&&!!o(e.commandId)&&l(e.captureGeneration)>0&&Number.isSafeInteger(Number(e.monitorIndex))&&Number(e.monitorIndex)>=0}function g(e,t){if(!e||S(e)||!S(t)||!h(e,t))return!1;const n=o(e.sessionId),s=o(t.sessionId);return!!n&&n===s&&Number(e.monitorIndex)===Number(t.monitorIndex)}function L(e,t,n){const s=Number(n);return!!e&&S(t)&&h(e,t)&&k(e,t.deviceId,t.sessionId)&&Number.isSafeInteger(s)&&s>=0&&Number(t.monitorIndex)===s}function P(e){return o(e).toLowerCase()==="connecting"?"active":e}function E(e,t){return S(e)&&S(t)&&h(e,t)&&o(e.sessionId)===o(t.sessionId)&&o(e.streamId)===o(t.streamId)&&o(e.commandId)===o(t.commandId)&&l(e.captureGeneration)===l(t.captureGeneration)&&Number(e.monitorIndex)===Number(t.monitorIndex)}function B(e,t){if(!h(e,t))return!1;const n=S(e),s=S(t);if(n||s)return E(e,t);const r=o(e.sessionId),c=o(t.sessionId);return!!r&&r===c&&Number(e.monitorIndex)===Number(t.monitorIndex)}function k(e,t,n){const s=o(t),r=o(n);return!!e&&!!s&&!!r&&o(e.deviceId)===s&&o(e.sessionId)===r}function D({deviceId:e,requestTransitionGeneration:t,currentTransitionGeneration:n,actualControlOwner:s}){const r=o(e),c=l(t),a=l(n);return!!r&&c>0&&c===a&&(!s||o(s.deviceId)===r)}function z(e,t){const n=Promise.resolve(e).catch(()=>{}).then(t);return{result:n,tail:n.then(()=>{},()=>{})}}function K(e,t,n){const s=o(e);return!s||!t||o(t.deviceId)!==s?!1:!n||o(n.deviceId)!==s}function H(e,t){if(!e||!t)return!1;const n=l(t.captureGeneration),s=o(t.commandId),r=o(t.sessionId),c=o(t.streamId),a=Number(e.monitorIndex);return!n||!s||!r||!c||!Number.isInteger(a)||a<0?!1:o(e.deviceId)===o(t.deviceId)&&o(e.sessionId)===r&&o(e.streamId)===c&&o(e.commandId)===s&&l(e.captureGeneration)===n&&o(e.streamPurpose).toLowerCase()==="control"&&a===t.monitorIndex}export{b as a,_ as b,x as c,M as d,T as e,p as f,y as g,A as h,F as i,B as j,g as k,k as l,H as m,G as n,L as o,E as p,P as q,R as r,h as s,v as t,S as u,z as v,K as w,D as x};
|