qBitrr2 5.4.0__py3-none-any.whl → 5.4.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. qBitrr/arss.py +2 -2
  2. qBitrr/bundled_data.py +2 -2
  3. qBitrr/static/assets/ArrView.js +2 -0
  4. qBitrr/static/assets/ArrView.js.map +1 -0
  5. qBitrr/static/assets/ConfigView.js +4 -0
  6. qBitrr/static/assets/ConfigView.js.map +1 -0
  7. qBitrr/static/assets/LogsView.js +230 -0
  8. qBitrr/static/assets/LogsView.js.map +1 -0
  9. qBitrr/static/assets/ProcessesView.js +2 -0
  10. qBitrr/static/assets/ProcessesView.js.map +1 -0
  11. qBitrr/static/assets/app.css +1 -0
  12. qBitrr/static/assets/app.js +11 -0
  13. qBitrr/static/assets/app.js.map +1 -0
  14. qBitrr/static/assets/build.svg +3 -0
  15. qBitrr/static/assets/check-mark.svg +5 -0
  16. qBitrr/static/assets/close.svg +4 -0
  17. qBitrr/static/assets/download.svg +5 -0
  18. qBitrr/static/assets/gear.svg +5 -0
  19. qBitrr/static/assets/lidarr.svg +1 -0
  20. qBitrr/static/assets/live-streaming.svg +8 -0
  21. qBitrr/static/assets/log.svg +3 -0
  22. qBitrr/static/assets/plus.svg +4 -0
  23. qBitrr/static/assets/process.svg +15 -0
  24. qBitrr/static/assets/react-select.esm.js +14 -0
  25. qBitrr/static/assets/react-select.esm.js.map +1 -0
  26. qBitrr/static/assets/refresh-arrow.svg +3 -0
  27. qBitrr/static/assets/table.js +23 -0
  28. qBitrr/static/assets/table.js.map +1 -0
  29. qBitrr/static/assets/trash.svg +8 -0
  30. qBitrr/static/assets/up-arrow.svg +3 -0
  31. qBitrr/static/assets/useInterval.js +2 -0
  32. qBitrr/static/assets/useInterval.js.map +1 -0
  33. qBitrr/static/assets/vendor.js +33 -0
  34. qBitrr/static/assets/vendor.js.map +1 -0
  35. qBitrr/static/assets/visibility.svg +9 -0
  36. qBitrr/static/index.html +33 -0
  37. qBitrr/static/manifest.json +23 -0
  38. qBitrr/static/sw.js +105 -0
  39. qBitrr/static/vite.svg +1 -0
  40. qBitrr/webui.py +12 -0
  41. {qbitrr2-5.4.0.dist-info → qbitrr2-5.4.2.dist-info}/METADATA +1 -1
  42. qbitrr2-5.4.2.dist-info/RECORD +61 -0
  43. qbitrr2-5.4.0.dist-info/RECORD +0 -24
  44. {qbitrr2-5.4.0.dist-info → qbitrr2-5.4.2.dist-info}/WHEEL +0 -0
  45. {qbitrr2-5.4.0.dist-info → qbitrr2-5.4.2.dist-info}/entry_points.txt +0 -0
  46. {qbitrr2-5.4.0.dist-info → qbitrr2-5.4.2.dist-info}/licenses/LICENSE +0 -0
  47. {qbitrr2-5.4.0.dist-info → qbitrr2-5.4.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,2 @@
1
+ import{j as e,I as P,C as U,u as V,g as W,a as J,r as K,b as Y,c as Z,R as M}from"./app.js";import{r as l}from"./table.js";import{u as ee}from"./useInterval.js";import"./vendor.js";function se({title:a,message:r,confirmLabel:h="Confirm",cancelLabel:f="Cancel",onConfirm:u,onCancel:x,danger:_=!1}){return e.jsx("div",{className:"modal-backdrop",onClick:x,children:e.jsxs("div",{className:"modal",style:{maxWidth:"500px"},onClick:b=>b.stopPropagation(),children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h2",{children:a}),e.jsx("button",{className:"btn ghost",onClick:x,children:e.jsx(P,{src:U})})]}),e.jsx("div",{className:"modal-body",children:e.jsx("p",{style:{margin:0,lineHeight:1.6},children:r})}),e.jsxs("div",{className:"modal-footer",children:[e.jsx("button",{className:"btn ghost",onClick:x,children:f}),e.jsx("button",{className:`btn ${_?"danger":"primary"}`,onClick:u,children:h})]})]})})}const re="/static/assets/build.svg",te=/\b(480p|576p|720p|1080p|2160p|4k|8k|web[-_. ]?(?:dl|rip)|hdrip|hdtv|bluray|bd(?:rip)?|brrip|webrip|remux|x264|x265|hevc|dts|truehd|atmos|proper|repack|dvdrip|hdr|amzn|nf)\b/i,ae=/\bS\d{1,3}E\d{1,3}\b/i,ne=/\bSeason\s+\d+\b/i;function ce(a){const r=a.trim();if(!r||/^\d+\s+queued item/i.test(r))return"";const h=r.replace(/\s+/g," "),f=h.match(/^(?<title>.+?)\s+(?<year>(?:19|20)\d{2})(?:\s+(?<rest>.*))?$/);if(f){const u=f.groups?.rest??"",x=ae.test(u)||ne.test(u);if(u&&!x&&te.test(u)){const b=(f.groups?.title??"").replace(/[-_.]/g," ").replace(/\s{2,}/g," ").trim(),A=f.groups?.year??"";if(b)return A?`${b} (${A})`:b}}return h}function oe(a,r){return a.category===r.category&&a.name===r.name&&a.kind===r.kind&&a.pid===r.pid&&a.alive===r.alive&&(a.rebuilding??!1)===(r.rebuilding??!1)&&(a.searchSummary??"")===(r.searchSummary??"")&&(a.searchTimestamp??"")===(r.searchTimestamp??"")&&(a.queueCount??null)===(r.queueCount??null)&&(a.categoryCount??null)===(r.categoryCount??null)&&(a.metricType??"")===(r.metricType??"")}function ie(a,r){if(a===r)return!0;if(a.length!==r.length)return!1;for(let h=0;h<a.length;h+=1)if(!oe(a[h],r[h]))return!1;return!0}function le(a,r){return a?r.some(u=>u.alive&&u.kind.toLowerCase()==="search")?5e3:r.some(u=>typeof u.queueCount=="number"&&u.queueCount>0)?1e4:2e4:null}function ge({active:a}){const[r,h]=l.useState([]),[f,u]=l.useState(!1),[x,_]=l.useState(!1),[b,A]=l.useState(!1),[I,D]=l.useState(null),[E,R]=l.useState(null),{push:d}=V(),F=l.useRef(!1),m=l.useCallback(async()=>{if(!F.current){F.current=!0,u(s=>s||!0);try{const[s,o]=await Promise.all([W(),J()]),g=(s.processes??[]).map(p=>{if(typeof p.searchSummary=="string"){const j=ce(p.searchSummary);return{...p,searchSummary:j}}return p});h(p=>ie(p,g)?p:g),D(o)}catch(s){d(s instanceof Error?s.message:"Failed to load processes list","error")}finally{F.current=!1,u(!1)}}},[d]);l.useEffect(()=>{m()},[m]),l.useEffect(()=>{a&&m()},[a,m]);const G=l.useMemo(()=>le(a,r),[a,r]);ee(()=>{m()},G);const z=l.useCallback(async(s,o)=>{try{await K(s,o),d(`Restarted ${s}:${o}`,"success"),m()}catch(g){d(g instanceof Error?g.message:`Failed to restart ${s}:${o}`,"error")}},[m,d]),B=l.useCallback(async()=>{R({title:"Restart All Processes",message:"Are you sure you want to restart all processes? This will temporarily interrupt all operations.",onConfirm:async()=>{R(null),_(!0);try{await Y(),d("Restarted all processes","success"),m()}catch(s){d(s instanceof Error?s.message:"Failed to restart all","error")}finally{_(!1)}}})},[m,d]),X=l.useCallback(async()=>{R({title:"Rebuild Arrs",message:"Are you sure you want to rebuild all Arr instances? This will refresh all connections and may take some time.",onConfirm:async()=>{R(null),A(!0);try{await Z(),d("Requested Arr rebuild","success"),m()}catch(s){d(s instanceof Error?s.message:"Failed to rebuild Arrs","error")}finally{A(!1)}}})},[m,d]),Q=l.useMemo(()=>{const s=new Map,o=n=>{const c=(n.category??"").toLowerCase(),i=(n.name??"").toLowerCase();return c.includes("radarr")||i.includes("radarr")?"Radarr":c.includes("sonarr")||i.includes("sonarr")?"Sonarr":c.includes("lidarr")||i.includes("lidarr")?"Lidarr":c.includes("qbit")||c.includes("qbittorrent")||i.includes("qbit")||i.includes("qbittorrent")?"qBittorrent":"Other"},g=I?.arrs??[],p=g.some(n=>n.type==="radarr"),j=g.some(n=>n.type==="sonarr"),v=g.some(n=>n.type==="lidarr");r.forEach(n=>{const c=o(n);if(c==="Radarr"&&!p||c==="Sonarr"&&!j||c==="Lidarr"&&!v)return;s.has(c)||s.set(c,new Map);const i=s.get(c),y=n.name||n.category||`${n.category}:${n.kind}`;i.has(y)||i.set(y,[]),i.get(y).push(n)});const N=["Radarr","Sonarr","Lidarr","qBittorrent","Other"],S=Array.from(s.entries()).map(([n,c])=>{const i=Array.from(c.entries()).map(([y,C])=>({name:y,items:C.sort((w,L)=>w.kind.localeCompare(L.kind))})).sort((y,C)=>y.name.localeCompare(C.name));return{app:n,instances:i}}).filter(n=>n.instances.length);return S.sort((n,c)=>{const i=y=>{const C=N.indexOf(y);return C===-1?Number.MAX_SAFE_INTEGER:C};return i(n.app)-i(c.app)||n.app.localeCompare(c.app)}),S},[r,I]),H=l.useCallback(async s=>{try{await Promise.all(s.map(o=>K(o.category,o.kind))),d(`Restarted ${s[0]?.name??"group"}`,"success"),m()}catch(o){d(o instanceof Error?o.message:"Failed to restart process group","error")}},[m,d]),O=Q.map(({app:s,instances:o})=>{const g=o.map(({name:p,items:j})=>{const v=j.filter(t=>t.alive).length,N=j.length,S=N===0?"":v===N?"status-indicator--ok":v===0?"status-indicator--bad":"",n=["status-indicator"];S&&n.push(S);const c=N===0?"No processes":v===N?"All running":v===0?"Stopped":`${v}/${N} running`,i=N===1?"1 process":`${N} processes`,y=p==="FreeSpaceManager"?"Free Space Manager":p,w=Array.from(new Set(j.map(t=>t.kind))).filter(t=>{const k=t.toLowerCase();return k!=="search"&&k!=="torrent"}),L=t=>t&&t.charAt(0).toUpperCase()+t.slice(1);return e.jsxs("div",{className:"process-card",children:[e.jsxs("div",{className:"process-card__header",children:[e.jsxs("div",{className:"process-card__title",children:[e.jsx("div",{className:"process-card__name",children:y}),e.jsx("div",{className:"process-card__summary",children:i}),w.length?e.jsx("div",{className:"process-card__badges",children:w.map(t=>e.jsx("span",{className:"process-card__badge",children:L(t)},`${p}:${t}:badge`))}):null]}),e.jsx("div",{className:n.join(" "),title:c})]}),e.jsx("div",{className:"process-card__list",children:j.map(t=>e.jsxs("div",{className:"process-chip",children:[e.jsxs("div",{className:"process-chip__top",children:[e.jsx("div",{className:"process-chip__name",children:L(t.kind)}),e.jsx("div",{className:`status-pill__dot ${t.alive?"text-success":"text-danger"}`})]}),e.jsx("div",{className:"process-chip__detail",children:(()=>{if(t.rebuilding)return"Rebuilding";const k=t.kind.toLowerCase();if(k==="search")return(t.searchSummary??"")||"No searches recorded";if(k==="torrent"){const T=t.metricType?.toLowerCase(),$=typeof t.categoryCount=="number"?t.categoryCount:null,q=typeof t.queueCount=="number"?t.queueCount:null;return T?T==="category"&&$!==null?`Torrent count ${$}`:T==="free-space"&&q!==null?`Torrent count ${q}`:"Torrent count unavailable":`Torrents in queue ${q!==null?q:"?"} / total ${$!==null?$:"?"}`}return""})()}),e.jsx("div",{className:"process-chip__actions",children:e.jsx("button",{className:"btn small",onClick:()=>z(t.category,t.kind),children:"Restart"})})]},`${t.category}:${t.kind}`))}),e.jsx("div",{className:"process-card__footer",children:e.jsx("button",{className:"btn small outline",onClick:()=>void H(j),children:"Restart All"})})]},p)});return{app:s,cards:g}});return e.jsxs(e.Fragment,{children:[e.jsxs("section",{className:"card",children:[e.jsx("div",{className:"card-header",children:"Processes"}),e.jsxs("div",{className:"card-body stack",children:[e.jsx("div",{className:"row",children:e.jsxs("div",{className:"col inline",children:[e.jsxs("button",{className:"btn ghost",onClick:()=>void m(),disabled:f,children:[f&&e.jsx("span",{className:"spinner"}),e.jsx(P,{src:M}),f?"Refreshing...":"Refresh"]}),e.jsxs("button",{className:"btn",onClick:()=>void B(),disabled:x,children:[x&&e.jsx("span",{className:"spinner"}),e.jsx(P,{src:M}),x?"Restarting...":"Restart All"]}),e.jsxs("button",{className:"btn",onClick:()=>void X(),disabled:b,children:[b&&e.jsx("span",{className:"spinner"}),e.jsx(P,{src:re}),b?"Rebuilding...":"Rebuild Arrs"]})]})}),O.length?O.map(({app:s,cards:o})=>e.jsxs("div",{className:"process-section",children:[e.jsx("div",{className:"process-section__title",children:s}),e.jsx("div",{className:"process-grid",children:o})]},s)):e.jsx("div",{className:"empty-state",children:"No processes available."})]})]}),E&&e.jsx(se,{title:E.title,message:E.message,confirmLabel:"Confirm",cancelLabel:"Cancel",danger:!0,onConfirm:E.onConfirm,onCancel:()=>R(null)})]})}export{ge as ProcessesView};
2
+ //# sourceMappingURL=ProcessesView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProcessesView.js","sources":["../../../webui/src/components/ConfirmDialog.tsx","../../../webui/src/icons/build.svg","../../../webui/src/pages/ProcessesView.tsx"],"sourcesContent":["import type { JSX } from \"react\";\nimport { IconImage } from \"./IconImage\";\nimport CloseIcon from \"../icons/close.svg\";\n\ninterface ConfirmDialogProps {\n title: string;\n message: string;\n confirmLabel?: string;\n cancelLabel?: string;\n onConfirm: () => void;\n onCancel: () => void;\n danger?: boolean;\n}\n\nexport function ConfirmDialog({\n title,\n message,\n confirmLabel = \"Confirm\",\n cancelLabel = \"Cancel\",\n onConfirm,\n onCancel,\n danger = false,\n}: ConfirmDialogProps): JSX.Element {\n return (\n <div className=\"modal-backdrop\" onClick={onCancel}>\n <div\n className=\"modal\"\n style={{ maxWidth: '500px' }}\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"modal-header\">\n <h2>{title}</h2>\n <button className=\"btn ghost\" onClick={onCancel}>\n <IconImage src={CloseIcon} />\n </button>\n </div>\n <div className=\"modal-body\">\n <p style={{ margin: 0, lineHeight: 1.6 }}>{message}</p>\n </div>\n <div className=\"modal-footer\">\n <button className=\"btn ghost\" onClick={onCancel}>\n {cancelLabel}\n </button>\n <button\n className={`btn ${danger ? 'danger' : 'primary'}`}\n onClick={onConfirm}\n >\n {confirmLabel}\n </button>\n </div>\n </div>\n </div>\n );\n}\n","export default \"__VITE_ASSET__DznMzWc1__\"","import { useCallback, useEffect, useMemo, useRef, useState, type JSX } from \"react\";\nimport {\n getProcesses,\n getStatus,\n rebuildArrs,\n restartAllProcesses,\n restartProcess,\n} from \"../api/client\";\nimport type { ProcessInfo, StatusResponse } from \"../api/types\";\nimport { useToast } from \"../context/ToastContext\";\nimport { useInterval } from \"../hooks/useInterval\";\nimport { IconImage } from \"../components/IconImage\";\nimport { ConfirmDialog } from \"../components/ConfirmDialog\";\n\nimport RefreshIcon from \"../icons/refresh-arrow.svg\";\nimport RestartIcon from \"../icons/refresh-arrow.svg\";\nimport ToolsIcon from \"../icons/build.svg\";\n\nconst RELEASE_TOKEN_REGEX =\n /\\b(480p|576p|720p|1080p|2160p|4k|8k|web[-_. ]?(?:dl|rip)|hdrip|hdtv|bluray|bd(?:rip)?|brrip|webrip|remux|x264|x265|hevc|dts|truehd|atmos|proper|repack|dvdrip|hdr|amzn|nf)\\b/i;\nconst EPISODE_TOKEN_REGEX = /\\bS\\d{1,3}E\\d{1,3}\\b/i;\nconst SEASON_TOKEN_REGEX = /\\bSeason\\s+\\d+\\b/i;\n\nfunction sanitizeSearchSummary(raw: string): string {\n const trimmed = raw.trim();\n if (!trimmed) return \"\";\n if (/^\\d+\\s+queued item/i.test(trimmed)) return \"\";\n const normalized = trimmed.replace(/\\s+/g, \" \");\n const releaseMatch = normalized.match(\n /^(?<title>.+?)\\s+(?<year>(?:19|20)\\d{2})(?:\\s+(?<rest>.*))?$/\n );\n\n if (releaseMatch) {\n const rest = releaseMatch.groups?.rest ?? \"\";\n const looksLikeEpisode =\n EPISODE_TOKEN_REGEX.test(rest) || SEASON_TOKEN_REGEX.test(rest);\n if (rest && !looksLikeEpisode && RELEASE_TOKEN_REGEX.test(rest)) {\n const rawTitle = releaseMatch.groups?.title ?? \"\";\n const cleanedTitle = rawTitle\n .replace(/[-_.]/g, \" \")\n .replace(/\\s{2,}/g, \" \")\n .trim();\n const year = releaseMatch.groups?.year ?? \"\";\n if (cleanedTitle) {\n return year ? `${cleanedTitle} (${year})` : cleanedTitle;\n }\n }\n }\n\n return normalized;\n}\n\nfunction isProcessEqual(a: ProcessInfo, b: ProcessInfo): boolean {\n return (\n a.category === b.category &&\n a.name === b.name &&\n a.kind === b.kind &&\n a.pid === b.pid &&\n a.alive === b.alive &&\n (a.rebuilding ?? false) === (b.rebuilding ?? false) &&\n (a.searchSummary ?? \"\") === (b.searchSummary ?? \"\") &&\n (a.searchTimestamp ?? \"\") === (b.searchTimestamp ?? \"\") &&\n (a.queueCount ?? null) === (b.queueCount ?? null) &&\n (a.categoryCount ?? null) === (b.categoryCount ?? null) &&\n (a.metricType ?? \"\") === (b.metricType ?? \"\")\n );\n}\n\nfunction areProcessListsEqual(a: ProcessInfo[], b: ProcessInfo[]): boolean {\n if (a === b) return true;\n if (a.length !== b.length) return false;\n for (let index = 0; index < a.length; index += 1) {\n if (!isProcessEqual(a[index], b[index])) {\n return false;\n }\n }\n return true;\n}\n\nfunction getRefreshDelay(active: boolean, processes: ProcessInfo[]): number | null {\n if (!active) return null;\n const hasActiveSearch = processes.some(\n (proc) => proc.alive && proc.kind.toLowerCase() === \"search\"\n );\n if (hasActiveSearch) return 5000;\n const hasQueueActivity = processes.some(\n (proc) =>\n typeof proc.queueCount === \"number\" && proc.queueCount > 0\n );\n if (hasQueueActivity) return 10000;\n return 20000;\n}\n\ninterface ProcessesViewProps {\n active: boolean;\n}\n\nexport function ProcessesView({ active }: ProcessesViewProps): JSX.Element {\n const [processes, setProcesses] = useState<ProcessInfo[]>([]);\n const [loading, setLoading] = useState(false);\n const [restartingAll, setRestartingAll] = useState(false);\n const [rebuildingArrs, setRebuildingArrs] = useState(false);\n const [statusData, setStatusData] = useState<StatusResponse | null>(null);\n const [confirmAction, setConfirmAction] = useState<{\n title: string;\n message: string;\n onConfirm: () => void;\n } | null>(null);\n const { push } = useToast();\n const isFetching = useRef(false);\n\n const load = useCallback(async () => {\n if (isFetching.current) {\n return;\n }\n isFetching.current = true;\n setLoading((prev) => (prev ? prev : true));\n try {\n const [processData, status] = await Promise.all([\n getProcesses(),\n getStatus(),\n ]);\n const next = (processData.processes ?? []).map((process) => {\n if (typeof process.searchSummary === \"string\") {\n const sanitized = sanitizeSearchSummary(process.searchSummary);\n return {\n ...process,\n searchSummary: sanitized,\n };\n }\n return process;\n });\n setProcesses((prev) =>\n areProcessListsEqual(prev, next) ? prev : next\n );\n setStatusData(status);\n } catch (error) {\n push(\n error instanceof Error\n ? error.message\n : \"Failed to load processes list\",\n \"error\"\n );\n } finally {\n isFetching.current = false;\n setLoading(false);\n }\n }, [push]);\n\n useEffect(() => {\n void load();\n }, [load]);\n\n useEffect(() => {\n if (active) {\n void load();\n }\n }, [active, load]);\n\n const refreshDelay = useMemo(\n () => getRefreshDelay(active, processes),\n [active, processes]\n );\n\n useInterval(() => {\n void load();\n }, refreshDelay);\n\n const handleRestart = useCallback(\n async (category: string, kind: string) => {\n try {\n await restartProcess(category, kind);\n push(`Restarted ${category}:${kind}`, \"success\");\n void load();\n } catch (error) {\n push(\n error instanceof Error\n ? error.message\n : `Failed to restart ${category}:${kind}`,\n \"error\"\n );\n }\n },\n [load, push]\n );\n\n const handleRestartAll = useCallback(async () => {\n setConfirmAction({\n title: \"Restart All Processes\",\n message: \"Are you sure you want to restart all processes? This will temporarily interrupt all operations.\",\n onConfirm: async () => {\n setConfirmAction(null);\n setRestartingAll(true);\n try {\n await restartAllProcesses();\n push(\"Restarted all processes\", \"success\");\n void load();\n } catch (error) {\n push(\n error instanceof Error ? error.message : \"Failed to restart all\",\n \"error\"\n );\n } finally {\n setRestartingAll(false);\n }\n }\n });\n }, [load, push]);\n\n const handleRebuildArrs = useCallback(async () => {\n setConfirmAction({\n title: \"Rebuild Arrs\",\n message: \"Are you sure you want to rebuild all Arr instances? This will refresh all connections and may take some time.\",\n onConfirm: async () => {\n setConfirmAction(null);\n setRebuildingArrs(true);\n try {\n await rebuildArrs();\n push(\"Requested Arr rebuild\", \"success\");\n void load();\n } catch (error) {\n push(\n error instanceof Error ? error.message : \"Failed to rebuild Arrs\",\n \"error\"\n );\n } finally {\n setRebuildingArrs(false);\n }\n }\n });\n }, [load, push]);\n\n const groupedProcesses = useMemo(() => {\n interface Instance {\n name: string;\n items: ProcessInfo[];\n }\n interface AppGroup {\n app: string;\n instances: Instance[];\n }\n const appBuckets = new Map<string, Map<string, ProcessInfo[]>>();\n\n const classifyApp = (proc: ProcessInfo): string => {\n const category = (proc.category ?? \"\").toLowerCase();\n const name = (proc.name ?? \"\").toLowerCase();\n if (category.includes(\"radarr\") || name.includes(\"radarr\")) return \"Radarr\";\n if (category.includes(\"sonarr\") || name.includes(\"sonarr\")) return \"Sonarr\";\n if (category.includes(\"lidarr\") || name.includes(\"lidarr\")) return \"Lidarr\";\n if (\n category.includes(\"qbit\") ||\n category.includes(\"qbittorrent\") ||\n name.includes(\"qbit\") ||\n name.includes(\"qbittorrent\")\n ) {\n return \"qBittorrent\";\n }\n return \"Other\";\n };\n\n // Check which Arr types are configured\n const arrs = statusData?.arrs ?? [];\n const hasRadarr = arrs.some((arr) => arr.type === \"radarr\");\n const hasSonarr = arrs.some((arr) => arr.type === \"sonarr\");\n const hasLidarr = arrs.some((arr) => arr.type === \"lidarr\");\n\n processes.forEach((proc) => {\n const app = classifyApp(proc);\n\n // Skip Arr processes if that Arr type is not configured\n if (app === \"Radarr\" && !hasRadarr) return;\n if (app === \"Sonarr\" && !hasSonarr) return;\n if (app === \"Lidarr\" && !hasLidarr) return;\n\n if (!appBuckets.has(app)) appBuckets.set(app, new Map());\n const instances = appBuckets.get(app)!;\n const instanceKey =\n proc.name || proc.category || `${proc.category}:${proc.kind}`;\n if (!instances.has(instanceKey)) instances.set(instanceKey, []);\n instances.get(instanceKey)!.push(proc);\n });\n\n const appOrder = [\"Radarr\", \"Sonarr\", \"Lidarr\", \"qBittorrent\", \"Other\"];\n\n const result: AppGroup[] = Array.from(appBuckets.entries())\n .map(([app, instances]) => {\n const sortedInstances = Array.from(instances.entries())\n .map(([name, items]) => ({\n name,\n items: items.sort((a, b) => a.kind.localeCompare(b.kind)),\n }))\n .sort((a, b) => a.name.localeCompare(b.name));\n return { app, instances: sortedInstances };\n })\n .filter((group) => group.instances.length);\n\n result.sort((a, b) => {\n const order = (label: string) => {\n const index = appOrder.indexOf(label);\n return index === -1 ? Number.MAX_SAFE_INTEGER : index;\n };\n return order(a.app) - order(b.app) || a.app.localeCompare(b.app);\n });\n\n return result;\n }, [processes, statusData]);\n\n const handleRestartGroup = useCallback(\n async (items: ProcessInfo[]) => {\n try {\n await Promise.all(\n items.map((item) => restartProcess(item.category, item.kind))\n );\n push(`Restarted ${items[0]?.name ?? \"group\"}`, \"success\");\n void load();\n } catch (error) {\n push(\n error instanceof Error\n ? error.message\n : \"Failed to restart process group\",\n \"error\"\n );\n }\n },\n [load, push]\n );\n\n const cardsByApp = groupedProcesses.map(({ app, instances }) => {\n const cards = instances.map(({ name, items }) => {\n const runningCount = items.filter((item) => item.alive).length;\n const totalCount = items.length;\n const tone =\n totalCount === 0\n ? \"\"\n : runningCount === totalCount\n ? \"status-indicator--ok\"\n : runningCount === 0\n ? \"status-indicator--bad\"\n : \"\";\n const statusClass = [\"status-indicator\"];\n if (tone) statusClass.push(tone);\n const statusLabel =\n totalCount === 0\n ? \"No processes\"\n : runningCount === totalCount\n ? \"All running\"\n : runningCount === 0\n ? \"Stopped\"\n : `${runningCount}/${totalCount} running`;\n const summaryLabel = totalCount === 1 ? \"1 process\" : `${totalCount} processes`;\n const displayName = name === \"FreeSpaceManager\" ? \"Free Space Manager\" : name;\n const uniqueKinds = Array.from(new Set(items.map((item) => item.kind)));\n const filteredKinds = uniqueKinds.filter((kind) => {\n const lower = kind.toLowerCase();\n return lower !== \"search\" && lower !== \"torrent\";\n });\n const formatKind = (kind: string) =>\n kind ? kind.charAt(0).toUpperCase() + kind.slice(1) : kind;\n\n return (\n <div className=\"process-card\" key={name}>\n <div className=\"process-card__header\">\n <div className=\"process-card__title\">\n <div className=\"process-card__name\">{displayName}</div>\n <div className=\"process-card__summary\">{summaryLabel}</div>\n {filteredKinds.length ? (\n <div className=\"process-card__badges\">\n {filteredKinds.map((kind) => (\n <span key={`${name}:${kind}:badge`} className=\"process-card__badge\">\n {formatKind(kind)}\n </span>\n ))}\n </div>\n ) : null}\n </div>\n <div className={statusClass.join(\" \")} title={statusLabel} />\n </div>\n <div className=\"process-card__list\">\n {items.map((item) => (\n <div className=\"process-chip\" key={`${item.category}:${item.kind}`}>\n <div className=\"process-chip__top\">\n <div className=\"process-chip__name\">{formatKind(item.kind)}</div>\n <div className={`status-pill__dot ${item.alive ? \"text-success\" : \"text-danger\"}`} />\n </div>\n <div className=\"process-chip__detail\">\n {(() => {\n if (item.rebuilding) {\n return \"Rebuilding\";\n }\n const kindLower = item.kind.toLowerCase();\n if (kindLower === \"search\") {\n const summary = item.searchSummary ?? \"\";\n return summary || \"No searches recorded\";\n }\n if (kindLower === \"torrent\") {\n const metricType = item.metricType?.toLowerCase();\n const categoryTotal =\n typeof item.categoryCount === \"number\" ? item.categoryCount : null;\n const queueTotal =\n typeof item.queueCount === \"number\" ? item.queueCount : null;\n\n if (!metricType) {\n const queueLabel = queueTotal !== null ? queueTotal : \"?\";\n const categoryLabel = categoryTotal !== null ? categoryTotal : \"?\";\n return `Torrents in queue ${queueLabel} / total ${categoryLabel}`;\n }\n\n if (metricType === \"category\" && categoryTotal !== null) {\n return `Torrent count ${categoryTotal}`;\n }\n\n if (metricType === \"free-space\" && queueTotal !== null) {\n return `Torrent count ${queueTotal}`;\n }\n\n return \"Torrent count unavailable\";\n }\n return \"\";\n })()}\n </div>\n <div className=\"process-chip__actions\">\n <button\n className=\"btn small\"\n onClick={() => handleRestart(item.category, item.kind)}\n >\n Restart\n </button>\n </div>\n </div>\n ))}\n </div>\n <div className=\"process-card__footer\">\n <button\n className=\"btn small outline\"\n onClick={() => void handleRestartGroup(items)}\n >\n Restart All\n </button>\n </div>\n </div>\n );\n });\n return { app, cards };\n });\n\n return (\n <>\n <section className=\"card\">\n <div className=\"card-header\">Processes</div>\n <div className=\"card-body stack\">\n <div className=\"row\">\n <div className=\"col inline\">\n <button className=\"btn ghost\" onClick={() => void load()} disabled={loading}>\n {loading && <span className=\"spinner\" />}\n <IconImage src={RefreshIcon} />\n {loading ? 'Refreshing...' : 'Refresh'}\n </button>\n <button className=\"btn\" onClick={() => void handleRestartAll()} disabled={restartingAll}>\n {restartingAll && <span className=\"spinner\" />}\n <IconImage src={RestartIcon} />\n {restartingAll ? 'Restarting...' : 'Restart All'}\n </button>\n <button className=\"btn\" onClick={() => void handleRebuildArrs()} disabled={rebuildingArrs}>\n {rebuildingArrs && <span className=\"spinner\" />}\n <IconImage src={ToolsIcon} />\n {rebuildingArrs ? 'Rebuilding...' : 'Rebuild Arrs'}\n </button>\n </div>\n </div>\n {cardsByApp.length ? (\n cardsByApp.map(({ app, cards }) => (\n <div className=\"process-section\" key={app}>\n <div className=\"process-section__title\">{app}</div>\n <div className=\"process-grid\">{cards}</div>\n </div>\n ))\n ) : (\n <div className=\"empty-state\">No processes available.</div>\n )}\n </div>\n </section>\n {confirmAction && (\n <ConfirmDialog\n title={confirmAction.title}\n message={confirmAction.message}\n confirmLabel=\"Confirm\"\n cancelLabel=\"Cancel\"\n danger={true}\n onConfirm={confirmAction.onConfirm}\n onCancel={() => setConfirmAction(null)}\n />\n )}\n </>\n );\n}\n"],"names":["ConfirmDialog","title","message","confirmLabel","cancelLabel","onConfirm","onCancel","danger","jsx","jsxs","e","IconImage","CloseIcon","ToolsIcon","RELEASE_TOKEN_REGEX","EPISODE_TOKEN_REGEX","SEASON_TOKEN_REGEX","sanitizeSearchSummary","raw","trimmed","normalized","releaseMatch","rest","looksLikeEpisode","cleanedTitle","year","isProcessEqual","b","areProcessListsEqual","index","getRefreshDelay","active","processes","proc","ProcessesView","setProcesses","useState","loading","setLoading","restartingAll","setRestartingAll","rebuildingArrs","setRebuildingArrs","statusData","setStatusData","confirmAction","setConfirmAction","push","useToast","isFetching","useRef","load","useCallback","prev","processData","status","getProcesses","getStatus","next","process","sanitized","error","useEffect","refreshDelay","useMemo","useInterval","handleRestart","category","kind","restartProcess","handleRestartAll","restartAllProcesses","handleRebuildArrs","rebuildArrs","groupedProcesses","appBuckets","classifyApp","name","arrs","hasRadarr","arr","hasSonarr","hasLidarr","app","instances","instanceKey","appOrder","result","sortedInstances","items","a","group","order","label","handleRestartGroup","item","cardsByApp","cards","runningCount","totalCount","tone","statusClass","statusLabel","summaryLabel","displayName","filteredKinds","lower","formatKind","kindLower","metricType","categoryTotal","queueTotal","Fragment","RefreshIcon","RestartIcon"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ :root,[data-theme=dark]{--bg: #101114;--surface: #1b1e22;--on-surface: #eaeef2;--muted: #9aa3ac;--primary: #7aa2f7;--primary-variant: #3b82f6;--success: #22c55e;--danger: #ef4444;--warning: #facc15;--border: #2a2f36;--elev: 8px;--layout-max-width: 1200px}[data-theme=light]{--bg: #f5f5f7;--surface: #ffffff;--on-surface: #1d1d1f;--muted: #6e6e73;--primary: #0071e3;--primary-variant: #0077ed;--success: #34c759;--danger: #ff3b30;--warning: #ff9500;--border: #d2d2d7;--elev: 4px;--layout-max-width: 1200px}*{box-sizing:border-box}html{scroll-behavior:smooth}html,body{height:100%}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol;margin:0;background:var(--bg);color:var(--on-surface);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility;font-feature-settings:"kern" 1;font-kerning:normal}*::-webkit-scrollbar{width:12px;height:12px}*::-webkit-scrollbar-track{background:#0003;border-radius:6px}*::-webkit-scrollbar-thumb{background:#7aa2f74d;border-radius:6px;border:2px solid transparent;background-clip:padding-box}*::-webkit-scrollbar-thumb:hover{background:#7aa2f780;background-clip:padding-box}.appbar{position:sticky;top:0;z-index:100;display:flex;justify-content:center;padding:16px 20px;background:var(--surface);border-bottom:1px solid var(--border);box-shadow:0 2px 16px #0000000f;backdrop-filter:blur(12px) saturate(180%);-webkit-backdrop-filter:blur(12px) saturate(180%)}[data-theme=light] .appbar{background:#fffc}[data-theme=dark] .appbar{background:linear-gradient(180deg,#0b0c0ff2,#0d0e11f2);box-shadow:0 4px 16px #0006}.appbar__inner{width:100%;display:flex;align-items:center;justify-content:space-between;gap:16px;padding:0 16px;flex-wrap:wrap}.appbar__title{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}.appbar h1{margin:0;font-size:20px;font-weight:700;letter-spacing:-.02em;background:linear-gradient(135deg,var(--on-surface) 0%,var(--primary) 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}[data-theme=light] .appbar h1{background:linear-gradient(135deg,var(--on-surface) 0%,var(--primary) 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}.appbar__version{font-size:12px;color:var(--muted);letter-spacing:.4px}.appbar__status{font-size:12px}.appbar__actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.appbar__update{display:inline-flex;align-items:center;gap:6px}.appbar__update-indicator{width:8px;height:8px;border-radius:50%;background:var(--danger);display:inline-block;animation:pulse 1s ease-in-out infinite;box-shadow:0 0 8px #ef444499}.container{padding:20px;display:grid;grid-template-columns:1fr;gap:20px;animation:fadeInUp .3s ease}.toolbar{display:flex;gap:8px;align-items:center;flex-wrap:wrap;color:var(--muted)}.nav{display:flex;gap:8px;flex-wrap:wrap;width:100%}.nav button{color:var(--muted);background:transparent;border:1px solid var(--border);padding:10px 14px;display:inline-flex;align-items:center;gap:8px;border-radius:8px;cursor:pointer;font-weight:500;transition:all .15s ease;position:relative;overflow:hidden}.nav button:before{content:"";position:absolute;inset:0;background:linear-gradient(135deg,rgba(122,162,247,.1),transparent);opacity:0;transition:opacity .15s ease}.nav button .icon{width:1.4em;height:1.4em;transition:transform .15s ease}.nav button:hover .icon{transform:scale(1.1)}.nav button.active{color:var(--primary);border-color:var(--primary);background:#7aa2f71f;box-shadow:0 0 0 2px #7aa2f71a,0 2px 8px #7aa2f733;font-weight:600}[data-theme=light] .nav button.active{box-shadow:0 0 0 2px #0071e31a,0 2px 8px #0071e333}.nav button:hover:not(.active){color:var(--on-surface);border-color:#7aa2f766;background:#7aa2f70f;transform:translateY(-1px)}.nav button:hover:before{opacity:1}.card{background:var(--surface);border:1px solid var(--border);border-radius:14px;box-shadow:0 2px 8px #00000014,0 1px 2px #0000000f;overflow:hidden;transition:transform .15s ease,box-shadow .15s ease,border-color .15s ease;position:relative}[data-theme=dark] .card{box-shadow:0 var(--elev) 24px #00000040,0 2px 4px #0000004d}.card:before{content:"";position:absolute;top:0;left:0;right:0;height:1px;background:linear-gradient(90deg,transparent,rgba(122,162,247,.1),transparent);opacity:0;transition:opacity .15s ease}.card:hover{transform:translateY(-2px);box-shadow:0 16px 40px #0000001f,0 4px 8px #00000014;border-color:#7aa2f74d}[data-theme=dark] .card:hover{box-shadow:0 12px 32px #00000059,0 4px 8px #0006}.card:hover:before{opacity:1}.card .card-header{padding:16px 20px;border-bottom:1px solid var(--border);font-weight:700;font-size:15px;letter-spacing:.01em;color:var(--on-surface);background:linear-gradient(180deg,#7aa2f70a,#7aa2f703);position:relative}[data-theme=light] .card .card-header{background:linear-gradient(180deg,rgba(0,113,227,.03) 0%,transparent 100%)}.card .card-header:after{content:"";position:absolute;bottom:0;left:20px;right:20px;height:1px;background:linear-gradient(90deg,transparent,var(--primary),transparent);opacity:.15}.card .card-body{padding:12px 14px}.btn{appearance:none;border:1px solid var(--border);background:var(--surface);color:var(--on-surface);padding:8px 14px;border-radius:8px;cursor:pointer;transition:all .15s ease;display:inline-flex;align-items:center;gap:6px;font-weight:500;position:relative;overflow:hidden}[data-theme=dark] .btn{background:#0f131a}.btn:before{content:"";position:absolute;inset:0;background:linear-gradient(135deg,#ffffff1a,#fff0);opacity:0;transition:opacity .15s ease}.btn:hover:not(:disabled):before{opacity:1}.btn.primary{border-color:var(--primary-variant);background:linear-gradient(135deg,#7aa2f72e,#7aa2f71f);color:var(--primary);font-weight:600;box-shadow:0 2px 8px #7aa2f726}[data-theme=light] .btn.primary{background:linear-gradient(135deg,#0071e31f,#0071e314);box-shadow:0 2px 8px #0071e326}.btn.danger{border-color:#ef444466;color:var(--danger);background:#ef44441f}.btn.danger:hover:not(:disabled){background:var(--danger);color:#0a0a0a;border-color:var(--danger);box-shadow:0 4px 12px #ef44444d}.btn.primary:hover:not(:disabled){background:var(--primary);color:#0a0a0a;border-color:var(--primary);box-shadow:0 4px 12px #7aa2f74d}.btn.ghost{background:transparent}.btn.ghost:hover:not(:disabled){background:#ffffff0d;border-color:#7aa2f74d}.btn:hover:not(:disabled){transform:translateY(-1px);box-shadow:0 3px 10px #0006}.btn:active:not(:disabled){transform:translateY(0)}.btn:focus-visible{outline:none;box-shadow:0 0 0 3px #7aa2f74d}[data-theme=light] .btn:focus-visible{box-shadow:0 0 0 3px #0071e34d}.nav button:focus-visible{outline:none;box-shadow:0 0 0 3px #7aa2f740}[data-theme=light] .nav button:focus-visible{box-shadow:0 0 0 3px #0071e340}.btn:disabled{opacity:.5;cursor:not-allowed}.btn.small{padding:6px 10px;font-size:12px}.btn.outline{background:transparent;border-color:var(--border)}.btn.outline:hover:not(:disabled){background:#ffffff0d;border-color:var(--primary-variant)}.btn.active{background:var(--primary);color:#0a0a0a;border-color:var(--primary)}.field{display:flex;flex-direction:column;gap:6px}.field--full-width{grid-column:1 / -1}.sonarr-hierarchical-view{display:flex;flex-direction:column;gap:8px}.series-details,.season-details{border:1px solid var(--border);border-radius:6px;background:var(--card-bg)}.series-summary,.season-summary{padding:12px 16px;cursor:pointer;-webkit-user-select:none;user-select:none;font-weight:600;color:var(--text);background:var(--card-header-bg);border-radius:6px 6px 0 0;display:flex;align-items:center;justify-content:space-between}.series-summary:hover,.season-summary:hover{background:var(--hover-bg)}.series-title{font-size:1.1em}.series-instance{font-size:.9em;color:var(--muted);font-weight:400}.season-title{font-size:1em}.season-count{font-size:.9em;color:var(--muted);font-weight:400}.series-content,.season-content{padding:8px}.episodes-table-wrapper{overflow-x:auto}.episodes-table{width:100%;border-collapse:collapse;font-size:.9em}.episodes-table th,.episodes-table td{padding:8px 12px;text-align:left;border-bottom:1px solid var(--border)}.episodes-table th{background:var(--table-header-bg);font-weight:600;color:var(--text);position:sticky;top:0}.episodes-table tr:hover{background:var(--hover-bg)}.lidarr-hierarchical-view{display:flex;flex-direction:column;gap:8px}.artist-details{border:1px solid var(--border);border-radius:6px;background:var(--card-bg)}.artist-summary{padding:12px 16px;cursor:pointer;-webkit-user-select:none;user-select:none;font-weight:600;color:var(--text);background:var(--card-header-bg);border-radius:6px 6px 0 0;display:flex;align-items:center;justify-content:space-between;gap:8px}.artist-summary:hover{background:var(--hover-bg)}.artist-title{font-size:1.1em;flex:1}.artist-instance,.artist-count{font-size:.9em;color:var(--muted);font-weight:400}.artist-content{padding:8px}.albums-table-wrapper{overflow-x:auto}.albums-table{width:100%;border-collapse:collapse;font-size:.9em}.albums-table th,.albums-table td{padding:8px 12px;text-align:left;border-bottom:1px solid var(--border)}.albums-table th{background:var(--table-header-bg);font-weight:600;color:var(--text);position:sticky;top:0}.albums-table tr:hover{background:var(--hover-bg)}.album-details{border:1px solid var(--border);border-radius:4px;background:var(--surface);margin-bottom:8px}.album-summary{padding:10px 14px;cursor:pointer;-webkit-user-select:none;user-select:none;font-weight:500;color:var(--text);background:var(--card-header-bg);border-radius:4px 4px 0 0;display:flex;align-items:center;gap:12px}.album-summary:hover{background:var(--hover-bg)}.album-title{font-size:1em;flex:1}.album-date,.album-track-count{font-size:.85em;color:var(--muted);font-weight:400}.album-status{font-size:1.1em;font-weight:700}.album-status.has-file{color:var(--success)}.album-status.missing{color:var(--danger)}.album-content{padding:8px}.album-info{padding:8px 12px;font-size:.9em}.album-info p{margin:4px 0}.tracks-table-wrapper{overflow-x:auto}.tracks-table{width:100%;border-collapse:collapse;font-size:.85em}.tracks-table th,.tracks-table td{padding:6px 10px;text-align:left;border-bottom:1px solid var(--border)}.tracks-table th{background:var(--table-header-bg);font-weight:600;color:var(--text);font-size:.9em}.tracks-table tr.track-available{opacity:1}.tracks-table tr.track-missing{opacity:.6}.tracks-table tr:hover{background:var(--hover-bg)}.track-status{display:inline-block;font-weight:700;font-size:1.1em}.track-status.available{color:var(--success)}.track-status.missing{color:var(--danger)}.table-badge{display:inline-block;padding:3px 8px;border-radius:6px;font-size:.8em;font-weight:600;border:1px solid transparent;transition:all .15s ease}.table-badge:hover{transform:scale(1.05)}.table-badge.monitored{background:#22c55e26;border-color:#22c55e4d;color:var(--success)}.table-badge.unmonitored{background:#facc1526;border-color:#facc154d;color:var(--warning)}.table-badge.has-file{background:#22c55e26;border-color:#22c55e4d;color:var(--success)}.table-badge.missing{background:#ef444426;border-color:#ef44444d;color:var(--danger)}.table-badge-reason{background:#facc1526;border-color:#facc154d;color:var(--warning);font-family:monospace;font-size:11px;font-weight:600}[data-theme=light] .table-badge-reason{background:#ff95001a;border-color:#ff95004d}.field label{color:var(--muted);font-size:12px}.field input,.field select,.field textarea{background:var(--surface);color:var(--on-surface);border:1px solid var(--border);border-radius:8px;padding:9px 12px;transition:all .15s ease}[data-theme=dark] .field input,[data-theme=dark] .field select,[data-theme=dark] .field textarea{background:#0f131a}.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--primary);box-shadow:0 0 0 4px #7aa2f71f,0 2px 8px #7aa2f726;background:var(--bg);transform:translateY(-1px)}[data-theme=light] .field input:focus,[data-theme=light] .field select:focus,[data-theme=light] .field textarea:focus{box-shadow:0 0 0 4px #0071e31a,0 2px 8px #0071e326}[data-theme=dark] .field input:focus,[data-theme=dark] .field select:focus,[data-theme=dark] .field textarea:focus{background:#12151a;box-shadow:0 0 0 4px #7aa2f71f,0 2px 8px #7aa2f733}.field input:hover:not(:focus),.field select:hover:not(:focus),.field textarea:hover:not(:focus){border-color:#7aa2f74d}.field input[type=checkbox]{width:auto}.field.mobile-instance-select{display:none}.field-description,.field-hint{display:block;margin:0;font-size:12px;line-height:1.35;color:var(--muted)}.field-description{margin-top:2px}.field-hint{color:var(--primary);font-weight:500;margin-top:4px}.row{display:flex;flex-wrap:wrap;gap:12px}.row .col{flex:1 1 260px}table{border-collapse:collapse;width:100%;border:1px solid var(--border);border-radius:12px;overflow:hidden;box-shadow:0 2px 8px #0000000a}[data-theme=dark] table{box-shadow:0 2px 8px #0003}th,td{border-bottom:1px solid var(--border);padding:10px 12px;font-size:13px;text-align:left}th{background:var(--surface);color:var(--muted);font-weight:600;text-transform:uppercase;font-size:11px;letter-spacing:.05em;border-bottom:2px solid var(--border)}[data-theme=dark] th{background:#12151a}tbody tr{transition:background-color .1s ease,transform .08s ease;border-left:3px solid transparent}tbody tr:hover{background:#7aa2f70d;cursor:default;border-left-color:var(--primary)}[data-theme=light] tbody tr:hover{background:#0071e30a}[data-theme=dark] tbody tr:hover{background:#7aa2f70f}th.sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.sort-arrow{font-size:10px;margin-left:4px;color:var(--muted)}details{margin:6px 0}details summary{cursor:pointer;transition:all .15s ease;padding:4px;border-radius:6px}details summary:hover{background:#7aa2f70d;color:var(--primary)}.ok{color:var(--success)}.bad{color:var(--danger)}.hint{color:var(--muted);font-size:12px}.spacer{flex:1}pre{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:14px;color:var(--on-surface);max-height:420px;overflow:auto;transition:border-color .15s ease}[data-theme=dark] pre{background:#0f131a}pre:hover{border-color:#7aa2f74d}pre::-webkit-scrollbar{width:10px;height:10px}pre::-webkit-scrollbar-track{background:#0003;border-radius:6px}pre::-webkit-scrollbar-thumb{background:#7aa2f74d;border-radius:6px}pre::-webkit-scrollbar-thumb:hover{background:#7aa2f780}.loading{color:var(--muted);display:inline-flex;align-items:center;gap:8px;font-weight:500;animation:pulse 1.5s ease-in-out infinite}.spinner{width:14px;height:14px;border:2.5px solid rgba(122,162,247,.15);border-top-color:var(--primary);border-radius:50%;display:inline-block;animation:spin .6s linear infinite;box-shadow:0 0 8px #7aa2f733}[data-theme=light] .spinner{border:2.5px solid rgba(0,113,227,.15);border-top-color:var(--primary);box-shadow:0 0 8px #0071e333}@keyframes spin{to{transform:rotate(360deg)}}.toasts{position:fixed;right:16px;bottom:16px;display:grid;gap:10px;z-index:9999}.toast{background:var(--surface);color:var(--on-surface);border:1px solid var(--border);border-left:4px solid var(--primary);padding:12px 16px;border-radius:10px;box-shadow:0 12px 32px #0003;min-width:260px;transition:all .2s ease;animation:slideIn .2s ease}[data-theme=dark] .toast{background:#12151a;border:1px solid rgba(255,255,255,.1);box-shadow:0 12px 32px #00000080}.toast:hover{transform:translate(-4px)}[data-theme=dark] .toast:hover{box-shadow:0 16px 40px #0009}[data-theme=light] .toast:hover{box-shadow:0 16px 40px #00000040}.toast.success{border-left-color:var(--success)}.toast.warning{border-left-color:var(--warning)}.toast.error{border-left-color:var(--danger)}[data-theme=dark] .toast.success{background:linear-gradient(90deg,#22c55e14,#12151a 20%)}[data-theme=dark] .toast.warning{background:linear-gradient(90deg,#facc1514,#12151a 20%)}[data-theme=dark] .toast.error{background:linear-gradient(90deg,#ef444414,#12151a 20%)}[data-theme=light] .toast.success{background:linear-gradient(90deg,rgba(52,199,89,.08) 0%,var(--surface) 20%)}[data-theme=light] .toast.warning{background:linear-gradient(90deg,rgba(255,149,0,.08) 0%,var(--surface) 20%)}[data-theme=light] .toast.error{background:linear-gradient(90deg,rgba(255,59,48,.08) 0%,var(--surface) 20%)}.status-pill{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:999px;font-size:12px;font-weight:500;background:#ffffff0d;border:1px solid rgba(255,255,255,.1);transition:all .15s ease}.status-pill:hover{background:#ffffff14;border-color:#ffffff26;transform:scale(1.02)}.stack{display:grid;gap:12px}.tabs{display:flex;gap:8px;flex-wrap:wrap}.tab-panel{margin-top:12px}.sidebar{display:grid;gap:8px;min-width:220px;align-content:start;align-items:start}.sidebar .btn{width:100%;text-align:left}.split{display:flex;gap:16px}.split .pane{flex:1}.split .pane.sidebar{flex:0 0 260px}.pagination{display:flex;justify-content:space-between;align-items:center;margin-top:16px;padding:12px 0;gap:12px;flex-wrap:wrap}.pagination-info{font-size:14px;color:var(--muted)}.pagination .inline{display:flex;gap:4px;align-items:center}.pagination .btn{min-width:70px;padding:8px 12px}.pagination-jump{width:80px;padding:8px 12px;border:1px solid var(--border);border-radius:8px;background:var(--surface);color:var(--on-surface);font-size:14px;text-align:center;transition:all .2s ease}.pagination-jump:focus{outline:none;border-color:var(--primary);box-shadow:0 0 0 3px #7aa2f71a}.pagination-jump:disabled{opacity:.5;cursor:not-allowed}.pagination-jump::-webkit-inner-spin-button,.pagination-jump::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.pagination-jump[type=number]{-moz-appearance:textfield}.badge{display:inline-block;padding:3px 8px;border-radius:6px;font-size:11px;font-weight:600;background:#7aa2f726;border:1px solid rgba(122,162,247,.25);color:var(--primary);transition:all .15s ease}.badge:hover{background:#7aa2f740;border-color:#7aa2f766;transform:scale(1.05)}.icon{display:inline-block;width:1.4em;height:1.4em;vertical-align:middle;object-fit:contain}.icon--small{width:1.2em;height:1.2em}.icon--large{width:1.6em;height:1.6em}svg{max-width:2em;max-height:2em}svg[width],svg[height]{width:1.4em!important;height:1.4em!important}.btn .icon{margin:0;transition:transform .2s ease}.icon-rotate{transform:scaleX(-1);transform-origin:center}.btn:hover .icon{transform:translateY(-1px)}.responsive-table{width:100%;border-collapse:collapse;transition:box-shadow .2s ease}.responsive-table tbody tr{animation:fadeInUp .2s ease}.responsive-table tbody tr:nth-child(2n){background:#ffffff05}.responsive-table td,.responsive-table th{padding:8px 12px;text-align:left}.table-wrapper{overflow-x:auto;border-radius:12px}.table-wrapper::-webkit-scrollbar{height:8px}.table-wrapper::-webkit-scrollbar-thumb{background:#ffffff1f;border-radius:999px}.animate-fade-in{animation:fadeInUp .2s ease}.table-badge{display:inline-flex;align-items:center;gap:4px}.inline{display:inline-flex;align-items:center;gap:6px}.text-info{color:var(--primary)}.text-success{color:var(--success)}.text-danger{color:var(--danger)}@keyframes fadeInUp{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@keyframes slideIn{0%{opacity:0;transform:translate(-10px)}to{opacity:1;transform:translate(0)}}@keyframes pulse{0%,to{opacity:1}50%{opacity:.7}}@keyframes glow{0%,to{box-shadow:0 0 8px #7aa2f74d}50%{box-shadow:0 0 16px #7aa2f780}}@media(max-width:900px){.split{flex-direction:column}.split .pane.sidebar{display:none}.field.mobile-instance-select{display:grid;margin-bottom:12px}}@media(max-width:640px){.appbar__inner{flex-direction:column;align-items:stretch;gap:12px;padding:0}.appbar__actions{width:100%;justify-content:flex-start}.appbar__title{gap:8px}.nav{gap:6px}.nav button{flex:1 1 calc(50% - 6px);justify-content:center}}@media(max-width:420px){.nav button{flex-basis:100%}}@media(max-width:720px){.responsive-table thead{display:none}.responsive-table,.responsive-table tbody,.responsive-table tr,.responsive-table td{display:block;width:100%}.responsive-table tbody tr{background:#12151ab3;border:1px solid rgba(255,255,255,.06);border-radius:8px;padding:8px;margin-bottom:8px;box-shadow:0 4px 12px #0003;user-select:none;-webkit-user-select:none;-moz-user-select:none}.responsive-table td{padding:4px 0;display:flex;justify-content:space-between;align-items:center;gap:8px;border:none;font-size:14px;line-height:1.4}.responsive-table td:before{content:attr(data-label);font-weight:600;font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;flex-shrink:0;min-width:80px}.table-wrapper{overflow:visible}.episodes-table thead{display:none}.episodes-table,.episodes-table tbody,.episodes-table tr,.episodes-table td{display:block;width:100%}.episodes-table tbody tr{background:#12151ab3;border:1px solid rgba(255,255,255,.06);border-radius:8px;padding:8px;margin-bottom:8px;box-shadow:0 4px 12px #0003}.episodes-table td{padding:4px 0;display:flex;justify-content:space-between;align-items:center;gap:8px;border:none;font-size:14px;line-height:1.4}.episodes-table td:before{content:attr(data-label);font-weight:600;font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;flex-shrink:0;min-width:80px}.episodes-table-wrapper{overflow:visible}.tracks-table thead{display:none}.tracks-table,.tracks-table tbody,.tracks-table tr,.tracks-table td{display:block;width:100%}.tracks-table tbody tr{background:#12151ab3;border:1px solid rgba(255,255,255,.06);border-radius:8px;padding:8px;margin-bottom:8px;box-shadow:0 4px 12px #0003}.tracks-table td{padding:4px 0;display:flex;justify-content:space-between;align-items:center;gap:8px;border:none;font-size:14px;line-height:1.4}.tracks-table td:before{content:attr(data-label);font-weight:600;font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;flex-shrink:0;min-width:80px}.tracks-table-wrapper{overflow:visible}}.process-grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.process-section{display:grid;gap:12px}.process-section+.process-section{margin-top:12px}.process-section__title{font-size:12px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;color:var(--primary);padding:0 4px;display:inline-flex;align-items:center;gap:10px}.process-section__title:before{content:"";width:4px;height:18px;background:linear-gradient(180deg,var(--primary),var(--primary-variant));border-radius:3px;box-shadow:0 0 8px #7aa2f74d}.process-card{border:1px solid var(--border);border-radius:14px;background:var(--surface);padding:18px;display:flex;flex-direction:column;gap:14px;transition:all .15s cubic-bezier(.4,0,.2,1);position:relative;overflow:hidden;box-shadow:0 2px 8px #0000000f}[data-theme=dark] .process-card{background:#ffffff08;box-shadow:0 2px 8px #0003}.process-card:before{content:"";position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,var(--primary),var(--primary-variant));opacity:0;transition:opacity .15s ease}.process-card:after{content:"";position:absolute;inset:0;background:radial-gradient(circle at top right,rgba(122,162,247,.05),transparent 60%);opacity:0;transition:opacity .15s ease;pointer-events:none}.process-card:hover{border-color:#7aa2f766;transform:translateY(-3px);box-shadow:0 12px 32px #0000001f}[data-theme=dark] .process-card:hover{box-shadow:0 8px 24px #00000059}.process-card:hover:before,.process-card:hover:after{opacity:1}.process-card__header{position:relative;display:flex;justify-content:space-between;align-items:flex-start;gap:8px;flex-wrap:wrap;padding-right:18px}.process-card__name{font-weight:700;font-size:17px;letter-spacing:-.01em;line-height:1.3}.process-card__title{display:grid;gap:4px;min-width:0}.process-card__summary{font-size:12px;color:var(--muted)}.process-card__badges{display:flex;flex-wrap:wrap;gap:6px;margin-top:4px}.process-card__badge{padding:3px 10px;border-radius:999px;font-size:11px;font-weight:600;background:#7aa2f726;border:1px solid rgba(122,162,247,.3);color:var(--primary);transition:all .15s ease}.process-card__badge:hover{background:#7aa2f740;border-color:#7aa2f780;transform:scale(1.05)}.status-indicator{position:absolute;top:0;right:0;width:12px;height:12px;border-radius:50%;background:#99a2ad99;box-shadow:0 0 6px #00000059;transition:all .2s ease}.status-indicator--ok{background:var(--success);box-shadow:0 0 12px #22c55e80;animation:pulse 1.5s ease-in-out infinite}.status-indicator--bad{background:var(--danger);box-shadow:0 0 12px #ef444480;animation:pulse 1s ease-in-out infinite}.process-card__footer{display:flex;justify-content:flex-end;margin-top:auto}.process-card__list{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.process-chip{display:grid;gap:10px;border:1px solid var(--border);border-radius:10px;padding:12px 14px;background:var(--bg);transition:all .15s ease}[data-theme=dark] .process-chip{border:1px solid rgba(255,255,255,.08);background:#0f131a99}.process-chip:hover{border-color:#7aa2f74d;transform:translate(2px)}[data-theme=dark] .process-chip:hover{background:#0f131acc;border-color:#7aa2f733}[data-theme=light] .process-chip:hover{background:#00000005}.process-chip__top{display:flex;justify-content:space-between;align-items:center;gap:10px}.process-chip__name{font-weight:600;font-size:14px}.process-chip__actions{display:flex;justify-content:flex-end}.process-chip .btn{padding:6px 10px}.process-chip__detail{margin-top:6px;font-size:12px;color:var(--muted);line-height:1.35}.process-chip__detail-time{font-style:italic;color:var(--muted)}.status-pill__dot{width:6px;height:6px;border-radius:50%;background:currentColor;display:inline-block;margin-right:6px}.status-pill--ok{border-color:#22c55e66;background:linear-gradient(135deg,#22c55e26,#22c55e14);color:var(--success);box-shadow:0 2px 8px #22c55e26}.status-pill--bad{border-color:#ef444466;background:linear-gradient(135deg,#ef444426,#ef444414);color:var(--danger);box-shadow:0 2px 8px #ef444426}[data-theme=light] .status-pill--ok{background:linear-gradient(135deg,#34c7591f,#34c7590f)}[data-theme=light] .status-pill--bad{background:linear-gradient(135deg,#ff3b301f,#ff3b300f)}.empty-state{border:2px dashed rgba(122,162,247,.25);border-radius:16px;padding:40px 32px;text-align:center;color:var(--muted);background:linear-gradient(135deg,#7aa2f708,#7aa2f703);transition:all .2s ease;position:relative;overflow:hidden}.empty-state:before{content:"";position:absolute;top:50%;left:50%;width:100px;height:100px;background:radial-gradient(circle,rgba(122,162,247,.08),transparent);transform:translate(-50%,-50%);border-radius:50%;opacity:0;transition:opacity .2s ease}.empty-state:hover{border-color:#7aa2f766;background:linear-gradient(135deg,#7aa2f70d,#7aa2f705)}.empty-state:hover:before{opacity:1}[data-theme=light] .empty-state{border-color:#0071e340;background:linear-gradient(135deg,rgba(0,113,227,.02) 0%,transparent 100%)}[data-theme=light] .empty-state:before{background:radial-gradient(circle,rgba(0,113,227,.06),transparent)}[data-theme=light] .empty-state:hover{border-color:#0071e366;background:linear-gradient(135deg,#0071e30a,#0071e303)}.config-card{border:1px solid var(--border);border-radius:12px;background:var(--surface)}.config-card summary{cursor:pointer;font-weight:600;color:var(--muted);list-style:none;outline:none;padding:12px 14px;border-bottom:1px solid var(--border)}.config-card summary::-webkit-details-marker{display:none}.config-card summary:before{content:">";display:inline-block;margin-right:8px;transition:transform .2s ease}.config-card[open] summary:before{transform:rotate(0)}.config-card:not([open]) summary:before{transform:rotate(-90deg)}.config-card>.card-body{display:grid;gap:12px}.config-summary-card{display:flex;flex-direction:column;gap:12px;min-height:160px;transition:transform .2s ease,box-shadow .2s ease}.config-summary-card:hover{transform:translateY(-2px);box-shadow:0 8px 20px #0000004d}.config-summary-card p{margin:0;color:var(--muted);line-height:1.4}.config-layout{display:grid;gap:16px}.config-actions{display:flex;flex-wrap:wrap;gap:8px}.config-grid{display:grid;gap:20px;grid-template-columns:repeat(auto-fit,minmax(320px,1fr))}.config-arr-groups{display:flex;flex-direction:column;gap:24px}.config-arr-group{display:flex;flex-direction:column;gap:12px}.config-arr-group__details{border:1px solid rgba(255,255,255,.08);border-radius:12px;padding:16px 18px;background:#ffffff08;box-shadow:0 2px 8px #0003}.config-arr-group__details summary{display:flex;justify-content:space-between;align-items:center;gap:12px;cursor:pointer;font-weight:600;font-size:15px;color:var(--on-surface);list-style:none;transition:color .2s ease}.config-arr-group__details summary:hover{color:var(--primary)}.config-arr-group__details summary::-webkit-details-marker{display:none}.config-arr-group__details[open] summary{margin-bottom:16px;padding-bottom:12px;border-bottom:1px solid rgba(255,255,255,.06)}.config-arr-group__count{display:inline-flex;align-items:center;justify-content:center;padding:4px 10px;border-radius:999px;font-size:12px;font-weight:600;background:#7aa2f726;border:1px solid rgba(122,162,247,.3);color:var(--primary)}.config-arr-group__title{margin:0;font-size:14px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.08em}.config-arr-grid{display:grid;gap:18px;grid-template-columns:repeat(auto-fit,minmax(360px,1fr));margin-top:4px}.config-arr-grid .card-body{display:flex;flex-direction:column;gap:12px}.config-arr-card{min-height:220px;transition:transform .2s ease,box-shadow .2s ease}.config-arr-card:hover{transform:translateY(-2px);box-shadow:0 8px 20px #0000004d}.config-arr-summary{display:grid;gap:8px;margin:0}.config-arr-summary__item{display:grid;gap:2px}.config-arr-summary__item dt{margin:0;font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--muted)}.config-arr-summary__item dd{margin:0;color:var(--on-surface);font-weight:500;font-size:13px}.config-arr-summary__uri{word-break:break-all}.config-arr-actions{display:flex;justify-content:flex-end;gap:8px;flex-wrap:wrap}.config-footer{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap}.field-grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.modal .field-grid{grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}@media(max-width:720px){.modal .field-grid{grid-template-columns:minmax(0,1fr)}}.field-label{display:flex;align-items:center;gap:6px;font-weight:600;color:var(--muted)}.checkbox-field{display:flex;flex-direction:column;gap:6px;font-size:13px;color:var(--muted)}.checkbox-field label{display:inline-flex;align-items:center;gap:8px;cursor:pointer;font-weight:600;color:var(--on-surface)}.checkbox-field input{margin:0;flex-shrink:0;cursor:pointer}.checkbox-field__content{display:flex;flex-direction:column;gap:6px;max-width:100%}.checkbox-field__text{display:inline-flex;align-items:center;gap:6px;font-weight:600;color:var(--muted);line-height:1.4}.secure-field{gap:8px}.secure-field__input-group{display:flex;align-items:center;gap:8px}.secure-field__input-group input{flex:1}.secure-field__controls{display:flex;gap:6px}.secure-field__controls .btn{padding:6px 10px}.help-icon{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;font-size:11px;border-radius:50%;border:1px solid rgba(255,255,255,.25);background:#ffffff14;color:var(--muted);cursor:help;transition:border-color .2s ease,color .2s ease}.help-icon:hover{border-color:var(--primary);color:var(--on-surface)}.config-section{border:1px solid rgba(255,255,255,.05);border-radius:10px;padding:8px 12px;background:#ffffff05}.config-section summary{cursor:pointer;font-weight:600;color:var(--muted);list-style:none;outline:none}.config-section summary::-webkit-details-marker{display:none}.config-section summary:before{content:">";display:inline-block;margin-right:8px;transition:transform .2s ease}.config-section[open] summary:before{transform:rotate(0)}.config-section:not([open]) summary:before{transform:rotate(-90deg)}.config-section__body{margin-top:12px}.modal-backdrop{position:fixed;inset:0;background:#00000080;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);display:flex;align-items:flex-start;justify-content:center;padding:24px;overflow-y:auto;overflow-x:hidden;z-index:120;animation:fadeIn .2s ease}[data-theme=dark] .modal-backdrop{background:#000000bf}[data-theme=light] .modal-backdrop{background:#0000004d}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.modal{background:var(--surface);border:1px solid var(--border);border-radius:20px;width:min(840px,calc(100% - 48px));max-height:min(92vh,calc(100vh - 80px));display:flex;flex-direction:column;margin:40px auto;box-shadow:0 24px 64px #0003,0 8px 16px #0000001a;animation:modalSlideIn .2s cubic-bezier(.4,0,.2,1);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px)}[data-theme=dark] .modal{background:#1b1e22f2;border:1px solid rgba(255,255,255,.1);box-shadow:0 20px 60px #0009,0 0 0 1px #ffffff0d}[data-theme=light] .modal{background:#fffffff2}@keyframes modalSlideIn{0%{opacity:0;transform:translateY(-20px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.modal-header{padding:20px 24px;border-bottom:1px solid rgba(255,255,255,.08);display:flex;justify-content:space-between;align-items:center;gap:12px;background:#ffffff05;border-radius:16px 16px 0 0}.modal-header h2{margin:0;font-size:20px;font-weight:600;color:var(--on-surface);letter-spacing:-.01em}.modal-body{padding:24px;overflow-y:auto;overflow-x:hidden;display:grid;gap:20px}.modal-footer{padding:16px 24px 20px;border-top:1px solid rgba(255,255,255,.08);display:flex;justify-content:flex-end;gap:12px;background:#ffffff03;border-radius:0 0 16px 16px}.changelog-modal__body{gap:12px}.changelog-meta{display:flex;flex-direction:column;gap:6px;font-size:13px;color:var(--muted)}.changelog-meta strong{color:var(--on-surface)}.changelog-body{background:var(--bg);border:1px solid var(--border);border-radius:10px;padding:14px;max-height:360px;overflow-y:auto;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,monospace;font-size:13px;line-height:1.5;white-space:pre-wrap;transition:border-color .15s ease}[data-theme=dark] .changelog-body{background:#0f131a}.changelog-body:hover{border-color:#7aa2f74d}.changelog-body::-webkit-scrollbar{width:10px}.changelog-body::-webkit-scrollbar-track{background:#0003;border-radius:6px}.changelog-body::-webkit-scrollbar-thumb{background:#7aa2f74d;border-radius:6px}.changelog-body::-webkit-scrollbar-thumb:hover{background:#7aa2f780}.changelog-links{margin-right:auto;display:flex;align-items:center;gap:8px}.changelog-buttons{display:flex;align-items:center;gap:8px}.tracker-grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(320px,1fr))}.tracker-card.card{background:#ffffff08;border-color:#ffffff14}.tracker-card .card-header{display:flex;justify-content:space-between;align-items:center;gap:12px;font-weight:600;color:var(--on-surface)}.tracker-card .card-body{padding-top:0}.tracker-card .field-grid{grid-template-columns:minmax(0,1fr)}.keyboard-hint{display:inline-flex;align-items:center;gap:4px;padding:2px 6px;border-radius:4px;font-size:10px;font-weight:600;background:#ffffff0d;border:1px solid rgba(255,255,255,.1);color:var(--muted);font-family:monospace}.skeleton{background:linear-gradient(90deg,var(--surface) 0%,rgba(122,162,247,.1) 50%,var(--surface) 100%);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:6px}@keyframes skeleton-loading{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-table{display:flex;flex-direction:column;gap:8px;padding:16px}.skeleton-table-header{display:grid;grid-template-columns:repeat(auto-fit,minmax(100px,1fr));gap:12px;margin-bottom:8px}.skeleton-header{height:24px}.skeleton-table-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(100px,1fr));gap:12px;padding:12px 0;border-bottom:1px solid var(--border)}.skeleton-cell{height:20px}.skeleton-card{padding:20px;background:var(--surface);border-radius:12px;border:1px solid var(--border)}.skeleton-title{height:28px;width:60%;margin-bottom:16px}.skeleton-text{height:16px;margin-bottom:12px}.skeleton-text:last-of-type{width:80%}.skeleton-button{height:40px;width:120px;margin-top:16px;border-radius:8px}.skeleton-text-group{display:flex;flex-direction:column;gap:12px}[data-density=compact] .responsive-table td,[data-density=compact] .responsive-table th{padding:4px 8px;font-size:12px;line-height:1.3}[data-density=compact] .responsive-table{font-size:12px}[data-density=compact] .episodes-table td,[data-density=compact] .episodes-table th{padding:4px 8px;font-size:12px}[data-density=compact] .card{padding:12px;border-radius:8px}[data-density=compact] .card-header{font-size:16px;padding:8px 12px;margin-bottom:8px}[data-density=compact] .card-body{padding:8px 12px}[data-density=compact] .btn{padding:4px 10px;font-size:12px;min-height:28px}[data-density=compact] .btn.small{padding:3px 8px;font-size:11px;min-height:24px}[data-density=compact] .field{margin-bottom:8px}[data-density=compact] .field label{font-size:11px;margin-bottom:2px}[data-density=compact] .field input,[data-density=compact] .field select,[data-density=compact] .field textarea{padding:4px 8px;font-size:12px;min-height:28px}[data-density=compact] .hint{font-size:11px;line-height:1.4}[data-density=compact] .stack{gap:8px}[data-density=compact] .row{gap:6px}[data-density=compact] .table-badge{padding:1px 4px;font-size:10px}[data-density=compact] .table-badge-reason{font-size:9px}[data-density=compact] .container{padding:12px}[data-density=compact] .nav{gap:4px;padding:8px 0}[data-density=compact] .nav button{padding:6px 12px;font-size:12px;gap:6px}[data-density=compact] .pagination{margin-top:8px;padding:8px 0;font-size:12px}[data-density=compact] .season-header{padding:8px 12px;font-size:13px}[data-density=compact] .season-content{padding:8px}[data-density=compact] .series-card{margin-bottom:12px}[data-density=compact] .field-grid{gap:8px}[data-density=compact] h2{font-size:18px;margin-bottom:12px}[data-density=compact] h3{font-size:14px;margin-bottom:8px}[data-density=compact] .modal{padding:16px}[data-density=compact] .modal-header{padding:12px 16px;margin-bottom:12px}[data-density=compact] .modal-body{padding:12px 16px}[data-density=compact] .modal-footer{padding:12px 16px;gap:8px}[data-density=compact] .process-grid{gap:10px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}[data-density=compact] .process-section{gap:8px}[data-density=compact] .process-section+.process-section{margin-top:8px}[data-density=compact] .process-section__title{font-size:11px;padding:0 2px;gap:6px}[data-density=compact] .process-section__title:before{width:3px;height:14px}[data-density=compact] .process-card{padding:10px;gap:8px;border-radius:10px}[data-density=compact] .process-card__header{padding-right:14px;gap:6px}[data-density=compact] .process-card__name{font-size:14px}[data-density=compact] .process-card__summary{font-size:11px}[data-density=compact] .process-card__badges{gap:4px;margin-top:2px}[data-density=compact] .process-card__badge{padding:2px 6px;font-size:10px}[data-density=compact] .process-card__list{gap:8px;grid-template-columns:repeat(auto-fit,minmax(140px,1fr))}[data-density=compact] .process-chip{gap:6px;padding:8px 10px;border-radius:8px}[data-density=compact] .process-chip__top{gap:6px}[data-density=compact] .process-chip__name{font-size:12px}[data-density=compact] .process-chip__detail{margin-top:4px;font-size:11px;line-height:1.3}[data-density=compact] .process-chip .btn{padding:3px 8px;font-size:11px}[data-density=compact] .status-indicator{width:10px;height:10px}[data-density=compact] .status-pill{padding:3px 8px;font-size:11px;gap:4px}[data-density=compact] .status-pill__dot{width:5px;height:5px;margin-right:4px}[data-density=compact] .config-card{border-radius:10px}[data-density=compact] .config-card summary{padding:8px 10px;font-size:13px}[data-density=compact] .config-card summary:before{margin-right:6px}[data-density=compact] .config-card>.card-body{gap:8px}[data-density=compact] .config-summary-card{gap:8px;min-height:120px}[data-density=compact] .config-summary-card p{font-size:12px;line-height:1.3}[data-density=compact] .config-layout{gap:10px}[data-density=compact] .config-actions{gap:6px}[data-density=compact] .config-grid{gap:12px;grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}[data-density=compact] .config-arr-groups{gap:16px}[data-density=compact] .config-arr-group{gap:8px}[data-density=compact] .config-arr-group__details{padding:10px 12px;border-radius:10px}[data-density=compact] .config-arr-group__details summary{gap:8px;font-size:13px}[data-density=compact] .config-arr-group__details[open] summary{margin-bottom:10px;padding-bottom:8px}[data-density=compact] .config-arr-group__count{padding:3px 8px;font-size:11px}[data-density=compact] .config-arr-group__title{font-size:12px}[data-density=compact] .config-arr-grid{gap:12px;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));margin-top:2px}[data-density=compact] .config-arr-grid .card-body{gap:8px}[data-density=compact] .config-arr-card{min-height:160px}[data-density=compact] .config-arr-summary{gap:6px}[data-density=compact] .config-arr-summary__item{gap:1px}[data-density=compact] .config-arr-summary__item dt{font-size:10px}[data-density=compact] .config-arr-summary__item dd{font-size:12px}[data-density=compact] .config-arr-actions{gap:6px}[data-density=compact] .config-footer{gap:8px}[data-density=compact] .config-section{padding:6px 10px;border-radius:8px}[data-density=compact] .config-section summary{font-size:13px}[data-density=compact] .config-section summary:before{margin-right:6px}[data-density=compact] .config-section__body{margin-top:8px}[data-density=compact] .field-description,[data-density=compact] .field-hint{font-size:11px;line-height:1.3;margin-top:2px}[data-density=compact] .field-description{margin-top:1px}[data-density=compact] .field-hint{margin-top:3px}[data-density=compact] .field-label{gap:4px;font-size:11px}[data-density=compact] .checkbox-field{gap:4px;font-size:12px}[data-density=compact] .checkbox-field label{gap:6px}[data-density=compact] .checkbox-field__content{gap:4px}[data-density=compact] .checkbox-field__text{gap:4px;line-height:1.3;font-size:12px}[data-density=compact] .secure-field,[data-density=compact] .secure-field__input-group{gap:6px}[data-density=compact] .secure-field__controls{gap:4px}[data-density=compact] .secure-field__controls .btn{padding:4px 8px}[data-density=compact] .help-icon{width:14px;height:14px;font-size:10px}[data-density=compact] .badge{padding:2px 6px;border-radius:5px;font-size:10px}[data-density=compact] .empty-state{padding:24px 20px;border-radius:12px;font-size:13px}[data-density=compact] .tracker-grid{gap:10px;grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}[data-density=compact] .tracker-card .card-header{gap:8px;font-size:13px}[data-density=compact] .tracker-card .card-body{padding-top:0}[data-density=compact] .keyboard-hint{gap:3px;padding:2px 5px;border-radius:3px;font-size:9px}[data-density=compact] .changelog-modal__body{gap:8px}[data-density=compact] .changelog-meta{gap:4px;font-size:12px}[data-density=compact] .changelog-body{padding:10px;max-height:280px;font-size:12px;line-height:1.4}[data-density=compact] .changelog-links,[data-density=compact] .changelog-buttons{gap:6px}[data-density=compact] details{margin:4px 0}[data-density=compact] details summary{padding:3px;border-radius:5px}[data-density=compact] .series-details,[data-density=compact] .season-details{border-radius:5px}[data-density=compact] .series-summary,[data-density=compact] .season-summary{padding:8px 12px;font-size:13px;border-radius:5px 5px 0 0}[data-density=compact] .series-title{font-size:1em}[data-density=compact] .series-instance{font-size:.85em}[data-density=compact] .season-title{font-size:.95em}[data-density=compact] .season-count{font-size:.85em}[data-density=compact] .series-content,[data-density=compact] .season-content{padding:6px}[data-density=compact] pre{padding:10px;max-height:320px;border-radius:10px;font-size:12px}[data-density=compact] .icon{width:1.2em;height:1.2em}[data-density=compact] .icon--small{width:1em;height:1em}[data-density=compact] .icon--large{width:1.4em;height:1.4em}[data-density=compact] svg[width],[data-density=compact] svg[height]{width:1.2em!important;height:1.2em!important}[data-density=compact] .spinner{width:12px;height:12px;border-width:2px}[data-density=compact] .loading{gap:6px;font-size:12px}[data-density=compact] .toasts{gap:8px;right:12px;bottom:12px}[data-density=compact] .toast{padding:8px 12px;border-radius:8px;min-width:220px;font-size:12px}[data-density=compact] .logs-container{height:calc(100vh - 110px)}[data-density=compact] .logs-toolbar{margin-bottom:8px;gap:8px}[data-density=compact] .logs-toolbar .field{margin-bottom:0}[data-density=compact] .logs-toolbar label{font-size:11px;margin-bottom:2px}[data-density=compact] .logs-toolbar .btn{padding:4px 10px;font-size:12px}[data-density=compact] .logs-content{padding:10px;border-radius:8px}[data-density=compact] .logs-content pre{font-size:11px;line-height:1.4}[data-density=compact] .badge{padding:2px 6px;font-size:10px}[data-density=comfortable] .responsive-table td,[data-density=comfortable] .responsive-table th{padding:12px 16px}.view-density-toggle{display:flex;gap:4px;background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:4px}.view-density-toggle button{padding:6px 12px;border:none;background:transparent;color:var(--muted);border-radius:6px;font-size:13px;font-weight:500;cursor:pointer;transition:all .2s ease}.view-density-toggle button:hover{color:var(--on-surface);background:#7aa2f71a}.view-density-toggle button.active{background:var(--primary);color:#fff}[data-density=compact] .css-13cymwt-control,[data-density=compact] .css-t3ipsp-control,[data-density=compact] .css-15evc9m-control,[data-density=compact] .css-hlgwow,[data-density=compact] [class*=-control]{min-height:32px!important;height:32px!important;font-size:12px!important}[data-density=compact] .css-hlgwow,[data-density=compact] [class*=-ValueContainer]{padding:2px 8px!important;font-size:12px!important}[data-density=compact] .css-1dimb5e-singleValue,[data-density=compact] .css-1jxntwc-singleValue,[data-density=compact] [class*=-singleValue]{font-size:12px!important;line-height:1.4!important}[data-density=compact] .css-1u3zge7,[data-density=compact] [class*=-Input]{padding:0!important;margin:0!important}[data-density=compact] .css-1u3zge7 input,[data-density=compact] [class*=-Input] input{font-size:12px!important;padding:0!important;margin:0!important}[data-density=compact] .css-1nmdiq5-menu,[data-density=compact] [class*=-menu]{font-size:12px!important}[data-density=compact] .css-1n6sfyn-MenuList,[data-density=compact] [class*=-MenuList]{padding:4px!important}[data-density=compact] .css-10wo9uf-option,[data-density=compact] [class*=-option]{padding:6px 10px!important;font-size:12px!important}[data-density=compact] .css-1wy0on6,[data-density=compact] [class*=-indicatorsContainer]{padding:0 4px!important}[data-density=compact] .css-1u9des2-indicatorSeparator,[data-density=compact] [class*=-indicatorSeparator]{margin-top:6px!important;margin-bottom:6px!important}[data-density=compact] .css-1hwfws3,[data-density=compact] .css-1xc3v61-indicatorContainer,[data-density=compact] [class*=-indicatorContainer]{padding:4px!important}[data-density=compact] .css-1xc3v61-indicatorContainer svg,[data-density=compact] [class*=-indicatorContainer] svg{width:16px!important;height:16px!important}[data-density=compact] .appbar{padding:6px 12px!important}[data-density=compact] .appbar__inner{padding:0 6px!important;gap:8px!important}[data-density=compact] .appbar__title{gap:6px!important}[data-density=compact] .appbar__title h1{font-size:15px!important;margin:0!important}[data-density=compact] .appbar__version{font-size:9px!important;padding:2px 5px!important;letter-spacing:.3px!important}[data-density=compact] .appbar__status{font-size:10px!important}[data-density=compact] .appbar__update{padding:4px 8px!important;font-size:10px!important;gap:3px!important}[data-density=compact] .appbar__update-indicator{width:5px!important;height:5px!important}[data-density=compact] .appbar__actions{gap:6px!important}[data-density=compact] .appbar__actions button,[data-density=compact] .appbar__actions a.btn{padding:4px 8px!important;font-size:10px!important;gap:4px!important}[data-density=compact] .appbar__actions .icon{width:14px!important;height:14px!important}[data-density=compact] .appbar__actions .badge{padding:2px 6px!important;font-size:9px!important}[data-density=compact] .spinner{width:11px!important;height:11px!important;border-width:2px!important}[data-density=compact] .view-density-toggle{padding:2px!important;gap:2px!important;border-radius:6px!important}[data-density=compact] .view-density-toggle button{padding:4px 8px!important;font-size:10px!important;border-radius:4px!important}.version-comparison{display:flex;align-items:center;gap:12px;padding:12px;background:#7aa2f70d;border:1px solid rgba(122,162,247,.2);border-radius:8px;margin-bottom:12px}.version-item{display:flex;align-items:center;gap:6px}.version-arrow{color:var(--primary);font-size:18px;font-weight:700}.version-badge{padding:4px 10px;border-radius:6px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,monospace;font-size:12px;font-weight:600}.version-current{background:#9aa3ac26;border:1px solid rgba(154,163,172,.3);color:var(--muted)}.version-latest{background:#7aa2f726;border:1px solid rgba(122,162,247,.3);color:var(--primary)}.update-status{padding:10px 14px;border-radius:8px;font-size:13px;font-weight:500;display:flex;align-items:center;gap:8px}.update-status.text-info{background:#3b82f61a;border:1px solid rgba(59,130,246,.3);color:#3b82f6}.update-status.text-success{background:#22c55e1a;border:1px solid rgba(34,197,94,.3);color:#22c55e}.update-status.text-danger{background:#ef44441a;border:1px solid rgba(239,68,68,.3);color:#ef4444}.changelog-section{display:flex;flex-direction:column;gap:8px}.changelog-section h3{margin:0;font-size:14px;font-weight:600;color:var(--on-surface)}[data-theme=light] .version-comparison{background:#0071e30d;border-color:#0071e326}[data-theme=light] .version-latest{background:#0071e31a;border-color:#0071e340}[data-density=compact] .version-comparison{padding:8px;gap:8px;font-size:12px}[data-density=compact] .version-badge{padding:3px 8px;font-size:11px}[data-density=compact] .version-arrow{font-size:14px}[data-density=compact] .update-status{padding:8px 12px;font-size:12px}[data-density=compact] .changelog-section h3{font-size:13px}.react-lazylog-searchbar{background:var(--surface)!important;border-bottom:1px solid var(--border)!important;padding:8px 12px!important}[data-theme=dark] .react-lazylog-searchbar{background:#0f131a!important}.react-lazylog-searchbar-input{background:var(--bg)!important;color:var(--on-surface)!important;border:1px solid var(--border)!important;border-radius:6px!important;padding:6px 10px!important;font-size:13px!important}[data-theme=dark] .react-lazylog-searchbar-input{background:#12151a!important}.react-lazylog-searchbar-input:focus{outline:none!important;border-color:var(--primary)!important;box-shadow:0 0 0 2px #7aa2f71a!important}[data-theme=light] .react-lazylog-searchbar-input:focus{box-shadow:0 0 0 2px #0071e31a!important}.react-lazylog-searchbar-input::placeholder{color:var(--muted)!important}.react-lazylog-searchbar-matches{color:var(--muted)!important;font-size:12px!important}.react-lazylog-searchbar-filter,.react-lazylog-searchbar-up-arrow,.react-lazylog-searchbar-down-arrow{background:transparent!important;border:1px solid var(--border)!important;border-radius:6px!important;padding:6px!important;cursor:pointer!important;transition:all .15s ease!important}.react-lazylog-searchbar-filter:hover,.react-lazylog-searchbar-up-arrow:hover,.react-lazylog-searchbar-down-arrow:hover{background:#7aa2f71a!important;border-color:var(--primary)!important}[data-theme=light] .react-lazylog-searchbar-filter:hover,[data-theme=light] .react-lazylog-searchbar-up-arrow:hover,[data-theme=light] .react-lazylog-searchbar-down-arrow:hover{background:#0071e314!important}.react-lazylog-searchbar-filter svg,.react-lazylog-searchbar-up-arrow svg,.react-lazylog-searchbar-down-arrow svg{fill:var(--on-surface)!important;width:16px!important;height:16px!important}.react-lazylog-searchbar-filter.inactive,.react-lazylog-searchbar-up-arrow.inactive,.react-lazylog-searchbar-down-arrow.inactive{opacity:.5!important;cursor:not-allowed!important}.react-lazylog-searchbar-matches.inactive{opacity:.5!important}
@@ -0,0 +1,11 @@
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/ProcessesView.js","assets/table.js","assets/vendor.js","assets/useInterval.js","assets/LogsView.js","assets/react-select.esm.js","assets/ArrView.js","assets/ConfigView.js"])))=>i.map(i=>d[i]);
2
+ import{r as Re,a as Le}from"./vendor.js";import{r as o}from"./table.js";(function(){const s=document.createElement("link").relList;if(s&&s.supports&&s.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))i(r);new MutationObserver(r=>{for(const a of r)if(a.type==="childList")for(const f of a.addedNodes)f.tagName==="LINK"&&f.rel==="modulepreload"&&i(f)}).observe(document,{childList:!0,subtree:!0});function n(r){const a={};return r.integrity&&(a.integrity=r.integrity),r.referrerPolicy&&(a.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?a.credentials="include":r.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function i(r){if(r.ep)return;r.ep=!0;const a=n(r);fetch(r.href,a)}})();var F={exports:{}},P={};/**
3
+ * @license React
4
+ * react-jsx-runtime.production.min.js
5
+ *
6
+ * Copyright (c) Facebook, Inc. and its affiliates.
7
+ *
8
+ * This source code is licensed under the MIT license found in the
9
+ * LICENSE file in the root directory of this source tree.
10
+ */var re;function Ne(){if(re)return P;re=1;var e=Re(),s=Symbol.for("react.element"),n=Symbol.for("react.fragment"),i=Object.prototype.hasOwnProperty,r=e.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,a={key:!0,ref:!0,__self:!0,__source:!0};function f(h,m,c){var p,y={},d=null,g=null;c!==void 0&&(d=""+c),m.key!==void 0&&(d=""+m.key),m.ref!==void 0&&(g=m.ref);for(p in m)i.call(m,p)&&!a.hasOwnProperty(p)&&(y[p]=m[p]);if(h&&h.defaultProps)for(p in m=h.defaultProps,m)y[p]===void 0&&(y[p]=m[p]);return{$$typeof:s,type:h,key:d,ref:g,props:y,_owner:r.current}}return P.Fragment=n,P.jsx=f,P.jsxs=f,P}var ne;function Ie(){return ne||(ne=1,F.exports=Ne()),F.exports}var t=Ie(),q={},oe;function Te(){if(oe)return q;oe=1;var e=Le();return q.createRoot=e.createRoot,q.hydrateRoot=e.hydrateRoot,q}var Pe=Te();const Ue="modulepreload",$e=function(e){return"/static/"+e},ae={},W=function(s,n,i){let r=Promise.resolve();if(n&&n.length>0){let m=function(c){return Promise.all(c.map(p=>Promise.resolve(p).then(y=>({status:"fulfilled",value:y}),y=>({status:"rejected",reason:y}))))};document.getElementsByTagName("link");const f=document.querySelector("meta[property=csp-nonce]"),h=f?.nonce||f?.getAttribute("nonce");r=m(n.map(c=>{if(c=$e(c),c in ae)return;ae[c]=!0;const p=c.endsWith(".css"),y=p?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${c}"]${y}`))return;const d=document.createElement("link");if(d.rel=p?"stylesheet":Ue,p||(d.as="script"),d.crossOrigin="",d.href=c,h&&d.setAttribute("nonce",h),document.head.appendChild(d),p)return new Promise((g,v)=>{d.addEventListener("load",g),d.addEventListener("error",()=>v(new Error(`Unable to preload CSS for ${c}`)))})}))}function a(f){const h=new Event("vite:preloadError",{cancelable:!0});if(h.payload=f,window.dispatchEvent(h),!h.defaultPrevented)throw f}return r.then(f=>{for(const h of f||[])h.status==="rejected"&&a(h.reason);return s().catch(a)})},ue=o.createContext(void 0);let Ae=0;function Oe({children:e}){const[s,n]=o.useState([]),i=o.useCallback(f=>{n(h=>h.filter(m=>m.id!==f))},[]),r=o.useCallback((f,h="info")=>{const m=++Ae;n(c=>[...c,{id:m,message:f,kind:h}]),window.setTimeout(()=>i(m),3500)},[i]),a=o.useMemo(()=>({toasts:s,push:r,dismiss:i}),[s,r,i]);return t.jsx(ue.Provider,{value:a,children:e})}function de(){const e=o.useContext(ue);if(!e)throw new Error("useToast must be used within a ToastProvider");return e}function De(){const{toasts:e,dismiss:s}=de();return e.length?t.jsx("div",{className:"toasts",children:e.map(n=>t.jsx("div",{className:`toast ${n.kind!=="info"?n.kind:""}`,role:"status",onClick:()=>s(n.id),children:n.message},n.id))}):null}const fe=o.createContext(void 0);function Ve({children:e}){const[s,n]=o.useState(""),i=o.useRef(new Set),r=o.useCallback(m=>{n(m),i.current.forEach(c=>{c?.(m)})},[]),a=o.useCallback(m=>{m&&i.current.add(m)},[]),f=o.useCallback(m=>{i.current.delete(m)},[]),h=o.useMemo(()=>({value:s,setValue:r,register:a,clearHandler:f}),[s,r,a,f]);return t.jsx(fe.Provider,{value:h,children:e})}function Me(){const e=o.useContext(fe);if(!e)throw new Error("useSearch must be used within a SearchProvider");return e}const qe={"Content-Type":"application/json"},Y=["token","webui-token","webui_token"],Be=1,J=new Map;function We(e,s){const n=e instanceof Request?e.url:String(e),i=s?.method||"GET",r=s?.body?String(s.body):"";return`${i}:${n}:${r}`}function me(){for(const e of Y){const s=localStorage.getItem(e)||sessionStorage.getItem(e);if(s)return e!=="token"&&localStorage.setItem("token",s),s}try{const s=new URLSearchParams(window.location.search).get("token");if(s)return localStorage.setItem("token",s),s}catch{}return null}function Ge(){for(const e of Y)localStorage.removeItem(e);try{for(const e of Y)sessionStorage.removeItem(e)}catch{}}function he(e,s){const n=new Headers(e?.headers||{});return Object.entries(qe).forEach(([i,r])=>{n.has(i)||n.set(i,r)}),s&&!n.has("Authorization")&&n.set("Authorization",`Bearer ${s}`),{...e,headers:n}}async function B(e,s,n,i=Be){const r=me(),a=await fetch(e,he(s,r));return a.status===401&&i>0&&r?(Ge(),B(e,s,n,i-1)):n(a)}async function k(e,s){if((s?.method||"GET")==="GET"){const i=We(e,s),r=J.get(i);if(r)return r;const a=B(e,s,f=>ce(f)).finally(()=>{J.delete(i)});return J.set(i,a),a}return B(e,s,i=>ce(i))}async function He(e,s){return B(e,s,n=>ze(n))}async function ce(e){if(!e.ok){let s=null;try{s=await e.json()}catch{}let n=`${e.status} ${e.statusText}`;if(s&&typeof s=="object"&&"error"in s&&typeof s.error=="string"){const i=s.error;i.trim()&&(n=i)}throw new Error(n)}return await e.json()}async function ze(e){if(!e.ok)throw new Error(`${e.status} ${e.statusText}`);return e.text()}async function ie(e){const s=e?.force?"?force=1":"";return k(`/web/meta${s}`)}async function le(){return k("/web/status")}async function gt(){return k("/web/processes")}async function pt(e,s){const n=`/web/processes/${encodeURIComponent(e)}/${encodeURIComponent(s)}/restart`;return k(n,{method:"POST"})}async function vt(){return k("/web/processes/restart_all",{method:"POST"})}async function yt(){return k("/web/arr/rebuild",{method:"POST"})}async function wt(){return k("/web/logs")}async function bt(e){return He(`/web/logs/${encodeURIComponent(e)}`)}function xt(e){return`/web/logs/${encodeURIComponent(e)}/download`}async function _t(){return k("/web/arr")}async function jt(e,s,n,i){const r=new URLSearchParams;return r.set("page",String(s)),r.set("page_size",String(n)),i&&r.set("q",i),k(`/web/radarr/${encodeURIComponent(e)}/movies?${r}`)}async function kt(e,s,n,i,r){const a=new URLSearchParams;return a.set("page",String(s)),a.set("page_size",String(n)),i&&a.set("q",i),r?.missingOnly&&a.set("missing","1"),k(`/web/sonarr/${encodeURIComponent(e)}/series?${a}`)}async function Ct(e,s,n,i){const r=new URLSearchParams;return r.set("page",s.toString()),r.set("page_size",n.toString()),i&&r.set("q",i),r.set("include_tracks","true"),k(`/web/lidarr/${encodeURIComponent(e)}/albums?${r}`)}async function St(e){await k(`/web/arr/${encodeURIComponent(e)}/restart`,{method:"POST"})}async function Fe(){return k("/web/config")}async function Je(e){const s=me(),n=await fetch("/web/config",he({method:"POST",body:JSON.stringify(e)},s));if(!n.ok){let r=null;try{r=await n.json()}catch{}let a=`${n.status} ${n.statusText}`;if(r&&typeof r=="object"&&"error"in r&&typeof r.error=="string"){const f=r.error;f.trim()&&(a=f)}throw new Error(a)}return await n.json()}async function Ke(){await k("/web/update",{method:"POST"})}const ge=o.createContext(null);function Ye({children:e}){const[s,n]=o.useState({liveArr:!0,groupSonarr:!0,groupLidarr:!0,viewDensity:"comfortable",theme:"dark"}),[i,r]=o.useState(!0);o.useEffect(()=>{(async()=>{try{const v=(await Fe())?.WebUI,x=localStorage.getItem("viewDensity"),S=localStorage.getItem("theme"),I=v?.Theme,E=S||I?.toLowerCase()||"dark";n({liveArr:v?.LiveArr===!0,groupSonarr:v?.GroupSonarr===!0,groupLidarr:v?.GroupLidarr===!0,viewDensity:x||"comfortable",theme:E}),document.documentElement.setAttribute("data-theme",E)}catch(g){console.error("Failed to load WebUI settings:",g)}finally{r(!1)}})()},[]);const a=o.useCallback(async(d,g)=>{try{const v={WebUI:{[d]:g}};await Je({changes:v})}catch(v){console.error(`Failed to save ${d}:`,v)}},[]),f=o.useCallback(d=>{n(g=>({...g,liveArr:d})),a("LiveArr",d)},[a]),h=o.useCallback(d=>{n(g=>({...g,groupSonarr:d})),a("GroupSonarr",d)},[a]),m=o.useCallback(d=>{n(g=>({...g,groupLidarr:d})),a("GroupLidarr",d)},[a]),c=o.useCallback(d=>{n(g=>({...g,viewDensity:d})),localStorage.setItem("viewDensity",d)},[]),p=o.useCallback(d=>{n(v=>({...v,theme:d})),localStorage.setItem("theme",d),document.documentElement.setAttribute("data-theme",d),a("Theme",d==="light"?"Light":"Dark")},[a]),y={liveArr:s.liveArr,groupSonarr:s.groupSonarr,groupLidarr:s.groupLidarr,viewDensity:s.viewDensity,theme:s.theme,setLiveArr:f,setGroupSonarr:h,setGroupLidarr:m,setViewDensity:c,setTheme:p,loading:i};return t.jsx(ge.Provider,{value:y,children:e})}function Qe(){const e=o.useContext(ge);if(!e)throw new Error("useWebUI must be used within WebUIProvider");return e}function Xe(){const[e,s]=o.useState(navigator.onLine);return o.useEffect(()=>{const n=()=>s(!0),i=()=>s(!1);return window.addEventListener("online",n),window.addEventListener("offline",i),()=>{window.removeEventListener("online",n),window.removeEventListener("offline",i)}},[]),e}function C({src:e,alt:s,className:n,...i}){return t.jsx("img",{src:e,alt:s??"",className:n?`icon ${n}`:"icon","aria-hidden":s?void 0:!0,...i})}const pe="/static/assets/close.svg",Q="data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20xml:space='preserve'%20viewBox='0%200%20512%20512'%3e%3cpath%20d='M256%206.3C114.6%206.3%200%20120.9%200%20262.3c0%20113.3%2073.3%20209%20175%20242.9%2012.8%202.2%2017.6-5.4%2017.6-12.2%200-6.1-.3-26.2-.3-47.7-64.3%2011.8-81-15.7-86.1-30.1-2.9-7.4-15.4-30.1-26.2-36.2-9-4.8-21.8-16.6-.3-17%2020.2-.3%2034.6%2018.6%2039.4%2026.2%2023%2038.7%2059.8%2027.8%2074.6%2021.1%202.2-16.6%209-27.8%2016.3-34.2-57-6.4-116.5-28.5-116.5-126.4%200-27.8%209.9-50.9%2026.2-68.8-2.6-6.4-11.5-32.6%202.6-67.8%200%200%2021.4-6.7%2070.4%2026.2%2020.5-5.8%2042.2-8.6%2064-8.6s43.5%202.9%2064%208.6c49-33.3%2070.4-26.2%2070.4-26.2%2014.1%2035.2%205.1%2061.4%202.6%2067.8%2016.3%2017.9%2026.2%2040.6%2026.2%2068.8%200%2098.2-59.8%20120-116.8%20126.4%209.3%208%2017.3%2023.4%2017.3%2047.4%200%2034.2-.3%2061.8-.3%2070.4%200%206.7%204.8%2014.7%2017.6%2012.2C438.7%20471.3%20512%20375.3%20512%20262.3c0-141.4-114.6-256-256-256'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%231b1f23'/%3e%3c/svg%3e",Ze="/static/assets/refresh-arrow.svg",ve="/static/assets/up-arrow.svg",et="/static/assets/process.svg",tt="/static/assets/log.svg",st="data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20xml:space='preserve'%20id='Layer_1'%20x='0'%20y='0'%20version='1.1'%20viewBox='0%200%20512%20512'%3e%3cstyle%3e.st0{fill:%2324292e}%3c/style%3e%3cg%20id='Group-Copy'%20transform='translate(70%2021)'%3e%3cpath%20id='Shape'%20d='m10.3%2059.8%203.9%20372.4c-31.4%203.9-54.9-11.8-54.9-43.1l-3.9-309.7c0-98%2090.2-121.5%20145.1-82.3l278.3%20160.7c39.2%2027.4%2047%2078.4%2027.4%20113.7-3.9-27.4-15.7-43.1-39.2-58.8L53.4%2036.2C29.9%2020.6%2010.3%2024.5%2010.3%2059.8'%20class='st0'/%3e%3cpath%20id='Shape_00000114049535938561773820000018271523940913105341_'%20d='M-13.2%20451.8c23.5%207.8%2047%203.9%2066.6-7.8l321.5-188.2c19.6%2027.4%2015.7%2054.9-7.8%2070.6L96.5%20483.2c-39.2%2019.6-90.1%200-109.7-31.4'%20class='st0'/%3e%3cpath%20id='Shape_00000165935924413286433040000003668002807793862576_'%20d='M80.9%20342%20273%20232.3%2084.8%20126.4z'%20style='fill:%23ffc230'/%3e%3c/g%3e%3c/svg%3e",rt="data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20xml:space='preserve'%20viewBox='0%200%20512%20512'%3e%3cpath%20d='M511.8%20256c0%2070.4-24.9%20130.8-74.6%20181.1-1.7%202-3.5%203.8-5.5%205.4-8.2%208-16.8%2015.3-26%2021.8Q341.05%20512%20256.3%20512c-56.6%200-106.3-15.9-149.2-47.7-11.3-8-22-17.1-31.9-27.3C36.5%20398.7%2012.8%20354%204%20303.2c-1.7-9.9-2.9-20-3.4-30.2-.2-5.7-.4-11.3-.4-17%200-6%20.1-11.7.4-17.1%200-.6.2-1.1.5-1.7%203.7-62.8%2028.4-117%2074.1-162.8C125.5%2024.8%20185.8%200%20256.2%200c70.7%200%20131%2024.8%20180.9%2074.5q74.7%2075.9%2074.7%20181.5'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%23eee'/%3e%3cpath%20d='m459.7%20100.3-52.9%2052.9c-30.9%2030.9-33.6%2057.8-33.6%20105.3%200%2042.3%206.7%2081.1%2038.2%20112.6%2023%2023%2044.9%2044.7%2044.9%2044.7-5.9%207.2-12.3%2014.3-19.1%2021.2-1.7%202-3.5%203.8-5.5%205.4-6%205.9-12.2%2011.4-18.6%2016.4l-41.4-41.4C334.9%20380.6%20305.6%20377%20257%20377c-46.7%200-78.4%204.3-112.6%2038.5-20.4%2020.4-43.8%2043.9-43.8%2043.9-8.9-6.8-17.3-14.2-25.3-22.4-6.6-6.6-12.8-13.4-18.5-20.3%200%200%2023.1-23.2%2045.2-45.3%2032.7-32.7%2038-70.6%2038-113%200-41.3-6.8-79.8-36.8-109.9C82.2%20127.7%2053.3%2099%2053.3%2099c6.7-8.5%2014-16.7%2021.8-24.5%206.9-6.8%2014-13.1%2021.2-19l48%2048c30.7%2030.7%2070%2038.6%20112.4%2038.6%2043.6%200%2082.8-8.4%20114.7-40.4C391%2082.1%20417%2056.3%20417%2056.3c6.8%205.6%2013.5%2011.6%2020.1%2018.2%208.3%208.3%2015.8%2016.9%2022.6%2025.8'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%233a3f51'/%3e%3cpath%20d='M186%20269.1c-.5-2.8-.8-5.5-.9-8.4-.1-1.6-.1-3.1-.1-4.7%200-1.7%200-3.2.1-4.7%200-.2%200-.3.1-.5%201-17.4%207.9-32.4%2020.5-45.1%2013.9-13.8%2030.6-20.7%2050.2-20.7s36.3%206.9%2050.2%2020.7c13.8%2014%2020.7%2030.8%2020.7%2050.3s-6.9%2036.2-20.7%2050.2c-.5.5-1%201.1-1.5%201.5q-3.45%203.3-7.2%206-18%2013.2-41.4%2013.2c-23.4%200-29.4-4.4-41.3-13.2-3.1-2.2-6.1-4.7-8.9-7.6-10.8-10.6-17.3-22.9-19.8-37'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%230cf'/%3e%3cpath%20d='m372.7%20141-35.4%2034.6M72.9%2076.8l96.5%2096.1m199.7%20198.9%2065.6%2067.9m4.4-363.3L372.7%20141M76.6%20438.5l64.6-64.7'%20style='fill:none;stroke:%230cf;stroke-width:2;stroke-miterlimit:1'/%3e%3cpath%20d='m372.7%20141-40%2040.6m-193.3-38.5%2040.6%2040.5M141%20374l39.5-41.1m146.2-3.3%2042.6%2042.4'%20style='fill:none;stroke:%230cf;stroke-width:7;stroke-miterlimit:1'/%3e%3c/svg%3e",nt="/static/assets/lidarr.svg",ot="/static/assets/gear.svg",at=o.lazy(()=>W(()=>import("./ProcessesView.js"),__vite__mapDeps([0,1,2,3])).then(e=>({default:e.ProcessesView}))),ct=o.lazy(()=>W(()=>import("./LogsView.js"),__vite__mapDeps([4,1,2,5,3])).then(e=>({default:e.LogsView}))),K=o.lazy(()=>W(()=>import("./ArrView.js"),__vite__mapDeps([6,1,2,3])).then(e=>({default:e.ArrView}))),it=o.lazy(()=>W(()=>import("./ConfigView.js"),__vite__mapDeps([7,1,2,5])).then(e=>({default:e.ConfigView})));function U(e){if(!e)return"unknown";const s=e.trim();return s?s[0]==="v"||s[0]==="V"?s:`v${s}`:"unknown"}function lt({currentVersion:e,changelog:s,changelogUrl:n,repositoryUrl:i,onClose:r}){return t.jsx("div",{className:"modal-backdrop",role:"presentation",onClick:r,children:t.jsxs("div",{className:"modal",role:"dialog","aria-modal":"true","aria-labelledby":"welcome-title",onClick:a=>a.stopPropagation(),children:[t.jsxs("div",{className:"modal-header",children:[t.jsxs("h2",{id:"welcome-title",children:["🎉 Welcome to qBitrr ",U(e),"!"]}),t.jsxs("button",{className:"btn ghost",type:"button",onClick:r,children:[t.jsx(C,{src:pe}),"Close"]})]}),t.jsxs("div",{className:"modal-body changelog-modal__body",children:[t.jsx("div",{className:"changelog-meta",children:t.jsxs("p",{style:{marginBottom:"1rem",color:"var(--text-secondary)"},children:["You've been updated to version ",t.jsx("strong",{children:U(e)}),". Here's what's new in this release:"]})}),t.jsxs("div",{className:"changelog-section",children:[t.jsx("h3",{children:"Release Notes"}),t.jsx("pre",{className:"changelog-body",children:s?.trim()?s.trim():"No changelog available for this version."})]})]}),t.jsxs("div",{className:"modal-footer",children:[t.jsx("div",{className:"changelog-links",children:(n||i)&&t.jsxs("a",{className:"btn ghost small",href:n??i,target:"_blank",rel:"noreferrer",children:[t.jsx(C,{src:Q}),"View Full Release on GitHub"]})}),t.jsx("div",{className:"changelog-buttons",children:t.jsx("button",{className:"btn primary",type:"button",onClick:r,children:"Got it!"})})]})]})})}function ut({currentVersion:e,latestVersion:s,changelog:n,changelogUrl:i,repositoryUrl:r,updateState:a,updating:f,onClose:h,onUpdate:m}){const[c,p]=o.useState(null),y=f||!!a?.in_progress,d=a?.completed_at?new Date(a.completed_at).toLocaleString():null;o.useEffect(()=>{if(a?.last_result==="success"&&a?.completed_at){let x=10;p(x);const S=setInterval(()=>{x-=1,x<=0?(clearInterval(S),window.location.reload()):p(x)},1e3);return()=>clearInterval(S)}},[a?.last_result,a?.completed_at]);let g="",v=null;if(a?.in_progress)g="text-info",v="⏳ Update in progress...";else if(a?.last_result==="success")g="text-success",c!==null?v=`✓ Update completed! Reloading in ${c}s...`:(v="✓ Update completed successfully",d&&(v=`${v} (${d})`));else if(a?.last_result==="error"){g="text-danger";const x=a.last_error?a.last_error.trim():"";v=x?`✗ Update failed: ${x}`:"✗ Update failed"}return t.jsx("div",{className:"modal-backdrop",role:"presentation",onClick:h,children:t.jsxs("div",{className:"modal",role:"dialog","aria-modal":"true","aria-labelledby":"changelog-title",onClick:x=>x.stopPropagation(),children:[t.jsxs("div",{className:"modal-header",children:[t.jsx("h2",{id:"changelog-title",children:a?.in_progress?"⚙️ Updating...":"🚀 Update Available"}),t.jsxs("button",{className:"btn ghost",type:"button",onClick:h,disabled:a?.in_progress,children:[t.jsx(C,{src:pe}),"Close"]})]}),t.jsxs("div",{className:"modal-body changelog-modal__body",children:[t.jsxs("div",{className:"changelog-meta",children:[t.jsxs("div",{className:"version-comparison",children:[t.jsxs("span",{className:"version-item",children:[t.jsx("strong",{children:"Current:"})," ",t.jsx("span",{className:"version-badge version-current",children:U(e)})]}),t.jsx("span",{className:"version-arrow",children:"→"}),t.jsxs("span",{className:"version-item",children:[t.jsx("strong",{children:"Latest:"})," ",t.jsx("span",{className:"version-badge version-latest",children:s?U(s):"Unknown"})]})]}),v?t.jsx("div",{className:`update-status ${g}`,children:v}):null]}),t.jsxs("div",{className:"changelog-section",children:[t.jsx("h3",{children:"What's New"}),t.jsx("pre",{className:"changelog-body",children:n?.trim()?n.trim():"No changelog provided."})]})]}),t.jsxs("div",{className:"modal-footer",children:[t.jsx("div",{className:"changelog-links",children:(i||r)&&t.jsxs("a",{className:"btn ghost small",href:i??r,target:"_blank",rel:"noreferrer",children:[t.jsx(C,{src:Q}),"View on GitHub"]})}),t.jsx("div",{className:"changelog-buttons",children:t.jsxs("button",{className:"btn primary",type:"button",onClick:m,disabled:y,children:[t.jsx(C,{src:ve}),y?"Updating...":"Update Now"]})})]})]})})}function dt(){const[e,s]=o.useState("processes"),[n,i]=o.useState(!1),{push:r}=de(),{setValue:a}=Me(),{viewDensity:f,setViewDensity:h}=Qe(),m=Xe(),[c,p]=o.useState(null),[y,d]=o.useState(!1),[g,v]=o.useState(!1),[x,S]=o.useState(!1),[I,E]=o.useState(!1),R=o.useRef(0),G=o.useRef(null),H=o.useRef(!1),$=o.useRef(!1),L=o.useRef(null),[N,X]=o.useState(0),[Z,ee]=o.useState(null),[ye,te]=o.useState(!1);o.useEffect(()=>{(async()=>{if("caches"in window)try{const l=await caches.keys();await Promise.all(l.map(b=>caches.delete(b))),console.log("Cache cleared on page load")}catch(l){console.error("Failed to clear cache:",l)}})()},[]);const _=o.useCallback(async u=>{const l=u?.force??!1,b=u?.silent??!l;b||d(!0);try{const j=await ie({force:l});p(j)}catch(j){if(!b){const w=j instanceof Error?j.message:"Failed to fetch version information";r(w,"error")}}finally{b||d(!1)}},[r]);o.useEffect(()=>{_({force:!0})},[_]),o.useEffect(()=>{if(!c?.current_version)return;const u=localStorage.getItem("lastSeenVersion"),l=c.current_version;u&&u!==l&&(!c.current_version_changelog&&!c.changelog&&_({force:!0,silent:!0}),te(!0)),u||localStorage.setItem("lastSeenVersion",l)},[c?.current_version,c?.changelog,_]),o.useEffect(()=>{m||r("You are offline. Some features may not work.","warning")},[m,r]),o.useEffect(()=>{const u=l=>{if(l.target instanceof HTMLInputElement||l.target instanceof HTMLTextAreaElement||l.target instanceof HTMLSelectElement)return;const b=l.ctrlKey||l.metaKey;if(b&&l.key==="k"){l.preventDefault(),document.querySelector('input[type="text"][placeholder*="Search"]')?.focus();return}if(l.key==="r"||l.key==="R"){l.preventDefault(),X(j=>j+1),r("Refreshed","success");return}if(l.key==="Escape"){a("");return}if(l.key>="1"&&l.key<="6"&&!b){l.preventDefault();const j=parseInt(l.key)-1,w=["processes","logs","radarr","sonarr","lidarr","config"];j<w.length&&s(w[j]);return}};return window.addEventListener("keydown",u),()=>window.removeEventListener("keydown",u)},[a,r]),o.useEffect(()=>{const u=window.setInterval(()=>{_()},3e5);return()=>window.clearInterval(u)},[_]),o.useEffect(()=>{const u=()=>{document.visibilityState==="visible"&&(X(l=>l+1),_({force:!0}),A())};return document.addEventListener("visibilitychange",u),()=>{document.removeEventListener("visibilitychange",u)}},[_]);const A=o.useCallback(async()=>{try{const u=await le();ee(u)}catch{}},[]);o.useEffect(()=>{A();const u=window.setInterval(()=>{A()},5*1e3);return()=>window.clearInterval(u)},[A]),o.useEffect(()=>{if(!c?.update_state?.in_progress&&!I){R.current=0;return}const u=window.setInterval(async()=>{try{const l=await ie({force:!0});p(l),I&&window.location.reload(),R.current=0}catch{if(R.current+=1,R.current>20){E(!1),R.current=0,r("Update completed but backend restart timed out. Please refresh the page manually.","warning");return}c?.update_state?.in_progress&&E(!0)}},3e3);return()=>window.clearInterval(u)},[c?.update_state?.in_progress,I,c,r]),o.useEffect(()=>{const u=c?.update_state;if(!u){G.current=null;return}const l=u.last_result??null;l&&l!==G.current&&(l==="success"?(r("Update completed successfully. Restarting...","success"),E(!0),R.current=0):l==="error"&&r(u.last_error||"Update failed.","error")),G.current=l},[c?.update_state,r]),o.useEffect(()=>{let u=!1,l=0;const b=w=>{L.current!==null&&window.clearTimeout(L.current),L.current=window.setTimeout(()=>{j()},w)},j=async()=>{if(!(u||H.current)){l+=1;try{const w=await le();if(u)return;if(ee(w),w.ready??(Array.isArray(w.arrs)&&w.arrs.length>0)){H.current=!0;return}w.ready===!1&&l>=3&&!$.current&&($.current=!0,r("qBitrr backend is still initialising. Check the logs if this persists.","warning"))}catch(w){if(!$.current&&l>=3){$.current=!0;const M=w instanceof Error?w.message:"Unknown backend error";r(`Unable to confirm qBitrr readiness (${M}). Please inspect the logs.`,"warning")}}finally{if(!u&&!H.current){const w=l<3?3e3:1e4;b(w)}}}};return b(0),()=>{u=!0,L.current!==null&&(window.clearTimeout(L.current),L.current=null)}},[r]);const O=o.useMemo(()=>{const u=[{id:"processes",label:"Processes",icon:et},{id:"logs",label:"Logs",icon:tt}],l=[],b=Z?.arrs??[],j=b.some(T=>T.type==="radarr"),w=b.some(T=>T.type==="sonarr"),M=b.some(T=>T.type==="lidarr");return j&&l.push({id:"radarr",label:"Radarr",icon:st}),w&&l.push({id:"sonarr",label:"Sonarr",icon:rt}),M&&l.push({id:"lidarr",label:"Lidarr",icon:nt}),[...u,...l,{id:"config",label:"Config",icon:ot}]},[Z]),D=c?.repository_url??"https://github.com/Feramance/qBitrr",we=c?.current_version?U(c.current_version):"...",be=c?.latest_version??null,xe=!!c?.update_available,z=c?.update_state,se=c?.changelog_url??D,V=[];c?.last_checked&&V.push(`Last checked ${new Date(c.last_checked).toLocaleString()}`),c?.error&&V.push(`Update check failed: ${c.error}`);const _e=V.length?V.join(" • "):void 0;o.useEffect(()=>{!O.some(l=>l.id===e)&&O.length>0&&s("processes")},[O,e]);const je=o.useCallback(()=>{_({force:!0})},[_]),ke=o.useCallback(()=>{v(!0),c?.changelog||_({force:!0,silent:!0})},[c?.changelog,_]),Ce=o.useCallback(()=>{v(!1)},[]),Se=o.useCallback(()=>{te(!1),c?.current_version&&localStorage.setItem("lastSeenVersion",c.current_version)},[c?.current_version]),Ee=o.useCallback(async()=>{S(!0),E(!1),R.current=0;try{await Ke(),r("Update started in the background.","info"),await _({force:!0,silent:!0})}catch(u){const l=u instanceof Error?u.message:"Failed to start update";r(l,"error")}finally{S(!1)}},[r,_]);return t.jsxs("div",{"data-density":f,children:[t.jsx("header",{className:"appbar",children:t.jsxs("div",{className:"appbar__inner",children:[t.jsxs("div",{className:"appbar__title",children:[t.jsx("h1",{children:"qBitrr"}),t.jsx("span",{className:"appbar__version",title:_e,children:we}),y?t.jsx("span",{className:"spinner","aria-hidden":"true"}):null,z?.in_progress?t.jsx("span",{className:"appbar__status text-info",children:"Updating..."}):null,xe?t.jsxs("button",{type:"button",className:"btn small primary appbar__update",onClick:ke,disabled:x||!!z?.in_progress,children:[t.jsx("span",{className:"appbar__update-indicator","aria-hidden":"true"}),t.jsx(C,{src:ve}),"Update available"]}):null]}),t.jsxs("div",{className:"appbar__actions",children:[!m&&t.jsx("span",{className:"badge",style:{background:"rgba(239, 68, 68, 0.15)",borderColor:"rgba(239, 68, 68, 0.3)",color:"var(--danger)"},children:"Offline"}),t.jsxs("div",{className:"view-density-toggle",children:[t.jsx("button",{type:"button",className:f==="comfortable"?"active":"",onClick:()=>h("comfortable"),title:"Comfortable view",children:"Comfortable"}),t.jsx("button",{type:"button",className:f==="compact"?"active":"",onClick:()=>h("compact"),title:"Compact view",children:"Compact"})]}),t.jsxs("button",{type:"button",className:"btn small ghost",onClick:je,disabled:y,children:[t.jsx(C,{src:Ze}),y?"Checking...":"Check Updates"]}),t.jsxs("a",{href:D,target:"_blank",rel:"noreferrer",className:"btn small ghost",children:[t.jsx(C,{src:Q}),"GitHub"]})]})]})}),t.jsxs("main",{className:"container",children:[t.jsx("nav",{className:"nav",children:O.map(u=>t.jsxs("button",{type:"button",className:e===u.id?"active":"",onClick:()=>{e==="config"&&u.id!=="config"&&n&&!window.confirm("You have unsaved configuration changes. Leave without saving?")||(s(u.id),a(""))},children:[t.jsx(C,{src:u.icon}),t.jsx("span",{children:u.label})]},u.id))}),t.jsxs(o.Suspense,{fallback:t.jsx("div",{className:"loading",children:"Loading..."}),children:[e==="processes"&&t.jsx(at,{active:!0},`processes-${N}`),e==="logs"&&t.jsx(ct,{active:!0},`logs-${N}`),e==="radarr"&&t.jsx(K,{type:"radarr",active:!0},`radarr-${N}`),e==="sonarr"&&t.jsx(K,{type:"sonarr",active:!0},`sonarr-${N}`),e==="lidarr"&&t.jsx(K,{type:"lidarr",active:!0},`lidarr-${N}`),e==="config"&&t.jsx(it,{onDirtyChange:i},`config-${N}`)]})]}),g&&c?t.jsx(ut,{currentVersion:c.current_version,latestVersion:be,changelog:c.changelog,changelogUrl:se,repositoryUrl:D,updateState:z,updating:x,onClose:Ce,onUpdate:Ee}):null,ye&&c?t.jsx(lt,{currentVersion:c.current_version,changelog:c.current_version_changelog||c.changelog,changelogUrl:se,repositoryUrl:D,onClose:Se}):null]})}function ft(){return t.jsx(Oe,{children:t.jsx(Ve,{children:t.jsxs(Ye,{children:[t.jsx(dt,{}),t.jsx(De,{})]})})})}Pe.createRoot(document.getElementById("root")).render(t.jsx(o.StrictMode,{children:t.jsx(ft,{})}));export{pe as C,C as I,Ze as R,le as a,vt as b,yt as c,wt as d,bt as e,xt as f,gt as g,Me as h,Qe as i,t as j,_t as k,jt as l,St as m,kt as n,Ct as o,Fe as p,Je as q,pt as r,ot as s,de as u};
11
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"mappings":"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","names":["f","require$$0","k","l","m","n","p","q","c","a","g","b","d","e","h","reactJsxRuntime_production_min","jsxRuntimeModule","client","ToastContext","createContext","toastCounter","ToastProvider","children","toasts","setToasts","useState","dismiss","useCallback","id","prev","t","push","message","kind","value","useMemo","jsx","useToast","ctx","useContext","ToastViewport","toast","SearchContext","SearchProvider","setValueState","handlers","useRef","setValue","term","handler","register","clearHandler","valueObj","useSearch","JSON_HEADERS","TOKEN_STORAGE_KEYS","MAX_AUTH_RETRIES","inflightRequests","createRequestKey","input","init","url","method","body","resolveToken","key","fromQuery","clearStoredToken","buildInit","token","headers","fetchWithAuthRetry","retries","response","fetchJson","existingRequest","promise","handleJson","fetchTextResponse","handleText","res","detail","errorText","getMeta","params","query","getStatus","getProcesses","restartProcess","category","restartAllProcesses","rebuildArrs","getLogs","getLogTail","name","getLogDownloadUrl","getArrList","getRadarrMovies","page","pageSize","getSonarrSeries","options","getLidarrAlbums","restartArr","getConfig","updateConfig","payload","triggerUpdate","WebUIContext","WebUIProvider","settings","setSettings","loading","setLoading","useEffect","webui","storedDensity","storedTheme","backendTheme","theme","error","saveSettings","changes","setLiveArr","setGroupSonarr","setGroupLidarr","setViewDensity","setTheme","useWebUI","context","useNetworkStatus","isOnline","setIsOnline","handleOnline","handleOffline","IconImage","src","alt","className","rest","CloseIcon","ExternalIcon","RefreshIcon","UpdateIcon","ProcessesIcon","LogsIcon","RadarrIcon","SonarrIcon","LidarrIcon","ConfigureIcon","ProcessesView","lazy","__vitePreload","module","LogsView","ArrView","ConfigView","formatVersionLabel","trimmed","WelcomeModal","currentVersion","changelog","changelogUrl","repositoryUrl","onClose","jsxs","event","ChangelogModal","latestVersion","updateState","updating","onUpdate","countdown","setCountdown","updateDisabled","completedLabel","timer","statusClass","statusMessage","AppShell","activeTab","setActiveTab","configDirty","setConfigDirty","setSearchValue","viewDensity","meta","setMeta","metaLoading","setMetaLoading","showChangelog","setShowChangelog","updateBusy","setUpdateBusy","backendRestarting","setBackendRestarting","restartPollCount","prevUpdateResult","backendReadyRef","backendWarnedRef","backendTimerRef","reloadKey","setReloadKey","statusData","setStatusData","showWelcomeChangelog","setShowWelcomeChangelog","cacheNames","cacheName","refreshMeta","force","silent","data","lastSeenVersion","handleKeyDown","isMod","tabIndex","tabIds","handleVisibilityChange","refreshStatus","status","state","result","cancelled","attempts","schedule","delay","poll","tabs","baseTabs","arrTabs","arrs","hasRadarr","arr","hasSonarr","hasLidarr","ConfigIcon","displayVersion","updateAvailable","versionTitleParts","versionTitle","tab","handleCheckUpdates","handleOpenChangelog","handleCloseChangelog","handleCloseWelcomeChangelog","handleTriggerUpdate","Suspense","App","createRoot","StrictMode"],"ignoreList":[0,1,2],"sources":["../../../webui/node_modules/react/cjs/react-jsx-runtime.production.min.js","../../../webui/node_modules/react/jsx-runtime.js","../../../webui/node_modules/react-dom/client.js","../../../webui/src/context/ToastContext.tsx","../../../webui/src/context/SearchContext.tsx","../../../webui/src/api/client.ts","../../../webui/src/context/WebUIContext.tsx","../../../webui/src/hooks/useNetworkStatus.ts","../../../webui/src/components/IconImage.tsx","../../../webui/src/icons/close.svg","../../../webui/src/icons/github.svg","../../../webui/src/icons/refresh-arrow.svg","../../../webui/src/icons/up-arrow.svg","../../../webui/src/icons/process.svg","../../../webui/src/icons/log.svg","../../../webui/src/icons/radarr.svg","../../../webui/src/icons/sonarr.svg","../../../webui/src/icons/lidarr.svg","../../../webui/src/icons/gear.svg","../../../webui/src/App.tsx","../../../webui/src/main.tsx"],"sourcesContent":["/**\n * @license React\n * react-jsx-runtime.production.min.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n'use strict';var f=require(\"react\"),k=Symbol.for(\"react.element\"),l=Symbol.for(\"react.fragment\"),m=Object.prototype.hasOwnProperty,n=f.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,p={key:!0,ref:!0,__self:!0,__source:!0};\nfunction q(c,a,g){var b,d={},e=null,h=null;void 0!==g&&(e=\"\"+g);void 0!==a.key&&(e=\"\"+a.key);void 0!==a.ref&&(h=a.ref);for(b in a)m.call(a,b)&&!p.hasOwnProperty(b)&&(d[b]=a[b]);if(c&&c.defaultProps)for(b in a=c.defaultProps,a)void 0===d[b]&&(d[b]=a[b]);return{$$typeof:k,type:c,key:e,ref:h,props:d,_owner:n.current}}exports.Fragment=l;exports.jsx=q;exports.jsxs=q;\n","'use strict';\n\nif (process.env.NODE_ENV === 'production') {\n module.exports = require('./cjs/react-jsx-runtime.production.min.js');\n} else {\n module.exports = require('./cjs/react-jsx-runtime.development.js');\n}\n","'use strict';\n\nvar m = require('react-dom');\nif (process.env.NODE_ENV === 'production') {\n exports.createRoot = m.createRoot;\n exports.hydrateRoot = m.hydrateRoot;\n} else {\n var i = m.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;\n exports.createRoot = function(c, o) {\n i.usingClientEntryPoint = true;\n try {\n return m.createRoot(c, o);\n } finally {\n i.usingClientEntryPoint = false;\n }\n };\n exports.hydrateRoot = function(c, h, o) {\n i.usingClientEntryPoint = true;\n try {\n return m.hydrateRoot(c, h, o);\n } finally {\n i.usingClientEntryPoint = false;\n }\n };\n}\n","/* eslint-disable react-refresh/only-export-components */\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useState,\n type PropsWithChildren,\n type JSX,\n} from \"react\";\n\nexport type ToastKind = \"info\" | \"success\" | \"warning\" | \"error\";\n\nexport interface Toast {\n id: number;\n message: string;\n kind: ToastKind;\n}\n\ninterface ToastContextValue {\n toasts: Toast[];\n push: (message: string, kind?: ToastKind) => void;\n dismiss: (id: number) => void;\n}\n\nconst ToastContext = createContext<ToastContextValue | undefined>(undefined);\n\nlet toastCounter = 0;\n\nexport function ToastProvider({ children }: PropsWithChildren): JSX.Element {\n const [toasts, setToasts] = useState<Toast[]>([]);\n\n const dismiss = useCallback((id: number) => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n }, []);\n\n const push = useCallback(\n (message: string, kind: ToastKind = \"info\") => {\n const id = ++toastCounter;\n setToasts((prev) => [...prev, { id, message, kind }]);\n // Auto dismiss\n window.setTimeout(() => dismiss(id), 3500);\n },\n [dismiss]\n );\n\n const value = useMemo(\n () => ({\n toasts,\n push,\n dismiss,\n }),\n [toasts, push, dismiss]\n );\n\n return (\n <ToastContext.Provider value={value}>{children}</ToastContext.Provider>\n );\n}\n\nexport function useToast(): ToastContextValue {\n const ctx = useContext(ToastContext);\n if (!ctx) {\n throw new Error(\"useToast must be used within a ToastProvider\");\n }\n return ctx;\n}\n\nexport function ToastViewport(): JSX.Element | null {\n const { toasts, dismiss } = useToast();\n if (!toasts.length) return null;\n return (\n <div className=\"toasts\">\n {toasts.map((toast) => (\n <div\n key={toast.id}\n className={`toast ${toast.kind !== \"info\" ? toast.kind : \"\"}`}\n role=\"status\"\n onClick={() => dismiss(toast.id)}\n >\n {toast.message}\n </div>\n ))}\n </div>\n );\n}\n","/* eslint-disable react-refresh/only-export-components */\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useState,\n type PropsWithChildren,\n type JSX,\n} from \"react\";\n\ntype SearchHandler = ((term: string) => void) | null;\n\ninterface SearchContextValue {\n value: string;\n setValue: (term: string) => void;\n register: (handler: SearchHandler) => void;\n clearHandler: (handler: SearchHandler) => void;\n}\n\nconst SearchContext = createContext<SearchContextValue | undefined>(undefined);\n\nexport function SearchProvider({ children }: PropsWithChildren): JSX.Element {\n const [value, setValueState] = useState(\"\");\n const handlers = useRef<Set<SearchHandler>>(new Set());\n\n const setValue = useCallback((term: string) => {\n setValueState(term);\n handlers.current.forEach((handler) => {\n handler?.(term);\n });\n }, []);\n\n const register = useCallback((handler: SearchHandler) => {\n if (!handler) return;\n handlers.current.add(handler);\n }, []);\n\n const clearHandler = useCallback((handler: SearchHandler) => {\n handlers.current.delete(handler);\n }, []);\n\n const valueObj = useMemo(\n () => ({\n value,\n setValue,\n register,\n clearHandler,\n }),\n [value, setValue, register, clearHandler]\n );\n\n return (\n <SearchContext.Provider value={valueObj}>\n {children}\n </SearchContext.Provider>\n );\n}\n\nexport function useSearch(): SearchContextValue {\n const ctx = useContext(SearchContext);\n if (!ctx) {\n throw new Error(\"useSearch must be used within a SearchProvider\");\n }\n return ctx;\n}\n","import type {\n ArrListResponse,\n ConfigDocument,\n ConfigUpdatePayload,\n ConfigUpdateResponse,\n MetaResponse,\n LogsListResponse,\n ProcessesResponse,\n RadarrMoviesResponse,\n RestartResponse,\n SonarrSeriesResponse,\n LidarrAlbumsResponse,\n LidarrAlbum,\n StatusResponse,\n} from \"./types\";\n\nconst JSON_HEADERS = { \"Content-Type\": \"application/json\" } as const;\nconst TOKEN_STORAGE_KEYS = [\"token\", \"webui-token\", \"webui_token\"] as const;\nconst MAX_AUTH_RETRIES = 1;\n\n// Request deduplication cache\nconst inflightRequests = new Map<string, Promise<unknown>>();\n\nfunction createRequestKey(input: RequestInfo | URL, init?: RequestInit): string {\n const url = input instanceof Request ? input.url : String(input);\n const method = init?.method || \"GET\";\n const body = init?.body ? String(init.body) : \"\";\n return `${method}:${url}:${body}`;\n}\n\nfunction resolveToken(): string | null {\n for (const key of TOKEN_STORAGE_KEYS) {\n const value = localStorage.getItem(key) || sessionStorage.getItem(key);\n if (value) {\n if (key !== \"token\") {\n localStorage.setItem(\"token\", value);\n }\n return value;\n }\n }\n try {\n const params = new URLSearchParams(window.location.search);\n const fromQuery = params.get(\"token\");\n if (fromQuery) {\n localStorage.setItem(\"token\", fromQuery);\n return fromQuery;\n }\n } catch {\n // ignore\n }\n return null;\n}\n\nfunction clearStoredToken(): void {\n for (const key of TOKEN_STORAGE_KEYS) {\n localStorage.removeItem(key);\n }\n try {\n for (const key of TOKEN_STORAGE_KEYS) {\n sessionStorage.removeItem(key);\n }\n } catch {\n // ignore session storage errors\n }\n}\n\nfunction buildInit(init: RequestInit | undefined, token: string | null): RequestInit {\n const headers = new Headers(init?.headers || {});\n Object.entries(JSON_HEADERS).forEach(([key, value]) => {\n if (!headers.has(key)) headers.set(key, value);\n });\n if (token && !headers.has(\"Authorization\")) {\n headers.set(\"Authorization\", `Bearer ${token}`);\n }\n return {\n ...init,\n headers,\n };\n}\n\nasync function fetchWithAuthRetry<T>(\n input: RequestInfo | URL,\n init: RequestInit | undefined,\n handler: (response: Response) => Promise<T>,\n retries = MAX_AUTH_RETRIES\n): Promise<T> {\n const token = resolveToken();\n const response = await fetch(input, buildInit(init, token));\n if (response.status === 401 && retries > 0 && token) {\n clearStoredToken();\n return fetchWithAuthRetry(input, init, handler, retries - 1);\n }\n return handler(response);\n}\n\nasync function fetchJson<T>(input: RequestInfo | URL, init?: RequestInit): Promise<T> {\n // Only deduplicate GET requests (safe to share)\n const method = init?.method || \"GET\";\n if (method === \"GET\") {\n const key = createRequestKey(input, init);\n const existingRequest = inflightRequests.get(key) as Promise<T> | undefined;\n\n if (existingRequest) {\n return existingRequest;\n }\n\n const promise = fetchWithAuthRetry<T>(input, init, (response) => handleJson<T>(response))\n .finally(() => {\n inflightRequests.delete(key);\n });\n\n inflightRequests.set(key, promise);\n return promise;\n }\n\n return fetchWithAuthRetry<T>(input, init, (response) => handleJson<T>(response));\n}\n\nasync function fetchTextResponse(input: RequestInfo | URL, init?: RequestInit): Promise<string> {\n return fetchWithAuthRetry<string>(input, init, (response) => handleText(response));\n}\n\nasync function handleJson<T>(res: Response): Promise<T> {\n if (!res.ok) {\n let detail: unknown = null;\n try {\n detail = await res.json();\n } catch {\n // ignore\n }\n let message = `${res.status} ${res.statusText}`;\n if (\n detail &&\n typeof detail === \"object\" &&\n \"error\" in detail &&\n typeof (detail as Record<string, unknown>).error === \"string\"\n ) {\n const errorText = (detail as Record<string, unknown>).error as string;\n if (errorText.trim()) {\n message = errorText;\n }\n }\n throw new Error(message);\n }\n return (await res.json()) as T;\n}\n\nasync function handleText(res: Response): Promise<string> {\n if (!res.ok) {\n throw new Error(`${res.status} ${res.statusText}`);\n }\n return res.text();\n}\n\nexport async function getMeta(params?: { force?: boolean }): Promise<MetaResponse> {\n const query = params?.force ? \"?force=1\" : \"\";\n return fetchJson<MetaResponse>(`/web/meta${query}`);\n}\n\nexport async function getStatus(): Promise<StatusResponse> {\n return fetchJson<StatusResponse>(\"/web/status\");\n}\n\nexport async function getProcesses(): Promise<ProcessesResponse> {\n return fetchJson<ProcessesResponse>(\"/web/processes\");\n}\n\nexport async function restartProcess(\n category: string,\n kind: string\n): Promise<RestartResponse> {\n const url = `/web/processes/${encodeURIComponent(\n category\n )}/${encodeURIComponent(kind)}/restart`;\n return fetchJson<RestartResponse>(url, { method: \"POST\" });\n}\n\nexport async function restartAllProcesses(): Promise<RestartResponse> {\n return fetchJson<RestartResponse>(\"/web/processes/restart_all\", {\n method: \"POST\",\n });\n}\n\nexport async function rebuildArrs(): Promise<RestartResponse> {\n return fetchJson<RestartResponse>(\"/web/arr/rebuild\", { method: \"POST\" });\n}\n\nexport async function setLogLevel(level: string): Promise<void> {\n await fetchJson<void>(\"/web/loglevel\", {\n method: \"POST\",\n body: JSON.stringify({ level }),\n });\n}\n\nexport async function getLogs(): Promise<LogsListResponse> {\n return fetchJson<LogsListResponse>(\"/web/logs\");\n}\n\nexport async function getLogTail(name: string): Promise<string> {\n return fetchTextResponse(`/web/logs/${encodeURIComponent(name)}`);\n}\n\nexport function getLogDownloadUrl(name: string): string {\n return `/web/logs/${encodeURIComponent(name)}/download`;\n}\n\nexport async function getArrList(): Promise<ArrListResponse> {\n return fetchJson<ArrListResponse>(\"/web/arr\");\n}\n\nexport async function getRadarrMovies(\n category: string,\n page: number,\n pageSize: number,\n q: string\n): Promise<RadarrMoviesResponse> {\n const params = new URLSearchParams();\n params.set(\"page\", String(page));\n params.set(\"page_size\", String(pageSize));\n if (q) params.set(\"q\", q);\n return fetchJson<RadarrMoviesResponse>(\n `/web/radarr/${encodeURIComponent(category)}/movies?${params}`\n );\n}\n\nexport async function getSonarrSeries(\n category: string,\n page: number,\n pageSize: number,\n q: string,\n options?: { missingOnly?: boolean }\n): Promise<SonarrSeriesResponse> {\n const params = new URLSearchParams();\n params.set(\"page\", String(page));\n params.set(\"page_size\", String(pageSize));\n if (q) params.set(\"q\", q);\n if (options?.missingOnly) {\n params.set(\"missing\", \"1\");\n }\n return fetchJson<SonarrSeriesResponse>(\n `/web/sonarr/${encodeURIComponent(category)}/series?${params}`\n );\n}\n\nexport async function getLidarrAlbums(\n category: string,\n page: number,\n pageSize: number,\n query?: string\n): Promise<LidarrAlbumsResponse> {\n const params = new URLSearchParams();\n params.set(\"page\", page.toString());\n params.set(\"page_size\", pageSize.toString());\n if (query) {\n params.set(\"q\", query);\n }\n // Always include tracks\n params.set(\"include_tracks\", \"true\");\n return fetchJson<LidarrAlbumsResponse>(\n `/web/lidarr/${encodeURIComponent(category)}/albums?${params}`\n );\n}\n\nexport async function restartArr(category: string): Promise<void> {\n await fetchJson<void>(\n `/web/arr/${encodeURIComponent(category)}/restart`,\n { method: \"POST\" }\n );\n}\n\nexport async function getConfig(): Promise<ConfigDocument> {\n return fetchJson<ConfigDocument>(\"/web/config\");\n}\n\nexport async function updateConfig(\n payload: ConfigUpdatePayload\n): Promise<ConfigUpdateResponse> {\n const token = resolveToken();\n const response = await fetch(\"/web/config\", buildInit({\n method: \"POST\",\n body: JSON.stringify(payload),\n }, token));\n\n if (!response.ok) {\n let detail: unknown = null;\n try {\n detail = await response.json();\n } catch {\n // ignore\n }\n let message = `${response.status} ${response.statusText}`;\n if (\n detail &&\n typeof detail === \"object\" &&\n \"error\" in detail &&\n typeof (detail as Record<string, unknown>).error === \"string\"\n ) {\n const errorText = (detail as Record<string, unknown>).error as string;\n if (errorText.trim()) {\n message = errorText;\n }\n }\n throw new Error(message);\n }\n\n // Parse response body with full type information\n const data = await response.json() as ConfigUpdateResponse;\n return data;\n}\n\nexport async function triggerUpdate(): Promise<void> {\n await fetchJson<void>(\"/web/update\", { method: \"POST\" });\n}\n","import { createContext, useCallback, useContext, useEffect, useState, type JSX, type ReactNode } from \"react\";\nimport { getConfig, updateConfig } from \"../api/client\";\n\ntype ViewDensity = \"comfortable\" | \"compact\";\ntype Theme = \"light\" | \"dark\";\n\ninterface WebUISettings {\n liveArr: boolean;\n groupSonarr: boolean;\n groupLidarr: boolean;\n viewDensity: ViewDensity;\n theme: Theme;\n}\n\ninterface WebUIContextValue {\n liveArr: boolean;\n groupSonarr: boolean;\n groupLidarr: boolean;\n viewDensity: ViewDensity;\n theme: Theme;\n setLiveArr: (value: boolean) => void;\n setGroupSonarr: (value: boolean) => void;\n setGroupLidarr: (value: boolean) => void;\n setViewDensity: (value: ViewDensity) => void;\n setTheme: (value: Theme) => void;\n loading: boolean;\n}\n\nconst WebUIContext = createContext<WebUIContextValue | null>(null);\n\nexport function WebUIProvider({ children }: { children: ReactNode }): JSX.Element {\n const [settings, setSettings] = useState<WebUISettings>({\n liveArr: true,\n groupSonarr: true,\n groupLidarr: true,\n viewDensity: \"comfortable\",\n theme: \"dark\",\n });\n const [loading, setLoading] = useState(true);\n\n // Load initial settings\n useEffect(() => {\n const loadSettings = async () => {\n try {\n const config = await getConfig();\n const webui = config?.WebUI as Record<string, unknown> | undefined;\n\n // Load from localStorage as fallback for view density (client-side preference)\n const storedDensity = localStorage.getItem(\"viewDensity\") as ViewDensity | null;\n const storedTheme = localStorage.getItem(\"theme\") as Theme | null;\n\n // Get theme from backend or localStorage\n const backendTheme = webui?.Theme as string | undefined;\n const theme: Theme = storedTheme || (backendTheme?.toLowerCase() as Theme) || \"dark\";\n\n setSettings({\n liveArr: webui?.LiveArr === true,\n groupSonarr: webui?.GroupSonarr === true,\n groupLidarr: webui?.GroupLidarr === true,\n viewDensity: storedDensity || \"comfortable\",\n theme,\n });\n\n // Apply theme immediately\n document.documentElement.setAttribute('data-theme', theme);\n } catch (error) {\n console.error(\"Failed to load WebUI settings:\", error);\n } finally {\n setLoading(false);\n }\n };\n\n void loadSettings();\n }, []);\n\n // Auto-save settings to backend\n const saveSettings = useCallback(async (key: string, value: boolean | string) => {\n try {\n const changes: Record<string, unknown> = {\n WebUI: {\n [key]: value,\n },\n };\n await updateConfig({ changes });\n } catch (error) {\n console.error(`Failed to save ${key}:`, error);\n }\n }, []);\n\n const setLiveArr = useCallback((value: boolean) => {\n setSettings(prev => ({ ...prev, liveArr: value }));\n void saveSettings(\"LiveArr\", value);\n }, [saveSettings]);\n\n const setGroupSonarr = useCallback((value: boolean) => {\n setSettings(prev => ({ ...prev, groupSonarr: value }));\n void saveSettings(\"GroupSonarr\", value);\n }, [saveSettings]);\n\n const setGroupLidarr = useCallback((value: boolean) => {\n setSettings(prev => ({ ...prev, groupLidarr: value }));\n void saveSettings(\"GroupLidarr\", value);\n }, [saveSettings]);\n\n const setViewDensity = useCallback((value: ViewDensity) => {\n setSettings(prev => ({ ...prev, viewDensity: value }));\n // Store in localStorage (client-side preference, not sent to backend)\n localStorage.setItem(\"viewDensity\", value);\n }, []);\n\n const setTheme = useCallback((value: Theme) => {\n setSettings(prev => ({ ...prev, theme: value }));\n // Store in localStorage for instant application\n localStorage.setItem(\"theme\", value);\n // Apply theme immediately to DOM\n document.documentElement.setAttribute('data-theme', value);\n // Save to backend with proper capitalization (Light or Dark)\n const capitalizedTheme = value === \"light\" ? \"Light\" : \"Dark\";\n void saveSettings(\"Theme\", capitalizedTheme);\n }, [saveSettings]);\n\n const value: WebUIContextValue = {\n liveArr: settings.liveArr,\n groupSonarr: settings.groupSonarr,\n groupLidarr: settings.groupLidarr,\n viewDensity: settings.viewDensity,\n theme: settings.theme,\n setLiveArr,\n setGroupSonarr,\n setGroupLidarr,\n setViewDensity,\n setTheme,\n loading,\n };\n\n return <WebUIContext.Provider value={value}>{children}</WebUIContext.Provider>;\n}\n\nexport function useWebUI(): WebUIContextValue {\n const context = useContext(WebUIContext);\n if (!context) {\n throw new Error(\"useWebUI must be used within WebUIProvider\");\n }\n return context;\n}\n","import { useEffect, useState } from \"react\";\n\nexport function useNetworkStatus(): boolean {\n const [isOnline, setIsOnline] = useState(navigator.onLine);\n\n useEffect(() => {\n const handleOnline = () => setIsOnline(true);\n const handleOffline = () => setIsOnline(false);\n\n window.addEventListener('online', handleOnline);\n window.addEventListener('offline', handleOffline);\n\n return () => {\n window.removeEventListener('online', handleOnline);\n window.removeEventListener('offline', handleOffline);\n };\n }, []);\n\n return isOnline;\n}\n","import type { ImgHTMLAttributes, JSX } from \"react\";\n\ninterface IconImageProps extends Omit<ImgHTMLAttributes<HTMLImageElement>, \"src\"> {\n src: string;\n alt?: string;\n}\n\nexport function IconImage({ src, alt, className, ...rest }: IconImageProps): JSX.Element {\n return (\n <img\n src={src}\n alt={alt ?? \"\"}\n className={className ? `icon ${className}` : \"icon\"}\n aria-hidden={alt ? undefined : true}\n {...rest}\n />\n );\n}\n","export default \"__VITE_ASSET__BwSX1QeM__\"","export default \"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20xml:space='preserve'%20viewBox='0%200%20512%20512'%3e%3cpath%20d='M256%206.3C114.6%206.3%200%20120.9%200%20262.3c0%20113.3%2073.3%20209%20175%20242.9%2012.8%202.2%2017.6-5.4%2017.6-12.2%200-6.1-.3-26.2-.3-47.7-64.3%2011.8-81-15.7-86.1-30.1-2.9-7.4-15.4-30.1-26.2-36.2-9-4.8-21.8-16.6-.3-17%2020.2-.3%2034.6%2018.6%2039.4%2026.2%2023%2038.7%2059.8%2027.8%2074.6%2021.1%202.2-16.6%209-27.8%2016.3-34.2-57-6.4-116.5-28.5-116.5-126.4%200-27.8%209.9-50.9%2026.2-68.8-2.6-6.4-11.5-32.6%202.6-67.8%200%200%2021.4-6.7%2070.4%2026.2%2020.5-5.8%2042.2-8.6%2064-8.6s43.5%202.9%2064%208.6c49-33.3%2070.4-26.2%2070.4-26.2%2014.1%2035.2%205.1%2061.4%202.6%2067.8%2016.3%2017.9%2026.2%2040.6%2026.2%2068.8%200%2098.2-59.8%20120-116.8%20126.4%209.3%208%2017.3%2023.4%2017.3%2047.4%200%2034.2-.3%2061.8-.3%2070.4%200%206.7%204.8%2014.7%2017.6%2012.2C438.7%20471.3%20512%20375.3%20512%20262.3c0-141.4-114.6-256-256-256'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%231b1f23'/%3e%3c/svg%3e\"","export default \"__VITE_ASSET__B5Abvgg6__\"","export default \"__VITE_ASSET__CFg2sUO1__\"","export default \"__VITE_ASSET__DruObj$B__\"","export default \"__VITE_ASSET__DKTRAwQu__\"","export default \"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20xml:space='preserve'%20id='Layer_1'%20x='0'%20y='0'%20version='1.1'%20viewBox='0%200%20512%20512'%3e%3cstyle%3e.st0{fill:%2324292e}%3c/style%3e%3cg%20id='Group-Copy'%20transform='translate(70%2021)'%3e%3cpath%20id='Shape'%20d='m10.3%2059.8%203.9%20372.4c-31.4%203.9-54.9-11.8-54.9-43.1l-3.9-309.7c0-98%2090.2-121.5%20145.1-82.3l278.3%20160.7c39.2%2027.4%2047%2078.4%2027.4%20113.7-3.9-27.4-15.7-43.1-39.2-58.8L53.4%2036.2C29.9%2020.6%2010.3%2024.5%2010.3%2059.8'%20class='st0'/%3e%3cpath%20id='Shape_00000114049535938561773820000018271523940913105341_'%20d='M-13.2%20451.8c23.5%207.8%2047%203.9%2066.6-7.8l321.5-188.2c19.6%2027.4%2015.7%2054.9-7.8%2070.6L96.5%20483.2c-39.2%2019.6-90.1%200-109.7-31.4'%20class='st0'/%3e%3cpath%20id='Shape_00000165935924413286433040000003668002807793862576_'%20d='M80.9%20342%20273%20232.3%2084.8%20126.4z'%20style='fill:%23ffc230'/%3e%3c/g%3e%3c/svg%3e\"","export default \"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20xml:space='preserve'%20viewBox='0%200%20512%20512'%3e%3cpath%20d='M511.8%20256c0%2070.4-24.9%20130.8-74.6%20181.1-1.7%202-3.5%203.8-5.5%205.4-8.2%208-16.8%2015.3-26%2021.8Q341.05%20512%20256.3%20512c-56.6%200-106.3-15.9-149.2-47.7-11.3-8-22-17.1-31.9-27.3C36.5%20398.7%2012.8%20354%204%20303.2c-1.7-9.9-2.9-20-3.4-30.2-.2-5.7-.4-11.3-.4-17%200-6%20.1-11.7.4-17.1%200-.6.2-1.1.5-1.7%203.7-62.8%2028.4-117%2074.1-162.8C125.5%2024.8%20185.8%200%20256.2%200c70.7%200%20131%2024.8%20180.9%2074.5q74.7%2075.9%2074.7%20181.5'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%23eee'/%3e%3cpath%20d='m459.7%20100.3-52.9%2052.9c-30.9%2030.9-33.6%2057.8-33.6%20105.3%200%2042.3%206.7%2081.1%2038.2%20112.6%2023%2023%2044.9%2044.7%2044.9%2044.7-5.9%207.2-12.3%2014.3-19.1%2021.2-1.7%202-3.5%203.8-5.5%205.4-6%205.9-12.2%2011.4-18.6%2016.4l-41.4-41.4C334.9%20380.6%20305.6%20377%20257%20377c-46.7%200-78.4%204.3-112.6%2038.5-20.4%2020.4-43.8%2043.9-43.8%2043.9-8.9-6.8-17.3-14.2-25.3-22.4-6.6-6.6-12.8-13.4-18.5-20.3%200%200%2023.1-23.2%2045.2-45.3%2032.7-32.7%2038-70.6%2038-113%200-41.3-6.8-79.8-36.8-109.9C82.2%20127.7%2053.3%2099%2053.3%2099c6.7-8.5%2014-16.7%2021.8-24.5%206.9-6.8%2014-13.1%2021.2-19l48%2048c30.7%2030.7%2070%2038.6%20112.4%2038.6%2043.6%200%2082.8-8.4%20114.7-40.4C391%2082.1%20417%2056.3%20417%2056.3c6.8%205.6%2013.5%2011.6%2020.1%2018.2%208.3%208.3%2015.8%2016.9%2022.6%2025.8'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%233a3f51'/%3e%3cpath%20d='M186%20269.1c-.5-2.8-.8-5.5-.9-8.4-.1-1.6-.1-3.1-.1-4.7%200-1.7%200-3.2.1-4.7%200-.2%200-.3.1-.5%201-17.4%207.9-32.4%2020.5-45.1%2013.9-13.8%2030.6-20.7%2050.2-20.7s36.3%206.9%2050.2%2020.7c13.8%2014%2020.7%2030.8%2020.7%2050.3s-6.9%2036.2-20.7%2050.2c-.5.5-1%201.1-1.5%201.5q-3.45%203.3-7.2%206-18%2013.2-41.4%2013.2c-23.4%200-29.4-4.4-41.3-13.2-3.1-2.2-6.1-4.7-8.9-7.6-10.8-10.6-17.3-22.9-19.8-37'%20style='fill-rule:evenodd;clip-rule:evenodd;fill:%230cf'/%3e%3cpath%20d='m372.7%20141-35.4%2034.6M72.9%2076.8l96.5%2096.1m199.7%20198.9%2065.6%2067.9m4.4-363.3L372.7%20141M76.6%20438.5l64.6-64.7'%20style='fill:none;stroke:%230cf;stroke-width:2;stroke-miterlimit:1'/%3e%3cpath%20d='m372.7%20141-40%2040.6m-193.3-38.5%2040.6%2040.5M141%20374l39.5-41.1m146.2-3.3%2042.6%2042.4'%20style='fill:none;stroke:%230cf;stroke-width:7;stroke-miterlimit:1'/%3e%3c/svg%3e\"","export default \"__VITE_ASSET__B_sq1wA9__\"","export default \"__VITE_ASSET__CITwrObj__\"","import { useCallback, useEffect, useMemo, useRef, useState, type JSX, lazy, Suspense } from \"react\";\nconst ProcessesView = lazy(() => import(\"./pages/ProcessesView\").then(module => ({ default: module.ProcessesView })));\nconst LogsView = lazy(() => import(\"./pages/LogsView\").then(module => ({ default: module.LogsView })));\nconst ArrView = lazy(() => import(\"./pages/ArrView\").then(module => ({ default: module.ArrView })));\nconst ConfigView = lazy(() => import(\"./pages/ConfigView\").then(module => ({ default: module.ConfigView })));\nimport { ToastProvider, ToastViewport, useToast } from \"./context/ToastContext\";\nimport { SearchProvider, useSearch } from \"./context/SearchContext\";\nimport { WebUIProvider, useWebUI } from \"./context/WebUIContext\";\nimport { useNetworkStatus } from \"./hooks/useNetworkStatus\";\nimport { getMeta, getStatus, triggerUpdate } from \"./api/client\";\nimport type { MetaResponse, StatusResponse } from \"./api/types\";\nimport { IconImage } from \"./components/IconImage\";\nimport CloseIcon from \"./icons/close.svg\";\nimport ExternalIcon from \"./icons/github.svg\";\nimport RefreshIcon from \"./icons/refresh-arrow.svg\";\nimport UpdateIcon from \"./icons/up-arrow.svg\";\nimport ProcessesIcon from \"./icons/process.svg\";\nimport LogsIcon from \"./icons/log.svg\";\nimport RadarrIcon from \"./icons/radarr.svg\";\nimport SonarrIcon from \"./icons/sonarr.svg\";\nimport LidarrIcon from \"./icons/lidarr.svg\";\nimport ConfigIcon from \"./icons/gear.svg\";\n\ntype Tab = \"processes\" | \"logs\" | \"radarr\" | \"sonarr\" | \"lidarr\" | \"config\";\n\ninterface NavTab {\n id: Tab;\n label: string;\n icon: string;\n}\n\nfunction formatVersionLabel(value: string | null | undefined): string {\n if (!value) {\n return \"unknown\";\n }\n const trimmed = value.trim();\n if (!trimmed) {\n return \"unknown\";\n }\n return trimmed[0] === \"v\" || trimmed[0] === \"V\" ? trimmed : `v${trimmed}`;\n}\n\ninterface WelcomeModalProps {\n currentVersion: string;\n changelog: string | null;\n changelogUrl: string | null;\n repositoryUrl: string;\n onClose: () => void;\n}\n\nfunction WelcomeModal({\n currentVersion,\n changelog,\n changelogUrl,\n repositoryUrl,\n onClose,\n}: WelcomeModalProps): JSX.Element {\n return (\n <div className=\"modal-backdrop\" role=\"presentation\" onClick={onClose}>\n <div\n className=\"modal\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"welcome-title\"\n onClick={(event) => event.stopPropagation()}\n >\n <div className=\"modal-header\">\n <h2 id=\"welcome-title\">\n 🎉 Welcome to qBitrr {formatVersionLabel(currentVersion)}!\n </h2>\n <button className=\"btn ghost\" type=\"button\" onClick={onClose}>\n <IconImage src={CloseIcon} />\n Close\n </button>\n </div>\n <div className=\"modal-body changelog-modal__body\">\n <div className=\"changelog-meta\">\n <p style={{ marginBottom: '1rem', color: 'var(--text-secondary)' }}>\n You've been updated to version <strong>{formatVersionLabel(currentVersion)}</strong>.\n Here's what's new in this release:\n </p>\n </div>\n <div className=\"changelog-section\">\n <h3>Release Notes</h3>\n <pre className=\"changelog-body\">\n {changelog?.trim() ? changelog.trim() : \"No changelog available for this version.\"}\n </pre>\n </div>\n </div>\n <div className=\"modal-footer\">\n <div className=\"changelog-links\">\n {(changelogUrl || repositoryUrl) && (\n <a\n className=\"btn ghost small\"\n href={changelogUrl ?? repositoryUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n <IconImage src={ExternalIcon} />\n View Full Release on GitHub\n </a>\n )}\n </div>\n <div className=\"changelog-buttons\">\n <button className=\"btn primary\" type=\"button\" onClick={onClose}>\n Got it!\n </button>\n </div>\n </div>\n </div>\n </div>\n );\n}\n\ninterface ChangelogModalProps {\n currentVersion: string;\n latestVersion: string | null;\n changelog: string | null;\n changelogUrl: string | null;\n repositoryUrl: string;\n updateState: MetaResponse[\"update_state\"] | null | undefined;\n updating: boolean;\n onClose: () => void;\n onUpdate: () => void;\n}\n\nfunction ChangelogModal({\n currentVersion,\n latestVersion,\n changelog,\n changelogUrl,\n repositoryUrl,\n updateState,\n updating,\n onClose,\n onUpdate,\n}: ChangelogModalProps): JSX.Element {\n const [countdown, setCountdown] = useState<number | null>(null);\n const updateDisabled = updating || Boolean(updateState?.in_progress);\n const completedLabel = updateState?.completed_at\n ? new Date(updateState.completed_at).toLocaleString()\n : null;\n\n // Start countdown when update completes successfully\n useEffect(() => {\n if (updateState?.last_result === \"success\" && updateState?.completed_at) {\n let countdown = 10;\n setCountdown(countdown);\n const timer = setInterval(() => {\n countdown -= 1;\n if (countdown <= 0) {\n clearInterval(timer);\n window.location.reload();\n } else {\n setCountdown(countdown);\n }\n }, 1000);\n return () => clearInterval(timer);\n }\n }, [updateState?.last_result, updateState?.completed_at]);\n\n let statusClass = \"\";\n let statusMessage: string | null = null;\n if (updateState?.in_progress) {\n statusClass = \"text-info\";\n statusMessage = \"⏳ Update in progress...\";\n } else if (updateState?.last_result === \"success\") {\n statusClass = \"text-success\";\n if (countdown !== null) {\n statusMessage = `✓ Update completed! Reloading in ${countdown}s...`;\n } else {\n statusMessage = \"✓ Update completed successfully\";\n if (completedLabel) {\n statusMessage = `${statusMessage} (${completedLabel})`;\n }\n }\n } else if (updateState?.last_result === \"error\") {\n statusClass = \"text-danger\";\n const detail = updateState.last_error ? updateState.last_error.trim() : \"\";\n statusMessage = detail ? `✗ Update failed: ${detail}` : \"✗ Update failed\";\n }\n\n return (\n <div className=\"modal-backdrop\" role=\"presentation\" onClick={onClose}>\n <div\n className=\"modal\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"changelog-title\"\n onClick={(event) => event.stopPropagation()}\n >\n <div className=\"modal-header\">\n <h2 id=\"changelog-title\">\n {updateState?.in_progress ? \"⚙️ Updating...\" : \"🚀 Update Available\"}\n </h2>\n <button className=\"btn ghost\" type=\"button\" onClick={onClose} disabled={updateState?.in_progress}>\n <IconImage src={CloseIcon} />\n Close\n </button>\n </div>\n <div className=\"modal-body changelog-modal__body\">\n <div className=\"changelog-meta\">\n <div className=\"version-comparison\">\n <span className=\"version-item\">\n <strong>Current:</strong>{\" \"}\n <span className=\"version-badge version-current\">{formatVersionLabel(currentVersion)}</span>\n </span>\n <span className=\"version-arrow\">→</span>\n <span className=\"version-item\">\n <strong>Latest:</strong>{\" \"}\n <span className=\"version-badge version-latest\">\n {latestVersion ? formatVersionLabel(latestVersion) : \"Unknown\"}\n </span>\n </span>\n </div>\n {statusMessage ? (\n <div className={`update-status ${statusClass}`}>\n {statusMessage}\n </div>\n ) : null}\n </div>\n <div className=\"changelog-section\">\n <h3>What's New</h3>\n <pre className=\"changelog-body\">\n {changelog?.trim() ? changelog.trim() : \"No changelog provided.\"}\n </pre>\n </div>\n </div>\n <div className=\"modal-footer\">\n <div className=\"changelog-links\">\n {(changelogUrl || repositoryUrl) && (\n <a\n className=\"btn ghost small\"\n href={changelogUrl ?? repositoryUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n <IconImage src={ExternalIcon} />\n View on GitHub\n </a>\n )}\n </div>\n <div className=\"changelog-buttons\">\n <button\n className=\"btn primary\"\n type=\"button\"\n onClick={onUpdate}\n disabled={updateDisabled}\n >\n <IconImage src={UpdateIcon} />\n {updateDisabled ? \"Updating...\" : \"Update Now\"}\n </button>\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nfunction AppShell(): JSX.Element {\n const [activeTab, setActiveTab] = useState<Tab>(\"processes\");\n const [configDirty, setConfigDirty] = useState(false);\n const { push } = useToast();\n const { setValue: setSearchValue } = useSearch();\n const { viewDensity, setViewDensity } = useWebUI();\n const isOnline = useNetworkStatus();\n const [meta, setMeta] = useState<MetaResponse | null>(null);\n const [metaLoading, setMetaLoading] = useState(false);\n const [showChangelog, setShowChangelog] = useState(false);\n const [updateBusy, setUpdateBusy] = useState(false);\n const [backendRestarting, setBackendRestarting] = useState(false);\n const restartPollCount = useRef(0);\n const prevUpdateResult = useRef<string | null>(null);\n const backendReadyRef = useRef(false);\n const backendWarnedRef = useRef(false);\n const backendTimerRef = useRef<number | null>(null);\n const [reloadKey, setReloadKey] = useState(0);\n const [statusData, setStatusData] = useState<StatusResponse | null>(null);\n const [showWelcomeChangelog, setShowWelcomeChangelog] = useState(false);\n\n // Theme is now managed by WebUIContext and applied automatically\n\n // Clear cache on every page load to ensure fresh content\n useEffect(() => {\n const clearCache = async () => {\n if ('caches' in window) {\n try {\n const cacheNames = await caches.keys();\n await Promise.all(\n cacheNames.map(cacheName => caches.delete(cacheName))\n );\n console.log('Cache cleared on page load');\n } catch (error) {\n console.error('Failed to clear cache:', error);\n }\n }\n };\n clearCache();\n }, []);\n\n const refreshMeta = useCallback(\n async (options?: { force?: boolean; silent?: boolean }) => {\n const force = options?.force ?? false;\n const silent = options?.silent ?? !force;\n if (!silent) {\n setMetaLoading(true);\n }\n try {\n const data = await getMeta({ force });\n setMeta(data);\n } catch (error) {\n if (!silent) {\n const message =\n error instanceof Error ? error.message : \"Failed to fetch version information\";\n push(message, \"error\");\n }\n } finally {\n if (!silent) {\n setMetaLoading(false);\n }\n }\n },\n [push]\n );\n\n useEffect(() => {\n void refreshMeta({ force: true });\n }, [refreshMeta]);\n\n // Check for new version on first launch - show welcome popup with changelog\n useEffect(() => {\n if (!meta?.current_version) {\n return;\n }\n\n const lastSeenVersion = localStorage.getItem(\"lastSeenVersion\");\n const currentVersion = meta.current_version;\n\n // Show welcome popup if this is a new version (but not on very first install)\n if (lastSeenVersion && lastSeenVersion !== currentVersion) {\n // Ensure we have changelog data before showing popup\n if (!meta.current_version_changelog && !meta.changelog) {\n void refreshMeta({ force: true, silent: true });\n }\n setShowWelcomeChangelog(true);\n }\n\n // Store current version as last seen when user opens the app (first install)\n if (!lastSeenVersion) {\n localStorage.setItem(\"lastSeenVersion\", currentVersion);\n }\n }, [meta?.current_version, meta?.changelog, refreshMeta]);\n\n // Network status notifications\n useEffect(() => {\n if (!isOnline) {\n push(\"You are offline. Some features may not work.\", \"warning\");\n }\n }, [isOnline, push]);\n\n // Keyboard shortcuts\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n // Don't trigger shortcuts when typing in inputs\n if (event.target instanceof HTMLInputElement ||\n event.target instanceof HTMLTextAreaElement ||\n event.target instanceof HTMLSelectElement) {\n return;\n }\n\n const isMod = event.ctrlKey || event.metaKey;\n\n // Ctrl/Cmd + K - Focus search\n if (isMod && event.key === 'k') {\n event.preventDefault();\n const searchInput = document.querySelector('input[type=\"text\"][placeholder*=\"Search\"]') as HTMLInputElement;\n searchInput?.focus();\n return;\n }\n\n // R - Refresh current view\n if (event.key === 'r' || event.key === 'R') {\n event.preventDefault();\n setReloadKey(prev => prev + 1);\n push('Refreshed', 'success');\n return;\n }\n\n // ESC - Clear search\n if (event.key === 'Escape') {\n setSearchValue('');\n return;\n }\n\n // Number keys 1-6 for tab switching\n if (event.key >= '1' && event.key <= '6' && !isMod) {\n event.preventDefault();\n const tabIndex = parseInt(event.key) - 1;\n const tabIds: Tab[] = ['processes', 'logs', 'radarr', 'sonarr', 'lidarr', 'config'];\n if (tabIndex < tabIds.length) {\n setActiveTab(tabIds[tabIndex]);\n }\n return;\n }\n };\n\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [setSearchValue, push]);\n\n useEffect(() => {\n const id = window.setInterval(() => {\n void refreshMeta();\n }, 5 * 60 * 1000);\n return () => window.clearInterval(id);\n }, [refreshMeta]);\n\n useEffect(() => {\n const handleVisibilityChange = () => {\n if (document.visibilityState === \"visible\") {\n // Force reload all data by incrementing the reload key\n setReloadKey((prev) => prev + 1);\n void refreshMeta({ force: true });\n void refreshStatus();\n }\n };\n\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n return () => {\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange);\n };\n }, [refreshMeta]);\n\n const refreshStatus = useCallback(async () => {\n try {\n const status = await getStatus();\n setStatusData(status);\n } catch {\n // Silently fail - status is not critical\n }\n }, []);\n\n useEffect(() => {\n void refreshStatus();\n const id = window.setInterval(() => {\n void refreshStatus();\n }, 5 * 1000); // Refresh every 5 seconds for more dynamic tab loading\n return () => window.clearInterval(id);\n }, [refreshStatus]);\n\n useEffect(() => {\n if (!meta?.update_state?.in_progress && !backendRestarting) {\n restartPollCount.current = 0;\n return;\n }\n const id = window.setInterval(async () => {\n try {\n const data = await getMeta({ force: true });\n setMeta(data);\n if (backendRestarting) {\n // Backend came back after restart\n window.location.reload();\n }\n restartPollCount.current = 0;\n } catch {\n restartPollCount.current += 1;\n if (restartPollCount.current > 20) { // 60 seconds\n setBackendRestarting(false);\n restartPollCount.current = 0;\n push(\"Update completed but backend restart timed out. Please refresh the page manually.\", \"warning\");\n return;\n }\n if (meta?.update_state?.in_progress) {\n // Failed while update in progress, likely restarting\n setBackendRestarting(true);\n }\n }\n }, 3000);\n return () => window.clearInterval(id);\n }, [meta?.update_state?.in_progress, backendRestarting, meta, push]);\n\n useEffect(() => {\n const state = meta?.update_state;\n if (!state) {\n prevUpdateResult.current = null;\n return;\n }\n const result = state.last_result ?? null;\n if (result && result !== prevUpdateResult.current) {\n if (result === \"success\") {\n push(\"Update completed successfully. Restarting...\", \"success\");\n setBackendRestarting(true);\n restartPollCount.current = 0;\n } else if (result === \"error\") {\n push(state.last_error || \"Update failed.\", \"error\");\n }\n }\n prevUpdateResult.current = result;\n }, [meta?.update_state, push]);\n\n useEffect(() => {\n let cancelled = false;\n let attempts = 0;\n\n const schedule = (delay: number) => {\n if (backendTimerRef.current !== null) {\n window.clearTimeout(backendTimerRef.current);\n }\n backendTimerRef.current = window.setTimeout(() => {\n void poll();\n }, delay);\n };\n\n const poll = async () => {\n if (cancelled || backendReadyRef.current) {\n return;\n }\n attempts += 1;\n try {\n const status = await getStatus();\n if (cancelled) {\n return;\n }\n setStatusData(status);\n const readyHint =\n status.ready ?? (Array.isArray(status.arrs) && status.arrs.length > 0);\n if (readyHint) {\n backendReadyRef.current = true;\n return;\n }\n if (status.ready === false && attempts >= 3 && !backendWarnedRef.current) {\n backendWarnedRef.current = true;\n push(\n \"qBitrr backend is still initialising. Check the logs if this persists.\",\n \"warning\"\n );\n }\n } catch (error) {\n if (!backendWarnedRef.current && attempts >= 3) {\n backendWarnedRef.current = true;\n const detail = error instanceof Error ? error.message : \"Unknown backend error\";\n push(\n `Unable to confirm qBitrr readiness (${detail}). Please inspect the logs.`,\n \"warning\"\n );\n }\n } finally {\n if (!cancelled && !backendReadyRef.current) {\n const delay = attempts < 3 ? 3000 : 10000;\n schedule(delay);\n }\n }\n };\n\n schedule(0);\n\n return () => {\n cancelled = true;\n if (backendTimerRef.current !== null) {\n window.clearTimeout(backendTimerRef.current);\n backendTimerRef.current = null;\n }\n };\n }, [push]);\n\n const tabs = useMemo<NavTab[]>(() => {\n const baseTabs: NavTab[] = [\n { id: \"processes\", label: \"Processes\", icon: ProcessesIcon },\n { id: \"logs\", label: \"Logs\", icon: LogsIcon },\n ];\n\n const arrTabs: NavTab[] = [];\n const arrs = statusData?.arrs ?? [];\n\n const hasRadarr = arrs.some((arr) => arr.type === \"radarr\");\n const hasSonarr = arrs.some((arr) => arr.type === \"sonarr\");\n const hasLidarr = arrs.some((arr) => arr.type === \"lidarr\");\n\n if (hasRadarr) {\n arrTabs.push({ id: \"radarr\", label: \"Radarr\", icon: RadarrIcon });\n }\n if (hasSonarr) {\n arrTabs.push({ id: \"sonarr\", label: \"Sonarr\", icon: SonarrIcon });\n }\n if (hasLidarr) {\n arrTabs.push({ id: \"lidarr\", label: \"Lidarr\", icon: LidarrIcon });\n }\n\n return [\n ...baseTabs,\n ...arrTabs,\n { id: \"config\", label: \"Config\", icon: ConfigIcon },\n ];\n }, [statusData]);\n\n const repositoryUrl = meta?.repository_url ?? \"https://github.com/Feramance/qBitrr\";\n const displayVersion = meta?.current_version\n ? formatVersionLabel(meta.current_version)\n : \"...\";\n const latestVersion = meta?.latest_version ?? null;\n const updateAvailable = Boolean(meta?.update_available);\n const updateState = meta?.update_state;\n const changelogUrl = meta?.changelog_url ?? repositoryUrl;\n\n const versionTitleParts: string[] = [];\n if (meta?.last_checked) {\n versionTitleParts.push(`Last checked ${new Date(meta.last_checked).toLocaleString()}`);\n }\n if (meta?.error) {\n versionTitleParts.push(`Update check failed: ${meta.error}`);\n }\n const versionTitle = versionTitleParts.length ? versionTitleParts.join(\" • \") : undefined;\n\n // Redirect to processes if active tab is no longer available\n useEffect(() => {\n const tabExists = tabs.some((tab) => tab.id === activeTab);\n if (!tabExists && tabs.length > 0) {\n setActiveTab(\"processes\");\n }\n }, [tabs, activeTab]);\n\n const handleCheckUpdates = useCallback(() => {\n void refreshMeta({ force: true });\n }, [refreshMeta]);\n\n const handleOpenChangelog = useCallback(() => {\n setShowChangelog(true);\n if (!meta?.changelog) {\n void refreshMeta({ force: true, silent: true });\n }\n }, [meta?.changelog, refreshMeta]);\n\n const handleCloseChangelog = useCallback(() => {\n setShowChangelog(false);\n }, []);\n\n const handleCloseWelcomeChangelog = useCallback(() => {\n setShowWelcomeChangelog(false);\n // Mark this version as seen\n if (meta?.current_version) {\n localStorage.setItem(\"lastSeenVersion\", meta.current_version);\n }\n }, [meta?.current_version]);\n\n const handleTriggerUpdate = useCallback(async () => {\n setUpdateBusy(true);\n setBackendRestarting(false);\n restartPollCount.current = 0;\n try {\n await triggerUpdate();\n push(\"Update started in the background.\", \"info\");\n await refreshMeta({ force: true, silent: true });\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Failed to start update\";\n push(message, \"error\");\n } finally {\n setUpdateBusy(false);\n }\n }, [push, refreshMeta]);\n\n return (\n <div data-density={viewDensity}>\n <header className=\"appbar\">\n <div className=\"appbar__inner\">\n <div className=\"appbar__title\">\n <h1>qBitrr</h1>\n <span className=\"appbar__version\" title={versionTitle}>\n {displayVersion}\n </span>\n {metaLoading ? <span className=\"spinner\" aria-hidden=\"true\" /> : null}\n {updateState?.in_progress ? (\n <span className=\"appbar__status text-info\">Updating...</span>\n ) : null}\n {updateAvailable ? (\n <button\n type=\"button\"\n className=\"btn small primary appbar__update\"\n onClick={handleOpenChangelog}\n disabled={updateBusy || Boolean(updateState?.in_progress)}\n >\n <span className=\"appbar__update-indicator\" aria-hidden=\"true\" />\n <IconImage src={UpdateIcon} />\n Update available\n </button>\n ) : null}\n </div>\n <div className=\"appbar__actions\">\n {!isOnline && (\n <span className=\"badge\" style={{ background: 'rgba(239, 68, 68, 0.15)', borderColor: 'rgba(239, 68, 68, 0.3)', color: 'var(--danger)' }}>\n Offline\n </span>\n )}\n <div className=\"view-density-toggle\">\n <button\n type=\"button\"\n className={viewDensity === \"comfortable\" ? \"active\" : \"\"}\n onClick={() => setViewDensity(\"comfortable\")}\n title=\"Comfortable view\"\n >\n Comfortable\n </button>\n <button\n type=\"button\"\n className={viewDensity === \"compact\" ? \"active\" : \"\"}\n onClick={() => setViewDensity(\"compact\")}\n title=\"Compact view\"\n >\n Compact\n </button>\n </div>\n <button\n type=\"button\"\n className=\"btn small ghost\"\n onClick={handleCheckUpdates}\n disabled={metaLoading}\n >\n <IconImage src={RefreshIcon} />\n {metaLoading ? \"Checking...\" : \"Check Updates\"}\n </button>\n <a\n href={repositoryUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"btn small ghost\"\n >\n <IconImage src={ExternalIcon} />\n GitHub\n </a>\n </div>\n </div>\n </header>\n <main className=\"container\">\n <nav className=\"nav\">\n {tabs.map((tab) => (\n <button\n type=\"button\"\n key={tab.id}\n className={activeTab === tab.id ? \"active\" : \"\"}\n onClick={() => {\n if (activeTab === \"config\" && tab.id !== \"config\" && configDirty) {\n const shouldLeave = window.confirm(\n \"You have unsaved configuration changes. Leave without saving?\"\n );\n if (!shouldLeave) {\n return;\n }\n }\n setActiveTab(tab.id);\n setSearchValue(\"\");\n }}\n >\n <IconImage src={tab.icon} />\n <span>{tab.label}</span>\n </button>\n ))}\n </nav>\n <Suspense fallback={<div className=\"loading\">Loading...</div>}>\n {activeTab === \"processes\" && <ProcessesView key={`processes-${reloadKey}`} active />}\n {activeTab === \"logs\" && <LogsView key={`logs-${reloadKey}`} active />}\n {activeTab === \"radarr\" && <ArrView key={`radarr-${reloadKey}`} type=\"radarr\" active />}\n {activeTab === \"sonarr\" && <ArrView key={`sonarr-${reloadKey}`} type=\"sonarr\" active />}\n {activeTab === \"lidarr\" && <ArrView key={`lidarr-${reloadKey}`} type=\"lidarr\" active />}\n {activeTab === \"config\" && <ConfigView key={`config-${reloadKey}`} onDirtyChange={setConfigDirty} />}\n </Suspense>\n </main>\n {showChangelog && meta ? (\n <ChangelogModal\n currentVersion={meta.current_version}\n latestVersion={latestVersion}\n changelog={meta.changelog}\n changelogUrl={changelogUrl}\n repositoryUrl={repositoryUrl}\n updateState={updateState}\n updating={updateBusy}\n onClose={handleCloseChangelog}\n onUpdate={handleTriggerUpdate}\n />\n ) : null}\n {showWelcomeChangelog && meta ? (\n <WelcomeModal\n currentVersion={meta.current_version}\n changelog={meta.current_version_changelog || meta.changelog}\n changelogUrl={changelogUrl}\n repositoryUrl={repositoryUrl}\n onClose={handleCloseWelcomeChangelog}\n />\n ) : null}\n </div>\n );\n}\n\nexport default function App(): JSX.Element {\n return (\n <ToastProvider>\n <SearchProvider>\n <WebUIProvider>\n <AppShell />\n <ToastViewport />\n </WebUIProvider>\n </SearchProvider>\n </ToastProvider>\n );\n}\n","import { StrictMode } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport \"./styles.css\";\nimport App from \"./App\";\n\ncreateRoot(document.getElementById(\"root\")!).render(\n <StrictMode>\n <App />\n </StrictMode>\n);\n"],"file":"app.js"}