From eafeaf333d2e54c9474a2d4c4ce5c7cae300f90f Mon Sep 17 00:00:00 2001 From: Hitonabi Date: Fri, 26 Jun 2026 15:03:24 +0200 Subject: [PATCH] Refactor: ModelsView in Cockpit/AddModel/Discover-Dateien zerlegen (Phase 4c) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ModelsView 1455 -> 46 Zeilen reiner Orchestrator. Die drei großen Komponenten in eigene Dateien verschoben (verbatim, kein Verhaltenswechsel): - views/models/Cockpit.tsx (~1007 Z., VRAM-HUD, Gateway-Graph, Modell-Bibliothek) - views/models/Discover.tsx (~285 Z., Empfehlungen) inkl. ROLE_METADATA - views/models/AddModel.tsx (~131 Z., HF-Download/Suche) Verifiziert: tsc grün, Build grün, Cockpit- und Discover-Tab rendern ohne Konsolenfehler. Co-Authored-By: Claude Opus 4.8 --- .../{index-DSczZxZr.js => index-paq9nNtl.js} | 2 +- frontend/dist/index.html | 2 +- frontend/src/views/ModelsView.tsx | 1419 +---------------- frontend/src/views/models/AddModel.tsx | 131 ++ frontend/src/views/models/Cockpit.tsx | 1008 ++++++++++++ frontend/src/views/models/Discover.tsx | 285 ++++ 6 files changed, 1431 insertions(+), 1416 deletions(-) rename frontend/dist/assets/{index-DSczZxZr.js => index-paq9nNtl.js} (99%) create mode 100644 frontend/src/views/models/AddModel.tsx create mode 100644 frontend/src/views/models/Cockpit.tsx create mode 100644 frontend/src/views/models/Discover.tsx diff --git a/frontend/dist/assets/index-DSczZxZr.js b/frontend/dist/assets/index-paq9nNtl.js similarity index 99% rename from frontend/dist/assets/index-DSczZxZr.js rename to frontend/dist/assets/index-paq9nNtl.js index 9420578..3b9cd87 100644 --- a/frontend/dist/assets/index-DSczZxZr.js +++ b/frontend/dist/assets/index-paq9nNtl.js @@ -352,7 +352,7 @@ Error generating stack: `+c.message+` `)},Up=function(){var s=parseInt(document.body.getAttribute(ms)||"0",10);return isFinite(s)?s:0},rv=function(){g.useEffect(function(){return document.body.setAttribute(ms,(Up()+1).toString()),function(){var s=Up()-1;s<=0?document.body.removeAttribute(ms):document.body.setAttribute(ms,s.toString())}},[])},nv=function(s){var o=s.noRelative,i=s.noImportant,u=s.gapMode,d=u===void 0?"margin":u;rv();var f=g.useMemo(function(){return Xy(d)},[d]);return g.createElement(ev,{styles:tv(f,!o,d,i?"":"!important")})},Xu=!1;if(typeof window<"u")try{var li=Object.defineProperty({},"passive",{get:function(){return Xu=!0,!0}});window.addEventListener("test",li,li),window.removeEventListener("test",li,li)}catch{Xu=!1}var us=Xu?{passive:!1}:!1,sv=function(s){return s.tagName==="TEXTAREA"},$h=function(s,o){if(!(s instanceof Element))return!1;var i=window.getComputedStyle(s);return i[o]!=="hidden"&&!(i.overflowY===i.overflowX&&!sv(s)&&i[o]==="visible")},ov=function(s){return $h(s,"overflowY")},lv=function(s){return $h(s,"overflowX")},$p=function(s,o){var i=o.ownerDocument,u=o;do{typeof ShadowRoot<"u"&&u instanceof ShadowRoot&&(u=u.host);var d=Bh(s,u);if(d){var f=Hh(s,u),m=f[1],p=f[2];if(m>p)return!0}u=u.parentNode}while(u&&u!==i.body);return!1},iv=function(s){var o=s.scrollTop,i=s.scrollHeight,u=s.clientHeight;return[o,i,u]},av=function(s){var o=s.scrollLeft,i=s.scrollWidth,u=s.clientWidth;return[o,i,u]},Bh=function(s,o){return s==="v"?ov(o):lv(o)},Hh=function(s,o){return s==="v"?iv(o):av(o)},uv=function(s,o){return s==="h"&&o==="rtl"?-1:1},cv=function(s,o,i,u,d){var f=uv(s,window.getComputedStyle(o).direction),m=f*u,p=i.target,b=o.contains(p),x=!1,j=m>0,w=0,_=0;do{if(!p)break;var M=Hh(s,p),z=M[0],v=M[1],S=M[2],O=v-S-f*z;(z||O)&&Bh(s,p)&&(w+=O,_+=z);var F=p.parentNode;p=F&&F.nodeType===Node.DOCUMENT_FRAGMENT_NODE?F.host:F}while(!b&&p!==document.body||b&&(o.contains(p)||o===p));return(j&&Math.abs(w)<1||!j&&Math.abs(_)<1)&&(x=!0),x},ii=function(s){return"changedTouches"in s?[s.changedTouches[0].clientX,s.changedTouches[0].clientY]:[0,0]},Bp=function(s){return[s.deltaX,s.deltaY]},Hp=function(s){return s&&"current"in s?s.current:s},dv=function(s,o){return s[0]===o[0]&&s[1]===o[1]},fv=function(s){return` .block-interactivity-`.concat(s,` {pointer-events: none;} .allow-interactivity-`).concat(s,` {pointer-events: all;} -`)},pv=0,cs=[];function hv(s){var o=g.useRef([]),i=g.useRef([0,0]),u=g.useRef(),d=g.useState(pv++)[0],f=g.useState(Uh)[0],m=g.useRef(s);g.useEffect(function(){m.current=s},[s]),g.useEffect(function(){if(s.inert){document.body.classList.add("block-interactivity-".concat(d));var v=Ay([s.lockRef.current],(s.shards||[]).map(Hp),!0).filter(Boolean);return v.forEach(function(S){return S.classList.add("allow-interactivity-".concat(d))}),function(){document.body.classList.remove("block-interactivity-".concat(d)),v.forEach(function(S){return S.classList.remove("allow-interactivity-".concat(d))})}}},[s.inert,s.lockRef.current,s.shards]);var p=g.useCallback(function(v,S){if("touches"in v&&v.touches.length===2||v.type==="wheel"&&v.ctrlKey)return!m.current.allowPinchZoom;var O=ii(v),F=i.current,B="deltaX"in v?v.deltaX:F[0]-O[0],I="deltaY"in v?v.deltaY:F[1]-O[1],D,$=v.target,H=Math.abs(B)>Math.abs(I)?"h":"v";if("touches"in v&&H==="h"&&$.type==="range")return!1;var ae=window.getSelection(),te=ae&&ae.anchorNode,fe=te?te===$||te.contains($):!1;if(fe)return!1;var ke=$p(H,$);if(!ke)return!0;if(ke?D=H:(D=H==="v"?"h":"v",ke=$p(H,$)),!ke)return!1;if(!u.current&&"changedTouches"in v&&(B||I)&&(u.current=D),!D)return!0;var de=u.current||D;return cv(de,S,v,de==="h"?B:I)},[]),b=g.useCallback(function(v){var S=v;if(!(!cs.length||cs[cs.length-1]!==f)){var O="deltaY"in S?Bp(S):ii(S),F=o.current.filter(function(D){return D.name===S.type&&(D.target===S.target||S.target===D.shadowParent)&&dv(D.delta,O)})[0];if(F&&F.should){S.cancelable&&S.preventDefault();return}if(!F){var B=(m.current.shards||[]).map(Hp).filter(Boolean).filter(function(D){return D.contains(S.target)}),I=B.length>0?p(S,B[0]):!m.current.noIsolation;I&&S.cancelable&&S.preventDefault()}}},[]),x=g.useCallback(function(v,S,O,F){var B={name:v,delta:S,target:O,should:F,shadowParent:mv(O)};o.current.push(B),setTimeout(function(){o.current=o.current.filter(function(I){return I!==B})},1)},[]),j=g.useCallback(function(v){i.current=ii(v),u.current=void 0},[]),w=g.useCallback(function(v){x(v.type,Bp(v),v.target,p(v,s.lockRef.current))},[]),_=g.useCallback(function(v){x(v.type,ii(v),v.target,p(v,s.lockRef.current))},[]);g.useEffect(function(){return cs.push(f),s.setCallbacks({onScrollCapture:w,onWheelCapture:w,onTouchMoveCapture:_}),document.addEventListener("wheel",b,us),document.addEventListener("touchmove",b,us),document.addEventListener("touchstart",j,us),function(){cs=cs.filter(function(v){return v!==f}),document.removeEventListener("wheel",b,us),document.removeEventListener("touchmove",b,us),document.removeEventListener("touchstart",j,us)}},[]);var M=s.removeScrollBar,z=s.inert;return g.createElement(g.Fragment,null,z?g.createElement(f,{styles:fv(d)}):null,M?g.createElement(nv,{noRelative:s.noRelative,gapMode:s.gapMode}):null)}function mv(s){for(var o=null;s!==null;)s instanceof ShadowRoot&&(o=s.host,s=s.host),s=s.parentNode;return o}const gv=Wy(Fh,hv);var Wh=g.forwardRef(function(s,o){return g.createElement(ji,lr({},s,{ref:o,sideCar:gv}))});Wh.classNames=ji.classNames;var xv=function(s){if(typeof document>"u")return null;var o=Array.isArray(s)?s[0]:s;return o.ownerDocument.body},ds=new WeakMap,ai=new WeakMap,ui={},Cu=0,Vh=function(s){return s&&(s.host||Vh(s.parentNode))},yv=function(s,o){return o.map(function(i){if(s.contains(i))return i;var u=Vh(i);return u&&s.contains(u)?u:(console.error("aria-hidden",i,"in not contained inside",s,". Doing nothing"),null)}).filter(function(i){return!!i})},vv=function(s,o,i,u){var d=yv(o,Array.isArray(s)?s:[s]);ui[i]||(ui[i]=new WeakMap);var f=ui[i],m=[],p=new Set,b=new Set(d),x=function(w){!w||p.has(w)||(p.add(w),x(w.parentNode))};d.forEach(x);var j=function(w){!w||b.has(w)||Array.prototype.forEach.call(w.children,function(_){if(p.has(_))j(_);else try{var M=_.getAttribute(u),z=M!==null&&M!=="false",v=(ds.get(_)||0)+1,S=(f.get(_)||0)+1;ds.set(_,v),f.set(_,S),m.push(_),v===1&&z&&ai.set(_,!0),S===1&&_.setAttribute(i,"true"),z||_.setAttribute(u,"true")}catch(O){console.error("aria-hidden: cannot operate on ",_,O)}})};return j(o),p.clear(),Cu++,function(){m.forEach(function(w){var _=ds.get(w)-1,M=f.get(w)-1;ds.set(w,_),f.set(w,M),_||(ai.has(w)||w.removeAttribute(u),ai.delete(w)),M||w.removeAttribute(i)}),Cu--,Cu||(ds=new WeakMap,ds=new WeakMap,ai=new WeakMap,ui={})}},bv=function(s,o,i){i===void 0&&(i="data-aria-hidden");var u=Array.from(Array.isArray(s)?s:[s]),d=xv(s);return d?(u.push.apply(u,Array.from(d.querySelectorAll("[aria-live], script"))),vv(u,d,i,"aria-hidden")):function(){return null}},ki="Dialog",[Gh]=Q0(ki),[wv,qt]=Gh(ki),Kh=s=>{const{__scopeDialog:o,children:i,open:u,defaultOpen:d,onOpenChange:f,modal:m=!0}=s,p=g.useRef(null),b=g.useRef(null),[x,j]=X0({prop:u,defaultProp:d??!1,onChange:f,caller:ki});return n.jsx(wv,{scope:o,triggerRef:p,contentRef:b,contentId:br(),titleId:br(),descriptionId:br(),open:x,onOpenChange:j,onOpenToggle:g.useCallback(()=>j(w=>!w),[j]),modal:m,children:i})};Kh.displayName=ki;var Qh="DialogTrigger",jv=g.forwardRef((s,o)=>{const{__scopeDialog:i,...u}=s,d=qt(Qh,i),f=Dn(o,d.triggerRef);return n.jsx(it.button,{type:"button","aria-haspopup":"dialog","aria-expanded":d.open,"aria-controls":d.open?d.contentId:void 0,"data-state":pc(d.open),...u,ref:f,onClick:Xr(s.onClick,d.onOpenToggle)})});jv.displayName=Qh;var fc="DialogPortal",[kv,qh]=Gh(fc,{forceMount:void 0}),Zh=s=>{const{__scopeDialog:o,forceMount:i,children:u,container:d}=s,f=qt(fc,o);return n.jsx(kv,{scope:o,forceMount:i,children:g.Children.map(u,m=>n.jsx(wi,{present:i||f.open,children:n.jsx(zh,{asChild:!0,container:d,children:m})}))})};Zh.displayName=fc;var bi="DialogOverlay",Yh=g.forwardRef((s,o)=>{const i=qh(bi,s.__scopeDialog),{forceMount:u=i.forceMount,...d}=s,f=qt(bi,s.__scopeDialog);return f.modal?n.jsx(wi,{present:u||f.open,children:n.jsx(Sv,{...d,ref:o})}):null});Yh.displayName=bi;var Nv=Rh("DialogOverlay.RemoveScroll"),Sv=g.forwardRef((s,o)=>{const{__scopeDialog:i,...u}=s,d=qt(bi,i),f=vy(),m=Dn(o,f);return n.jsx(Wh,{as:Nv,allowPinchZoom:!0,shards:[d.contentRef],children:n.jsx(it.div,{"data-state":pc(d.open),...u,ref:m,style:{pointerEvents:"auto",...u.style}})})}),Os="DialogContent",Jh=g.forwardRef((s,o)=>{const i=qh(Os,s.__scopeDialog),{forceMount:u=i.forceMount,...d}=s,f=qt(Os,s.__scopeDialog);return n.jsx(wi,{present:u||f.open,children:f.modal?n.jsx(Cv,{...d,ref:o}):n.jsx(Ev,{...d,ref:o})})});Jh.displayName=Os;var Cv=g.forwardRef((s,o)=>{const i=qt(Os,s.__scopeDialog),u=g.useRef(null),d=Dn(o,i.contentRef,u);return g.useEffect(()=>{const f=u.current;if(f)return bv(f)},[]),n.jsx(Xh,{...s,ref:d,trapFocus:i.open,disableOutsidePointerEvents:i.open,onCloseAutoFocus:Xr(s.onCloseAutoFocus,f=>{var m;f.preventDefault(),(m=i.triggerRef.current)==null||m.focus()}),onPointerDownOutside:Xr(s.onPointerDownOutside,f=>{const m=f.detail.originalEvent,p=m.button===0&&m.ctrlKey===!0;(m.button===2||p)&&f.preventDefault()}),onFocusOutside:Xr(s.onFocusOutside,f=>f.preventDefault())})}),Ev=g.forwardRef((s,o)=>{const i=qt(Os,s.__scopeDialog),u=g.useRef(!1),d=g.useRef(!1);return n.jsx(Xh,{...s,ref:o,trapFocus:!1,disableOutsidePointerEvents:!1,onCloseAutoFocus:f=>{var m,p;(m=s.onCloseAutoFocus)==null||m.call(s,f),f.defaultPrevented||(u.current||(p=i.triggerRef.current)==null||p.focus(),f.preventDefault()),u.current=!1,d.current=!1},onInteractOutside:f=>{var b,x;(b=s.onInteractOutside)==null||b.call(s,f),f.defaultPrevented||(u.current=!0,f.detail.originalEvent.type==="pointerdown"&&(d.current=!0));const m=f.target;((x=i.triggerRef.current)==null?void 0:x.contains(m))&&f.preventDefault(),f.detail.originalEvent.type==="focusin"&&d.current&&f.preventDefault()}})}),Xh=g.forwardRef((s,o)=>{const{__scopeDialog:i,trapFocus:u,onOpenAutoFocus:d,onCloseAutoFocus:f,...m}=s,p=qt(Os,i);return Ty(),n.jsx(n.Fragment,{children:n.jsx(Th,{asChild:!0,loop:!0,trapped:u,onMountAutoFocus:d,onUnmountAutoFocus:f,children:n.jsx(Oh,{role:"dialog",id:p.contentId,"aria-describedby":p.descriptionId,"aria-labelledby":p.titleId,"data-state":pc(p.open),...m,ref:o,deferPointerDownOutside:!0,onDismiss:()=>p.onOpenChange(!1)})})})}),em="DialogTitle",Pv=g.forwardRef((s,o)=>{const{__scopeDialog:i,...u}=s,d=qt(em,i);return n.jsx(it.h2,{id:d.titleId,...u,ref:o})});Pv.displayName=em;var tm="DialogDescription",_v=g.forwardRef((s,o)=>{const{__scopeDialog:i,...u}=s,d=qt(tm,i);return n.jsx(it.p,{id:d.descriptionId,...u,ref:o})});_v.displayName=tm;var rm="DialogClose",Mv=g.forwardRef((s,o)=>{const{__scopeDialog:i,...u}=s,d=qt(rm,i);return n.jsx(it.button,{type:"button",...u,ref:o,onClick:Xr(s.onClick,()=>d.onOpenChange(!1))})});Mv.displayName=rm;function pc(s){return s?"open":"closed"}var So='[cmdk-group=""]',Eu='[cmdk-group-items=""]',Rv='[cmdk-group-heading=""]',nm='[cmdk-item=""]',Wp=`${nm}:not([aria-disabled="true"])`,ec="cmdk-item-select",ps="data-value",Ov=(s,o,i)=>K0(s,o,i),sm=g.createContext(void 0),Wo=()=>g.useContext(sm),om=g.createContext(void 0),hc=()=>g.useContext(om),lm=g.createContext(void 0),im=g.forwardRef((s,o)=>{let i=hs(()=>{var C,Z;return{search:"",value:(Z=(C=s.value)!=null?C:s.defaultValue)!=null?Z:"",selectedItemId:void 0,filtered:{count:0,items:new Map,groups:new Set}}}),u=hs(()=>new Set),d=hs(()=>new Map),f=hs(()=>new Map),m=hs(()=>new Set),p=am(s),{label:b,children:x,value:j,onValueChange:w,filter:_,shouldFilter:M,loop:z,disablePointerSelection:v=!1,vimBindings:S=!0,...O}=s,F=br(),B=br(),I=br(),D=g.useRef(null),$=Hv();On(()=>{if(j!==void 0){let C=j.trim();i.current.value=C,H.emit()}},[j]),On(()=>{$(6,ze)},[]);let H=g.useMemo(()=>({subscribe:C=>(m.current.add(C),()=>m.current.delete(C)),snapshot:()=>i.current,setState:(C,Z,J)=>{var q,oe,pe,ve;if(!Object.is(i.current[C],Z)){if(i.current[C]=Z,C==="search")de(),fe(),$(1,ke);else if(C==="value"){if(document.activeElement.hasAttribute("cmdk-input")||document.activeElement.hasAttribute("cmdk-root")){let U=document.getElementById(I);U?U.focus():(q=document.getElementById(F))==null||q.focus()}if($(7,()=>{var U;i.current.selectedItemId=(U=Ce())==null?void 0:U.id,H.emit()}),J||$(5,ze),((oe=p.current)==null?void 0:oe.value)!==void 0){let U=Z??"";(ve=(pe=p.current).onValueChange)==null||ve.call(pe,U);return}}H.emit()}},emit:()=>{m.current.forEach(C=>C())}}),[]),ae=g.useMemo(()=>({value:(C,Z,J)=>{var q;Z!==((q=f.current.get(C))==null?void 0:q.value)&&(f.current.set(C,{value:Z,keywords:J}),i.current.filtered.items.set(C,te(Z,J)),$(2,()=>{fe(),H.emit()}))},item:(C,Z)=>(u.current.add(C),Z&&(d.current.has(Z)?d.current.get(Z).add(C):d.current.set(Z,new Set([C]))),$(3,()=>{de(),fe(),i.current.value||ke(),H.emit()}),()=>{f.current.delete(C),u.current.delete(C),i.current.filtered.items.delete(C);let J=Ce();$(4,()=>{de(),(J==null?void 0:J.getAttribute("id"))===C&&ke(),H.emit()})}),group:C=>(d.current.has(C)||d.current.set(C,new Set),()=>{f.current.delete(C),d.current.delete(C)}),filter:()=>p.current.shouldFilter,label:b||s["aria-label"],getDisablePointerSelection:()=>p.current.disablePointerSelection,listId:F,inputId:I,labelId:B,listInnerRef:D}),[]);function te(C,Z){var J,q;let oe=(q=(J=p.current)==null?void 0:J.filter)!=null?q:Ov;return C?oe(C,i.current.search,Z):0}function fe(){if(!i.current.search||p.current.shouldFilter===!1)return;let C=i.current.filtered.items,Z=[];i.current.filtered.groups.forEach(q=>{let oe=d.current.get(q),pe=0;oe.forEach(ve=>{let U=C.get(ve);pe=Math.max(U,pe)}),Z.push([q,pe])});let J=D.current;Le().sort((q,oe)=>{var pe,ve;let U=q.getAttribute("id"),he=oe.getAttribute("id");return((pe=C.get(he))!=null?pe:0)-((ve=C.get(U))!=null?ve:0)}).forEach(q=>{let oe=q.closest(Eu);oe?oe.appendChild(q.parentElement===oe?q:q.closest(`${Eu} > *`)):J.appendChild(q.parentElement===J?q:q.closest(`${Eu} > *`))}),Z.sort((q,oe)=>oe[1]-q[1]).forEach(q=>{var oe;let pe=(oe=D.current)==null?void 0:oe.querySelector(`${So}[${ps}="${encodeURIComponent(q[0])}"]`);pe==null||pe.parentElement.appendChild(pe)})}function ke(){let C=Le().find(J=>J.getAttribute("aria-disabled")!=="true"),Z=C==null?void 0:C.getAttribute(ps);H.setState("value",Z||void 0)}function de(){var C,Z,J,q;if(!i.current.search||p.current.shouldFilter===!1){i.current.filtered.count=u.current.size;return}i.current.filtered.groups=new Set;let oe=0;for(let pe of u.current){let ve=(Z=(C=f.current.get(pe))==null?void 0:C.value)!=null?Z:"",U=(q=(J=f.current.get(pe))==null?void 0:J.keywords)!=null?q:[],he=te(ve,U);i.current.filtered.items.set(pe,he),he>0&&oe++}for(let[pe,ve]of d.current)for(let U of ve)if(i.current.filtered.items.get(U)>0){i.current.filtered.groups.add(pe);break}i.current.filtered.count=oe}function ze(){var C,Z,J;let q=Ce();q&&(((C=q.parentElement)==null?void 0:C.firstChild)===q&&((J=(Z=q.closest(So))==null?void 0:Z.querySelector(Rv))==null||J.scrollIntoView({block:"nearest"})),q.scrollIntoView({block:"nearest"}))}function Ce(){var C;return(C=D.current)==null?void 0:C.querySelector(`${nm}[aria-selected="true"]`)}function Le(){var C;return Array.from(((C=D.current)==null?void 0:C.querySelectorAll(Wp))||[])}function Ee(C){let Z=Le()[C];Z&&H.setState("value",Z.getAttribute(ps))}function Pe(C){var Z;let J=Ce(),q=Le(),oe=q.findIndex(ve=>ve===J),pe=q[oe+C];(Z=p.current)!=null&&Z.loop&&(pe=oe+C<0?q[q.length-1]:oe+C===q.length?q[0]:q[oe+C]),pe&&H.setState("value",pe.getAttribute(ps))}function K(C){let Z=Ce(),J=Z==null?void 0:Z.closest(So),q;for(;J&&!q;)J=C>0?$v(J,So):Bv(J,So),q=J==null?void 0:J.querySelector(Wp);q?H.setState("value",q.getAttribute(ps)):Pe(C)}let X=()=>Ee(Le().length-1),Y=C=>{C.preventDefault(),C.metaKey?X():C.altKey?K(1):Pe(1)},P=C=>{C.preventDefault(),C.metaKey?Ee(0):C.altKey?K(-1):Pe(-1)};return g.createElement(it.div,{ref:o,tabIndex:-1,...O,"cmdk-root":"",onKeyDown:C=>{var Z;(Z=O.onKeyDown)==null||Z.call(O,C);let J=C.nativeEvent.isComposing||C.keyCode===229;if(!(C.defaultPrevented||J))switch(C.key){case"n":case"j":{S&&C.ctrlKey&&Y(C);break}case"ArrowDown":{Y(C);break}case"p":case"k":{S&&C.ctrlKey&&P(C);break}case"ArrowUp":{P(C);break}case"Home":{C.preventDefault(),Ee(0);break}case"End":{C.preventDefault(),X();break}case"Enter":{C.preventDefault();let q=Ce();if(q){let oe=new Event(ec);q.dispatchEvent(oe)}}}}},g.createElement("label",{"cmdk-label":"",htmlFor:ae.inputId,id:ae.labelId,style:Vv},b),Ni(s,C=>g.createElement(om.Provider,{value:H},g.createElement(sm.Provider,{value:ae},C))))}),Dv=g.forwardRef((s,o)=>{var i,u;let d=br(),f=g.useRef(null),m=g.useContext(lm),p=Wo(),b=am(s),x=(u=(i=b.current)==null?void 0:i.forceMount)!=null?u:m==null?void 0:m.forceMount;On(()=>{if(!x)return p.item(d,m==null?void 0:m.id)},[x]);let j=um(d,f,[s.value,s.children,f],s.keywords),w=hc(),_=en($=>$.value&&$.value===j.current),M=en($=>x||p.filter()===!1?!0:$.search?$.filtered.items.get(d)>0:!0);g.useEffect(()=>{let $=f.current;if(!(!$||s.disabled))return $.addEventListener(ec,z),()=>$.removeEventListener(ec,z)},[M,s.onSelect,s.disabled]);function z(){var $,H;v(),(H=($=b.current).onSelect)==null||H.call($,j.current)}function v(){w.setState("value",j.current,!0)}if(!M)return null;let{disabled:S,value:O,onSelect:F,forceMount:B,keywords:I,...D}=s;return g.createElement(it.div,{ref:Rs(f,o),...D,id:d,"cmdk-item":"",role:"option","aria-disabled":!!S,"aria-selected":!!_,"data-disabled":!!S,"data-selected":!!_,onPointerMove:S||p.getDisablePointerSelection()?void 0:v,onClick:S?void 0:z},s.children)}),Tv=g.forwardRef((s,o)=>{let{heading:i,children:u,forceMount:d,...f}=s,m=br(),p=g.useRef(null),b=g.useRef(null),x=br(),j=Wo(),w=en(M=>d||j.filter()===!1?!0:M.search?M.filtered.groups.has(m):!0);On(()=>j.group(m),[]),um(m,p,[s.value,s.heading,b]);let _=g.useMemo(()=>({id:m,forceMount:d}),[d]);return g.createElement(it.div,{ref:Rs(p,o),...f,"cmdk-group":"",role:"presentation",hidden:w?void 0:!0},i&&g.createElement("div",{ref:b,"cmdk-group-heading":"","aria-hidden":!0,id:x},i),Ni(s,M=>g.createElement("div",{"cmdk-group-items":"",role:"group","aria-labelledby":i?x:void 0},g.createElement(lm.Provider,{value:_},M))))}),Av=g.forwardRef((s,o)=>{let{alwaysRender:i,...u}=s,d=g.useRef(null),f=en(m=>!m.search);return!i&&!f?null:g.createElement(it.div,{ref:Rs(d,o),...u,"cmdk-separator":"",role:"separator"})}),zv=g.forwardRef((s,o)=>{let{onValueChange:i,...u}=s,d=s.value!=null,f=hc(),m=en(x=>x.search),p=en(x=>x.selectedItemId),b=Wo();return g.useEffect(()=>{s.value!=null&&f.setState("search",s.value)},[s.value]),g.createElement(it.input,{ref:o,...u,"cmdk-input":"",autoComplete:"off",autoCorrect:"off",spellCheck:!1,"aria-autocomplete":"list",role:"combobox","aria-expanded":!0,"aria-controls":b.listId,"aria-labelledby":b.labelId,"aria-activedescendant":p,id:b.inputId,type:"text",value:d?s.value:m,onChange:x=>{d||f.setState("search",x.target.value),i==null||i(x.target.value)}})}),Lv=g.forwardRef((s,o)=>{let{children:i,label:u="Suggestions",...d}=s,f=g.useRef(null),m=g.useRef(null),p=en(x=>x.selectedItemId),b=Wo();return g.useEffect(()=>{if(m.current&&f.current){let x=m.current,j=f.current,w,_=new ResizeObserver(()=>{w=requestAnimationFrame(()=>{let M=x.offsetHeight;j.style.setProperty("--cmdk-list-height",M.toFixed(1)+"px")})});return _.observe(x),()=>{cancelAnimationFrame(w),_.unobserve(x)}}},[]),g.createElement(it.div,{ref:Rs(f,o),...d,"cmdk-list":"",role:"listbox",tabIndex:-1,"aria-activedescendant":p,"aria-label":u,id:b.listId},Ni(s,x=>g.createElement("div",{ref:Rs(m,b.listInnerRef),"cmdk-list-sizer":""},x)))}),Iv=g.forwardRef((s,o)=>{let{open:i,onOpenChange:u,overlayClassName:d,contentClassName:f,container:m,...p}=s;return g.createElement(Kh,{open:i,onOpenChange:u},g.createElement(Zh,{container:m},g.createElement(Yh,{"cmdk-overlay":"",className:d}),g.createElement(Jh,{"aria-label":s.label,"cmdk-dialog":"",className:f},g.createElement(im,{ref:o,...p}))))}),Fv=g.forwardRef((s,o)=>en(i=>i.filtered.count===0)?g.createElement(it.div,{ref:o,...s,"cmdk-empty":"",role:"presentation"}):null),Uv=g.forwardRef((s,o)=>{let{progress:i,children:u,label:d="Loading...",...f}=s;return g.createElement(it.div,{ref:o,...f,"cmdk-loading":"",role:"progressbar","aria-valuenow":i,"aria-valuemin":0,"aria-valuemax":100,"aria-label":d},Ni(s,m=>g.createElement("div",{"aria-hidden":!0},m)))}),fs=Object.assign(im,{List:Lv,Item:Dv,Input:zv,Group:Tv,Separator:Av,Dialog:Iv,Empty:Fv,Loading:Uv});function $v(s,o){let i=s.nextElementSibling;for(;i;){if(i.matches(o))return i;i=i.nextElementSibling}}function Bv(s,o){let i=s.previousElementSibling;for(;i;){if(i.matches(o))return i;i=i.previousElementSibling}}function am(s){let o=g.useRef(s);return On(()=>{o.current=s}),o}var On=typeof window>"u"?g.useEffect:g.useLayoutEffect;function hs(s){let o=g.useRef();return o.current===void 0&&(o.current=s()),o}function en(s){let o=hc(),i=()=>s(o.snapshot());return g.useSyncExternalStore(o.subscribe,i,i)}function um(s,o,i,u=[]){let d=g.useRef(),f=Wo();return On(()=>{var m;let p=(()=>{var x;for(let j of i){if(typeof j=="string")return j.trim();if(typeof j=="object"&&"current"in j)return j.current?(x=j.current.textContent)==null?void 0:x.trim():d.current}})(),b=u.map(x=>x.trim());f.value(s,p,b),(m=o.current)==null||m.setAttribute(ps,p),d.current=p}),d}var Hv=()=>{let[s,o]=g.useState(),i=hs(()=>new Map);return On(()=>{i.current.forEach(u=>u()),i.current=new Map},[s]),(u,d)=>{i.current.set(u,d),o({})}};function Wv(s){let o=s.type;return typeof o=="function"?o(s.props):"render"in o?o.render(s.props):s}function Ni({asChild:s,children:o},i){return s&&g.isValidElement(o)?g.cloneElement(Wv(o),{ref:o.ref},i(o.props.children)):i(o)}var Vv={position:"absolute",width:"1px",height:"1px",padding:"0",margin:"-1px",overflow:"hidden",clip:"rect(0, 0, 0, 0)",whiteSpace:"nowrap",borderWidth:"0"};function Gv({onNavigate:s}){const[o,i]=g.useState(!1);return g.useEffect(()=>{const u=d=>{(d.metaKey||d.ctrlKey)&&d.key.toLowerCase()==="k"&&(d.preventDefault(),i(f=>!f))};return document.addEventListener("keydown",u),()=>document.removeEventListener("keydown",u)},[]),n.jsx(fs.Dialog,{open:o,onOpenChange:i,label:"Befehlspalette",className:"fixed inset-0 z-50 flex items-start justify-center bg-black/50 p-4 pt-[12vh]",onClick:()=>i(!1),children:n.jsxs("div",{className:"w-full max-w-lg overflow-hidden rounded-xl border border-border bg-popover text-popover-foreground shadow-2xl",onClick:u=>u.stopPropagation(),children:[n.jsx(fs.Input,{autoFocus:!0,placeholder:"Springe zu… (Modelle, Routing, System …)",className:"w-full border-b border-border bg-transparent px-4 py-3 text-sm outline-none placeholder:text-muted-foreground"}),n.jsxs(fs.List,{className:"max-h-80 overflow-y-auto p-2",children:[n.jsx(fs.Empty,{className:"px-3 py-6 text-center text-sm text-muted-foreground",children:"Nichts gefunden."}),n.jsx(fs.Group,{heading:"Bereiche",className:"px-1 py-1 text-xs text-muted-foreground",children:Zu.map(u=>n.jsxs(fs.Item,{value:`${u.label} ${u.hint}`,onSelect:()=>{s(u.id),i(!1)},className:"flex cursor-pointer items-center gap-3 rounded-md px-3 py-2 text-sm text-foreground aria-selected:bg-accent aria-selected:text-accent-foreground",children:[n.jsx(u.icon,{className:"h-4 w-4 text-primary"}),n.jsx("span",{children:u.label}),n.jsx("span",{className:"ml-auto truncate text-xs text-muted-foreground",children:u.hint})]},u.id))})]})]})})}async function we(s,o){var b;const i={"Content-Type":"application/json",...o==null?void 0:o.headers},u=localStorage.getItem("mc_sudo_password"),d=localStorage.getItem("mc_hf_token");u&&(i["X-Sudo-Password"]=u);let f=o==null?void 0:o.body;if((((b=o==null?void 0:o.method)==null?void 0:b.toUpperCase())||"GET")==="POST"){if(typeof f=="string")try{const x=JSON.parse(f);let j=!1;u&&!("sudo_password"in x)&&(x.sudo_password=u,j=!0),d&&!("hf_token"in x)&&(x.hf_token=d,j=!0),j&&(f=JSON.stringify(x))}catch{}else if(!f){const x={};u&&(x.sudo_password=u),d&&(x.hf_token=d),Object.keys(x).length>0&&(f=JSON.stringify(x))}}const p=await fetch(s,{...o,headers:i,body:f});if(!p.ok)throw new Error(`${p.status} ${p.statusText}`);return p.json()}const Ye={health:["health"],systemStatus:["system-status"],services:["services"],models:["models"],routing:["routing"],jobs:["jobs"],tokenStats:["token-stats"],agentStatus:["agent-status"],updates:["updates"],discover:["discover"],connect:s=>["connect",s??""],memory:(s,o)=>["memory",s??"",o??""]},Kv=()=>Ut({queryKey:Ye.health,queryFn:()=>we("/api/health"),refetchInterval:1e4}),mc=(s=5e3)=>Ut({queryKey:Ye.systemStatus,queryFn:()=>we("/api/system/status"),refetchInterval:s}),Qv=(s=3e3)=>Ut({queryKey:Ye.services,queryFn:()=>we("/api/system/services"),refetchInterval:s}),Vo=(s=4e3)=>Ut({queryKey:Ye.models,queryFn:()=>we("/api/models"),refetchInterval:s}),qv=(s=4e3)=>Ut({queryKey:Ye.routing,queryFn:()=>we("/api/routing"),refetchInterval:s}),cm=(s=2e3)=>Ut({queryKey:Ye.jobs,queryFn:()=>we("/api/jobs"),refetchInterval:s,select:o=>o.jobs??[]}),Zv=(s=3e3)=>Ut({queryKey:Ye.tokenStats,queryFn:()=>we("/api/system/token-stats"),refetchInterval:s}),dm=(s=5e3)=>Ut({queryKey:Ye.agentStatus,queryFn:()=>we("/api/agent/status"),refetchInterval:s}),gc=s=>Ut({queryKey:Ye.updates,queryFn:()=>we("/api/maintenance/updates"),refetchInterval:s}),Yv=()=>Ut({queryKey:Ye.discover,queryFn:()=>we("/api/discover")}),fm=s=>Ut({queryKey:Ye.connect(s),queryFn:()=>we(s?`/api/connect?${s}`:"/api/connect")}),pm=s=>Ut({queryKey:Ye.memory(s==null?void 0:s.q,s==null?void 0:s.category),queryFn:()=>{const o=new URLSearchParams;return s!=null&&s.q&&o.set("q",s.q),s!=null&&s.category&&o.set("category",s.category),we(`/api/memory?${o}`)},select:o=>s!=null&&s.limit?o.slice(0,s.limit):o});function St(s){return(s/1024**3).toFixed(1)}function tc(s){return s?s>1024**3?`${(s/1024**3).toFixed(1)} GB`:`${(s/1024**2).toFixed(0)} MB`:""}function gn(s){if(!s)return"—";const o=s/1024**3;return o>=1?`${o.toFixed(1)} GB`:`${(s/1024**2).toFixed(0)} MB`}function Jv(s){if(!s)return"";const o=Math.floor(s/60);return o>0?`${o} min`:`${s} s`}function Vp(s){return s?`${Math.round(s/1024)}k`:"—"}function hm(s){var o,i,u="";if(typeof s=="string"||typeof s=="number")u+=s;else if(typeof s=="object")if(Array.isArray(s)){var d=s.length;for(o=0;o{const o=rb(s),{conflictingClassGroups:i,conflictingClassGroupModifiers:u}=s;return{getClassGroupId:m=>{const p=m.split(xc);return p[0]===""&&p.length!==1&&p.shift(),mm(p,o)||tb(m)},getConflictingClassGroupIds:(m,p)=>{const b=i[m]||[];return p&&u[m]?[...b,...u[m]]:b}}},mm=(s,o)=>{var m;if(s.length===0)return o.classGroupId;const i=s[0],u=o.nextPart.get(i),d=u?mm(s.slice(1),u):void 0;if(d)return d;if(o.validators.length===0)return;const f=s.join(xc);return(m=o.validators.find(({validator:p})=>p(f)))==null?void 0:m.classGroupId},Gp=/^\[(.+)\]$/,tb=s=>{if(Gp.test(s)){const o=Gp.exec(s)[1],i=o==null?void 0:o.substring(0,o.indexOf(":"));if(i)return"arbitrary.."+i}},rb=s=>{const{theme:o,prefix:i}=s,u={nextPart:new Map,validators:[]};return sb(Object.entries(s.classGroups),i).forEach(([f,m])=>{rc(m,u,f,o)}),u},rc=(s,o,i,u)=>{s.forEach(d=>{if(typeof d=="string"){const f=d===""?o:Kp(o,d);f.classGroupId=i;return}if(typeof d=="function"){if(nb(d)){rc(d(u),o,i,u);return}o.validators.push({validator:d,classGroupId:i});return}Object.entries(d).forEach(([f,m])=>{rc(m,Kp(o,f),i,u)})})},Kp=(s,o)=>{let i=s;return o.split(xc).forEach(u=>{i.nextPart.has(u)||i.nextPart.set(u,{nextPart:new Map,validators:[]}),i=i.nextPart.get(u)}),i},nb=s=>s.isThemeGetter,sb=(s,o)=>o?s.map(([i,u])=>{const d=u.map(f=>typeof f=="string"?o+f:typeof f=="object"?Object.fromEntries(Object.entries(f).map(([m,p])=>[o+m,p])):f);return[i,d]}):s,ob=s=>{if(s<1)return{get:()=>{},set:()=>{}};let o=0,i=new Map,u=new Map;const d=(f,m)=>{i.set(f,m),o++,o>s&&(o=0,u=i,i=new Map)};return{get(f){let m=i.get(f);if(m!==void 0)return m;if((m=u.get(f))!==void 0)return d(f,m),m},set(f,m){i.has(f)?i.set(f,m):d(f,m)}}},gm="!",lb=s=>{const{separator:o,experimentalParseClassName:i}=s,u=o.length===1,d=o[0],f=o.length,m=p=>{const b=[];let x=0,j=0,w;for(let S=0;Sj?w-j:void 0;return{modifiers:b,hasImportantModifier:M,baseClassName:z,maybePostfixModifierPosition:v}};return i?p=>i({className:p,parseClassName:m}):m},ib=s=>{if(s.length<=1)return s;const o=[];let i=[];return s.forEach(u=>{u[0]==="["?(o.push(...i.sort(),u),i=[]):i.push(u)}),o.push(...i.sort()),o},ab=s=>({cache:ob(s.cacheSize),parseClassName:lb(s),...eb(s)}),ub=/\s+/,cb=(s,o)=>{const{parseClassName:i,getClassGroupId:u,getConflictingClassGroupIds:d}=o,f=[],m=s.trim().split(ub);let p="";for(let b=m.length-1;b>=0;b-=1){const x=m[b],{modifiers:j,hasImportantModifier:w,baseClassName:_,maybePostfixModifierPosition:M}=i(x);let z=!!M,v=u(z?_.substring(0,M):_);if(!v){if(!z){p=x+(p.length>0?" "+p:p);continue}if(v=u(_),!v){p=x+(p.length>0?" "+p:p);continue}z=!1}const S=ib(j).join(":"),O=w?S+gm:S,F=O+v;if(f.includes(F))continue;f.push(F);const B=d(v,z);for(let I=0;I0?" "+p:p)}return p};function db(){let s=0,o,i,u="";for(;s{if(typeof s=="string")return s;let o,i="";for(let u=0;uw(j),s());return i=ab(x),u=i.cache.get,d=i.cache.set,f=p,p(b)}function p(b){const x=u(b);if(x)return x;const j=cb(b,i);return d(b,j),j}return function(){return f(db.apply(null,arguments))}}const $e=s=>{const o=i=>i[s]||[];return o.isThemeGetter=!0,o},ym=/^\[(?:([a-z-]+):)?(.+)\]$/i,pb=/^\d+\/\d+$/,hb=new Set(["px","full","screen"]),mb=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,gb=/\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/,xb=/^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/,yb=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,vb=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,gr=s=>gs(s)||hb.has(s)||pb.test(s),Ur=s=>Ds(s,"length",Eb),gs=s=>!!s&&!Number.isNaN(Number(s)),Pu=s=>Ds(s,"number",gs),Co=s=>!!s&&Number.isInteger(Number(s)),bb=s=>s.endsWith("%")&&gs(s.slice(0,-1)),Ne=s=>ym.test(s),$r=s=>mb.test(s),wb=new Set(["length","size","percentage"]),jb=s=>Ds(s,wb,vm),kb=s=>Ds(s,"position",vm),Nb=new Set(["image","url"]),Sb=s=>Ds(s,Nb,_b),Cb=s=>Ds(s,"",Pb),Eo=()=>!0,Ds=(s,o,i)=>{const u=ym.exec(s);return u?u[1]?typeof o=="string"?u[1]===o:o.has(u[1]):i(u[2]):!1},Eb=s=>gb.test(s)&&!xb.test(s),vm=()=>!1,Pb=s=>yb.test(s),_b=s=>vb.test(s),Mb=()=>{const s=$e("colors"),o=$e("spacing"),i=$e("blur"),u=$e("brightness"),d=$e("borderColor"),f=$e("borderRadius"),m=$e("borderSpacing"),p=$e("borderWidth"),b=$e("contrast"),x=$e("grayscale"),j=$e("hueRotate"),w=$e("invert"),_=$e("gap"),M=$e("gradientColorStops"),z=$e("gradientColorStopPositions"),v=$e("inset"),S=$e("margin"),O=$e("opacity"),F=$e("padding"),B=$e("saturate"),I=$e("scale"),D=$e("sepia"),$=$e("skew"),H=$e("space"),ae=$e("translate"),te=()=>["auto","contain","none"],fe=()=>["auto","hidden","clip","visible","scroll"],ke=()=>["auto",Ne,o],de=()=>[Ne,o],ze=()=>["",gr,Ur],Ce=()=>["auto",gs,Ne],Le=()=>["bottom","center","left","left-bottom","left-top","right","right-bottom","right-top","top"],Ee=()=>["solid","dashed","dotted","double","none"],Pe=()=>["normal","multiply","screen","overlay","darken","lighten","color-dodge","color-burn","hard-light","soft-light","difference","exclusion","hue","saturation","color","luminosity"],K=()=>["start","end","center","between","around","evenly","stretch"],X=()=>["","0",Ne],Y=()=>["auto","avoid","all","avoid-page","page","left","right","column"],P=()=>[gs,Ne];return{cacheSize:500,separator:":",theme:{colors:[Eo],spacing:[gr,Ur],blur:["none","",$r,Ne],brightness:P(),borderColor:[s],borderRadius:["none","","full",$r,Ne],borderSpacing:de(),borderWidth:ze(),contrast:P(),grayscale:X(),hueRotate:P(),invert:X(),gap:de(),gradientColorStops:[s],gradientColorStopPositions:[bb,Ur],inset:ke(),margin:ke(),opacity:P(),padding:de(),saturate:P(),scale:P(),sepia:X(),skew:P(),space:de(),translate:de()},classGroups:{aspect:[{aspect:["auto","square","video",Ne]}],container:["container"],columns:[{columns:[$r]}],"break-after":[{"break-after":Y()}],"break-before":[{"break-before":Y()}],"break-inside":[{"break-inside":["auto","avoid","avoid-page","avoid-column"]}],"box-decoration":[{"box-decoration":["slice","clone"]}],box:[{box:["border","content"]}],display:["block","inline-block","inline","flex","inline-flex","table","inline-table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row-group","table-row","flow-root","grid","inline-grid","contents","list-item","hidden"],float:[{float:["right","left","none","start","end"]}],clear:[{clear:["left","right","both","none","start","end"]}],isolation:["isolate","isolation-auto"],"object-fit":[{object:["contain","cover","fill","none","scale-down"]}],"object-position":[{object:[...Le(),Ne]}],overflow:[{overflow:fe()}],"overflow-x":[{"overflow-x":fe()}],"overflow-y":[{"overflow-y":fe()}],overscroll:[{overscroll:te()}],"overscroll-x":[{"overscroll-x":te()}],"overscroll-y":[{"overscroll-y":te()}],position:["static","fixed","absolute","relative","sticky"],inset:[{inset:[v]}],"inset-x":[{"inset-x":[v]}],"inset-y":[{"inset-y":[v]}],start:[{start:[v]}],end:[{end:[v]}],top:[{top:[v]}],right:[{right:[v]}],bottom:[{bottom:[v]}],left:[{left:[v]}],visibility:["visible","invisible","collapse"],z:[{z:["auto",Co,Ne]}],basis:[{basis:ke()}],"flex-direction":[{flex:["row","row-reverse","col","col-reverse"]}],"flex-wrap":[{flex:["wrap","wrap-reverse","nowrap"]}],flex:[{flex:["1","auto","initial","none",Ne]}],grow:[{grow:X()}],shrink:[{shrink:X()}],order:[{order:["first","last","none",Co,Ne]}],"grid-cols":[{"grid-cols":[Eo]}],"col-start-end":[{col:["auto",{span:["full",Co,Ne]},Ne]}],"col-start":[{"col-start":Ce()}],"col-end":[{"col-end":Ce()}],"grid-rows":[{"grid-rows":[Eo]}],"row-start-end":[{row:["auto",{span:[Co,Ne]},Ne]}],"row-start":[{"row-start":Ce()}],"row-end":[{"row-end":Ce()}],"grid-flow":[{"grid-flow":["row","col","dense","row-dense","col-dense"]}],"auto-cols":[{"auto-cols":["auto","min","max","fr",Ne]}],"auto-rows":[{"auto-rows":["auto","min","max","fr",Ne]}],gap:[{gap:[_]}],"gap-x":[{"gap-x":[_]}],"gap-y":[{"gap-y":[_]}],"justify-content":[{justify:["normal",...K()]}],"justify-items":[{"justify-items":["start","end","center","stretch"]}],"justify-self":[{"justify-self":["auto","start","end","center","stretch"]}],"align-content":[{content:["normal",...K(),"baseline"]}],"align-items":[{items:["start","end","center","baseline","stretch"]}],"align-self":[{self:["auto","start","end","center","stretch","baseline"]}],"place-content":[{"place-content":[...K(),"baseline"]}],"place-items":[{"place-items":["start","end","center","baseline","stretch"]}],"place-self":[{"place-self":["auto","start","end","center","stretch"]}],p:[{p:[F]}],px:[{px:[F]}],py:[{py:[F]}],ps:[{ps:[F]}],pe:[{pe:[F]}],pt:[{pt:[F]}],pr:[{pr:[F]}],pb:[{pb:[F]}],pl:[{pl:[F]}],m:[{m:[S]}],mx:[{mx:[S]}],my:[{my:[S]}],ms:[{ms:[S]}],me:[{me:[S]}],mt:[{mt:[S]}],mr:[{mr:[S]}],mb:[{mb:[S]}],ml:[{ml:[S]}],"space-x":[{"space-x":[H]}],"space-x-reverse":["space-x-reverse"],"space-y":[{"space-y":[H]}],"space-y-reverse":["space-y-reverse"],w:[{w:["auto","min","max","fit","svw","lvw","dvw",Ne,o]}],"min-w":[{"min-w":[Ne,o,"min","max","fit"]}],"max-w":[{"max-w":[Ne,o,"none","full","min","max","fit","prose",{screen:[$r]},$r]}],h:[{h:[Ne,o,"auto","min","max","fit","svh","lvh","dvh"]}],"min-h":[{"min-h":[Ne,o,"min","max","fit","svh","lvh","dvh"]}],"max-h":[{"max-h":[Ne,o,"min","max","fit","svh","lvh","dvh"]}],size:[{size:[Ne,o,"auto","min","max","fit"]}],"font-size":[{text:["base",$r,Ur]}],"font-smoothing":["antialiased","subpixel-antialiased"],"font-style":["italic","not-italic"],"font-weight":[{font:["thin","extralight","light","normal","medium","semibold","bold","extrabold","black",Pu]}],"font-family":[{font:[Eo]}],"fvn-normal":["normal-nums"],"fvn-ordinal":["ordinal"],"fvn-slashed-zero":["slashed-zero"],"fvn-figure":["lining-nums","oldstyle-nums"],"fvn-spacing":["proportional-nums","tabular-nums"],"fvn-fraction":["diagonal-fractions","stacked-fractions"],tracking:[{tracking:["tighter","tight","normal","wide","wider","widest",Ne]}],"line-clamp":[{"line-clamp":["none",gs,Pu]}],leading:[{leading:["none","tight","snug","normal","relaxed","loose",gr,Ne]}],"list-image":[{"list-image":["none",Ne]}],"list-style-type":[{list:["none","disc","decimal",Ne]}],"list-style-position":[{list:["inside","outside"]}],"placeholder-color":[{placeholder:[s]}],"placeholder-opacity":[{"placeholder-opacity":[O]}],"text-alignment":[{text:["left","center","right","justify","start","end"]}],"text-color":[{text:[s]}],"text-opacity":[{"text-opacity":[O]}],"text-decoration":["underline","overline","line-through","no-underline"],"text-decoration-style":[{decoration:[...Ee(),"wavy"]}],"text-decoration-thickness":[{decoration:["auto","from-font",gr,Ur]}],"underline-offset":[{"underline-offset":["auto",gr,Ne]}],"text-decoration-color":[{decoration:[s]}],"text-transform":["uppercase","lowercase","capitalize","normal-case"],"text-overflow":["truncate","text-ellipsis","text-clip"],"text-wrap":[{text:["wrap","nowrap","balance","pretty"]}],indent:[{indent:de()}],"vertical-align":[{align:["baseline","top","middle","bottom","text-top","text-bottom","sub","super",Ne]}],whitespace:[{whitespace:["normal","nowrap","pre","pre-line","pre-wrap","break-spaces"]}],break:[{break:["normal","words","all","keep"]}],hyphens:[{hyphens:["none","manual","auto"]}],content:[{content:["none",Ne]}],"bg-attachment":[{bg:["fixed","local","scroll"]}],"bg-clip":[{"bg-clip":["border","padding","content","text"]}],"bg-opacity":[{"bg-opacity":[O]}],"bg-origin":[{"bg-origin":["border","padding","content"]}],"bg-position":[{bg:[...Le(),kb]}],"bg-repeat":[{bg:["no-repeat",{repeat:["","x","y","round","space"]}]}],"bg-size":[{bg:["auto","cover","contain",jb]}],"bg-image":[{bg:["none",{"gradient-to":["t","tr","r","br","b","bl","l","tl"]},Sb]}],"bg-color":[{bg:[s]}],"gradient-from-pos":[{from:[z]}],"gradient-via-pos":[{via:[z]}],"gradient-to-pos":[{to:[z]}],"gradient-from":[{from:[M]}],"gradient-via":[{via:[M]}],"gradient-to":[{to:[M]}],rounded:[{rounded:[f]}],"rounded-s":[{"rounded-s":[f]}],"rounded-e":[{"rounded-e":[f]}],"rounded-t":[{"rounded-t":[f]}],"rounded-r":[{"rounded-r":[f]}],"rounded-b":[{"rounded-b":[f]}],"rounded-l":[{"rounded-l":[f]}],"rounded-ss":[{"rounded-ss":[f]}],"rounded-se":[{"rounded-se":[f]}],"rounded-ee":[{"rounded-ee":[f]}],"rounded-es":[{"rounded-es":[f]}],"rounded-tl":[{"rounded-tl":[f]}],"rounded-tr":[{"rounded-tr":[f]}],"rounded-br":[{"rounded-br":[f]}],"rounded-bl":[{"rounded-bl":[f]}],"border-w":[{border:[p]}],"border-w-x":[{"border-x":[p]}],"border-w-y":[{"border-y":[p]}],"border-w-s":[{"border-s":[p]}],"border-w-e":[{"border-e":[p]}],"border-w-t":[{"border-t":[p]}],"border-w-r":[{"border-r":[p]}],"border-w-b":[{"border-b":[p]}],"border-w-l":[{"border-l":[p]}],"border-opacity":[{"border-opacity":[O]}],"border-style":[{border:[...Ee(),"hidden"]}],"divide-x":[{"divide-x":[p]}],"divide-x-reverse":["divide-x-reverse"],"divide-y":[{"divide-y":[p]}],"divide-y-reverse":["divide-y-reverse"],"divide-opacity":[{"divide-opacity":[O]}],"divide-style":[{divide:Ee()}],"border-color":[{border:[d]}],"border-color-x":[{"border-x":[d]}],"border-color-y":[{"border-y":[d]}],"border-color-s":[{"border-s":[d]}],"border-color-e":[{"border-e":[d]}],"border-color-t":[{"border-t":[d]}],"border-color-r":[{"border-r":[d]}],"border-color-b":[{"border-b":[d]}],"border-color-l":[{"border-l":[d]}],"divide-color":[{divide:[d]}],"outline-style":[{outline:["",...Ee()]}],"outline-offset":[{"outline-offset":[gr,Ne]}],"outline-w":[{outline:[gr,Ur]}],"outline-color":[{outline:[s]}],"ring-w":[{ring:ze()}],"ring-w-inset":["ring-inset"],"ring-color":[{ring:[s]}],"ring-opacity":[{"ring-opacity":[O]}],"ring-offset-w":[{"ring-offset":[gr,Ur]}],"ring-offset-color":[{"ring-offset":[s]}],shadow:[{shadow:["","inner","none",$r,Cb]}],"shadow-color":[{shadow:[Eo]}],opacity:[{opacity:[O]}],"mix-blend":[{"mix-blend":[...Pe(),"plus-lighter","plus-darker"]}],"bg-blend":[{"bg-blend":Pe()}],filter:[{filter:["","none"]}],blur:[{blur:[i]}],brightness:[{brightness:[u]}],contrast:[{contrast:[b]}],"drop-shadow":[{"drop-shadow":["","none",$r,Ne]}],grayscale:[{grayscale:[x]}],"hue-rotate":[{"hue-rotate":[j]}],invert:[{invert:[w]}],saturate:[{saturate:[B]}],sepia:[{sepia:[D]}],"backdrop-filter":[{"backdrop-filter":["","none"]}],"backdrop-blur":[{"backdrop-blur":[i]}],"backdrop-brightness":[{"backdrop-brightness":[u]}],"backdrop-contrast":[{"backdrop-contrast":[b]}],"backdrop-grayscale":[{"backdrop-grayscale":[x]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[j]}],"backdrop-invert":[{"backdrop-invert":[w]}],"backdrop-opacity":[{"backdrop-opacity":[O]}],"backdrop-saturate":[{"backdrop-saturate":[B]}],"backdrop-sepia":[{"backdrop-sepia":[D]}],"border-collapse":[{border:["collapse","separate"]}],"border-spacing":[{"border-spacing":[m]}],"border-spacing-x":[{"border-spacing-x":[m]}],"border-spacing-y":[{"border-spacing-y":[m]}],"table-layout":[{table:["auto","fixed"]}],caption:[{caption:["top","bottom"]}],transition:[{transition:["none","all","","colors","opacity","shadow","transform",Ne]}],duration:[{duration:P()}],ease:[{ease:["linear","in","out","in-out",Ne]}],delay:[{delay:P()}],animate:[{animate:["none","spin","ping","pulse","bounce",Ne]}],transform:[{transform:["","gpu","none"]}],scale:[{scale:[I]}],"scale-x":[{"scale-x":[I]}],"scale-y":[{"scale-y":[I]}],rotate:[{rotate:[Co,Ne]}],"translate-x":[{"translate-x":[ae]}],"translate-y":[{"translate-y":[ae]}],"skew-x":[{"skew-x":[$]}],"skew-y":[{"skew-y":[$]}],"transform-origin":[{origin:["center","top","top-right","right","bottom-right","bottom","bottom-left","left","top-left",Ne]}],accent:[{accent:["auto",s]}],appearance:[{appearance:["none","auto"]}],cursor:[{cursor:["auto","default","pointer","wait","text","move","help","not-allowed","none","context-menu","progress","cell","crosshair","vertical-text","alias","copy","no-drop","grab","grabbing","all-scroll","col-resize","row-resize","n-resize","e-resize","s-resize","w-resize","ne-resize","nw-resize","se-resize","sw-resize","ew-resize","ns-resize","nesw-resize","nwse-resize","zoom-in","zoom-out",Ne]}],"caret-color":[{caret:[s]}],"pointer-events":[{"pointer-events":["none","auto"]}],resize:[{resize:["none","y","x",""]}],"scroll-behavior":[{scroll:["auto","smooth"]}],"scroll-m":[{"scroll-m":de()}],"scroll-mx":[{"scroll-mx":de()}],"scroll-my":[{"scroll-my":de()}],"scroll-ms":[{"scroll-ms":de()}],"scroll-me":[{"scroll-me":de()}],"scroll-mt":[{"scroll-mt":de()}],"scroll-mr":[{"scroll-mr":de()}],"scroll-mb":[{"scroll-mb":de()}],"scroll-ml":[{"scroll-ml":de()}],"scroll-p":[{"scroll-p":de()}],"scroll-px":[{"scroll-px":de()}],"scroll-py":[{"scroll-py":de()}],"scroll-ps":[{"scroll-ps":de()}],"scroll-pe":[{"scroll-pe":de()}],"scroll-pt":[{"scroll-pt":de()}],"scroll-pr":[{"scroll-pr":de()}],"scroll-pb":[{"scroll-pb":de()}],"scroll-pl":[{"scroll-pl":de()}],"snap-align":[{snap:["start","end","center","align-none"]}],"snap-stop":[{snap:["normal","always"]}],"snap-type":[{snap:["none","x","y","both"]}],"snap-strictness":[{snap:["mandatory","proximity"]}],touch:[{touch:["auto","none","manipulation"]}],"touch-x":[{"touch-pan":["x","left","right"]}],"touch-y":[{"touch-pan":["y","up","down"]}],"touch-pz":["touch-pinch-zoom"],select:[{select:["none","text","all","auto"]}],"will-change":[{"will-change":["auto","scroll","contents","transform",Ne]}],fill:[{fill:[s,"none"]}],"stroke-w":[{stroke:[gr,Ur,Pu]}],stroke:[{stroke:[s,"none"]}],sr:["sr-only","not-sr-only"],"forced-color-adjust":[{"forced-color-adjust":["auto","none"]}]},conflictingClassGroups:{overflow:["overflow-x","overflow-y"],overscroll:["overscroll-x","overscroll-y"],inset:["inset-x","inset-y","start","end","top","right","bottom","left"],"inset-x":["right","left"],"inset-y":["top","bottom"],flex:["basis","grow","shrink"],gap:["gap-x","gap-y"],p:["px","py","ps","pe","pt","pr","pb","pl"],px:["pr","pl"],py:["pt","pb"],m:["mx","my","ms","me","mt","mr","mb","ml"],mx:["mr","ml"],my:["mt","mb"],size:["w","h"],"font-size":["leading"],"fvn-normal":["fvn-ordinal","fvn-slashed-zero","fvn-figure","fvn-spacing","fvn-fraction"],"fvn-ordinal":["fvn-normal"],"fvn-slashed-zero":["fvn-normal"],"fvn-figure":["fvn-normal"],"fvn-spacing":["fvn-normal"],"fvn-fraction":["fvn-normal"],"line-clamp":["display","overflow"],rounded:["rounded-s","rounded-e","rounded-t","rounded-r","rounded-b","rounded-l","rounded-ss","rounded-se","rounded-ee","rounded-es","rounded-tl","rounded-tr","rounded-br","rounded-bl"],"rounded-s":["rounded-ss","rounded-es"],"rounded-e":["rounded-se","rounded-ee"],"rounded-t":["rounded-tl","rounded-tr"],"rounded-r":["rounded-tr","rounded-br"],"rounded-b":["rounded-br","rounded-bl"],"rounded-l":["rounded-tl","rounded-bl"],"border-spacing":["border-spacing-x","border-spacing-y"],"border-w":["border-w-s","border-w-e","border-w-t","border-w-r","border-w-b","border-w-l"],"border-w-x":["border-w-r","border-w-l"],"border-w-y":["border-w-t","border-w-b"],"border-color":["border-color-s","border-color-e","border-color-t","border-color-r","border-color-b","border-color-l"],"border-color-x":["border-color-r","border-color-l"],"border-color-y":["border-color-t","border-color-b"],"scroll-m":["scroll-mx","scroll-my","scroll-ms","scroll-me","scroll-mt","scroll-mr","scroll-mb","scroll-ml"],"scroll-mx":["scroll-mr","scroll-ml"],"scroll-my":["scroll-mt","scroll-mb"],"scroll-p":["scroll-px","scroll-py","scroll-ps","scroll-pe","scroll-pt","scroll-pr","scroll-pb","scroll-pl"],"scroll-px":["scroll-pr","scroll-pl"],"scroll-py":["scroll-pt","scroll-pb"],touch:["touch-x","touch-y","touch-pz"],"touch-x":["touch"],"touch-y":["touch"],"touch-pz":["touch"]},conflictingClassGroupModifiers:{"font-size":["leading"]}}},Rb=fb(Mb);function ee(...s){return Rb(Xv(s))}function Lo(s){return s?s.replace(/127\.0\.0\.1|localhost/g,"192.168.178.151"):""}function ci({value:s,label:o,detail:i}){const d=2*Math.PI*24,f=d-Math.min(s,100)/100*d,m=s>90?"stroke-red-500":s>75?"stroke-amber-500":"stroke-primary";return n.jsxs("div",{className:"flex flex-col items-center gap-1.5 p-2 bg-background/20 rounded-xl border border-border/40",children:[n.jsxs("div",{className:"relative flex h-16 w-16 items-center justify-center",children:[n.jsxs("svg",{className:"absolute inset-0 h-full w-full -rotate-90",children:[n.jsx("circle",{cx:"32",cy:"32",r:24,className:"stroke-muted fill-none",strokeWidth:"4.5"}),n.jsx("circle",{cx:"32",cy:"32",r:24,className:ee("fill-none transition-all duration-700 ease-out",m),strokeWidth:"4.5",strokeDasharray:d,strokeDashoffset:f,strokeLinecap:"round"})]}),n.jsxs("span",{className:"text-xs font-mono font-bold tracking-tight text-foreground",children:[Math.round(s),"%"]})]}),n.jsx("span",{className:"text-[11px] font-semibold text-muted-foreground uppercase tracking-wider",children:o}),i&&n.jsx("span",{className:"text-[10px] font-mono text-muted-foreground/80",children:i})]})}function Ob(){const{data:s}=mc(3e3);return n.jsxs("div",{className:"md:col-span-2 flex flex-col justify-between rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/15",children:[n.jsxs("div",{children:[n.jsxs("div",{className:"flex items-center gap-2 mb-4",children:[n.jsx(Ot,{className:"h-4.5 w-4.5 text-primary"}),n.jsx("h2",{className:"text-sm font-semibold tracking-wide uppercase text-foreground",children:"System-Status"})]}),s?n.jsxs("div",{className:"grid grid-cols-2 gap-3 sm:grid-cols-4",children:[n.jsx(ci,{value:s.cpu.percent,label:"CPU",detail:s.cpu.cores?`${s.cpu.cores} Cores`:void 0}),n.jsx(ci,{value:s.ram.percent,label:"RAM",detail:`${St(s.ram.used)} / ${St(s.ram.total)} GB`}),s.gpu&&s.gpu.busy_percent!=null&&s.gpu.gtt_used!=null&&s.gpu.gtt_total!=null&&n.jsx(ci,{value:s.gpu.busy_percent,label:"GPU",detail:`${St(s.gpu.gtt_used)} / ${St(s.gpu.gtt_total)} GB`}),s.disk&&n.jsx(ci,{value:s.disk.percent,label:"Disk",detail:`${St(s.disk.used)} / ${St(s.disk.total)} GB`})]}):n.jsx("div",{className:"h-28 flex items-center justify-center text-xs text-muted-foreground",children:"Lade Systemdaten…"})]}),(s==null?void 0:s.temp)&&(s.temp.cpu||s.temp.gpu)&&n.jsxs("div",{className:"mt-4 flex gap-4 text-xs font-mono text-muted-foreground/80 border-t border-border/30 pt-3",children:[s.temp.cpu!=null&&n.jsxs("span",{children:["CPU Temp: ",s.temp.cpu," °C"]}),s.temp.gpu!=null&&n.jsxs("span",{children:["GPU Temp: ",s.temp.gpu," °C"]})]})]})}function bm({type:s,title:o,message:i,defaultValue:u,onConfirm:d,onCancel:f}){const m=g.useRef(null);return n.jsx("div",{className:"fixed inset-0 z-[99] bg-black/60 backdrop-blur-sm flex items-center justify-center p-4",children:n.jsxs("div",{className:"w-full max-w-sm rounded-2xl border border-border/80 bg-card p-6 shadow-2xl space-y-4 animate-in fade-in zoom-in-95 duration-200",children:[n.jsxs("div",{className:"flex items-center justify-between border-b border-border/20 pb-2",children:[n.jsx("h3",{className:"text-xs font-bold uppercase tracking-wider text-primary",children:o}),n.jsx("button",{onClick:f||(()=>d()),className:"p-1 rounded hover:bg-accent text-muted-foreground hover:text-foreground cursor-pointer",children:n.jsx(Rn,{className:"h-4 w-4"})})]}),n.jsx("p",{className:"text-xs text-muted-foreground leading-relaxed",children:i}),s==="prompt"&&n.jsx("input",{ref:m,type:"text",defaultValue:u,className:"w-full h-9 px-3 text-xs bg-background/40 border border-border/60 rounded-lg outline-none focus:border-primary transition-colors text-foreground",autoFocus:!0,onKeyDown:p=>{var b;p.key==="Enter"&&d((b=m.current)==null?void 0:b.value)}}),n.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[(s==="confirm"||s==="prompt")&&n.jsx("button",{onClick:f,className:"h-8 px-4 flex items-center justify-center text-xs font-semibold text-muted-foreground border border-border/60 bg-background/20 hover:bg-accent rounded-lg transition-colors cursor-pointer",children:"Abbrechen"}),n.jsx("button",{onClick:()=>{var b;const p=s==="prompt"?(b=m.current)==null?void 0:b.value:void 0;d(p)},className:"h-8 px-4 flex items-center justify-center text-xs font-semibold text-primary-foreground bg-primary hover:bg-primary/95 rounded-lg transition-colors cursor-pointer",children:s==="confirm"?"Ja, fortfahren":s==="prompt"?"Übernehmen":"OK"})]})]})})}function Tn(){const[s,o]=g.useState(null),i=g.useCallback(()=>o(null),[]),u=g.useCallback((p,b,x)=>{o({type:"alert",title:p,message:b,onConfirm:()=>{o(null),x==null||x()}})},[]),d=g.useCallback((p,b,x,j)=>{o({type:"confirm",title:p,message:b,onConfirm:()=>{o(null),x()},onCancel:()=>{o(null),j==null||j()}})},[]),f=g.useCallback((p,b,x,j,w)=>{o({type:"prompt",title:p,message:b,defaultValue:x,onConfirm:_=>{o(null),j(_)},onCancel:()=>{o(null),w==null||w()}})},[]),m=s?n.jsx(bm,{...s}):null;return{showAlert:u,showConfirm:d,showPrompt:f,close:i,dialogElement:m}}function Db(){const s=tn(),{data:o}=gc(3e3),{data:i=[]}=cm(3e3),{showConfirm:u,dialogElement:d}=Tn(),[f,m]=g.useState(""),[p,b]=g.useState(!1),[x,j]=g.useState(""),[w,_]=g.useState(!1),[M,z]=g.useState({open:!1,actionPath:"",actionLabel:""}),v=()=>{s.invalidateQueries({queryKey:Ye.updates}),s.invalidateQueries({queryKey:Ye.jobs}),s.invalidateQueries({queryKey:Ye.models})};async function S(D,$,H,ae){m(`${$} wird ausgeführt...`),b(!0);try{const te={...H},fe=await we(D,{method:"POST",body:JSON.stringify(te)});if(fe.status==="password_required"||fe.status==="incorrect_password"){z({open:!0,actionPath:D,actionLabel:$,payload:H,error:fe.status==="incorrect_password"?"Falsches Sudo-Passwort. Bitte erneut versuchen.":void 0}),m("");return}fe.job_id?m(`${$} gestartet (Job-ID: ${fe.job_id})`):fe.ok?m(`${$} erfolgreich ausgeführt.`):m(`Fehler: ${fe.err||"Unbekannter Fehler"}`),v()}catch(te){m(`Fehler bei ${$}: ${te.message}`)}finally{b(!1)}}async function O(){_(!0);try{const D={...M.payload,sudo_password:x},$=await we(M.actionPath,{method:"POST",body:JSON.stringify(D)});if($.status==="password_required"||$.status==="incorrect_password"){z(H=>({...H,error:"Falsches Sudo-Passwort. Bitte erneut versuchen."}));return}$.job_id?m(`${M.actionLabel} gestartet (Job-ID: ${$.job_id})`):$.ok?m(`${M.actionLabel} erfolgreich ausgeführt.`):m(`Fehler: ${$.err||"Unbekannter Fehler"}`),z({open:!1,actionPath:"",actionLabel:""}),j(""),v()}catch(D){m(`Fehler: ${D.message}`),z({open:!1,actionPath:"",actionLabel:""}),j("")}finally{_(!1)}}async function F(D,$){m(`Upgrade für ${D} wird gestartet...`);try{await we("/api/models/install",{method:"POST",body:JSON.stringify({repo:D,role:$,quant:"Q4_K_M",jinja:!0})}),m("Upgrade-Download gestartet."),v()}catch(H){m(`Upgrade fehlgeschlagen: ${H.message}`)}}const B=i.find(D=>D.label.includes("OS-Update")&&(D.state==="running"||D.state==="queued")),I=i.find(D=>D.label.includes("Engine-Update")&&(D.state==="running"||D.state==="queued"));return n.jsxs("div",{className:"rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/15 flex flex-col justify-between",children:[M.open&&n.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm p-4",children:n.jsxs("div",{className:"w-full max-w-sm rounded-2xl border border-border/60 bg-card/90 backdrop-blur-xl p-5 shadow-2xl space-y-4",children:[n.jsxs("div",{className:"flex items-center justify-between border-b border-border/20 pb-2",children:[n.jsx("span",{className:"text-xs font-bold uppercase tracking-wider text-primary font-space",children:"Sudo-Passwort erforderlich"}),n.jsx("button",{onClick:()=>{z({open:!1,actionPath:"",actionLabel:""}),j("")},className:"p-1 rounded hover:bg-accent text-muted-foreground hover:text-foreground cursor-pointer",children:n.jsx(Rn,{className:"h-4 w-4"})})]}),n.jsxs("p",{className:"text-[10px] text-muted-foreground leading-normal",children:["Für die Aktion ",n.jsx("strong",{children:M.actionLabel})," wird das Administrator-Passwort (Sudo) auf der Box benötigt."]}),n.jsxs("div",{className:"space-y-2",children:[n.jsx("input",{type:"password",value:x,onChange:D=>j(D.target.value),placeholder:"Sudo-Passwort eingeben...",className:"w-full h-9 rounded-lg border border-border/60 bg-background/40 px-3 text-xs outline-none focus:ring-1 focus:ring-primary/50 text-foreground",onKeyDown:D=>D.key==="Enter"&&O(),autoFocus:!0}),M.error&&n.jsx("div",{className:"text-[10px] font-semibold text-red-400",children:M.error})]}),n.jsxs("div",{className:"flex gap-2 justify-end",children:[n.jsx("button",{onClick:()=>{z({open:!1,actionPath:"",actionLabel:""}),j("")},className:"h-8 px-3 rounded-lg border border-border/60 bg-background/25 text-[10px] font-bold uppercase hover:bg-accent transition-all cursor-pointer",children:"Abbrechen"}),n.jsx("button",{onClick:O,disabled:!x||w,className:"h-8 px-4 rounded-lg bg-primary text-primary-foreground text-[10px] font-bold uppercase hover:opacity-90 transition-all disabled:opacity-50 cursor-pointer flex items-center justify-center gap-1.5",children:w?"Prüfe...":"Ausführen"})]})]})}),n.jsxs("div",{className:"space-y-4",children:[n.jsxs("div",{className:"flex items-center justify-between flex-wrap gap-2 border-b border-border/20 pb-2",children:[n.jsxs("div",{className:"flex items-center gap-2",children:[n.jsx(T0,{className:"h-4.5 w-4.5 text-primary"}),n.jsx("h2",{className:"text-sm font-semibold tracking-wide uppercase text-foreground",children:"Updates & Pflege"})]}),(o==null?void 0:o.last_check)&&n.jsxs("span",{className:"text-[9px] text-muted-foreground/80 font-mono",children:["Zuletzt gesucht: ",new Date(o.last_check*1e3).toLocaleString("de-DE",{day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit"})]})]}),o?n.jsxs("div",{className:"space-y-3",children:[n.jsxs("div",{className:"space-y-1.5",children:[n.jsxs("div",{className:ee("flex items-center justify-between px-3 py-1.5 rounded-lg border text-xs",o.os>0?"border-amber-500/30 bg-amber-500/5 text-amber-400 font-semibold":"border-border/30 bg-background/25 text-muted-foreground"),children:[n.jsx("span",{children:"OS-Pakete"}),n.jsx("span",{className:"font-mono",children:o.os>0?`${o.os} verfügbar`:"aktuell"})]}),n.jsxs("div",{className:ee("flex items-center justify-between px-3 py-1.5 rounded-lg border text-xs",o.engine>0?"border-amber-500/30 bg-amber-500/5 text-amber-400 font-semibold":"border-border/30 bg-background/25 text-muted-foreground"),children:[n.jsx("span",{children:"Engine (llama.cpp)"}),n.jsx("span",{className:"font-mono",children:o.engine>0?"Update verfügbar":"aktuell"})]}),n.jsxs("div",{className:ee("flex items-center justify-between px-3 py-1.5 rounded-lg border text-xs",o.models>0?"border-primary/30 bg-primary/5 text-primary font-semibold animate-pulse":"border-border/30 bg-background/25 text-muted-foreground"),children:[n.jsx("span",{children:"Modell-Upgrades"}),n.jsx("span",{className:"font-mono",children:o.models>0?`${o.models} verfügbar`:"aktuell"})]})]}),n.jsxs("div",{className:"grid grid-cols-2 gap-2 border-t border-border/20 pt-3",children:[n.jsx("button",{onClick:()=>S("/api/maintenance/os-update","OS-Update"),disabled:p||!!B,className:"h-8 px-2 rounded-lg border border-border/60 bg-background/20 text-[10px] font-bold uppercase hover:border-primary/50 hover:bg-background/40 transition-all cursor-pointer disabled:opacity-50 flex items-center justify-center gap-1",children:B?n.jsxs(n.Fragment,{children:[n.jsx(Pn,{className:"h-3 w-3 animate-spin text-primary"}),n.jsxs("span",{children:["Aktiv (",B.progress??0,"%)"]})]}):n.jsx("span",{children:"OS Update"})}),n.jsx("button",{onClick:()=>S("/api/maintenance/engine-update","Engine-Update"),disabled:p||!!I,className:"h-8 px-2 rounded-lg border border-border/60 bg-background/20 text-[10px] font-bold uppercase hover:border-primary/50 hover:bg-background/40 transition-all cursor-pointer disabled:opacity-50 flex items-center justify-center gap-1",children:I?n.jsxs(n.Fragment,{children:[n.jsx(Pn,{className:"h-3 w-3 animate-spin text-primary"}),n.jsxs("span",{children:["Aktiv (",I.progress??0,"%)"]})]}):n.jsx("span",{children:"Engine Update"})})]}),n.jsxs("button",{onClick:()=>{u("Host-System neu starten?","Bist du sicher, dass du das Host-System neu starten willst?",()=>S("/api/maintenance/reboot","Reboot"))},disabled:p,className:"w-full h-8 flex items-center justify-center gap-1.5 rounded-lg border border-red-500/30 bg-red-500/5 text-red-400 text-[10px] font-bold uppercase hover:bg-red-500/10 transition-all cursor-pointer disabled:opacity-50",children:[n.jsx(Eh,{className:"h-3.5 w-3.5"}),n.jsx("span",{children:"Host Reboot"})]}),o.model_list.length>0&&n.jsxs("div",{className:"space-y-1.5 border-t border-border/20 pt-3",children:[n.jsx("div",{className:"text-[9px] uppercase font-bold text-muted-foreground/60 tracking-wider",children:"Verfügbare Modell-Upgrades:"}),n.jsx("div",{className:"max-h-24 overflow-y-auto space-y-1.5 pr-1 scrollbar-thin",children:o.model_list.map(D=>n.jsxs("div",{className:"flex items-center justify-between p-2 rounded bg-background/25 border border-border/30 text-[10px] font-mono text-muted-foreground",children:[n.jsxs("span",{className:"truncate flex-1 mr-1.5",title:`${D.role}: ${D.repo}`,children:[n.jsx("span",{className:"text-primary font-bold uppercase",children:D.role}),": ",D.repo.split("/").pop()]}),n.jsxs("button",{onClick:()=>F(D.repo,D.role),className:"px-2 py-0.5 text-[8px] font-bold uppercase rounded bg-primary text-primary-foreground hover:opacity-90 transition-all cursor-pointer flex items-center gap-0.5",children:[n.jsx(_n,{className:"h-2.5 w-2.5"})," Laden"]})]},D.repo))})]})]}):n.jsx("div",{className:"h-24 flex items-center justify-center text-xs text-muted-foreground",children:"Lade Updates..."}),f&&n.jsx("div",{className:"text-[10px] font-mono text-primary font-medium bg-primary/5 p-2 rounded-lg border border-primary/20 break-all leading-normal",children:f}),n.jsxs("div",{className:"text-[9px] text-muted-foreground/60 leading-normal border-t border-border/10 pt-2.5 flex items-start gap-1",children:[n.jsx(Mn,{className:"h-3 w-3 shrink-0 text-muted-foreground/50 mt-0.5"}),n.jsxs("span",{children:["OS-Update & Reboot benötigen NOPASSWD in ",n.jsx("code",{children:"/etc/sudoers"})," (z.B. ",n.jsx("code",{children:"hitonabi ALL=(root) NOPASSWD:..."}),") oder ein gültiges Sudo-Passwort per Pop-up."]})]})]}),n.jsx("div",{className:"mt-4 border-t border-border/30 pt-3 shrink-0",children:n.jsx("button",{onClick:()=>window.dispatchEvent(new CustomEvent("open-system-drawer")),className:"w-full h-8 flex items-center justify-center gap-1.5 rounded-lg bg-primary text-primary-foreground text-xs font-semibold hover:opacity-90 transition-all cursor-pointer shadow-md shadow-primary/10",children:"System-Zentrale öffnen"})}),d]})}function Tb(){const s=tn(),{data:o}=dm(3e3),{data:i}=Vo(),{showAlert:u,dialogElement:d}=Tn(),[f,m]=g.useState(!1),p=(i==null?void 0:i.models)??[];async function b(x){try{await we("/api/agent/brain",{method:"POST",body:JSON.stringify({model:x})}),u("Erfolgreich",`Hermes-Gehirn wurde auf '${x}' geändert. Der Gateway-Dienst wurde neu gestartet.`),s.invalidateQueries({queryKey:Ye.agentStatus}),m(!1)}catch(j){u("Fehler",`Fehler beim Wechseln des Gehirns: ${j.message}`)}}return n.jsxs("div",{className:"rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/15 flex flex-col justify-between",children:[n.jsxs("div",{children:[n.jsxs("div",{className:"flex items-center justify-between mb-4",children:[n.jsxs("div",{className:"flex items-center gap-2",children:[n.jsx(Oo,{className:"h-4.5 w-4.5 text-primary"}),n.jsx("h2",{className:"text-sm font-semibold tracking-wide uppercase text-foreground",children:"Hermes Agent"})]}),(o==null?void 0:o.webui_url)&&n.jsxs("a",{href:Lo(o.webui_url),target:"_blank",rel:"noopener",className:ee("flex items-center gap-1 px-3 py-1 rounded-lg text-xs font-medium transition-all",o.webui_reachable?"bg-primary text-primary-foreground hover:opacity-90 shadow-md shadow-primary/20":"border border-border text-muted-foreground"),children:[n.jsx(xi,{className:"h-3 w-3"})," Hermes öffnen"]})]}),o?n.jsxs("div",{className:"space-y-3",children:[n.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[n.jsxs("div",{className:"p-3 bg-background/20 rounded-xl border border-border/40",children:[n.jsx("div",{className:"text-[10px] text-muted-foreground uppercase font-semibold",children:"Gateway"}),n.jsxs("div",{className:"flex items-center gap-2 mt-1",children:[n.jsx("span",{className:ee("h-2 w-2 rounded-full",o.gateway_reachable?"bg-emerald-500 animate-pulse":"bg-amber-500")}),n.jsx("span",{className:"text-xs font-medium",children:o.gateway_reachable?"Online":"Offline"})]})]}),n.jsxs("div",{className:"p-3 bg-background/20 rounded-xl border border-border/40",children:[n.jsx("div",{className:"text-[10px] text-muted-foreground uppercase font-semibold",children:"WebUI"}),n.jsxs("div",{className:"flex items-center gap-2 mt-1",children:[n.jsx("span",{className:ee("h-2 w-2 rounded-full",o.webui_reachable?"bg-emerald-500 animate-pulse":"bg-amber-500")}),n.jsx("span",{className:"text-xs font-medium",children:o.webui_reachable?"Online":"Offline"})]})]})]}),n.jsxs("div",{onClick:()=>m(!0),className:"p-3 bg-background/20 rounded-xl border border-border/40 hover:border-primary/45 hover:bg-background/30 transition-all duration-300 cursor-pointer group",children:[n.jsxs("div",{className:"flex justify-between items-center",children:[n.jsx("span",{className:"text-[10px] text-muted-foreground uppercase font-semibold",children:"Aktives Gehirn"}),n.jsxs("button",{className:"flex items-center gap-1 text-[9px] font-bold uppercase tracking-wider text-primary border border-primary/20 bg-primary/10 hover:bg-primary/20 px-1.5 py-0.5 rounded transition-all cursor-pointer font-space",children:[n.jsx(Ot,{className:"h-3 w-3"})," Ändern"]})]}),n.jsxs("div",{className:"text-xs font-medium mt-1 font-mono text-primary flex items-center gap-1.5",children:[n.jsx(To,{className:"h-3.5 w-3.5"}),o.brain_model?`model: ${o.brain_model}`:"model: auto"]})]})]}):n.jsx("div",{className:"h-28 flex items-center justify-center text-xs text-muted-foreground",children:"Lade Agenten-Status…"})]}),n.jsx("div",{className:"mt-3 text-[10px] text-muted-foreground/80 border-t border-border/30 pt-3",children:"Gedächtnis & Stack-Tools via MCP gekoppelt."}),o&&f&&n.jsx("div",{className:"fixed inset-0 z-50 bg-black/60 backdrop-blur-sm flex items-center justify-center p-4",children:n.jsxs("div",{className:"w-full max-w-md rounded-2xl border border-border/80 bg-card p-6 shadow-2xl space-y-4 animate-in fade-in zoom-in-95 duration-200",children:[n.jsxs("div",{className:"flex items-center justify-between border-b border-border/20 pb-2",children:[n.jsxs("h3",{className:"text-xs font-bold uppercase tracking-wider text-primary flex items-center gap-1.5",children:[n.jsx(Ot,{className:"h-4 w-4"}),n.jsx("span",{children:"Hermes-Gehirn konfigurieren"})]}),n.jsx("button",{onClick:()=>m(!1),className:"p-1 rounded hover:bg-accent text-muted-foreground hover:text-foreground cursor-pointer",children:n.jsx(Rn,{className:"h-4 w-4"})})]}),n.jsxs("p",{className:"text-xs text-muted-foreground leading-relaxed",children:['Das „Gehirn" ist das primäre LLM für Hermes. Wähle ein Modell aus deiner Bibliothek oder nutze ein Gateway-Alias (',n.jsx("code",{className:"text-primary font-semibold",children:"auto"})," / ",n.jsx("code",{className:"text-primary font-semibold",children:"fast"})," / ",n.jsx("code",{className:"text-primary font-semibold",children:"heavy"}),"):"]}),n.jsx("div",{className:"space-y-1.5 max-h-60 overflow-y-auto pr-1",children:["auto","fast","heavy",...p.map(x=>{var j;return((j=x.name.split("/").pop())==null?void 0:j.replace(".gguf",""))||x.name})].map(x=>{const j=["auto","fast","heavy"].includes(x);return n.jsxs("button",{onClick:()=>b(x),className:ee("w-full text-left px-3 py-2.5 rounded-lg text-xs hover:bg-accent flex items-center justify-between font-mono cursor-pointer border border-border/30",o.brain_model===x||!o.brain_model&&x==="auto"?"text-primary font-bold bg-primary/10 border-primary/30":"text-foreground bg-background/20"),children:[n.jsxs("div",{className:"flex flex-col text-left",children:[n.jsx("span",{className:"font-semibold truncate max-w-[280px]",children:x}),n.jsx("span",{className:"text-[9px] text-muted-foreground mt-0.5",children:j?"Gateway Routing Alias":"Installiertes GGUF Modell"})]}),(o.brain_model===x||!o.brain_model&&x==="auto")&&n.jsx(Ms,{className:"h-4 w-4 shrink-0 text-primary"})]},x)})})]})}),d]})}const Ab=["fast","heavy","coder","reasoning","vision","scout"];function zb(){const{data:s}=Vo(3e3),o=(s==null?void 0:s.models)??[],i=(s==null?void 0:s.running)??[];return n.jsxs("div",{className:"rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/15 flex flex-col justify-between",children:[n.jsxs("div",{children:[n.jsxs("div",{className:"flex items-center gap-2 mb-4",children:[n.jsx(To,{className:"h-4.5 w-4.5 text-primary"}),n.jsx("h2",{className:"text-sm font-semibold tracking-wide uppercase text-foreground",children:"Rollen-Belegung"})]}),n.jsx("div",{className:"space-y-2 max-h-48 overflow-y-auto pr-1 scrollbar-thin",children:Ab.map(u=>{var m;const d=o.find(p=>p.role===u),f=d?i.includes(d.name):!1;return n.jsxs("div",{className:ee("flex items-center justify-between p-2 rounded-xl border transition-all duration-300",f?"border-emerald-500/30 bg-emerald-500/5 shadow-sm shadow-emerald-500/5":d?"border-primary/20 bg-primary/5":"border-border/30 bg-background/10 opacity-60"),children:[n.jsx("div",{className:"min-w-0 flex-1 mr-2",children:n.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[n.jsx("span",{className:ee("text-[9px] font-semibold uppercase px-1.5 py-0.5 rounded font-mono border tracking-wider shrink-0",u==="fast"?"bg-cyan-500/15 text-cyan-400 border-cyan-500/25":u==="heavy"?"bg-amber-500/15 text-amber-400 border-amber-500/25":u==="coder"?"bg-violet-500/15 text-violet-400 border-violet-500/25":u==="reasoning"?"bg-emerald-500/15 text-emerald-400 border-emerald-500/25":u==="vision"?"bg-pink-500/15 text-pink-400 border-pink-500/25":"bg-teal-500/15 text-teal-400 border-teal-500/25"),children:u}),n.jsxs("div",{className:"flex flex-col min-w-0",children:[n.jsx("span",{className:"text-xs font-semibold truncate font-mono text-foreground",children:d?(m=d.name.split("/").pop())==null?void 0:m.replace(/\.gguf$/i,""):"nicht zugewiesen"}),d&&n.jsxs("div",{className:"flex gap-1 items-center mt-0.5 flex-wrap",children:[d.prompt_cache&&n.jsx("span",{className:"text-[7px] leading-none font-mono font-bold bg-cyan-500/10 text-cyan-400 border border-cyan-500/20 px-1 py-0.5 rounded",title:"Prompt Caching aktiv",children:"PC"}),d.spec_draft_model&&n.jsx("span",{className:"text-[7px] leading-none font-mono font-bold bg-emerald-500/10 text-emerald-400 border border-emerald-500/20 px-1 py-0.5 rounded",title:`Speculative Decoding aktiv (Draft: ${d.spec_draft_model})`,children:"SPEC"}),d.parallel_slots>1&&n.jsxs("span",{className:"text-[7px] leading-none font-mono font-bold bg-violet-500/10 text-violet-400 border border-violet-500/20 px-1 py-0.5 rounded",title:`${d.parallel_slots} parallele Slots aktiv`,children:["SLOTS: ",d.parallel_slots]})]})]})]})}),n.jsx("div",{className:"flex items-center gap-1.5 shrink-0",children:d?f?n.jsxs("span",{className:"flex items-center gap-1 text-[8px] font-semibold text-emerald-400 uppercase tracking-wider font-mono",children:[n.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-emerald-500 animate-pulse"})," warm"]}):n.jsx("span",{className:"text-[8px] font-semibold text-muted-foreground uppercase tracking-wider font-mono",children:"bereit"}):n.jsx("span",{className:"text-[8px] font-semibold text-muted-foreground/60 uppercase tracking-wider font-mono",children:"—"})})]},u)})})]}),n.jsx("div",{className:"mt-4 text-[10px] text-muted-foreground/80 border-t border-border/30 pt-3",children:"Laden erfolgt automatisch per Auto-Swap."})]})}function Lb(){const s=tn(),{data:o=[]}=pm({limit:3}),[i,u]=g.useState(""),[d,f]=g.useState("stable"),[m,p]=g.useState(!1);async function b(){if(!(!i.trim()||m)){p(!0);try{await we("/api/memory",{method:"POST",body:JSON.stringify({content:i,category:d,source:"dashboard"})}),u(""),s.invalidateQueries({queryKey:["memory"]})}catch(x){console.error(x)}finally{p(!1)}}}return n.jsxs("div",{className:"rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/15 flex flex-col justify-between",children:[n.jsxs("div",{children:[n.jsxs("div",{className:"flex items-center gap-2 mb-4",children:[n.jsx(Do,{className:"h-4.5 w-4.5 text-primary"}),n.jsx("h2",{className:"text-sm font-semibold tracking-wide uppercase text-foreground",children:"Gedächtnis"})]}),n.jsxs("div",{className:"space-y-3",children:[n.jsx("textarea",{value:i,onChange:x=>u(x.target.value),placeholder:"Fakt / Regel im Pool speichern...",rows:2,className:"w-full resize-none rounded-xl border border-border/50 bg-background/30 p-2 text-[10px] outline-none focus:ring-1 focus:ring-primary transition-all leading-normal"}),n.jsxs("div",{className:"flex items-center gap-2 justify-between",children:[n.jsxs("select",{value:d,onChange:x=>f(x.target.value),className:"h-7 rounded-lg border border-border/50 bg-background/50 px-2 text-[10px] outline-none cursor-pointer",children:[n.jsx("option",{value:"stable",children:"🔵 Fakt"}),n.jsx("option",{value:"instruction",children:"📋 Regel"}),n.jsx("option",{value:"user",children:"👤 User"}),n.jsx("option",{value:"versioned",children:"🟡 Version"})]}),n.jsxs("button",{onClick:b,disabled:!i.trim()||m,className:"flex h-7 items-center gap-1 rounded-lg bg-primary px-3 text-[10px] font-semibold text-primary-foreground hover:opacity-90 disabled:opacity-50 transition-all cursor-pointer",children:[n.jsx(Ch,{className:"h-3.5 w-3.5"})," Speichern"]})]})]}),n.jsxs("div",{className:"mt-3.5 space-y-1.5",children:[n.jsx("div",{className:"text-[9px] text-muted-foreground uppercase font-bold tracking-wider",children:"Zuletzt gespeichert:"}),n.jsx("div",{className:"max-h-20 overflow-y-auto space-y-1 pr-1 scrollbar-thin",children:o.length===0?n.jsx("div",{className:"text-[10px] text-muted-foreground/75 py-1",children:"Keine Einträge vorhanden."}):o.map(x=>n.jsxs("div",{className:"text-[10px] bg-background/10 border border-border/30 rounded p-1.5 flex items-start gap-1.5",children:[n.jsx("span",{className:"shrink-0 text-[8px] font-mono text-muted-foreground/80 px-1 py-0.5 rounded bg-muted/20",children:x.category}),n.jsx("span",{className:"truncate flex-1 text-muted-foreground hover:text-foreground transition-colors",title:x.content,children:x.content})]},x.id))})]})]}),n.jsx("div",{className:"mt-4 text-[10px] text-muted-foreground/80 border-t border-border/30 pt-3",children:"Steht allen Clients per MCP zur Verfügung."})]})}function Ib(){var o;const{data:s}=Zv(3e3);return n.jsxs("div",{className:"rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/15 flex flex-col justify-between",children:[n.jsxs("div",{children:[n.jsxs("div",{className:"flex items-center gap-2 mb-4",children:[n.jsx(w0,{className:"h-4.5 w-4.5 text-primary animate-pulse"}),n.jsx("h2",{className:"text-sm font-semibold tracking-wide uppercase text-foreground",children:"Effizienz & Ersparnis"})]}),s?n.jsxs("div",{className:"space-y-4",children:[n.jsxs("div",{className:"grid grid-cols-2 gap-2.5",children:[n.jsxs("div",{className:"p-3 bg-background/20 rounded-xl border border-border/40 text-left",children:[n.jsx("div",{className:"text-[8px] uppercase tracking-wider font-semibold text-muted-foreground/60",children:"Geld gespart"}),n.jsxs("div",{className:"text-base font-bold text-emerald-400 mt-0.5 tracking-tight font-space",children:[s.saved_eur.toLocaleString("de-DE",{minimumFractionDigits:2})," €"]}),n.jsxs("div",{className:"text-[8px] text-muted-foreground/80 mt-0.5 font-mono",children:["(",s.saved_usd.toLocaleString("en-US",{minimumFractionDigits:2})," $)"]})]}),n.jsxs("div",{className:"p-3 bg-background/20 rounded-xl border border-border/40 text-left",children:[n.jsx("div",{className:"text-[8px] uppercase tracking-wider font-semibold text-muted-foreground/60",children:"Gesamt-Tokens"}),n.jsx("div",{className:"text-base font-bold text-primary mt-0.5 tracking-tight font-space",children:s.total_tokens.toLocaleString("de-DE")}),n.jsx("div",{className:"text-[8px] text-muted-foreground/80 mt-0.5 font-mono",children:"(Lokale Inferenz)"})]})]}),n.jsxs("div",{className:"space-y-2 border-t border-border/20 pt-3 text-[10px] text-muted-foreground",children:[n.jsxs("div",{className:"flex justify-between items-center font-mono",children:[n.jsx("span",{children:"Input (Prompts):"}),n.jsxs("span",{className:"font-semibold text-foreground",children:[s.prompt_tokens.toLocaleString("de-DE")," tkn"]})]}),n.jsxs("div",{className:"flex justify-between items-center font-mono",children:[n.jsx("span",{children:"Output (Antworten):"}),n.jsxs("span",{className:"font-semibold text-foreground",children:[s.completion_tokens.toLocaleString("de-DE")," tkn"]})]})]})]}):n.jsx("div",{className:"h-28 flex items-center justify-center text-xs text-muted-foreground",children:"Lade Statistiken…"})]}),n.jsxs("div",{className:"mt-4 text-[9px] text-muted-foreground/70 border-t border-border/30 pt-2.5 leading-normal",children:["Berechnet im Vergleich zu Cloud-APIs von Juni 2026",(o=s==null?void 0:s.pricing)!=null&&o.heavy?` (Ø ${s.pricing.heavy.in.toFixed(2).replace(".",",")} $ / ${s.pricing.heavy.out.toFixed(2).replace(".",",")} $ pro 1M tkn).`:"."]})]})}function Fb(){return n.jsxs("div",{className:"space-y-6",children:[n.jsxs("div",{children:[n.jsx("h1",{className:"text-2xl font-space font-bold tracking-tight bg-gradient-to-r from-foreground via-foreground to-primary bg-clip-text text-transparent",children:"Zentrale"}),n.jsx("p",{className:"text-sm text-muted-foreground",children:"Aktueller Status von System, Modellen und Agent."})]}),n.jsxs("div",{className:"grid gap-6 md:grid-cols-3",children:[n.jsx(Ob,{}),n.jsx(Db,{})]}),n.jsxs("div",{className:"grid gap-6 md:grid-cols-2 xl:grid-cols-4",children:[n.jsx(Tb,{}),n.jsx(zb,{}),n.jsx(Lb,{}),n.jsx(Ib,{})]})]})}function xn({children:s,tone:o="muted"}){const i={muted:"bg-muted text-muted-foreground",primary:"bg-primary/15 text-primary",warn:"bg-amber-500/15 text-amber-500"};return n.jsx("span",{className:`rounded px-1.5 py-0.5 text-[11px] font-medium ${i[o]}`,children:s})}function Qp({caps:s}){return s?n.jsxs("span",{className:"inline-flex flex-wrap gap-1",children:[s.coder&&n.jsx(xn,{children:"💻 Code"}),s.vision&&n.jsx(xn,{children:"👁 Bild"}),s.reasoning&&n.jsx(xn,{children:"🧠 Reason"}),s.moe&&n.jsxs(xn,{tone:"primary",children:["🧩 MoE",s.active_b?`·${s.active_b}b`:""]}),s.tools==="yes"&&n.jsx(xn,{tone:"primary",children:"🛠 Tools"}),s.tools==="likely"&&n.jsx(xn,{tone:"warn",children:"🛠 Tools?"}),s.embedding&&n.jsx(xn,{children:"🔢 Embed"})]}):null}function Ub(){const s=tn(),{data:o=[]}=cm(2e3),{showAlert:i,dialogElement:u}=Tn();async function d(p){try{await we(`/api/jobs/${p}/cancel`,{method:"POST"}),s.invalidateQueries({queryKey:Ye.jobs})}catch(b){i("Fehler",b.message)}}const f=o.filter(p=>p.state==="running"||p.state==="queued"),m=o.filter(p=>p.state!=="running"&&p.state!=="queued").slice(-3);return f.length===0&&m.length===0?null:n.jsxs("div",{className:"space-y-3 rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-4 shadow-lg shadow-black/10",children:[n.jsx("div",{className:"text-[11px] font-semibold text-muted-foreground uppercase tracking-wider",children:"Aktive Downloads"}),f.map(p=>n.jsxs("div",{className:"space-y-1.5 p-3 rounded-xl bg-background/20 border border-border/40",children:[n.jsxs("div",{className:"flex justify-between items-center text-xs",children:[n.jsx("span",{className:"font-semibold truncate max-w-[250px]",children:p.label}),n.jsxs("div",{className:"flex items-center gap-3",children:[n.jsxs("span",{className:"text-muted-foreground font-mono",children:[p.progress??0,"% • ",tc(p.done_bytes),"/",tc(p.total_bytes),p.eta_s?` • ETA ${Jv(p.eta_s)}`:""]}),n.jsx("button",{onClick:()=>d(p.id),className:"text-[10px] text-red-400 hover:text-red-300 font-semibold border border-red-500/25 bg-red-500/5 px-2 py-0.5 rounded transition-all cursor-pointer",children:"Abbrechen"})]})]}),n.jsx("div",{className:"h-1.5 overflow-hidden rounded-full bg-muted",children:n.jsx("div",{className:"h-full rounded-full bg-primary transition-all duration-500",style:{width:`${p.progress??0}%`}})})]},p.id)),m.map(p=>n.jsxs("div",{className:"flex justify-between items-center text-xs text-muted-foreground px-1",children:[n.jsx("span",{className:"truncate",children:p.label}),n.jsx("span",{className:ee("font-semibold text-[10px] px-1.5 py-0.5 rounded uppercase font-mono",p.state==="done"?"bg-emerald-500/10 text-emerald-400":"bg-amber-500/10 text-amber-400"),children:p.state})]},p.id)),u]})}const $b=["fast","heavy","coder","reasoning","agent","vision","scout"];function Bb({fit:s}){const o={perfect:"bg-emerald-500/15 text-emerald-400 border border-emerald-500/20",marginal:"bg-amber-500/15 text-amber-400 border border-amber-500/20",too_tight:"bg-red-500/15 text-red-400 border border-red-500/20"}[s.level];return n.jsxs("span",{className:ee("rounded px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wider font-mono",o),children:[s.text," • ",s.req_gb," GB RAM"]})}function qp(s){const o=s.toLowerCase();return o.includes("qwen")?{name:"Qwen",color:"bg-purple-500/20 text-purple-300 border-purple-500/30",initial:"Q"}:o.includes("gemma")?{name:"Gemma",color:"bg-blue-500/20 text-blue-300 border-blue-500/30",initial:"G"}:o.includes("llama")?{name:"Llama",color:"bg-red-500/20 text-red-300 border-red-500/30",initial:"🦙"}:o.includes("mistral")||o.includes("mixtral")?{name:"Mistral",color:"bg-orange-500/20 text-orange-300 border-orange-500/30",initial:"M"}:o.includes("deepseek")?{name:"DeepSeek",color:"bg-cyan-500/20 text-cyan-300 border-cyan-500/30",initial:"D"}:o.includes("hermes")||o.includes("nous")?{name:"Hermes",color:"bg-amber-500/20 text-amber-300 border-amber-500/30",initial:"H"}:o.includes("phi")?{name:"Phi",color:"bg-emerald-500/20 text-emerald-300 border-emerald-500/30",initial:"Φ"}:{name:"Other",color:"bg-slate-500/20 text-slate-300 border-slate-500/30",initial:"AI"}}function Hb(){var An,As,zs,zn,Ls;const s=tn(),{data:o,isLoading:i,error:u}=Vo(4e3),{data:d}=qv(4e3),{data:f}=fm(),{data:m}=gc(4e3),{showAlert:p,showConfirm:b,showPrompt:x,dialogElement:j}=Tn(),w=(o==null?void 0:o.models)??[],_=(o==null?void 0:o.running)??[],M=u?String(u):"",z=()=>{s.invalidateQueries({queryKey:Ye.models}),s.invalidateQueries({queryKey:Ye.routing})},[v,S]=g.useState(null),[O,F]=g.useState(null),[B,I]=g.useState(!1),[D,$]=g.useState(null),[H,ae]=g.useState("grid"),[te,fe]=g.useState("all"),ke=w.filter(L=>te==="in_use"?!!L.role||_.includes(L.name):!0),[de,ze]=g.useState({width:800,height:360}),Ce=g.useRef(null),Le=g.useCallback(L=>{if(Ce.current&&(Ce.current.disconnect(),Ce.current=null),L){const ie=new ResizeObserver(je=>{if(!je||je.length===0)return;const De=je[0].contentRect;ze({width:De.width,height:De.height})});ie.observe(L),Ce.current=ie}},[]),Ee=de.width,Pe=de.height,K=L=>{const ie=Ee*.1,je=Pe*L,De=Ee*.5,He=Pe*.5,ir=Ee*.3,Ln=je,In=Ee*.3;return`M ${ie} ${je} C ${ir} ${Ln}, ${In} ${He}, ${De} ${He}`},X=L=>{const ie=Ee*.5,je=Pe*.5,De=Ee*.9,He=Pe*L,ir=Ee*.7,Ln=je,In=Ee*.7;return`M ${ie} ${je} C ${ir} ${Ln}, ${In} ${He}, ${De} ${He}`};async function Y(L){try{await we(`/api/models/${encodeURIComponent(L)}/load`,{method:"POST"}),z()}catch(ie){p("Fehler",`Fehler beim Laden des Modells: ${ie.message}`)}}async function P(L){try{await we(`/api/models/${encodeURIComponent(L)}/unload`,{method:"POST"}),z()}catch(ie){p("Fehler",`Fehler beim Entladen des Modells: ${ie.message}`)}}async function C(){try{await we("/api/models/unload",{method:"POST"}),z()}catch(L){p("Fehler",`Fehler beim Entladen aller Modelle: ${L.message}`)}}async function Z(L,ie){try{await we(`/api/models/${encodeURIComponent(ie)}/role`,{method:"POST",body:JSON.stringify({role:L||null})}),z()}catch(je){p("Fehler",`Fehler beim Zuweisen der Rolle: ${je.message||je}`)}}async function J(L,ie){x("Kontextlänge anpassen","Gib die gewünschte Kontextlänge in Tokens an:",String(ie||32768),async je=>{if(je)try{await we(`/api/models/${encodeURIComponent(L)}/ctx`,{method:"POST",body:JSON.stringify({ctx:parseInt(je,10)})}),z()}catch(De){p("Fehler",`Fehler beim Setzen des Kontexts: ${De.message||De}`)}})}async function q(L){b("Modell löschen?",`Modell '${L}' und alle zugehörigen GGUF-Dateien unwiderruflich von der Box löschen?`,async()=>{try{await we(`/api/models/${encodeURIComponent(L)}`,{method:"DELETE"}),z()}catch(ie){p("Fehler",`Fehler beim Löschen: ${ie.message||ie}`)}})}async function oe(L,ie,je,De){try{await we("/api/models/install",{method:"POST",body:JSON.stringify({repo:L,role:ie,quant:je,jinja:De})}),p("Herunterladen gestartet",`Download für '${L}' gestartet! Der Fortschritt wird oben angezeigt.`)}catch(He){p("Fehler",`Fehler beim Starten des Upgrades: ${He.message||He}`)}}async function pe(L){L&&(await navigator.clipboard.writeText(L),I(!0),setTimeout(()=>I(!1),1500))}if(i)return n.jsx("div",{className:"text-xs text-muted-foreground py-12 text-center",children:"Initialisiere HUD Cockpit…"});if(M)return n.jsxs("div",{className:"rounded-xl border border-red-500/20 bg-red-500/5 p-4 text-xs text-red-400",children:["Gateway oder Engine nicht erreichbar (",M,")."]});const ve=w.filter(L=>_.includes(L.name)),U=ve.reduce((L,ie)=>L+(ie.size_bytes||0),0),he=16*1024**3,gt=U>he?U*1.2:he,Ts=L=>w.find(ie=>ie.role===L),Zt=L=>{const ie=Ts(L);return ie?_.includes(ie.name):!1};return n.jsxs("div",{className:"space-y-8",children:[n.jsx("style",{children:` +`)},pv=0,cs=[];function hv(s){var o=g.useRef([]),i=g.useRef([0,0]),u=g.useRef(),d=g.useState(pv++)[0],f=g.useState(Uh)[0],m=g.useRef(s);g.useEffect(function(){m.current=s},[s]),g.useEffect(function(){if(s.inert){document.body.classList.add("block-interactivity-".concat(d));var v=Ay([s.lockRef.current],(s.shards||[]).map(Hp),!0).filter(Boolean);return v.forEach(function(S){return S.classList.add("allow-interactivity-".concat(d))}),function(){document.body.classList.remove("block-interactivity-".concat(d)),v.forEach(function(S){return S.classList.remove("allow-interactivity-".concat(d))})}}},[s.inert,s.lockRef.current,s.shards]);var p=g.useCallback(function(v,S){if("touches"in v&&v.touches.length===2||v.type==="wheel"&&v.ctrlKey)return!m.current.allowPinchZoom;var O=ii(v),F=i.current,B="deltaX"in v?v.deltaX:F[0]-O[0],I="deltaY"in v?v.deltaY:F[1]-O[1],D,$=v.target,H=Math.abs(B)>Math.abs(I)?"h":"v";if("touches"in v&&H==="h"&&$.type==="range")return!1;var ae=window.getSelection(),te=ae&&ae.anchorNode,fe=te?te===$||te.contains($):!1;if(fe)return!1;var ke=$p(H,$);if(!ke)return!0;if(ke?D=H:(D=H==="v"?"h":"v",ke=$p(H,$)),!ke)return!1;if(!u.current&&"changedTouches"in v&&(B||I)&&(u.current=D),!D)return!0;var de=u.current||D;return cv(de,S,v,de==="h"?B:I)},[]),b=g.useCallback(function(v){var S=v;if(!(!cs.length||cs[cs.length-1]!==f)){var O="deltaY"in S?Bp(S):ii(S),F=o.current.filter(function(D){return D.name===S.type&&(D.target===S.target||S.target===D.shadowParent)&&dv(D.delta,O)})[0];if(F&&F.should){S.cancelable&&S.preventDefault();return}if(!F){var B=(m.current.shards||[]).map(Hp).filter(Boolean).filter(function(D){return D.contains(S.target)}),I=B.length>0?p(S,B[0]):!m.current.noIsolation;I&&S.cancelable&&S.preventDefault()}}},[]),x=g.useCallback(function(v,S,O,F){var B={name:v,delta:S,target:O,should:F,shadowParent:mv(O)};o.current.push(B),setTimeout(function(){o.current=o.current.filter(function(I){return I!==B})},1)},[]),j=g.useCallback(function(v){i.current=ii(v),u.current=void 0},[]),w=g.useCallback(function(v){x(v.type,Bp(v),v.target,p(v,s.lockRef.current))},[]),_=g.useCallback(function(v){x(v.type,ii(v),v.target,p(v,s.lockRef.current))},[]);g.useEffect(function(){return cs.push(f),s.setCallbacks({onScrollCapture:w,onWheelCapture:w,onTouchMoveCapture:_}),document.addEventListener("wheel",b,us),document.addEventListener("touchmove",b,us),document.addEventListener("touchstart",j,us),function(){cs=cs.filter(function(v){return v!==f}),document.removeEventListener("wheel",b,us),document.removeEventListener("touchmove",b,us),document.removeEventListener("touchstart",j,us)}},[]);var M=s.removeScrollBar,z=s.inert;return g.createElement(g.Fragment,null,z?g.createElement(f,{styles:fv(d)}):null,M?g.createElement(nv,{noRelative:s.noRelative,gapMode:s.gapMode}):null)}function mv(s){for(var o=null;s!==null;)s instanceof ShadowRoot&&(o=s.host,s=s.host),s=s.parentNode;return o}const gv=Wy(Fh,hv);var Wh=g.forwardRef(function(s,o){return g.createElement(ji,lr({},s,{ref:o,sideCar:gv}))});Wh.classNames=ji.classNames;var xv=function(s){if(typeof document>"u")return null;var o=Array.isArray(s)?s[0]:s;return o.ownerDocument.body},ds=new WeakMap,ai=new WeakMap,ui={},Cu=0,Vh=function(s){return s&&(s.host||Vh(s.parentNode))},yv=function(s,o){return o.map(function(i){if(s.contains(i))return i;var u=Vh(i);return u&&s.contains(u)?u:(console.error("aria-hidden",i,"in not contained inside",s,". Doing nothing"),null)}).filter(function(i){return!!i})},vv=function(s,o,i,u){var d=yv(o,Array.isArray(s)?s:[s]);ui[i]||(ui[i]=new WeakMap);var f=ui[i],m=[],p=new Set,b=new Set(d),x=function(w){!w||p.has(w)||(p.add(w),x(w.parentNode))};d.forEach(x);var j=function(w){!w||b.has(w)||Array.prototype.forEach.call(w.children,function(_){if(p.has(_))j(_);else try{var M=_.getAttribute(u),z=M!==null&&M!=="false",v=(ds.get(_)||0)+1,S=(f.get(_)||0)+1;ds.set(_,v),f.set(_,S),m.push(_),v===1&&z&&ai.set(_,!0),S===1&&_.setAttribute(i,"true"),z||_.setAttribute(u,"true")}catch(O){console.error("aria-hidden: cannot operate on ",_,O)}})};return j(o),p.clear(),Cu++,function(){m.forEach(function(w){var _=ds.get(w)-1,M=f.get(w)-1;ds.set(w,_),f.set(w,M),_||(ai.has(w)||w.removeAttribute(u),ai.delete(w)),M||w.removeAttribute(i)}),Cu--,Cu||(ds=new WeakMap,ds=new WeakMap,ai=new WeakMap,ui={})}},bv=function(s,o,i){i===void 0&&(i="data-aria-hidden");var u=Array.from(Array.isArray(s)?s:[s]),d=xv(s);return d?(u.push.apply(u,Array.from(d.querySelectorAll("[aria-live], script"))),vv(u,d,i,"aria-hidden")):function(){return null}},ki="Dialog",[Gh]=Q0(ki),[wv,qt]=Gh(ki),Kh=s=>{const{__scopeDialog:o,children:i,open:u,defaultOpen:d,onOpenChange:f,modal:m=!0}=s,p=g.useRef(null),b=g.useRef(null),[x,j]=X0({prop:u,defaultProp:d??!1,onChange:f,caller:ki});return n.jsx(wv,{scope:o,triggerRef:p,contentRef:b,contentId:br(),titleId:br(),descriptionId:br(),open:x,onOpenChange:j,onOpenToggle:g.useCallback(()=>j(w=>!w),[j]),modal:m,children:i})};Kh.displayName=ki;var Qh="DialogTrigger",jv=g.forwardRef((s,o)=>{const{__scopeDialog:i,...u}=s,d=qt(Qh,i),f=Dn(o,d.triggerRef);return n.jsx(it.button,{type:"button","aria-haspopup":"dialog","aria-expanded":d.open,"aria-controls":d.open?d.contentId:void 0,"data-state":pc(d.open),...u,ref:f,onClick:Xr(s.onClick,d.onOpenToggle)})});jv.displayName=Qh;var fc="DialogPortal",[kv,qh]=Gh(fc,{forceMount:void 0}),Zh=s=>{const{__scopeDialog:o,forceMount:i,children:u,container:d}=s,f=qt(fc,o);return n.jsx(kv,{scope:o,forceMount:i,children:g.Children.map(u,m=>n.jsx(wi,{present:i||f.open,children:n.jsx(zh,{asChild:!0,container:d,children:m})}))})};Zh.displayName=fc;var bi="DialogOverlay",Yh=g.forwardRef((s,o)=>{const i=qh(bi,s.__scopeDialog),{forceMount:u=i.forceMount,...d}=s,f=qt(bi,s.__scopeDialog);return f.modal?n.jsx(wi,{present:u||f.open,children:n.jsx(Sv,{...d,ref:o})}):null});Yh.displayName=bi;var Nv=Rh("DialogOverlay.RemoveScroll"),Sv=g.forwardRef((s,o)=>{const{__scopeDialog:i,...u}=s,d=qt(bi,i),f=vy(),m=Dn(o,f);return n.jsx(Wh,{as:Nv,allowPinchZoom:!0,shards:[d.contentRef],children:n.jsx(it.div,{"data-state":pc(d.open),...u,ref:m,style:{pointerEvents:"auto",...u.style}})})}),Os="DialogContent",Jh=g.forwardRef((s,o)=>{const i=qh(Os,s.__scopeDialog),{forceMount:u=i.forceMount,...d}=s,f=qt(Os,s.__scopeDialog);return n.jsx(wi,{present:u||f.open,children:f.modal?n.jsx(Cv,{...d,ref:o}):n.jsx(Ev,{...d,ref:o})})});Jh.displayName=Os;var Cv=g.forwardRef((s,o)=>{const i=qt(Os,s.__scopeDialog),u=g.useRef(null),d=Dn(o,i.contentRef,u);return g.useEffect(()=>{const f=u.current;if(f)return bv(f)},[]),n.jsx(Xh,{...s,ref:d,trapFocus:i.open,disableOutsidePointerEvents:i.open,onCloseAutoFocus:Xr(s.onCloseAutoFocus,f=>{var m;f.preventDefault(),(m=i.triggerRef.current)==null||m.focus()}),onPointerDownOutside:Xr(s.onPointerDownOutside,f=>{const m=f.detail.originalEvent,p=m.button===0&&m.ctrlKey===!0;(m.button===2||p)&&f.preventDefault()}),onFocusOutside:Xr(s.onFocusOutside,f=>f.preventDefault())})}),Ev=g.forwardRef((s,o)=>{const i=qt(Os,s.__scopeDialog),u=g.useRef(!1),d=g.useRef(!1);return n.jsx(Xh,{...s,ref:o,trapFocus:!1,disableOutsidePointerEvents:!1,onCloseAutoFocus:f=>{var m,p;(m=s.onCloseAutoFocus)==null||m.call(s,f),f.defaultPrevented||(u.current||(p=i.triggerRef.current)==null||p.focus(),f.preventDefault()),u.current=!1,d.current=!1},onInteractOutside:f=>{var b,x;(b=s.onInteractOutside)==null||b.call(s,f),f.defaultPrevented||(u.current=!0,f.detail.originalEvent.type==="pointerdown"&&(d.current=!0));const m=f.target;((x=i.triggerRef.current)==null?void 0:x.contains(m))&&f.preventDefault(),f.detail.originalEvent.type==="focusin"&&d.current&&f.preventDefault()}})}),Xh=g.forwardRef((s,o)=>{const{__scopeDialog:i,trapFocus:u,onOpenAutoFocus:d,onCloseAutoFocus:f,...m}=s,p=qt(Os,i);return Ty(),n.jsx(n.Fragment,{children:n.jsx(Th,{asChild:!0,loop:!0,trapped:u,onMountAutoFocus:d,onUnmountAutoFocus:f,children:n.jsx(Oh,{role:"dialog",id:p.contentId,"aria-describedby":p.descriptionId,"aria-labelledby":p.titleId,"data-state":pc(p.open),...m,ref:o,deferPointerDownOutside:!0,onDismiss:()=>p.onOpenChange(!1)})})})}),em="DialogTitle",Pv=g.forwardRef((s,o)=>{const{__scopeDialog:i,...u}=s,d=qt(em,i);return n.jsx(it.h2,{id:d.titleId,...u,ref:o})});Pv.displayName=em;var tm="DialogDescription",_v=g.forwardRef((s,o)=>{const{__scopeDialog:i,...u}=s,d=qt(tm,i);return n.jsx(it.p,{id:d.descriptionId,...u,ref:o})});_v.displayName=tm;var rm="DialogClose",Mv=g.forwardRef((s,o)=>{const{__scopeDialog:i,...u}=s,d=qt(rm,i);return n.jsx(it.button,{type:"button",...u,ref:o,onClick:Xr(s.onClick,()=>d.onOpenChange(!1))})});Mv.displayName=rm;function pc(s){return s?"open":"closed"}var So='[cmdk-group=""]',Eu='[cmdk-group-items=""]',Rv='[cmdk-group-heading=""]',nm='[cmdk-item=""]',Wp=`${nm}:not([aria-disabled="true"])`,ec="cmdk-item-select",ps="data-value",Ov=(s,o,i)=>K0(s,o,i),sm=g.createContext(void 0),Wo=()=>g.useContext(sm),om=g.createContext(void 0),hc=()=>g.useContext(om),lm=g.createContext(void 0),im=g.forwardRef((s,o)=>{let i=hs(()=>{var C,Z;return{search:"",value:(Z=(C=s.value)!=null?C:s.defaultValue)!=null?Z:"",selectedItemId:void 0,filtered:{count:0,items:new Map,groups:new Set}}}),u=hs(()=>new Set),d=hs(()=>new Map),f=hs(()=>new Map),m=hs(()=>new Set),p=am(s),{label:b,children:x,value:j,onValueChange:w,filter:_,shouldFilter:M,loop:z,disablePointerSelection:v=!1,vimBindings:S=!0,...O}=s,F=br(),B=br(),I=br(),D=g.useRef(null),$=Hv();On(()=>{if(j!==void 0){let C=j.trim();i.current.value=C,H.emit()}},[j]),On(()=>{$(6,ze)},[]);let H=g.useMemo(()=>({subscribe:C=>(m.current.add(C),()=>m.current.delete(C)),snapshot:()=>i.current,setState:(C,Z,J)=>{var q,oe,pe,ve;if(!Object.is(i.current[C],Z)){if(i.current[C]=Z,C==="search")de(),fe(),$(1,ke);else if(C==="value"){if(document.activeElement.hasAttribute("cmdk-input")||document.activeElement.hasAttribute("cmdk-root")){let U=document.getElementById(I);U?U.focus():(q=document.getElementById(F))==null||q.focus()}if($(7,()=>{var U;i.current.selectedItemId=(U=Ce())==null?void 0:U.id,H.emit()}),J||$(5,ze),((oe=p.current)==null?void 0:oe.value)!==void 0){let U=Z??"";(ve=(pe=p.current).onValueChange)==null||ve.call(pe,U);return}}H.emit()}},emit:()=>{m.current.forEach(C=>C())}}),[]),ae=g.useMemo(()=>({value:(C,Z,J)=>{var q;Z!==((q=f.current.get(C))==null?void 0:q.value)&&(f.current.set(C,{value:Z,keywords:J}),i.current.filtered.items.set(C,te(Z,J)),$(2,()=>{fe(),H.emit()}))},item:(C,Z)=>(u.current.add(C),Z&&(d.current.has(Z)?d.current.get(Z).add(C):d.current.set(Z,new Set([C]))),$(3,()=>{de(),fe(),i.current.value||ke(),H.emit()}),()=>{f.current.delete(C),u.current.delete(C),i.current.filtered.items.delete(C);let J=Ce();$(4,()=>{de(),(J==null?void 0:J.getAttribute("id"))===C&&ke(),H.emit()})}),group:C=>(d.current.has(C)||d.current.set(C,new Set),()=>{f.current.delete(C),d.current.delete(C)}),filter:()=>p.current.shouldFilter,label:b||s["aria-label"],getDisablePointerSelection:()=>p.current.disablePointerSelection,listId:F,inputId:I,labelId:B,listInnerRef:D}),[]);function te(C,Z){var J,q;let oe=(q=(J=p.current)==null?void 0:J.filter)!=null?q:Ov;return C?oe(C,i.current.search,Z):0}function fe(){if(!i.current.search||p.current.shouldFilter===!1)return;let C=i.current.filtered.items,Z=[];i.current.filtered.groups.forEach(q=>{let oe=d.current.get(q),pe=0;oe.forEach(ve=>{let U=C.get(ve);pe=Math.max(U,pe)}),Z.push([q,pe])});let J=D.current;Le().sort((q,oe)=>{var pe,ve;let U=q.getAttribute("id"),he=oe.getAttribute("id");return((pe=C.get(he))!=null?pe:0)-((ve=C.get(U))!=null?ve:0)}).forEach(q=>{let oe=q.closest(Eu);oe?oe.appendChild(q.parentElement===oe?q:q.closest(`${Eu} > *`)):J.appendChild(q.parentElement===J?q:q.closest(`${Eu} > *`))}),Z.sort((q,oe)=>oe[1]-q[1]).forEach(q=>{var oe;let pe=(oe=D.current)==null?void 0:oe.querySelector(`${So}[${ps}="${encodeURIComponent(q[0])}"]`);pe==null||pe.parentElement.appendChild(pe)})}function ke(){let C=Le().find(J=>J.getAttribute("aria-disabled")!=="true"),Z=C==null?void 0:C.getAttribute(ps);H.setState("value",Z||void 0)}function de(){var C,Z,J,q;if(!i.current.search||p.current.shouldFilter===!1){i.current.filtered.count=u.current.size;return}i.current.filtered.groups=new Set;let oe=0;for(let pe of u.current){let ve=(Z=(C=f.current.get(pe))==null?void 0:C.value)!=null?Z:"",U=(q=(J=f.current.get(pe))==null?void 0:J.keywords)!=null?q:[],he=te(ve,U);i.current.filtered.items.set(pe,he),he>0&&oe++}for(let[pe,ve]of d.current)for(let U of ve)if(i.current.filtered.items.get(U)>0){i.current.filtered.groups.add(pe);break}i.current.filtered.count=oe}function ze(){var C,Z,J;let q=Ce();q&&(((C=q.parentElement)==null?void 0:C.firstChild)===q&&((J=(Z=q.closest(So))==null?void 0:Z.querySelector(Rv))==null||J.scrollIntoView({block:"nearest"})),q.scrollIntoView({block:"nearest"}))}function Ce(){var C;return(C=D.current)==null?void 0:C.querySelector(`${nm}[aria-selected="true"]`)}function Le(){var C;return Array.from(((C=D.current)==null?void 0:C.querySelectorAll(Wp))||[])}function Ee(C){let Z=Le()[C];Z&&H.setState("value",Z.getAttribute(ps))}function Pe(C){var Z;let J=Ce(),q=Le(),oe=q.findIndex(ve=>ve===J),pe=q[oe+C];(Z=p.current)!=null&&Z.loop&&(pe=oe+C<0?q[q.length-1]:oe+C===q.length?q[0]:q[oe+C]),pe&&H.setState("value",pe.getAttribute(ps))}function K(C){let Z=Ce(),J=Z==null?void 0:Z.closest(So),q;for(;J&&!q;)J=C>0?$v(J,So):Bv(J,So),q=J==null?void 0:J.querySelector(Wp);q?H.setState("value",q.getAttribute(ps)):Pe(C)}let X=()=>Ee(Le().length-1),Y=C=>{C.preventDefault(),C.metaKey?X():C.altKey?K(1):Pe(1)},P=C=>{C.preventDefault(),C.metaKey?Ee(0):C.altKey?K(-1):Pe(-1)};return g.createElement(it.div,{ref:o,tabIndex:-1,...O,"cmdk-root":"",onKeyDown:C=>{var Z;(Z=O.onKeyDown)==null||Z.call(O,C);let J=C.nativeEvent.isComposing||C.keyCode===229;if(!(C.defaultPrevented||J))switch(C.key){case"n":case"j":{S&&C.ctrlKey&&Y(C);break}case"ArrowDown":{Y(C);break}case"p":case"k":{S&&C.ctrlKey&&P(C);break}case"ArrowUp":{P(C);break}case"Home":{C.preventDefault(),Ee(0);break}case"End":{C.preventDefault(),X();break}case"Enter":{C.preventDefault();let q=Ce();if(q){let oe=new Event(ec);q.dispatchEvent(oe)}}}}},g.createElement("label",{"cmdk-label":"",htmlFor:ae.inputId,id:ae.labelId,style:Vv},b),Ni(s,C=>g.createElement(om.Provider,{value:H},g.createElement(sm.Provider,{value:ae},C))))}),Dv=g.forwardRef((s,o)=>{var i,u;let d=br(),f=g.useRef(null),m=g.useContext(lm),p=Wo(),b=am(s),x=(u=(i=b.current)==null?void 0:i.forceMount)!=null?u:m==null?void 0:m.forceMount;On(()=>{if(!x)return p.item(d,m==null?void 0:m.id)},[x]);let j=um(d,f,[s.value,s.children,f],s.keywords),w=hc(),_=en($=>$.value&&$.value===j.current),M=en($=>x||p.filter()===!1?!0:$.search?$.filtered.items.get(d)>0:!0);g.useEffect(()=>{let $=f.current;if(!(!$||s.disabled))return $.addEventListener(ec,z),()=>$.removeEventListener(ec,z)},[M,s.onSelect,s.disabled]);function z(){var $,H;v(),(H=($=b.current).onSelect)==null||H.call($,j.current)}function v(){w.setState("value",j.current,!0)}if(!M)return null;let{disabled:S,value:O,onSelect:F,forceMount:B,keywords:I,...D}=s;return g.createElement(it.div,{ref:Rs(f,o),...D,id:d,"cmdk-item":"",role:"option","aria-disabled":!!S,"aria-selected":!!_,"data-disabled":!!S,"data-selected":!!_,onPointerMove:S||p.getDisablePointerSelection()?void 0:v,onClick:S?void 0:z},s.children)}),Tv=g.forwardRef((s,o)=>{let{heading:i,children:u,forceMount:d,...f}=s,m=br(),p=g.useRef(null),b=g.useRef(null),x=br(),j=Wo(),w=en(M=>d||j.filter()===!1?!0:M.search?M.filtered.groups.has(m):!0);On(()=>j.group(m),[]),um(m,p,[s.value,s.heading,b]);let _=g.useMemo(()=>({id:m,forceMount:d}),[d]);return g.createElement(it.div,{ref:Rs(p,o),...f,"cmdk-group":"",role:"presentation",hidden:w?void 0:!0},i&&g.createElement("div",{ref:b,"cmdk-group-heading":"","aria-hidden":!0,id:x},i),Ni(s,M=>g.createElement("div",{"cmdk-group-items":"",role:"group","aria-labelledby":i?x:void 0},g.createElement(lm.Provider,{value:_},M))))}),Av=g.forwardRef((s,o)=>{let{alwaysRender:i,...u}=s,d=g.useRef(null),f=en(m=>!m.search);return!i&&!f?null:g.createElement(it.div,{ref:Rs(d,o),...u,"cmdk-separator":"",role:"separator"})}),zv=g.forwardRef((s,o)=>{let{onValueChange:i,...u}=s,d=s.value!=null,f=hc(),m=en(x=>x.search),p=en(x=>x.selectedItemId),b=Wo();return g.useEffect(()=>{s.value!=null&&f.setState("search",s.value)},[s.value]),g.createElement(it.input,{ref:o,...u,"cmdk-input":"",autoComplete:"off",autoCorrect:"off",spellCheck:!1,"aria-autocomplete":"list",role:"combobox","aria-expanded":!0,"aria-controls":b.listId,"aria-labelledby":b.labelId,"aria-activedescendant":p,id:b.inputId,type:"text",value:d?s.value:m,onChange:x=>{d||f.setState("search",x.target.value),i==null||i(x.target.value)}})}),Lv=g.forwardRef((s,o)=>{let{children:i,label:u="Suggestions",...d}=s,f=g.useRef(null),m=g.useRef(null),p=en(x=>x.selectedItemId),b=Wo();return g.useEffect(()=>{if(m.current&&f.current){let x=m.current,j=f.current,w,_=new ResizeObserver(()=>{w=requestAnimationFrame(()=>{let M=x.offsetHeight;j.style.setProperty("--cmdk-list-height",M.toFixed(1)+"px")})});return _.observe(x),()=>{cancelAnimationFrame(w),_.unobserve(x)}}},[]),g.createElement(it.div,{ref:Rs(f,o),...d,"cmdk-list":"",role:"listbox",tabIndex:-1,"aria-activedescendant":p,"aria-label":u,id:b.listId},Ni(s,x=>g.createElement("div",{ref:Rs(m,b.listInnerRef),"cmdk-list-sizer":""},x)))}),Iv=g.forwardRef((s,o)=>{let{open:i,onOpenChange:u,overlayClassName:d,contentClassName:f,container:m,...p}=s;return g.createElement(Kh,{open:i,onOpenChange:u},g.createElement(Zh,{container:m},g.createElement(Yh,{"cmdk-overlay":"",className:d}),g.createElement(Jh,{"aria-label":s.label,"cmdk-dialog":"",className:f},g.createElement(im,{ref:o,...p}))))}),Fv=g.forwardRef((s,o)=>en(i=>i.filtered.count===0)?g.createElement(it.div,{ref:o,...s,"cmdk-empty":"",role:"presentation"}):null),Uv=g.forwardRef((s,o)=>{let{progress:i,children:u,label:d="Loading...",...f}=s;return g.createElement(it.div,{ref:o,...f,"cmdk-loading":"",role:"progressbar","aria-valuenow":i,"aria-valuemin":0,"aria-valuemax":100,"aria-label":d},Ni(s,m=>g.createElement("div",{"aria-hidden":!0},m)))}),fs=Object.assign(im,{List:Lv,Item:Dv,Input:zv,Group:Tv,Separator:Av,Dialog:Iv,Empty:Fv,Loading:Uv});function $v(s,o){let i=s.nextElementSibling;for(;i;){if(i.matches(o))return i;i=i.nextElementSibling}}function Bv(s,o){let i=s.previousElementSibling;for(;i;){if(i.matches(o))return i;i=i.previousElementSibling}}function am(s){let o=g.useRef(s);return On(()=>{o.current=s}),o}var On=typeof window>"u"?g.useEffect:g.useLayoutEffect;function hs(s){let o=g.useRef();return o.current===void 0&&(o.current=s()),o}function en(s){let o=hc(),i=()=>s(o.snapshot());return g.useSyncExternalStore(o.subscribe,i,i)}function um(s,o,i,u=[]){let d=g.useRef(),f=Wo();return On(()=>{var m;let p=(()=>{var x;for(let j of i){if(typeof j=="string")return j.trim();if(typeof j=="object"&&"current"in j)return j.current?(x=j.current.textContent)==null?void 0:x.trim():d.current}})(),b=u.map(x=>x.trim());f.value(s,p,b),(m=o.current)==null||m.setAttribute(ps,p),d.current=p}),d}var Hv=()=>{let[s,o]=g.useState(),i=hs(()=>new Map);return On(()=>{i.current.forEach(u=>u()),i.current=new Map},[s]),(u,d)=>{i.current.set(u,d),o({})}};function Wv(s){let o=s.type;return typeof o=="function"?o(s.props):"render"in o?o.render(s.props):s}function Ni({asChild:s,children:o},i){return s&&g.isValidElement(o)?g.cloneElement(Wv(o),{ref:o.ref},i(o.props.children)):i(o)}var Vv={position:"absolute",width:"1px",height:"1px",padding:"0",margin:"-1px",overflow:"hidden",clip:"rect(0, 0, 0, 0)",whiteSpace:"nowrap",borderWidth:"0"};function Gv({onNavigate:s}){const[o,i]=g.useState(!1);return g.useEffect(()=>{const u=d=>{(d.metaKey||d.ctrlKey)&&d.key.toLowerCase()==="k"&&(d.preventDefault(),i(f=>!f))};return document.addEventListener("keydown",u),()=>document.removeEventListener("keydown",u)},[]),n.jsx(fs.Dialog,{open:o,onOpenChange:i,label:"Befehlspalette",className:"fixed inset-0 z-50 flex items-start justify-center bg-black/50 p-4 pt-[12vh]",onClick:()=>i(!1),children:n.jsxs("div",{className:"w-full max-w-lg overflow-hidden rounded-xl border border-border bg-popover text-popover-foreground shadow-2xl",onClick:u=>u.stopPropagation(),children:[n.jsx(fs.Input,{autoFocus:!0,placeholder:"Springe zu… (Modelle, Routing, System …)",className:"w-full border-b border-border bg-transparent px-4 py-3 text-sm outline-none placeholder:text-muted-foreground"}),n.jsxs(fs.List,{className:"max-h-80 overflow-y-auto p-2",children:[n.jsx(fs.Empty,{className:"px-3 py-6 text-center text-sm text-muted-foreground",children:"Nichts gefunden."}),n.jsx(fs.Group,{heading:"Bereiche",className:"px-1 py-1 text-xs text-muted-foreground",children:Zu.map(u=>n.jsxs(fs.Item,{value:`${u.label} ${u.hint}`,onSelect:()=>{s(u.id),i(!1)},className:"flex cursor-pointer items-center gap-3 rounded-md px-3 py-2 text-sm text-foreground aria-selected:bg-accent aria-selected:text-accent-foreground",children:[n.jsx(u.icon,{className:"h-4 w-4 text-primary"}),n.jsx("span",{children:u.label}),n.jsx("span",{className:"ml-auto truncate text-xs text-muted-foreground",children:u.hint})]},u.id))})]})]})})}async function we(s,o){var b;const i={"Content-Type":"application/json",...o==null?void 0:o.headers},u=localStorage.getItem("mc_sudo_password"),d=localStorage.getItem("mc_hf_token");u&&(i["X-Sudo-Password"]=u);let f=o==null?void 0:o.body;if((((b=o==null?void 0:o.method)==null?void 0:b.toUpperCase())||"GET")==="POST"){if(typeof f=="string")try{const x=JSON.parse(f);let j=!1;u&&!("sudo_password"in x)&&(x.sudo_password=u,j=!0),d&&!("hf_token"in x)&&(x.hf_token=d,j=!0),j&&(f=JSON.stringify(x))}catch{}else if(!f){const x={};u&&(x.sudo_password=u),d&&(x.hf_token=d),Object.keys(x).length>0&&(f=JSON.stringify(x))}}const p=await fetch(s,{...o,headers:i,body:f});if(!p.ok)throw new Error(`${p.status} ${p.statusText}`);return p.json()}const Ye={health:["health"],systemStatus:["system-status"],services:["services"],models:["models"],routing:["routing"],jobs:["jobs"],tokenStats:["token-stats"],agentStatus:["agent-status"],updates:["updates"],discover:["discover"],connect:s=>["connect",s??""],memory:(s,o)=>["memory",s??"",o??""]},Kv=()=>Ut({queryKey:Ye.health,queryFn:()=>we("/api/health"),refetchInterval:1e4}),mc=(s=5e3)=>Ut({queryKey:Ye.systemStatus,queryFn:()=>we("/api/system/status"),refetchInterval:s}),Qv=(s=3e3)=>Ut({queryKey:Ye.services,queryFn:()=>we("/api/system/services"),refetchInterval:s}),Vo=(s=4e3)=>Ut({queryKey:Ye.models,queryFn:()=>we("/api/models"),refetchInterval:s}),qv=(s=4e3)=>Ut({queryKey:Ye.routing,queryFn:()=>we("/api/routing"),refetchInterval:s}),cm=(s=2e3)=>Ut({queryKey:Ye.jobs,queryFn:()=>we("/api/jobs"),refetchInterval:s,select:o=>o.jobs??[]}),Zv=(s=3e3)=>Ut({queryKey:Ye.tokenStats,queryFn:()=>we("/api/system/token-stats"),refetchInterval:s}),dm=(s=5e3)=>Ut({queryKey:Ye.agentStatus,queryFn:()=>we("/api/agent/status"),refetchInterval:s}),gc=s=>Ut({queryKey:Ye.updates,queryFn:()=>we("/api/maintenance/updates"),refetchInterval:s}),Yv=()=>Ut({queryKey:Ye.discover,queryFn:()=>we("/api/discover")}),fm=s=>Ut({queryKey:Ye.connect(s),queryFn:()=>we(s?`/api/connect?${s}`:"/api/connect")}),pm=s=>Ut({queryKey:Ye.memory(s==null?void 0:s.q,s==null?void 0:s.category),queryFn:()=>{const o=new URLSearchParams;return s!=null&&s.q&&o.set("q",s.q),s!=null&&s.category&&o.set("category",s.category),we(`/api/memory?${o}`)},select:o=>s!=null&&s.limit?o.slice(0,s.limit):o});function St(s){return(s/1024**3).toFixed(1)}function tc(s){return s?s>1024**3?`${(s/1024**3).toFixed(1)} GB`:`${(s/1024**2).toFixed(0)} MB`:""}function gn(s){if(!s)return"—";const o=s/1024**3;return o>=1?`${o.toFixed(1)} GB`:`${(s/1024**2).toFixed(0)} MB`}function Jv(s){if(!s)return"";const o=Math.floor(s/60);return o>0?`${o} min`:`${s} s`}function Vp(s){return s?`${Math.round(s/1024)}k`:"—"}function hm(s){var o,i,u="";if(typeof s=="string"||typeof s=="number")u+=s;else if(typeof s=="object")if(Array.isArray(s)){var d=s.length;for(o=0;o{const o=rb(s),{conflictingClassGroups:i,conflictingClassGroupModifiers:u}=s;return{getClassGroupId:m=>{const p=m.split(xc);return p[0]===""&&p.length!==1&&p.shift(),mm(p,o)||tb(m)},getConflictingClassGroupIds:(m,p)=>{const b=i[m]||[];return p&&u[m]?[...b,...u[m]]:b}}},mm=(s,o)=>{var m;if(s.length===0)return o.classGroupId;const i=s[0],u=o.nextPart.get(i),d=u?mm(s.slice(1),u):void 0;if(d)return d;if(o.validators.length===0)return;const f=s.join(xc);return(m=o.validators.find(({validator:p})=>p(f)))==null?void 0:m.classGroupId},Gp=/^\[(.+)\]$/,tb=s=>{if(Gp.test(s)){const o=Gp.exec(s)[1],i=o==null?void 0:o.substring(0,o.indexOf(":"));if(i)return"arbitrary.."+i}},rb=s=>{const{theme:o,prefix:i}=s,u={nextPart:new Map,validators:[]};return sb(Object.entries(s.classGroups),i).forEach(([f,m])=>{rc(m,u,f,o)}),u},rc=(s,o,i,u)=>{s.forEach(d=>{if(typeof d=="string"){const f=d===""?o:Kp(o,d);f.classGroupId=i;return}if(typeof d=="function"){if(nb(d)){rc(d(u),o,i,u);return}o.validators.push({validator:d,classGroupId:i});return}Object.entries(d).forEach(([f,m])=>{rc(m,Kp(o,f),i,u)})})},Kp=(s,o)=>{let i=s;return o.split(xc).forEach(u=>{i.nextPart.has(u)||i.nextPart.set(u,{nextPart:new Map,validators:[]}),i=i.nextPart.get(u)}),i},nb=s=>s.isThemeGetter,sb=(s,o)=>o?s.map(([i,u])=>{const d=u.map(f=>typeof f=="string"?o+f:typeof f=="object"?Object.fromEntries(Object.entries(f).map(([m,p])=>[o+m,p])):f);return[i,d]}):s,ob=s=>{if(s<1)return{get:()=>{},set:()=>{}};let o=0,i=new Map,u=new Map;const d=(f,m)=>{i.set(f,m),o++,o>s&&(o=0,u=i,i=new Map)};return{get(f){let m=i.get(f);if(m!==void 0)return m;if((m=u.get(f))!==void 0)return d(f,m),m},set(f,m){i.has(f)?i.set(f,m):d(f,m)}}},gm="!",lb=s=>{const{separator:o,experimentalParseClassName:i}=s,u=o.length===1,d=o[0],f=o.length,m=p=>{const b=[];let x=0,j=0,w;for(let S=0;Sj?w-j:void 0;return{modifiers:b,hasImportantModifier:M,baseClassName:z,maybePostfixModifierPosition:v}};return i?p=>i({className:p,parseClassName:m}):m},ib=s=>{if(s.length<=1)return s;const o=[];let i=[];return s.forEach(u=>{u[0]==="["?(o.push(...i.sort(),u),i=[]):i.push(u)}),o.push(...i.sort()),o},ab=s=>({cache:ob(s.cacheSize),parseClassName:lb(s),...eb(s)}),ub=/\s+/,cb=(s,o)=>{const{parseClassName:i,getClassGroupId:u,getConflictingClassGroupIds:d}=o,f=[],m=s.trim().split(ub);let p="";for(let b=m.length-1;b>=0;b-=1){const x=m[b],{modifiers:j,hasImportantModifier:w,baseClassName:_,maybePostfixModifierPosition:M}=i(x);let z=!!M,v=u(z?_.substring(0,M):_);if(!v){if(!z){p=x+(p.length>0?" "+p:p);continue}if(v=u(_),!v){p=x+(p.length>0?" "+p:p);continue}z=!1}const S=ib(j).join(":"),O=w?S+gm:S,F=O+v;if(f.includes(F))continue;f.push(F);const B=d(v,z);for(let I=0;I0?" "+p:p)}return p};function db(){let s=0,o,i,u="";for(;s{if(typeof s=="string")return s;let o,i="";for(let u=0;uw(j),s());return i=ab(x),u=i.cache.get,d=i.cache.set,f=p,p(b)}function p(b){const x=u(b);if(x)return x;const j=cb(b,i);return d(b,j),j}return function(){return f(db.apply(null,arguments))}}const $e=s=>{const o=i=>i[s]||[];return o.isThemeGetter=!0,o},ym=/^\[(?:([a-z-]+):)?(.+)\]$/i,pb=/^\d+\/\d+$/,hb=new Set(["px","full","screen"]),mb=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,gb=/\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/,xb=/^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/,yb=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,vb=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,gr=s=>gs(s)||hb.has(s)||pb.test(s),Ur=s=>Ds(s,"length",Eb),gs=s=>!!s&&!Number.isNaN(Number(s)),Pu=s=>Ds(s,"number",gs),Co=s=>!!s&&Number.isInteger(Number(s)),bb=s=>s.endsWith("%")&&gs(s.slice(0,-1)),Ne=s=>ym.test(s),$r=s=>mb.test(s),wb=new Set(["length","size","percentage"]),jb=s=>Ds(s,wb,vm),kb=s=>Ds(s,"position",vm),Nb=new Set(["image","url"]),Sb=s=>Ds(s,Nb,_b),Cb=s=>Ds(s,"",Pb),Eo=()=>!0,Ds=(s,o,i)=>{const u=ym.exec(s);return u?u[1]?typeof o=="string"?u[1]===o:o.has(u[1]):i(u[2]):!1},Eb=s=>gb.test(s)&&!xb.test(s),vm=()=>!1,Pb=s=>yb.test(s),_b=s=>vb.test(s),Mb=()=>{const s=$e("colors"),o=$e("spacing"),i=$e("blur"),u=$e("brightness"),d=$e("borderColor"),f=$e("borderRadius"),m=$e("borderSpacing"),p=$e("borderWidth"),b=$e("contrast"),x=$e("grayscale"),j=$e("hueRotate"),w=$e("invert"),_=$e("gap"),M=$e("gradientColorStops"),z=$e("gradientColorStopPositions"),v=$e("inset"),S=$e("margin"),O=$e("opacity"),F=$e("padding"),B=$e("saturate"),I=$e("scale"),D=$e("sepia"),$=$e("skew"),H=$e("space"),ae=$e("translate"),te=()=>["auto","contain","none"],fe=()=>["auto","hidden","clip","visible","scroll"],ke=()=>["auto",Ne,o],de=()=>[Ne,o],ze=()=>["",gr,Ur],Ce=()=>["auto",gs,Ne],Le=()=>["bottom","center","left","left-bottom","left-top","right","right-bottom","right-top","top"],Ee=()=>["solid","dashed","dotted","double","none"],Pe=()=>["normal","multiply","screen","overlay","darken","lighten","color-dodge","color-burn","hard-light","soft-light","difference","exclusion","hue","saturation","color","luminosity"],K=()=>["start","end","center","between","around","evenly","stretch"],X=()=>["","0",Ne],Y=()=>["auto","avoid","all","avoid-page","page","left","right","column"],P=()=>[gs,Ne];return{cacheSize:500,separator:":",theme:{colors:[Eo],spacing:[gr,Ur],blur:["none","",$r,Ne],brightness:P(),borderColor:[s],borderRadius:["none","","full",$r,Ne],borderSpacing:de(),borderWidth:ze(),contrast:P(),grayscale:X(),hueRotate:P(),invert:X(),gap:de(),gradientColorStops:[s],gradientColorStopPositions:[bb,Ur],inset:ke(),margin:ke(),opacity:P(),padding:de(),saturate:P(),scale:P(),sepia:X(),skew:P(),space:de(),translate:de()},classGroups:{aspect:[{aspect:["auto","square","video",Ne]}],container:["container"],columns:[{columns:[$r]}],"break-after":[{"break-after":Y()}],"break-before":[{"break-before":Y()}],"break-inside":[{"break-inside":["auto","avoid","avoid-page","avoid-column"]}],"box-decoration":[{"box-decoration":["slice","clone"]}],box:[{box:["border","content"]}],display:["block","inline-block","inline","flex","inline-flex","table","inline-table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row-group","table-row","flow-root","grid","inline-grid","contents","list-item","hidden"],float:[{float:["right","left","none","start","end"]}],clear:[{clear:["left","right","both","none","start","end"]}],isolation:["isolate","isolation-auto"],"object-fit":[{object:["contain","cover","fill","none","scale-down"]}],"object-position":[{object:[...Le(),Ne]}],overflow:[{overflow:fe()}],"overflow-x":[{"overflow-x":fe()}],"overflow-y":[{"overflow-y":fe()}],overscroll:[{overscroll:te()}],"overscroll-x":[{"overscroll-x":te()}],"overscroll-y":[{"overscroll-y":te()}],position:["static","fixed","absolute","relative","sticky"],inset:[{inset:[v]}],"inset-x":[{"inset-x":[v]}],"inset-y":[{"inset-y":[v]}],start:[{start:[v]}],end:[{end:[v]}],top:[{top:[v]}],right:[{right:[v]}],bottom:[{bottom:[v]}],left:[{left:[v]}],visibility:["visible","invisible","collapse"],z:[{z:["auto",Co,Ne]}],basis:[{basis:ke()}],"flex-direction":[{flex:["row","row-reverse","col","col-reverse"]}],"flex-wrap":[{flex:["wrap","wrap-reverse","nowrap"]}],flex:[{flex:["1","auto","initial","none",Ne]}],grow:[{grow:X()}],shrink:[{shrink:X()}],order:[{order:["first","last","none",Co,Ne]}],"grid-cols":[{"grid-cols":[Eo]}],"col-start-end":[{col:["auto",{span:["full",Co,Ne]},Ne]}],"col-start":[{"col-start":Ce()}],"col-end":[{"col-end":Ce()}],"grid-rows":[{"grid-rows":[Eo]}],"row-start-end":[{row:["auto",{span:[Co,Ne]},Ne]}],"row-start":[{"row-start":Ce()}],"row-end":[{"row-end":Ce()}],"grid-flow":[{"grid-flow":["row","col","dense","row-dense","col-dense"]}],"auto-cols":[{"auto-cols":["auto","min","max","fr",Ne]}],"auto-rows":[{"auto-rows":["auto","min","max","fr",Ne]}],gap:[{gap:[_]}],"gap-x":[{"gap-x":[_]}],"gap-y":[{"gap-y":[_]}],"justify-content":[{justify:["normal",...K()]}],"justify-items":[{"justify-items":["start","end","center","stretch"]}],"justify-self":[{"justify-self":["auto","start","end","center","stretch"]}],"align-content":[{content:["normal",...K(),"baseline"]}],"align-items":[{items:["start","end","center","baseline","stretch"]}],"align-self":[{self:["auto","start","end","center","stretch","baseline"]}],"place-content":[{"place-content":[...K(),"baseline"]}],"place-items":[{"place-items":["start","end","center","baseline","stretch"]}],"place-self":[{"place-self":["auto","start","end","center","stretch"]}],p:[{p:[F]}],px:[{px:[F]}],py:[{py:[F]}],ps:[{ps:[F]}],pe:[{pe:[F]}],pt:[{pt:[F]}],pr:[{pr:[F]}],pb:[{pb:[F]}],pl:[{pl:[F]}],m:[{m:[S]}],mx:[{mx:[S]}],my:[{my:[S]}],ms:[{ms:[S]}],me:[{me:[S]}],mt:[{mt:[S]}],mr:[{mr:[S]}],mb:[{mb:[S]}],ml:[{ml:[S]}],"space-x":[{"space-x":[H]}],"space-x-reverse":["space-x-reverse"],"space-y":[{"space-y":[H]}],"space-y-reverse":["space-y-reverse"],w:[{w:["auto","min","max","fit","svw","lvw","dvw",Ne,o]}],"min-w":[{"min-w":[Ne,o,"min","max","fit"]}],"max-w":[{"max-w":[Ne,o,"none","full","min","max","fit","prose",{screen:[$r]},$r]}],h:[{h:[Ne,o,"auto","min","max","fit","svh","lvh","dvh"]}],"min-h":[{"min-h":[Ne,o,"min","max","fit","svh","lvh","dvh"]}],"max-h":[{"max-h":[Ne,o,"min","max","fit","svh","lvh","dvh"]}],size:[{size:[Ne,o,"auto","min","max","fit"]}],"font-size":[{text:["base",$r,Ur]}],"font-smoothing":["antialiased","subpixel-antialiased"],"font-style":["italic","not-italic"],"font-weight":[{font:["thin","extralight","light","normal","medium","semibold","bold","extrabold","black",Pu]}],"font-family":[{font:[Eo]}],"fvn-normal":["normal-nums"],"fvn-ordinal":["ordinal"],"fvn-slashed-zero":["slashed-zero"],"fvn-figure":["lining-nums","oldstyle-nums"],"fvn-spacing":["proportional-nums","tabular-nums"],"fvn-fraction":["diagonal-fractions","stacked-fractions"],tracking:[{tracking:["tighter","tight","normal","wide","wider","widest",Ne]}],"line-clamp":[{"line-clamp":["none",gs,Pu]}],leading:[{leading:["none","tight","snug","normal","relaxed","loose",gr,Ne]}],"list-image":[{"list-image":["none",Ne]}],"list-style-type":[{list:["none","disc","decimal",Ne]}],"list-style-position":[{list:["inside","outside"]}],"placeholder-color":[{placeholder:[s]}],"placeholder-opacity":[{"placeholder-opacity":[O]}],"text-alignment":[{text:["left","center","right","justify","start","end"]}],"text-color":[{text:[s]}],"text-opacity":[{"text-opacity":[O]}],"text-decoration":["underline","overline","line-through","no-underline"],"text-decoration-style":[{decoration:[...Ee(),"wavy"]}],"text-decoration-thickness":[{decoration:["auto","from-font",gr,Ur]}],"underline-offset":[{"underline-offset":["auto",gr,Ne]}],"text-decoration-color":[{decoration:[s]}],"text-transform":["uppercase","lowercase","capitalize","normal-case"],"text-overflow":["truncate","text-ellipsis","text-clip"],"text-wrap":[{text:["wrap","nowrap","balance","pretty"]}],indent:[{indent:de()}],"vertical-align":[{align:["baseline","top","middle","bottom","text-top","text-bottom","sub","super",Ne]}],whitespace:[{whitespace:["normal","nowrap","pre","pre-line","pre-wrap","break-spaces"]}],break:[{break:["normal","words","all","keep"]}],hyphens:[{hyphens:["none","manual","auto"]}],content:[{content:["none",Ne]}],"bg-attachment":[{bg:["fixed","local","scroll"]}],"bg-clip":[{"bg-clip":["border","padding","content","text"]}],"bg-opacity":[{"bg-opacity":[O]}],"bg-origin":[{"bg-origin":["border","padding","content"]}],"bg-position":[{bg:[...Le(),kb]}],"bg-repeat":[{bg:["no-repeat",{repeat:["","x","y","round","space"]}]}],"bg-size":[{bg:["auto","cover","contain",jb]}],"bg-image":[{bg:["none",{"gradient-to":["t","tr","r","br","b","bl","l","tl"]},Sb]}],"bg-color":[{bg:[s]}],"gradient-from-pos":[{from:[z]}],"gradient-via-pos":[{via:[z]}],"gradient-to-pos":[{to:[z]}],"gradient-from":[{from:[M]}],"gradient-via":[{via:[M]}],"gradient-to":[{to:[M]}],rounded:[{rounded:[f]}],"rounded-s":[{"rounded-s":[f]}],"rounded-e":[{"rounded-e":[f]}],"rounded-t":[{"rounded-t":[f]}],"rounded-r":[{"rounded-r":[f]}],"rounded-b":[{"rounded-b":[f]}],"rounded-l":[{"rounded-l":[f]}],"rounded-ss":[{"rounded-ss":[f]}],"rounded-se":[{"rounded-se":[f]}],"rounded-ee":[{"rounded-ee":[f]}],"rounded-es":[{"rounded-es":[f]}],"rounded-tl":[{"rounded-tl":[f]}],"rounded-tr":[{"rounded-tr":[f]}],"rounded-br":[{"rounded-br":[f]}],"rounded-bl":[{"rounded-bl":[f]}],"border-w":[{border:[p]}],"border-w-x":[{"border-x":[p]}],"border-w-y":[{"border-y":[p]}],"border-w-s":[{"border-s":[p]}],"border-w-e":[{"border-e":[p]}],"border-w-t":[{"border-t":[p]}],"border-w-r":[{"border-r":[p]}],"border-w-b":[{"border-b":[p]}],"border-w-l":[{"border-l":[p]}],"border-opacity":[{"border-opacity":[O]}],"border-style":[{border:[...Ee(),"hidden"]}],"divide-x":[{"divide-x":[p]}],"divide-x-reverse":["divide-x-reverse"],"divide-y":[{"divide-y":[p]}],"divide-y-reverse":["divide-y-reverse"],"divide-opacity":[{"divide-opacity":[O]}],"divide-style":[{divide:Ee()}],"border-color":[{border:[d]}],"border-color-x":[{"border-x":[d]}],"border-color-y":[{"border-y":[d]}],"border-color-s":[{"border-s":[d]}],"border-color-e":[{"border-e":[d]}],"border-color-t":[{"border-t":[d]}],"border-color-r":[{"border-r":[d]}],"border-color-b":[{"border-b":[d]}],"border-color-l":[{"border-l":[d]}],"divide-color":[{divide:[d]}],"outline-style":[{outline:["",...Ee()]}],"outline-offset":[{"outline-offset":[gr,Ne]}],"outline-w":[{outline:[gr,Ur]}],"outline-color":[{outline:[s]}],"ring-w":[{ring:ze()}],"ring-w-inset":["ring-inset"],"ring-color":[{ring:[s]}],"ring-opacity":[{"ring-opacity":[O]}],"ring-offset-w":[{"ring-offset":[gr,Ur]}],"ring-offset-color":[{"ring-offset":[s]}],shadow:[{shadow:["","inner","none",$r,Cb]}],"shadow-color":[{shadow:[Eo]}],opacity:[{opacity:[O]}],"mix-blend":[{"mix-blend":[...Pe(),"plus-lighter","plus-darker"]}],"bg-blend":[{"bg-blend":Pe()}],filter:[{filter:["","none"]}],blur:[{blur:[i]}],brightness:[{brightness:[u]}],contrast:[{contrast:[b]}],"drop-shadow":[{"drop-shadow":["","none",$r,Ne]}],grayscale:[{grayscale:[x]}],"hue-rotate":[{"hue-rotate":[j]}],invert:[{invert:[w]}],saturate:[{saturate:[B]}],sepia:[{sepia:[D]}],"backdrop-filter":[{"backdrop-filter":["","none"]}],"backdrop-blur":[{"backdrop-blur":[i]}],"backdrop-brightness":[{"backdrop-brightness":[u]}],"backdrop-contrast":[{"backdrop-contrast":[b]}],"backdrop-grayscale":[{"backdrop-grayscale":[x]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[j]}],"backdrop-invert":[{"backdrop-invert":[w]}],"backdrop-opacity":[{"backdrop-opacity":[O]}],"backdrop-saturate":[{"backdrop-saturate":[B]}],"backdrop-sepia":[{"backdrop-sepia":[D]}],"border-collapse":[{border:["collapse","separate"]}],"border-spacing":[{"border-spacing":[m]}],"border-spacing-x":[{"border-spacing-x":[m]}],"border-spacing-y":[{"border-spacing-y":[m]}],"table-layout":[{table:["auto","fixed"]}],caption:[{caption:["top","bottom"]}],transition:[{transition:["none","all","","colors","opacity","shadow","transform",Ne]}],duration:[{duration:P()}],ease:[{ease:["linear","in","out","in-out",Ne]}],delay:[{delay:P()}],animate:[{animate:["none","spin","ping","pulse","bounce",Ne]}],transform:[{transform:["","gpu","none"]}],scale:[{scale:[I]}],"scale-x":[{"scale-x":[I]}],"scale-y":[{"scale-y":[I]}],rotate:[{rotate:[Co,Ne]}],"translate-x":[{"translate-x":[ae]}],"translate-y":[{"translate-y":[ae]}],"skew-x":[{"skew-x":[$]}],"skew-y":[{"skew-y":[$]}],"transform-origin":[{origin:["center","top","top-right","right","bottom-right","bottom","bottom-left","left","top-left",Ne]}],accent:[{accent:["auto",s]}],appearance:[{appearance:["none","auto"]}],cursor:[{cursor:["auto","default","pointer","wait","text","move","help","not-allowed","none","context-menu","progress","cell","crosshair","vertical-text","alias","copy","no-drop","grab","grabbing","all-scroll","col-resize","row-resize","n-resize","e-resize","s-resize","w-resize","ne-resize","nw-resize","se-resize","sw-resize","ew-resize","ns-resize","nesw-resize","nwse-resize","zoom-in","zoom-out",Ne]}],"caret-color":[{caret:[s]}],"pointer-events":[{"pointer-events":["none","auto"]}],resize:[{resize:["none","y","x",""]}],"scroll-behavior":[{scroll:["auto","smooth"]}],"scroll-m":[{"scroll-m":de()}],"scroll-mx":[{"scroll-mx":de()}],"scroll-my":[{"scroll-my":de()}],"scroll-ms":[{"scroll-ms":de()}],"scroll-me":[{"scroll-me":de()}],"scroll-mt":[{"scroll-mt":de()}],"scroll-mr":[{"scroll-mr":de()}],"scroll-mb":[{"scroll-mb":de()}],"scroll-ml":[{"scroll-ml":de()}],"scroll-p":[{"scroll-p":de()}],"scroll-px":[{"scroll-px":de()}],"scroll-py":[{"scroll-py":de()}],"scroll-ps":[{"scroll-ps":de()}],"scroll-pe":[{"scroll-pe":de()}],"scroll-pt":[{"scroll-pt":de()}],"scroll-pr":[{"scroll-pr":de()}],"scroll-pb":[{"scroll-pb":de()}],"scroll-pl":[{"scroll-pl":de()}],"snap-align":[{snap:["start","end","center","align-none"]}],"snap-stop":[{snap:["normal","always"]}],"snap-type":[{snap:["none","x","y","both"]}],"snap-strictness":[{snap:["mandatory","proximity"]}],touch:[{touch:["auto","none","manipulation"]}],"touch-x":[{"touch-pan":["x","left","right"]}],"touch-y":[{"touch-pan":["y","up","down"]}],"touch-pz":["touch-pinch-zoom"],select:[{select:["none","text","all","auto"]}],"will-change":[{"will-change":["auto","scroll","contents","transform",Ne]}],fill:[{fill:[s,"none"]}],"stroke-w":[{stroke:[gr,Ur,Pu]}],stroke:[{stroke:[s,"none"]}],sr:["sr-only","not-sr-only"],"forced-color-adjust":[{"forced-color-adjust":["auto","none"]}]},conflictingClassGroups:{overflow:["overflow-x","overflow-y"],overscroll:["overscroll-x","overscroll-y"],inset:["inset-x","inset-y","start","end","top","right","bottom","left"],"inset-x":["right","left"],"inset-y":["top","bottom"],flex:["basis","grow","shrink"],gap:["gap-x","gap-y"],p:["px","py","ps","pe","pt","pr","pb","pl"],px:["pr","pl"],py:["pt","pb"],m:["mx","my","ms","me","mt","mr","mb","ml"],mx:["mr","ml"],my:["mt","mb"],size:["w","h"],"font-size":["leading"],"fvn-normal":["fvn-ordinal","fvn-slashed-zero","fvn-figure","fvn-spacing","fvn-fraction"],"fvn-ordinal":["fvn-normal"],"fvn-slashed-zero":["fvn-normal"],"fvn-figure":["fvn-normal"],"fvn-spacing":["fvn-normal"],"fvn-fraction":["fvn-normal"],"line-clamp":["display","overflow"],rounded:["rounded-s","rounded-e","rounded-t","rounded-r","rounded-b","rounded-l","rounded-ss","rounded-se","rounded-ee","rounded-es","rounded-tl","rounded-tr","rounded-br","rounded-bl"],"rounded-s":["rounded-ss","rounded-es"],"rounded-e":["rounded-se","rounded-ee"],"rounded-t":["rounded-tl","rounded-tr"],"rounded-r":["rounded-tr","rounded-br"],"rounded-b":["rounded-br","rounded-bl"],"rounded-l":["rounded-tl","rounded-bl"],"border-spacing":["border-spacing-x","border-spacing-y"],"border-w":["border-w-s","border-w-e","border-w-t","border-w-r","border-w-b","border-w-l"],"border-w-x":["border-w-r","border-w-l"],"border-w-y":["border-w-t","border-w-b"],"border-color":["border-color-s","border-color-e","border-color-t","border-color-r","border-color-b","border-color-l"],"border-color-x":["border-color-r","border-color-l"],"border-color-y":["border-color-t","border-color-b"],"scroll-m":["scroll-mx","scroll-my","scroll-ms","scroll-me","scroll-mt","scroll-mr","scroll-mb","scroll-ml"],"scroll-mx":["scroll-mr","scroll-ml"],"scroll-my":["scroll-mt","scroll-mb"],"scroll-p":["scroll-px","scroll-py","scroll-ps","scroll-pe","scroll-pt","scroll-pr","scroll-pb","scroll-pl"],"scroll-px":["scroll-pr","scroll-pl"],"scroll-py":["scroll-pt","scroll-pb"],touch:["touch-x","touch-y","touch-pz"],"touch-x":["touch"],"touch-y":["touch"],"touch-pz":["touch"]},conflictingClassGroupModifiers:{"font-size":["leading"]}}},Rb=fb(Mb);function ee(...s){return Rb(Xv(s))}function Lo(s){return s?s.replace(/127\.0\.0\.1|localhost/g,"192.168.178.151"):""}function ci({value:s,label:o,detail:i}){const d=2*Math.PI*24,f=d-Math.min(s,100)/100*d,m=s>90?"stroke-red-500":s>75?"stroke-amber-500":"stroke-primary";return n.jsxs("div",{className:"flex flex-col items-center gap-1.5 p-2 bg-background/20 rounded-xl border border-border/40",children:[n.jsxs("div",{className:"relative flex h-16 w-16 items-center justify-center",children:[n.jsxs("svg",{className:"absolute inset-0 h-full w-full -rotate-90",children:[n.jsx("circle",{cx:"32",cy:"32",r:24,className:"stroke-muted fill-none",strokeWidth:"4.5"}),n.jsx("circle",{cx:"32",cy:"32",r:24,className:ee("fill-none transition-all duration-700 ease-out",m),strokeWidth:"4.5",strokeDasharray:d,strokeDashoffset:f,strokeLinecap:"round"})]}),n.jsxs("span",{className:"text-xs font-mono font-bold tracking-tight text-foreground",children:[Math.round(s),"%"]})]}),n.jsx("span",{className:"text-[11px] font-semibold text-muted-foreground uppercase tracking-wider",children:o}),i&&n.jsx("span",{className:"text-[10px] font-mono text-muted-foreground/80",children:i})]})}function Ob(){const{data:s}=mc(3e3);return n.jsxs("div",{className:"md:col-span-2 flex flex-col justify-between rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/15",children:[n.jsxs("div",{children:[n.jsxs("div",{className:"flex items-center gap-2 mb-4",children:[n.jsx(Ot,{className:"h-4.5 w-4.5 text-primary"}),n.jsx("h2",{className:"text-sm font-semibold tracking-wide uppercase text-foreground",children:"System-Status"})]}),s?n.jsxs("div",{className:"grid grid-cols-2 gap-3 sm:grid-cols-4",children:[n.jsx(ci,{value:s.cpu.percent,label:"CPU",detail:s.cpu.cores?`${s.cpu.cores} Cores`:void 0}),n.jsx(ci,{value:s.ram.percent,label:"RAM",detail:`${St(s.ram.used)} / ${St(s.ram.total)} GB`}),s.gpu&&s.gpu.busy_percent!=null&&s.gpu.gtt_used!=null&&s.gpu.gtt_total!=null&&n.jsx(ci,{value:s.gpu.busy_percent,label:"GPU",detail:`${St(s.gpu.gtt_used)} / ${St(s.gpu.gtt_total)} GB`}),s.disk&&n.jsx(ci,{value:s.disk.percent,label:"Disk",detail:`${St(s.disk.used)} / ${St(s.disk.total)} GB`})]}):n.jsx("div",{className:"h-28 flex items-center justify-center text-xs text-muted-foreground",children:"Lade Systemdaten…"})]}),(s==null?void 0:s.temp)&&(s.temp.cpu||s.temp.gpu)&&n.jsxs("div",{className:"mt-4 flex gap-4 text-xs font-mono text-muted-foreground/80 border-t border-border/30 pt-3",children:[s.temp.cpu!=null&&n.jsxs("span",{children:["CPU Temp: ",s.temp.cpu," °C"]}),s.temp.gpu!=null&&n.jsxs("span",{children:["GPU Temp: ",s.temp.gpu," °C"]})]})]})}function bm({type:s,title:o,message:i,defaultValue:u,onConfirm:d,onCancel:f}){const m=g.useRef(null);return n.jsx("div",{className:"fixed inset-0 z-[99] bg-black/60 backdrop-blur-sm flex items-center justify-center p-4",children:n.jsxs("div",{className:"w-full max-w-sm rounded-2xl border border-border/80 bg-card p-6 shadow-2xl space-y-4 animate-in fade-in zoom-in-95 duration-200",children:[n.jsxs("div",{className:"flex items-center justify-between border-b border-border/20 pb-2",children:[n.jsx("h3",{className:"text-xs font-bold uppercase tracking-wider text-primary",children:o}),n.jsx("button",{onClick:f||(()=>d()),className:"p-1 rounded hover:bg-accent text-muted-foreground hover:text-foreground cursor-pointer",children:n.jsx(Rn,{className:"h-4 w-4"})})]}),n.jsx("p",{className:"text-xs text-muted-foreground leading-relaxed",children:i}),s==="prompt"&&n.jsx("input",{ref:m,type:"text",defaultValue:u,className:"w-full h-9 px-3 text-xs bg-background/40 border border-border/60 rounded-lg outline-none focus:border-primary transition-colors text-foreground",autoFocus:!0,onKeyDown:p=>{var b;p.key==="Enter"&&d((b=m.current)==null?void 0:b.value)}}),n.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[(s==="confirm"||s==="prompt")&&n.jsx("button",{onClick:f,className:"h-8 px-4 flex items-center justify-center text-xs font-semibold text-muted-foreground border border-border/60 bg-background/20 hover:bg-accent rounded-lg transition-colors cursor-pointer",children:"Abbrechen"}),n.jsx("button",{onClick:()=>{var b;const p=s==="prompt"?(b=m.current)==null?void 0:b.value:void 0;d(p)},className:"h-8 px-4 flex items-center justify-center text-xs font-semibold text-primary-foreground bg-primary hover:bg-primary/95 rounded-lg transition-colors cursor-pointer",children:s==="confirm"?"Ja, fortfahren":s==="prompt"?"Übernehmen":"OK"})]})]})})}function Tn(){const[s,o]=g.useState(null),i=g.useCallback(()=>o(null),[]),u=g.useCallback((p,b,x)=>{o({type:"alert",title:p,message:b,onConfirm:()=>{o(null),x==null||x()}})},[]),d=g.useCallback((p,b,x,j)=>{o({type:"confirm",title:p,message:b,onConfirm:()=>{o(null),x()},onCancel:()=>{o(null),j==null||j()}})},[]),f=g.useCallback((p,b,x,j,w)=>{o({type:"prompt",title:p,message:b,defaultValue:x,onConfirm:_=>{o(null),j(_)},onCancel:()=>{o(null),w==null||w()}})},[]),m=s?n.jsx(bm,{...s}):null;return{showAlert:u,showConfirm:d,showPrompt:f,close:i,dialogElement:m}}function Db(){const s=tn(),{data:o}=gc(3e3),{data:i=[]}=cm(3e3),{showConfirm:u,dialogElement:d}=Tn(),[f,m]=g.useState(""),[p,b]=g.useState(!1),[x,j]=g.useState(""),[w,_]=g.useState(!1),[M,z]=g.useState({open:!1,actionPath:"",actionLabel:""}),v=()=>{s.invalidateQueries({queryKey:Ye.updates}),s.invalidateQueries({queryKey:Ye.jobs}),s.invalidateQueries({queryKey:Ye.models})};async function S(D,$,H,ae){m(`${$} wird ausgeführt...`),b(!0);try{const te={...H},fe=await we(D,{method:"POST",body:JSON.stringify(te)});if(fe.status==="password_required"||fe.status==="incorrect_password"){z({open:!0,actionPath:D,actionLabel:$,payload:H,error:fe.status==="incorrect_password"?"Falsches Sudo-Passwort. Bitte erneut versuchen.":void 0}),m("");return}fe.job_id?m(`${$} gestartet (Job-ID: ${fe.job_id})`):fe.ok?m(`${$} erfolgreich ausgeführt.`):m(`Fehler: ${fe.err||"Unbekannter Fehler"}`),v()}catch(te){m(`Fehler bei ${$}: ${te.message}`)}finally{b(!1)}}async function O(){_(!0);try{const D={...M.payload,sudo_password:x},$=await we(M.actionPath,{method:"POST",body:JSON.stringify(D)});if($.status==="password_required"||$.status==="incorrect_password"){z(H=>({...H,error:"Falsches Sudo-Passwort. Bitte erneut versuchen."}));return}$.job_id?m(`${M.actionLabel} gestartet (Job-ID: ${$.job_id})`):$.ok?m(`${M.actionLabel} erfolgreich ausgeführt.`):m(`Fehler: ${$.err||"Unbekannter Fehler"}`),z({open:!1,actionPath:"",actionLabel:""}),j(""),v()}catch(D){m(`Fehler: ${D.message}`),z({open:!1,actionPath:"",actionLabel:""}),j("")}finally{_(!1)}}async function F(D,$){m(`Upgrade für ${D} wird gestartet...`);try{await we("/api/models/install",{method:"POST",body:JSON.stringify({repo:D,role:$,quant:"Q4_K_M",jinja:!0})}),m("Upgrade-Download gestartet."),v()}catch(H){m(`Upgrade fehlgeschlagen: ${H.message}`)}}const B=i.find(D=>D.label.includes("OS-Update")&&(D.state==="running"||D.state==="queued")),I=i.find(D=>D.label.includes("Engine-Update")&&(D.state==="running"||D.state==="queued"));return n.jsxs("div",{className:"rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/15 flex flex-col justify-between",children:[M.open&&n.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm p-4",children:n.jsxs("div",{className:"w-full max-w-sm rounded-2xl border border-border/60 bg-card/90 backdrop-blur-xl p-5 shadow-2xl space-y-4",children:[n.jsxs("div",{className:"flex items-center justify-between border-b border-border/20 pb-2",children:[n.jsx("span",{className:"text-xs font-bold uppercase tracking-wider text-primary font-space",children:"Sudo-Passwort erforderlich"}),n.jsx("button",{onClick:()=>{z({open:!1,actionPath:"",actionLabel:""}),j("")},className:"p-1 rounded hover:bg-accent text-muted-foreground hover:text-foreground cursor-pointer",children:n.jsx(Rn,{className:"h-4 w-4"})})]}),n.jsxs("p",{className:"text-[10px] text-muted-foreground leading-normal",children:["Für die Aktion ",n.jsx("strong",{children:M.actionLabel})," wird das Administrator-Passwort (Sudo) auf der Box benötigt."]}),n.jsxs("div",{className:"space-y-2",children:[n.jsx("input",{type:"password",value:x,onChange:D=>j(D.target.value),placeholder:"Sudo-Passwort eingeben...",className:"w-full h-9 rounded-lg border border-border/60 bg-background/40 px-3 text-xs outline-none focus:ring-1 focus:ring-primary/50 text-foreground",onKeyDown:D=>D.key==="Enter"&&O(),autoFocus:!0}),M.error&&n.jsx("div",{className:"text-[10px] font-semibold text-red-400",children:M.error})]}),n.jsxs("div",{className:"flex gap-2 justify-end",children:[n.jsx("button",{onClick:()=>{z({open:!1,actionPath:"",actionLabel:""}),j("")},className:"h-8 px-3 rounded-lg border border-border/60 bg-background/25 text-[10px] font-bold uppercase hover:bg-accent transition-all cursor-pointer",children:"Abbrechen"}),n.jsx("button",{onClick:O,disabled:!x||w,className:"h-8 px-4 rounded-lg bg-primary text-primary-foreground text-[10px] font-bold uppercase hover:opacity-90 transition-all disabled:opacity-50 cursor-pointer flex items-center justify-center gap-1.5",children:w?"Prüfe...":"Ausführen"})]})]})}),n.jsxs("div",{className:"space-y-4",children:[n.jsxs("div",{className:"flex items-center justify-between flex-wrap gap-2 border-b border-border/20 pb-2",children:[n.jsxs("div",{className:"flex items-center gap-2",children:[n.jsx(T0,{className:"h-4.5 w-4.5 text-primary"}),n.jsx("h2",{className:"text-sm font-semibold tracking-wide uppercase text-foreground",children:"Updates & Pflege"})]}),(o==null?void 0:o.last_check)&&n.jsxs("span",{className:"text-[9px] text-muted-foreground/80 font-mono",children:["Zuletzt gesucht: ",new Date(o.last_check*1e3).toLocaleString("de-DE",{day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit"})]})]}),o?n.jsxs("div",{className:"space-y-3",children:[n.jsxs("div",{className:"space-y-1.5",children:[n.jsxs("div",{className:ee("flex items-center justify-between px-3 py-1.5 rounded-lg border text-xs",o.os>0?"border-amber-500/30 bg-amber-500/5 text-amber-400 font-semibold":"border-border/30 bg-background/25 text-muted-foreground"),children:[n.jsx("span",{children:"OS-Pakete"}),n.jsx("span",{className:"font-mono",children:o.os>0?`${o.os} verfügbar`:"aktuell"})]}),n.jsxs("div",{className:ee("flex items-center justify-between px-3 py-1.5 rounded-lg border text-xs",o.engine>0?"border-amber-500/30 bg-amber-500/5 text-amber-400 font-semibold":"border-border/30 bg-background/25 text-muted-foreground"),children:[n.jsx("span",{children:"Engine (llama.cpp)"}),n.jsx("span",{className:"font-mono",children:o.engine>0?"Update verfügbar":"aktuell"})]}),n.jsxs("div",{className:ee("flex items-center justify-between px-3 py-1.5 rounded-lg border text-xs",o.models>0?"border-primary/30 bg-primary/5 text-primary font-semibold animate-pulse":"border-border/30 bg-background/25 text-muted-foreground"),children:[n.jsx("span",{children:"Modell-Upgrades"}),n.jsx("span",{className:"font-mono",children:o.models>0?`${o.models} verfügbar`:"aktuell"})]})]}),n.jsxs("div",{className:"grid grid-cols-2 gap-2 border-t border-border/20 pt-3",children:[n.jsx("button",{onClick:()=>S("/api/maintenance/os-update","OS-Update"),disabled:p||!!B,className:"h-8 px-2 rounded-lg border border-border/60 bg-background/20 text-[10px] font-bold uppercase hover:border-primary/50 hover:bg-background/40 transition-all cursor-pointer disabled:opacity-50 flex items-center justify-center gap-1",children:B?n.jsxs(n.Fragment,{children:[n.jsx(Pn,{className:"h-3 w-3 animate-spin text-primary"}),n.jsxs("span",{children:["Aktiv (",B.progress??0,"%)"]})]}):n.jsx("span",{children:"OS Update"})}),n.jsx("button",{onClick:()=>S("/api/maintenance/engine-update","Engine-Update"),disabled:p||!!I,className:"h-8 px-2 rounded-lg border border-border/60 bg-background/20 text-[10px] font-bold uppercase hover:border-primary/50 hover:bg-background/40 transition-all cursor-pointer disabled:opacity-50 flex items-center justify-center gap-1",children:I?n.jsxs(n.Fragment,{children:[n.jsx(Pn,{className:"h-3 w-3 animate-spin text-primary"}),n.jsxs("span",{children:["Aktiv (",I.progress??0,"%)"]})]}):n.jsx("span",{children:"Engine Update"})})]}),n.jsxs("button",{onClick:()=>{u("Host-System neu starten?","Bist du sicher, dass du das Host-System neu starten willst?",()=>S("/api/maintenance/reboot","Reboot"))},disabled:p,className:"w-full h-8 flex items-center justify-center gap-1.5 rounded-lg border border-red-500/30 bg-red-500/5 text-red-400 text-[10px] font-bold uppercase hover:bg-red-500/10 transition-all cursor-pointer disabled:opacity-50",children:[n.jsx(Eh,{className:"h-3.5 w-3.5"}),n.jsx("span",{children:"Host Reboot"})]}),o.model_list.length>0&&n.jsxs("div",{className:"space-y-1.5 border-t border-border/20 pt-3",children:[n.jsx("div",{className:"text-[9px] uppercase font-bold text-muted-foreground/60 tracking-wider",children:"Verfügbare Modell-Upgrades:"}),n.jsx("div",{className:"max-h-24 overflow-y-auto space-y-1.5 pr-1 scrollbar-thin",children:o.model_list.map(D=>n.jsxs("div",{className:"flex items-center justify-between p-2 rounded bg-background/25 border border-border/30 text-[10px] font-mono text-muted-foreground",children:[n.jsxs("span",{className:"truncate flex-1 mr-1.5",title:`${D.role}: ${D.repo}`,children:[n.jsx("span",{className:"text-primary font-bold uppercase",children:D.role}),": ",D.repo.split("/").pop()]}),n.jsxs("button",{onClick:()=>F(D.repo,D.role),className:"px-2 py-0.5 text-[8px] font-bold uppercase rounded bg-primary text-primary-foreground hover:opacity-90 transition-all cursor-pointer flex items-center gap-0.5",children:[n.jsx(_n,{className:"h-2.5 w-2.5"})," Laden"]})]},D.repo))})]})]}):n.jsx("div",{className:"h-24 flex items-center justify-center text-xs text-muted-foreground",children:"Lade Updates..."}),f&&n.jsx("div",{className:"text-[10px] font-mono text-primary font-medium bg-primary/5 p-2 rounded-lg border border-primary/20 break-all leading-normal",children:f}),n.jsxs("div",{className:"text-[9px] text-muted-foreground/60 leading-normal border-t border-border/10 pt-2.5 flex items-start gap-1",children:[n.jsx(Mn,{className:"h-3 w-3 shrink-0 text-muted-foreground/50 mt-0.5"}),n.jsxs("span",{children:["OS-Update & Reboot benötigen NOPASSWD in ",n.jsx("code",{children:"/etc/sudoers"})," (z.B. ",n.jsx("code",{children:"hitonabi ALL=(root) NOPASSWD:..."}),") oder ein gültiges Sudo-Passwort per Pop-up."]})]})]}),n.jsx("div",{className:"mt-4 border-t border-border/30 pt-3 shrink-0",children:n.jsx("button",{onClick:()=>window.dispatchEvent(new CustomEvent("open-system-drawer")),className:"w-full h-8 flex items-center justify-center gap-1.5 rounded-lg bg-primary text-primary-foreground text-xs font-semibold hover:opacity-90 transition-all cursor-pointer shadow-md shadow-primary/10",children:"System-Zentrale öffnen"})}),d]})}function Tb(){const s=tn(),{data:o}=dm(3e3),{data:i}=Vo(),{showAlert:u,dialogElement:d}=Tn(),[f,m]=g.useState(!1),p=(i==null?void 0:i.models)??[];async function b(x){try{await we("/api/agent/brain",{method:"POST",body:JSON.stringify({model:x})}),u("Erfolgreich",`Hermes-Gehirn wurde auf '${x}' geändert. Der Gateway-Dienst wurde neu gestartet.`),s.invalidateQueries({queryKey:Ye.agentStatus}),m(!1)}catch(j){u("Fehler",`Fehler beim Wechseln des Gehirns: ${j.message}`)}}return n.jsxs("div",{className:"rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/15 flex flex-col justify-between",children:[n.jsxs("div",{children:[n.jsxs("div",{className:"flex items-center justify-between mb-4",children:[n.jsxs("div",{className:"flex items-center gap-2",children:[n.jsx(Oo,{className:"h-4.5 w-4.5 text-primary"}),n.jsx("h2",{className:"text-sm font-semibold tracking-wide uppercase text-foreground",children:"Hermes Agent"})]}),(o==null?void 0:o.webui_url)&&n.jsxs("a",{href:Lo(o.webui_url),target:"_blank",rel:"noopener",className:ee("flex items-center gap-1 px-3 py-1 rounded-lg text-xs font-medium transition-all",o.webui_reachable?"bg-primary text-primary-foreground hover:opacity-90 shadow-md shadow-primary/20":"border border-border text-muted-foreground"),children:[n.jsx(xi,{className:"h-3 w-3"})," Hermes öffnen"]})]}),o?n.jsxs("div",{className:"space-y-3",children:[n.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[n.jsxs("div",{className:"p-3 bg-background/20 rounded-xl border border-border/40",children:[n.jsx("div",{className:"text-[10px] text-muted-foreground uppercase font-semibold",children:"Gateway"}),n.jsxs("div",{className:"flex items-center gap-2 mt-1",children:[n.jsx("span",{className:ee("h-2 w-2 rounded-full",o.gateway_reachable?"bg-emerald-500 animate-pulse":"bg-amber-500")}),n.jsx("span",{className:"text-xs font-medium",children:o.gateway_reachable?"Online":"Offline"})]})]}),n.jsxs("div",{className:"p-3 bg-background/20 rounded-xl border border-border/40",children:[n.jsx("div",{className:"text-[10px] text-muted-foreground uppercase font-semibold",children:"WebUI"}),n.jsxs("div",{className:"flex items-center gap-2 mt-1",children:[n.jsx("span",{className:ee("h-2 w-2 rounded-full",o.webui_reachable?"bg-emerald-500 animate-pulse":"bg-amber-500")}),n.jsx("span",{className:"text-xs font-medium",children:o.webui_reachable?"Online":"Offline"})]})]})]}),n.jsxs("div",{onClick:()=>m(!0),className:"p-3 bg-background/20 rounded-xl border border-border/40 hover:border-primary/45 hover:bg-background/30 transition-all duration-300 cursor-pointer group",children:[n.jsxs("div",{className:"flex justify-between items-center",children:[n.jsx("span",{className:"text-[10px] text-muted-foreground uppercase font-semibold",children:"Aktives Gehirn"}),n.jsxs("button",{className:"flex items-center gap-1 text-[9px] font-bold uppercase tracking-wider text-primary border border-primary/20 bg-primary/10 hover:bg-primary/20 px-1.5 py-0.5 rounded transition-all cursor-pointer font-space",children:[n.jsx(Ot,{className:"h-3 w-3"})," Ändern"]})]}),n.jsxs("div",{className:"text-xs font-medium mt-1 font-mono text-primary flex items-center gap-1.5",children:[n.jsx(To,{className:"h-3.5 w-3.5"}),o.brain_model?`model: ${o.brain_model}`:"model: auto"]})]})]}):n.jsx("div",{className:"h-28 flex items-center justify-center text-xs text-muted-foreground",children:"Lade Agenten-Status…"})]}),n.jsx("div",{className:"mt-3 text-[10px] text-muted-foreground/80 border-t border-border/30 pt-3",children:"Gedächtnis & Stack-Tools via MCP gekoppelt."}),o&&f&&n.jsx("div",{className:"fixed inset-0 z-50 bg-black/60 backdrop-blur-sm flex items-center justify-center p-4",children:n.jsxs("div",{className:"w-full max-w-md rounded-2xl border border-border/80 bg-card p-6 shadow-2xl space-y-4 animate-in fade-in zoom-in-95 duration-200",children:[n.jsxs("div",{className:"flex items-center justify-between border-b border-border/20 pb-2",children:[n.jsxs("h3",{className:"text-xs font-bold uppercase tracking-wider text-primary flex items-center gap-1.5",children:[n.jsx(Ot,{className:"h-4 w-4"}),n.jsx("span",{children:"Hermes-Gehirn konfigurieren"})]}),n.jsx("button",{onClick:()=>m(!1),className:"p-1 rounded hover:bg-accent text-muted-foreground hover:text-foreground cursor-pointer",children:n.jsx(Rn,{className:"h-4 w-4"})})]}),n.jsxs("p",{className:"text-xs text-muted-foreground leading-relaxed",children:['Das „Gehirn" ist das primäre LLM für Hermes. Wähle ein Modell aus deiner Bibliothek oder nutze ein Gateway-Alias (',n.jsx("code",{className:"text-primary font-semibold",children:"auto"})," / ",n.jsx("code",{className:"text-primary font-semibold",children:"fast"})," / ",n.jsx("code",{className:"text-primary font-semibold",children:"heavy"}),"):"]}),n.jsx("div",{className:"space-y-1.5 max-h-60 overflow-y-auto pr-1",children:["auto","fast","heavy",...p.map(x=>{var j;return((j=x.name.split("/").pop())==null?void 0:j.replace(".gguf",""))||x.name})].map(x=>{const j=["auto","fast","heavy"].includes(x);return n.jsxs("button",{onClick:()=>b(x),className:ee("w-full text-left px-3 py-2.5 rounded-lg text-xs hover:bg-accent flex items-center justify-between font-mono cursor-pointer border border-border/30",o.brain_model===x||!o.brain_model&&x==="auto"?"text-primary font-bold bg-primary/10 border-primary/30":"text-foreground bg-background/20"),children:[n.jsxs("div",{className:"flex flex-col text-left",children:[n.jsx("span",{className:"font-semibold truncate max-w-[280px]",children:x}),n.jsx("span",{className:"text-[9px] text-muted-foreground mt-0.5",children:j?"Gateway Routing Alias":"Installiertes GGUF Modell"})]}),(o.brain_model===x||!o.brain_model&&x==="auto")&&n.jsx(Ms,{className:"h-4 w-4 shrink-0 text-primary"})]},x)})})]})}),d]})}const Ab=["fast","heavy","coder","reasoning","vision","scout"];function zb(){const{data:s}=Vo(3e3),o=(s==null?void 0:s.models)??[],i=(s==null?void 0:s.running)??[];return n.jsxs("div",{className:"rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/15 flex flex-col justify-between",children:[n.jsxs("div",{children:[n.jsxs("div",{className:"flex items-center gap-2 mb-4",children:[n.jsx(To,{className:"h-4.5 w-4.5 text-primary"}),n.jsx("h2",{className:"text-sm font-semibold tracking-wide uppercase text-foreground",children:"Rollen-Belegung"})]}),n.jsx("div",{className:"space-y-2 max-h-48 overflow-y-auto pr-1 scrollbar-thin",children:Ab.map(u=>{var m;const d=o.find(p=>p.role===u),f=d?i.includes(d.name):!1;return n.jsxs("div",{className:ee("flex items-center justify-between p-2 rounded-xl border transition-all duration-300",f?"border-emerald-500/30 bg-emerald-500/5 shadow-sm shadow-emerald-500/5":d?"border-primary/20 bg-primary/5":"border-border/30 bg-background/10 opacity-60"),children:[n.jsx("div",{className:"min-w-0 flex-1 mr-2",children:n.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[n.jsx("span",{className:ee("text-[9px] font-semibold uppercase px-1.5 py-0.5 rounded font-mono border tracking-wider shrink-0",u==="fast"?"bg-cyan-500/15 text-cyan-400 border-cyan-500/25":u==="heavy"?"bg-amber-500/15 text-amber-400 border-amber-500/25":u==="coder"?"bg-violet-500/15 text-violet-400 border-violet-500/25":u==="reasoning"?"bg-emerald-500/15 text-emerald-400 border-emerald-500/25":u==="vision"?"bg-pink-500/15 text-pink-400 border-pink-500/25":"bg-teal-500/15 text-teal-400 border-teal-500/25"),children:u}),n.jsxs("div",{className:"flex flex-col min-w-0",children:[n.jsx("span",{className:"text-xs font-semibold truncate font-mono text-foreground",children:d?(m=d.name.split("/").pop())==null?void 0:m.replace(/\.gguf$/i,""):"nicht zugewiesen"}),d&&n.jsxs("div",{className:"flex gap-1 items-center mt-0.5 flex-wrap",children:[d.prompt_cache&&n.jsx("span",{className:"text-[7px] leading-none font-mono font-bold bg-cyan-500/10 text-cyan-400 border border-cyan-500/20 px-1 py-0.5 rounded",title:"Prompt Caching aktiv",children:"PC"}),d.spec_draft_model&&n.jsx("span",{className:"text-[7px] leading-none font-mono font-bold bg-emerald-500/10 text-emerald-400 border border-emerald-500/20 px-1 py-0.5 rounded",title:`Speculative Decoding aktiv (Draft: ${d.spec_draft_model})`,children:"SPEC"}),d.parallel_slots>1&&n.jsxs("span",{className:"text-[7px] leading-none font-mono font-bold bg-violet-500/10 text-violet-400 border border-violet-500/20 px-1 py-0.5 rounded",title:`${d.parallel_slots} parallele Slots aktiv`,children:["SLOTS: ",d.parallel_slots]})]})]})]})}),n.jsx("div",{className:"flex items-center gap-1.5 shrink-0",children:d?f?n.jsxs("span",{className:"flex items-center gap-1 text-[8px] font-semibold text-emerald-400 uppercase tracking-wider font-mono",children:[n.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-emerald-500 animate-pulse"})," warm"]}):n.jsx("span",{className:"text-[8px] font-semibold text-muted-foreground uppercase tracking-wider font-mono",children:"bereit"}):n.jsx("span",{className:"text-[8px] font-semibold text-muted-foreground/60 uppercase tracking-wider font-mono",children:"—"})})]},u)})})]}),n.jsx("div",{className:"mt-4 text-[10px] text-muted-foreground/80 border-t border-border/30 pt-3",children:"Laden erfolgt automatisch per Auto-Swap."})]})}function Lb(){const s=tn(),{data:o=[]}=pm({limit:3}),[i,u]=g.useState(""),[d,f]=g.useState("stable"),[m,p]=g.useState(!1);async function b(){if(!(!i.trim()||m)){p(!0);try{await we("/api/memory",{method:"POST",body:JSON.stringify({content:i,category:d,source:"dashboard"})}),u(""),s.invalidateQueries({queryKey:["memory"]})}catch(x){console.error(x)}finally{p(!1)}}}return n.jsxs("div",{className:"rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/15 flex flex-col justify-between",children:[n.jsxs("div",{children:[n.jsxs("div",{className:"flex items-center gap-2 mb-4",children:[n.jsx(Do,{className:"h-4.5 w-4.5 text-primary"}),n.jsx("h2",{className:"text-sm font-semibold tracking-wide uppercase text-foreground",children:"Gedächtnis"})]}),n.jsxs("div",{className:"space-y-3",children:[n.jsx("textarea",{value:i,onChange:x=>u(x.target.value),placeholder:"Fakt / Regel im Pool speichern...",rows:2,className:"w-full resize-none rounded-xl border border-border/50 bg-background/30 p-2 text-[10px] outline-none focus:ring-1 focus:ring-primary transition-all leading-normal"}),n.jsxs("div",{className:"flex items-center gap-2 justify-between",children:[n.jsxs("select",{value:d,onChange:x=>f(x.target.value),className:"h-7 rounded-lg border border-border/50 bg-background/50 px-2 text-[10px] outline-none cursor-pointer",children:[n.jsx("option",{value:"stable",children:"🔵 Fakt"}),n.jsx("option",{value:"instruction",children:"📋 Regel"}),n.jsx("option",{value:"user",children:"👤 User"}),n.jsx("option",{value:"versioned",children:"🟡 Version"})]}),n.jsxs("button",{onClick:b,disabled:!i.trim()||m,className:"flex h-7 items-center gap-1 rounded-lg bg-primary px-3 text-[10px] font-semibold text-primary-foreground hover:opacity-90 disabled:opacity-50 transition-all cursor-pointer",children:[n.jsx(Ch,{className:"h-3.5 w-3.5"})," Speichern"]})]})]}),n.jsxs("div",{className:"mt-3.5 space-y-1.5",children:[n.jsx("div",{className:"text-[9px] text-muted-foreground uppercase font-bold tracking-wider",children:"Zuletzt gespeichert:"}),n.jsx("div",{className:"max-h-20 overflow-y-auto space-y-1 pr-1 scrollbar-thin",children:o.length===0?n.jsx("div",{className:"text-[10px] text-muted-foreground/75 py-1",children:"Keine Einträge vorhanden."}):o.map(x=>n.jsxs("div",{className:"text-[10px] bg-background/10 border border-border/30 rounded p-1.5 flex items-start gap-1.5",children:[n.jsx("span",{className:"shrink-0 text-[8px] font-mono text-muted-foreground/80 px-1 py-0.5 rounded bg-muted/20",children:x.category}),n.jsx("span",{className:"truncate flex-1 text-muted-foreground hover:text-foreground transition-colors",title:x.content,children:x.content})]},x.id))})]})]}),n.jsx("div",{className:"mt-4 text-[10px] text-muted-foreground/80 border-t border-border/30 pt-3",children:"Steht allen Clients per MCP zur Verfügung."})]})}function Ib(){var o;const{data:s}=Zv(3e3);return n.jsxs("div",{className:"rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/15 flex flex-col justify-between",children:[n.jsxs("div",{children:[n.jsxs("div",{className:"flex items-center gap-2 mb-4",children:[n.jsx(w0,{className:"h-4.5 w-4.5 text-primary animate-pulse"}),n.jsx("h2",{className:"text-sm font-semibold tracking-wide uppercase text-foreground",children:"Effizienz & Ersparnis"})]}),s?n.jsxs("div",{className:"space-y-4",children:[n.jsxs("div",{className:"grid grid-cols-2 gap-2.5",children:[n.jsxs("div",{className:"p-3 bg-background/20 rounded-xl border border-border/40 text-left",children:[n.jsx("div",{className:"text-[8px] uppercase tracking-wider font-semibold text-muted-foreground/60",children:"Geld gespart"}),n.jsxs("div",{className:"text-base font-bold text-emerald-400 mt-0.5 tracking-tight font-space",children:[s.saved_eur.toLocaleString("de-DE",{minimumFractionDigits:2})," €"]}),n.jsxs("div",{className:"text-[8px] text-muted-foreground/80 mt-0.5 font-mono",children:["(",s.saved_usd.toLocaleString("en-US",{minimumFractionDigits:2})," $)"]})]}),n.jsxs("div",{className:"p-3 bg-background/20 rounded-xl border border-border/40 text-left",children:[n.jsx("div",{className:"text-[8px] uppercase tracking-wider font-semibold text-muted-foreground/60",children:"Gesamt-Tokens"}),n.jsx("div",{className:"text-base font-bold text-primary mt-0.5 tracking-tight font-space",children:s.total_tokens.toLocaleString("de-DE")}),n.jsx("div",{className:"text-[8px] text-muted-foreground/80 mt-0.5 font-mono",children:"(Lokale Inferenz)"})]})]}),n.jsxs("div",{className:"space-y-2 border-t border-border/20 pt-3 text-[10px] text-muted-foreground",children:[n.jsxs("div",{className:"flex justify-between items-center font-mono",children:[n.jsx("span",{children:"Input (Prompts):"}),n.jsxs("span",{className:"font-semibold text-foreground",children:[s.prompt_tokens.toLocaleString("de-DE")," tkn"]})]}),n.jsxs("div",{className:"flex justify-between items-center font-mono",children:[n.jsx("span",{children:"Output (Antworten):"}),n.jsxs("span",{className:"font-semibold text-foreground",children:[s.completion_tokens.toLocaleString("de-DE")," tkn"]})]})]})]}):n.jsx("div",{className:"h-28 flex items-center justify-center text-xs text-muted-foreground",children:"Lade Statistiken…"})]}),n.jsxs("div",{className:"mt-4 text-[9px] text-muted-foreground/70 border-t border-border/30 pt-2.5 leading-normal",children:["Berechnet im Vergleich zu Cloud-APIs von Juni 2026",(o=s==null?void 0:s.pricing)!=null&&o.heavy?` (Ø ${s.pricing.heavy.in.toFixed(2).replace(".",",")} $ / ${s.pricing.heavy.out.toFixed(2).replace(".",",")} $ pro 1M tkn).`:"."]})]})}function Fb(){return n.jsxs("div",{className:"space-y-6",children:[n.jsxs("div",{children:[n.jsx("h1",{className:"text-2xl font-space font-bold tracking-tight bg-gradient-to-r from-foreground via-foreground to-primary bg-clip-text text-transparent",children:"Zentrale"}),n.jsx("p",{className:"text-sm text-muted-foreground",children:"Aktueller Status von System, Modellen und Agent."})]}),n.jsxs("div",{className:"grid gap-6 md:grid-cols-3",children:[n.jsx(Ob,{}),n.jsx(Db,{})]}),n.jsxs("div",{className:"grid gap-6 md:grid-cols-2 xl:grid-cols-4",children:[n.jsx(Tb,{}),n.jsx(zb,{}),n.jsx(Lb,{}),n.jsx(Ib,{})]})]})}function Ub(){const s=tn(),{data:o=[]}=cm(2e3),{showAlert:i,dialogElement:u}=Tn();async function d(p){try{await we(`/api/jobs/${p}/cancel`,{method:"POST"}),s.invalidateQueries({queryKey:Ye.jobs})}catch(b){i("Fehler",b.message)}}const f=o.filter(p=>p.state==="running"||p.state==="queued"),m=o.filter(p=>p.state!=="running"&&p.state!=="queued").slice(-3);return f.length===0&&m.length===0?null:n.jsxs("div",{className:"space-y-3 rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-4 shadow-lg shadow-black/10",children:[n.jsx("div",{className:"text-[11px] font-semibold text-muted-foreground uppercase tracking-wider",children:"Aktive Downloads"}),f.map(p=>n.jsxs("div",{className:"space-y-1.5 p-3 rounded-xl bg-background/20 border border-border/40",children:[n.jsxs("div",{className:"flex justify-between items-center text-xs",children:[n.jsx("span",{className:"font-semibold truncate max-w-[250px]",children:p.label}),n.jsxs("div",{className:"flex items-center gap-3",children:[n.jsxs("span",{className:"text-muted-foreground font-mono",children:[p.progress??0,"% • ",tc(p.done_bytes),"/",tc(p.total_bytes),p.eta_s?` • ETA ${Jv(p.eta_s)}`:""]}),n.jsx("button",{onClick:()=>d(p.id),className:"text-[10px] text-red-400 hover:text-red-300 font-semibold border border-red-500/25 bg-red-500/5 px-2 py-0.5 rounded transition-all cursor-pointer",children:"Abbrechen"})]})]}),n.jsx("div",{className:"h-1.5 overflow-hidden rounded-full bg-muted",children:n.jsx("div",{className:"h-full rounded-full bg-primary transition-all duration-500",style:{width:`${p.progress??0}%`}})})]},p.id)),m.map(p=>n.jsxs("div",{className:"flex justify-between items-center text-xs text-muted-foreground px-1",children:[n.jsx("span",{className:"truncate",children:p.label}),n.jsx("span",{className:ee("font-semibold text-[10px] px-1.5 py-0.5 rounded uppercase font-mono",p.state==="done"?"bg-emerald-500/10 text-emerald-400":"bg-amber-500/10 text-amber-400"),children:p.state})]},p.id)),u]})}function xn({children:s,tone:o="muted"}){const i={muted:"bg-muted text-muted-foreground",primary:"bg-primary/15 text-primary",warn:"bg-amber-500/15 text-amber-500"};return n.jsx("span",{className:`rounded px-1.5 py-0.5 text-[11px] font-medium ${i[o]}`,children:s})}function Qp({caps:s}){return s?n.jsxs("span",{className:"inline-flex flex-wrap gap-1",children:[s.coder&&n.jsx(xn,{children:"💻 Code"}),s.vision&&n.jsx(xn,{children:"👁 Bild"}),s.reasoning&&n.jsx(xn,{children:"🧠 Reason"}),s.moe&&n.jsxs(xn,{tone:"primary",children:["🧩 MoE",s.active_b?`·${s.active_b}b`:""]}),s.tools==="yes"&&n.jsx(xn,{tone:"primary",children:"🛠 Tools"}),s.tools==="likely"&&n.jsx(xn,{tone:"warn",children:"🛠 Tools?"}),s.embedding&&n.jsx(xn,{children:"🔢 Embed"})]}):null}const $b=["fast","heavy","coder","reasoning","agent","vision","scout"];function Bb({fit:s}){const o={perfect:"bg-emerald-500/15 text-emerald-400 border border-emerald-500/20",marginal:"bg-amber-500/15 text-amber-400 border border-amber-500/20",too_tight:"bg-red-500/15 text-red-400 border border-red-500/20"}[s.level];return n.jsxs("span",{className:ee("rounded px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wider font-mono",o),children:[s.text," • ",s.req_gb," GB RAM"]})}function qp(s){const o=s.toLowerCase();return o.includes("qwen")?{name:"Qwen",color:"bg-purple-500/20 text-purple-300 border-purple-500/30",initial:"Q"}:o.includes("gemma")?{name:"Gemma",color:"bg-blue-500/20 text-blue-300 border-blue-500/30",initial:"G"}:o.includes("llama")?{name:"Llama",color:"bg-red-500/20 text-red-300 border-red-500/30",initial:"🦙"}:o.includes("mistral")||o.includes("mixtral")?{name:"Mistral",color:"bg-orange-500/20 text-orange-300 border-orange-500/30",initial:"M"}:o.includes("deepseek")?{name:"DeepSeek",color:"bg-cyan-500/20 text-cyan-300 border-cyan-500/30",initial:"D"}:o.includes("hermes")||o.includes("nous")?{name:"Hermes",color:"bg-amber-500/20 text-amber-300 border-amber-500/30",initial:"H"}:o.includes("phi")?{name:"Phi",color:"bg-emerald-500/20 text-emerald-300 border-emerald-500/30",initial:"Φ"}:{name:"Other",color:"bg-slate-500/20 text-slate-300 border-slate-500/30",initial:"AI"}}function Hb(){var An,As,zs,zn,Ls;const s=tn(),{data:o,isLoading:i,error:u}=Vo(4e3),{data:d}=qv(4e3),{data:f}=fm(),{data:m}=gc(4e3),{showAlert:p,showConfirm:b,showPrompt:x,dialogElement:j}=Tn(),w=(o==null?void 0:o.models)??[],_=(o==null?void 0:o.running)??[],M=u?String(u):"",z=()=>{s.invalidateQueries({queryKey:Ye.models}),s.invalidateQueries({queryKey:Ye.routing})},[v,S]=g.useState(null),[O,F]=g.useState(null),[B,I]=g.useState(!1),[D,$]=g.useState(null),[H,ae]=g.useState("grid"),[te,fe]=g.useState("all"),ke=w.filter(L=>te==="in_use"?!!L.role||_.includes(L.name):!0),[de,ze]=g.useState({width:800,height:360}),Ce=g.useRef(null),Le=g.useCallback(L=>{if(Ce.current&&(Ce.current.disconnect(),Ce.current=null),L){const ie=new ResizeObserver(je=>{if(!je||je.length===0)return;const De=je[0].contentRect;ze({width:De.width,height:De.height})});ie.observe(L),Ce.current=ie}},[]),Ee=de.width,Pe=de.height,K=L=>{const ie=Ee*.1,je=Pe*L,De=Ee*.5,He=Pe*.5,ir=Ee*.3,Ln=je,In=Ee*.3;return`M ${ie} ${je} C ${ir} ${Ln}, ${In} ${He}, ${De} ${He}`},X=L=>{const ie=Ee*.5,je=Pe*.5,De=Ee*.9,He=Pe*L,ir=Ee*.7,Ln=je,In=Ee*.7;return`M ${ie} ${je} C ${ir} ${Ln}, ${In} ${He}, ${De} ${He}`};async function Y(L){try{await we(`/api/models/${encodeURIComponent(L)}/load`,{method:"POST"}),z()}catch(ie){p("Fehler",`Fehler beim Laden des Modells: ${ie.message}`)}}async function P(L){try{await we(`/api/models/${encodeURIComponent(L)}/unload`,{method:"POST"}),z()}catch(ie){p("Fehler",`Fehler beim Entladen des Modells: ${ie.message}`)}}async function C(){try{await we("/api/models/unload",{method:"POST"}),z()}catch(L){p("Fehler",`Fehler beim Entladen aller Modelle: ${L.message}`)}}async function Z(L,ie){try{await we(`/api/models/${encodeURIComponent(ie)}/role`,{method:"POST",body:JSON.stringify({role:L||null})}),z()}catch(je){p("Fehler",`Fehler beim Zuweisen der Rolle: ${je.message||je}`)}}async function J(L,ie){x("Kontextlänge anpassen","Gib die gewünschte Kontextlänge in Tokens an:",String(ie||32768),async je=>{if(je)try{await we(`/api/models/${encodeURIComponent(L)}/ctx`,{method:"POST",body:JSON.stringify({ctx:parseInt(je,10)})}),z()}catch(De){p("Fehler",`Fehler beim Setzen des Kontexts: ${De.message||De}`)}})}async function q(L){b("Modell löschen?",`Modell '${L}' und alle zugehörigen GGUF-Dateien unwiderruflich von der Box löschen?`,async()=>{try{await we(`/api/models/${encodeURIComponent(L)}`,{method:"DELETE"}),z()}catch(ie){p("Fehler",`Fehler beim Löschen: ${ie.message||ie}`)}})}async function oe(L,ie,je,De){try{await we("/api/models/install",{method:"POST",body:JSON.stringify({repo:L,role:ie,quant:je,jinja:De})}),p("Herunterladen gestartet",`Download für '${L}' gestartet! Der Fortschritt wird oben angezeigt.`)}catch(He){p("Fehler",`Fehler beim Starten des Upgrades: ${He.message||He}`)}}async function pe(L){L&&(await navigator.clipboard.writeText(L),I(!0),setTimeout(()=>I(!1),1500))}if(i)return n.jsx("div",{className:"text-xs text-muted-foreground py-12 text-center",children:"Initialisiere HUD Cockpit…"});if(M)return n.jsxs("div",{className:"rounded-xl border border-red-500/20 bg-red-500/5 p-4 text-xs text-red-400",children:["Gateway oder Engine nicht erreichbar (",M,")."]});const ve=w.filter(L=>_.includes(L.name)),U=ve.reduce((L,ie)=>L+(ie.size_bytes||0),0),he=16*1024**3,gt=U>he?U*1.2:he,Ts=L=>w.find(ie=>ie.role===L),Zt=L=>{const ie=Ts(L);return ie?_.includes(ie.name):!1};return n.jsxs("div",{className:"space-y-8",children:[n.jsx("style",{children:` @keyframes flow-dash { to { stroke-dashoffset: -20; diff --git a/frontend/dist/index.html b/frontend/dist/index.html index 7e4dd19..72b8d99 100644 --- a/frontend/dist/index.html +++ b/frontend/dist/index.html @@ -7,7 +7,7 @@ Mission Control 2.0 - + diff --git a/frontend/src/views/ModelsView.tsx b/frontend/src/views/ModelsView.tsx index 0b0903f..7d178e3 100644 --- a/frontend/src/views/ModelsView.tsx +++ b/frontend/src/views/ModelsView.tsx @@ -1,1417 +1,8 @@ -import { useState, useRef, useCallback } from "react" -import { Download, Search, Trash2, Edit3, Star, Layers, Activity, HardDrive, X, Check, Copy, Bot, Eye, Code, Brain, Compass, ChevronDown, ChevronUp } from "lucide-react" -import { api } from "@/lib/api" -import { useModels, useRouting, useConnect, useUpdates, useDiscover, useQueryClient, qk } from "@/lib/queries" -import { useDialog } from "@/lib/useDialog" -import { CapsChips } from "@/components/CapsChips" +import { useState } from "react" import { cn } from "@/lib/utils" -import { fmtBytes, fmtSize, fmtCtx } from "@/lib/format" import { JobsBar } from "@/components/models/JobsBar" -import { FitBadge, getBrandInfo, ROLES } from "@/components/models/ModelBadges" - -function Cockpit() { - const qc = useQueryClient() - const { data: modelsResp, isLoading: loading, error: loadErr } = useModels(4_000) - const { data: routing } = useRouting(4_000) - const { data: connectData } = useConnect() - const { data: updates } = useUpdates(4_000) - const { showAlert, showConfirm, showPrompt, dialogElement } = useDialog() - const models = modelsResp?.models ?? [] - const running = modelsResp?.running ?? [] - const error = loadErr ? String(loadErr) : "" - const reload = () => { - qc.invalidateQueries({ queryKey: qk.models }) - qc.invalidateQueries({ queryKey: qk.routing }) - } - - // UI state - const [activeClient, setActiveClient] = useState<"roocode" | "cursor" | "opencode" | "zed" | "continue" | null>(null) - const [activeRoleForAssign, setActiveRoleForAssign] = useState(null) - const [copied, setCopied] = useState(false) - const [hoveredNode, setHoveredNode] = useState(null) - const [viewMode, setViewMode] = useState<"grid" | "list">("grid") - const [filterMode, setFilterMode] = useState<"all" | "in_use">("all") - - const filteredModels = models.filter((m) => { - if (filterMode === "in_use") { - return !!m.role || running.includes(m.name) - } - return true - }) - - // Canvas pixel tracking for pixel-perfect connection graph without non-uniform scaling - const [dimensions, setDimensions] = useState({ width: 800, height: 360 }) - const observerRef = useRef(null) - - const containerRef = useCallback((node: HTMLDivElement | null) => { - if (observerRef.current) { - observerRef.current.disconnect() - observerRef.current = null - } - if (node) { - const observer = new ResizeObserver((entries) => { - if (!entries || entries.length === 0) return - const rect = entries[0].contentRect - setDimensions({ width: rect.width, height: rect.height }) - }) - observer.observe(node) - observerRef.current = observer - } - }, []) - - const w = dimensions.width - const h = dimensions.height - - // Helper to generate curve from client to gateway - const getClientPath = (yPercent: number) => { - const startX = w * 0.1 - const startY = h * yPercent - const endX = w * 0.5 - const endY = h * 0.5 - const cp1X = w * 0.3 - const cp1Y = startY - const cp2X = w * 0.3 - const cp2Y = endY - return `M ${startX} ${startY} C ${cp1X} ${cp1Y}, ${cp2X} ${cp2Y}, ${endX} ${endY}` - } - - // Helper to generate curve from gateway to role - const getRolePath = (yPercent: number) => { - const startX = w * 0.5 - const startY = h * 0.5 - const endX = w * 0.9 - const endY = h * yPercent - const cp1X = w * 0.7 - const cp1Y = startY - const cp2X = w * 0.7 - const cp2Y = endY - return `M ${startX} ${startY} C ${cp1X} ${cp1Y}, ${cp2X} ${cp2Y}, ${endX} ${endY}` - } - - async function handleLoadModel(name: string) { - try { - await api(`/api/models/${encodeURIComponent(name)}/load`, { method: "POST" }) - reload() - } catch (e: any) { - showAlert("Fehler", `Fehler beim Laden des Modells: ${e.message}`) - } - } - - async function handleUnloadModel(name: string) { - try { - await api(`/api/models/${encodeURIComponent(name)}/unload`, { method: "POST" }) - reload() - } catch (e: any) { - showAlert("Fehler", `Fehler beim Entladen des Modells: ${e.message}`) - } - } - - async function handleUnloadAll() { - try { - await api("/api/models/unload", { method: "POST" }) - reload() - } catch (e: any) { - showAlert("Fehler", `Fehler beim Entladen aller Modelle: ${e.message}`) - } - } - - async function handleRoleChange(role: string, modelName: string) { - try { - await api(`/api/models/${encodeURIComponent(modelName)}/role`, { - method: "POST", - body: JSON.stringify({ role: role || null }), - }) - reload() - } catch (e: any) { - showAlert("Fehler", `Fehler beim Zuweisen der Rolle: ${e.message || e}`) - } - } - - async function handleSetCtx(name: string, cur: number | null) { - showPrompt( - "Kontextlänge anpassen", - "Gib die gewünschte Kontextlänge in Tokens an:", - String(cur || 32768), - async (v) => { - if (!v) return - try { - await api(`/api/models/${encodeURIComponent(name)}/ctx`, { - method: "POST", - body: JSON.stringify({ ctx: parseInt(v, 10) }), - }) - reload() - } catch (e: any) { - showAlert("Fehler", `Fehler beim Setzen des Kontexts: ${e.message || e}`) - } - } - ) - } - - async function handleDelete(name: string) { - showConfirm( - "Modell löschen?", - `Modell '${name}' und alle zugehörigen GGUF-Dateien unwiderruflich von der Box löschen?`, - async () => { - try { - await api(`/api/models/${encodeURIComponent(name)}`, { method: "DELETE" }) - reload() - } catch (e: any) { - showAlert("Fehler", `Fehler beim Löschen: ${e.message || e}`) - } - } - ) - } - - async function handleSmartUpgrade(repo: string, role: string, quant: string, toolCapable: boolean) { - try { - await api("/api/models/install", { - method: "POST", - body: JSON.stringify({ repo, role, quant, jinja: toolCapable }), - }) - showAlert("Herunterladen gestartet", `Download für '${repo}' gestartet! Der Fortschritt wird oben angezeigt.`) - } catch (e: any) { - showAlert("Fehler", `Fehler beim Starten des Upgrades: ${e.message || e}`) - } - } - - async function copySnippet(snippet?: string) { - if (!snippet) return - await navigator.clipboard.writeText(snippet) - setCopied(true) - setTimeout(() => setCopied(false), 1500) - } - - if (loading) return
Initialisiere HUD Cockpit…
- if (error) { - return ( -
- Gateway oder Engine nicht erreichbar ({error}). -
- ) - } - - // VRAM calculation: APU fallback 16GB if sysfs returns 0 - const runningWithInfo = models.filter((m) => running.includes(m.name)) - const totalRunningSize = runningWithInfo.reduce((acc, m) => acc + (m.size_bytes || 0), 0) - const virtualMax = 16 * 1024 ** 3 // 16 GB Default - const capacity = totalRunningSize > virtualMax ? totalRunningSize * 1.2 : virtualMax - - // Find model by role - const getModelForRole = (role: string) => models.find((m) => m.role === role) - const isRoleRunning = (role: string) => { - const m = getModelForRole(role) - return m ? running.includes(m.name) : false - } - - return ( -
- {/* Styles inside Cockpit for dash flow animations */} - - - {/* ZONE A: Widescreen VRAM HUD */} -
-
-
- - VRAM / Memory Belegung -
-
- - Llama Swap VRAM-Pool: {fmtSize(totalRunningSize)} / {fmtSize(capacity)} geladen - - {running.length > 0 && ( - - )} -
-
- - {/* The memory bar */} -
- {runningWithInfo.length === 0 ? ( -
- VRAM Leer — Auto-Swap lädt Modelle bei Anfrage -
- ) : ( - runningWithInfo.map((m, idx) => { - const widthPct = ((m.size_bytes || 0) / capacity) * 100 - const bgClass = [ - "from-teal-500 to-emerald-500", - "from-indigo-500 to-blue-500", - "from-purple-500 to-pink-500", - "from-cyan-500 to-sky-500" - ][idx % 4] - return ( -
- - {m.role ? `[${m.role}] ` : ""}{m.name.split("/").pop()?.replace(".gguf", "")} - - {fmtSize(m.size_bytes)} -
- ) - }) - )} -
-
- - {/* ZONE B: SVG Node Router */} -
-
- Interactive Gateway Graph -

- Klicke links auf Editoren, um Configs zu kopieren. Klicke rechts auf Rollen, um GGUF-Zuweisungen live zu ändern. -

-
- - {/* The Graph Canvas Area */} -
- {/* SVG Overlay behind HTML Nodes */} - - {/* Gradients */} - - - - - - - - - - - - {/* Bezier Curves: Clients to Gateway (10% -> 50%) */} - {/* Roo Code (y=10) */} - - {(hoveredNode === "roocode" || activeClient === "roocode") && ( - - )} - - {/* Cursor (y=30) */} - - {(hoveredNode === "cursor" || activeClient === "cursor") && ( - - )} - - {/* OpenCode (y=50) */} - - {(hoveredNode === "opencode" || activeClient === "opencode") && ( - - )} - - {/* Zed (y=70) */} - - {(hoveredNode === "zed" || activeClient === "zed") && ( - - )} - - {/* Continue (y=90) */} - - {(hoveredNode === "continue" || activeClient === "continue") && ( - - )} - - {/* Bezier Curves: Gateway to Roles (50% -> 90%) */} - {/* fast (y=12) */} - - {isRoleRunning("fast") && ( - - )} - - {/* heavy (y=31) */} - - {isRoleRunning("heavy") && ( - - )} - - {/* coder (y=50) */} - - {isRoleRunning("coder") && ( - - )} - - {/* vision (y=69) */} - - {isRoleRunning("vision") && ( - - )} - - {/* scout (y=88) */} - - {isRoleRunning("scout") && ( - - )} - - - {/* HTML Nodes */} - {/* COLUMN 1: Client nodes */} -
setHoveredNode("roocode")} - onMouseLeave={() => setHoveredNode(null)} - onClick={() => setActiveClient(c => c === "roocode" ? null : "roocode")} - > - - Roo Code -
- -
setHoveredNode("cursor")} - onMouseLeave={() => setHoveredNode(null)} - onClick={() => setActiveClient(c => c === "cursor" ? null : "cursor")} - > - - Cursor IDE -
- -
setHoveredNode("opencode")} - onMouseLeave={() => setHoveredNode(null)} - onClick={() => setActiveClient(c => c === "opencode" ? null : "opencode")} - > - - OpenCode -
- -
setHoveredNode("zed")} - onMouseLeave={() => setHoveredNode(null)} - onClick={() => setActiveClient(c => c === "zed" ? null : "zed")} - > - - Zed -
- -
setHoveredNode("continue")} - onMouseLeave={() => setHoveredNode(null)} - onClick={() => setActiveClient(c => c === "continue" ? null : "continue")} - > - - Continue -
- - {/* COLUMN 2: Central Gateway Node */} -
-
Gateway Auto
-
- Schwelle: > {routing?.heavy_threshold_chars ? (routing.heavy_threshold_chars / 1000) : "4"}k Zeichen -
-
- Auto-Swap -
-
- - {/* COLUMN 3: Role nodes (fast, heavy, coder, vision, scout) */} - {ROLES.map((role) => { - const yPositions = ["12%", "31%", "50%", "69%", "88%"] - const activeModel = getModelForRole(role) - const isWarm = activeModel ? running.includes(activeModel.name) : false - - // Skip "reasoning" & "agent" to keep layout neat and identical to canonical roles - if (role === "reasoning" || role === "agent") return null - const indexMap = { fast: 0, heavy: 1, coder: 2, vision: 3, scout: 4 }[role] as number - - return ( -
setActiveRoleForAssign(role)} - > -
- {role} - {isWarm && } -
-
- {activeModel ? activeModel.name.split("/").pop()?.replace(".gguf", "") : "Keine Zuweisung"} -
-
- ) - })} - - {/* CLIENT SETUP MODAL WINDOW */} - {activeClient && connectData && ( -
-
- {/* Modal Header */} -
- - {activeClient === "roocode" && "Roo Code Setup"} - {activeClient === "cursor" && "Cursor Setup"} - {activeClient === "opencode" && "OpenCode Setup"} - {activeClient === "zed" && "Zed Setup"} - {activeClient === "continue" && "Continue Setup"} - - -
- - {/* Modal Guide Steps */} -
- {activeClient === "roocode" && ( -
    -
  • Suche in VS Code nach der Erweiterung Roo Code und installiere sie.
  • -
  • Wähle in den Roo Code Einstellungen: Provider: OpenAI Compatible.
  • -
  • Füge das untenstehende JSON-Snippet in die settings.json ein.
  • -
- )} - {activeClient === "cursor" && ( -
    -
  • Öffne Cursor Settings ➔ Models.
  • -
  • Deaktiviere Cloud-Modelle, klappe OpenAI API auf.
  • -
  • Trage die Base URL unten ein und aktiviere das Modell auto.
  • -
- )} - {activeClient === "opencode" && ( -
    -
  • Öffne die opencode.jsonc Konfigurationsdatei.
  • -
  • Ersetze den Provider-Eintrag unter provider mit dem Snippet unten.
  • -
- )} - {activeClient === "zed" && ( -
    -
  • Öffne die Zed Settings (ctrl+,).
  • -
  • Füge das untenstehende JSON-Segment unter language_models ein.
  • -
- )} - {activeClient === "continue" && ( -
    -
  • Klicke auf das Zahnrad-Symbol in der Continue-Erweiterung.
  • -
  • Füge den Gateway-Eintrag zum models-Array hinzu.
  • -
- )} -
- - {/* Snippet box */} - {connectData.tools && ( -
-
- JSON Config - -
-
-                      
-                        {activeClient === "roocode" && connectData.tools.cline?.snippet}
-                        {activeClient === "cursor" && connectData.tools.cursor?.snippet}
-                        {activeClient === "opencode" && connectData.tools.opencode?.snippet}
-                        {activeClient === "zed" && connectData.tools.zed?.snippet}
-                        {activeClient === "continue" && connectData.tools.continue?.snippet}
-                      
-                    
-
- )} - - -
-
- )} -
- - {/* Legend for the connection graph */} -
- - - Cyan-Fluss: Client-Anfrage an Gateway - - - - Grüner Puls: Aktive Verbindung / Warmes Modell geladen - - - - VRAM-Verlauf: Modellspezifischer Speicheranteil - -
-
- - {/* ZONE B.5: Slot-Belegung */} -
-
- Gateway Steckplatz-Belegung (Slot-Zuweisung) -
-
- {["fast", "heavy", "coder", "reasoning", "vision", "scout"].map((role) => { - const m = models.find((x) => x.role === role) - const isWarm = m ? running.includes(m.name) : false - - return ( -
setActiveRoleForAssign(role)} - className={cn( - "rounded-xl border p-3 flex flex-col justify-between gap-2.5 transition-all cursor-pointer select-none text-left bg-background/25 hover:border-primary/45 hover:bg-background/40 group min-h-[90px]", - isWarm - ? "border-emerald-500/40 shadow-sm shadow-emerald-500/5" - : m - ? "border-primary/20 bg-primary/5" - : "border-border/30 border-dashed opacity-75" - )} - > -
- {role} - {isWarm && } -
- -
- {m ? m.name.split("/").pop()?.replace(/\.gguf$/i, "") : "nicht zugewiesen"} -
- -
- Ändern ➔ -
-
- ) - })} -
-
- - {/* ZONE C: Library list cards & Upgrade Radar */} -
-
-
- Installierte Modell-Bibliothek ({filteredModels.length} von {models.length}) -
- -
- {/* Filter mode selector */} -
- - -
- - {/* Grid/List layout selector */} -
- - -
-
-
- - {viewMode === "grid" ? ( -
- {filteredModels.length === 0 ? ( -
- {filterMode === "in_use" - ? "Keine Modelle in Benutzung (keine Zuweisung oder warm geladene Modelle)." - : "Keine Modelle konfiguriert. Verwende den Tab \"Modelle finden\" zum Herunterladen."} -
- ) : ( - filteredModels.map((m) => { - const isRunning = running.includes(m.name) - const hasUpgrade = updates?.model_list.find((u) => u.role === m.role) - const brand = getBrandInfo(m.name) - - return ( -
-
-
-
- {/* Brand Icon Badge */} -
- {brand.initial} -
- -
-

- {m.name.split("/").pop()} -

-
- - {m.quant || "GGUF"} - - {isRunning && ( - - Warm - - )} - {m.role && ( - - {m.role} - - )} - {m.prompt_cache && ( - - PC - - )} - {m.spec_draft_model && ( - - SPEC - - )} - {m.parallel_slots > 1 && ( - - SLOTS: {m.parallel_slots} - - )} -
-
-
-
- -
- -
-
- -
-
-
- -
-
Größe
-
{fmtSize(m.size_bytes)}
-
-
- -
- -
-
Kontext
-
{fmtCtx(m.ctx)}
-
-
-
- - {/* Smart Upgrade radar trigger banner */} - {hasUpgrade && ( -
-
- - Upgrade verfügbar: {hasUpgrade.repo.split("/").pop()} -
- -
- )} - - {/* Actions row at the bottom of Grid Card */} -
- - - -
-
-
- ) - }) - )} -
- ) : ( -
- {filteredModels.length === 0 ? ( -
- {filterMode === "in_use" - ? "Keine Modelle in Benutzung (keine Zuweisung oder warm geladene Modelle)." - : "Keine Modelle konfiguriert. Verwende den Tab \"Modelle finden\" zum Herunterladen."} -
- ) : ( - filteredModels.map((m) => { - const isRunning = running.includes(m.name) - const brand = getBrandInfo(m.name) - - return ( -
-
- {/* Brand Icon */} -
- {brand.initial} -
- -
-
-

- {m.name.split("/").pop()} -

- {m.role && ( - - {m.role} - - )} - {m.prompt_cache && ( - - PC - - )} - {m.spec_draft_model && ( - - SPEC - - )} - {m.parallel_slots > 1 && ( - - SLOTS: {m.parallel_slots} - - )} - {isRunning && ( - - warm - - )} -
-
- Größe: {fmtSize(m.size_bytes)} - - Kontext: {fmtCtx(m.ctx)} - - {m.quant || "GGUF"} -
-
-
- - {/* Chips and Actions */} -
-
- -
- -
- - - -
-
-
- ) - }) - )} -
- )} -
- - {/* Role Assignment Modal */} - {activeRoleForAssign && ( -
-
-
-

- Rolle '{activeRoleForAssign}' konfigurieren -

- -
-

- Wähle ein Modell aus deiner Bibliothek für die Rolle {activeRoleForAssign}: -

- -
- - {models.map((m) => ( - - ))} -
-
-
- )} - - {dialogElement} -
- ) -} - -function AddModel() { - const [repo, setRepo] = useState("") - const [quants, setQuants] = useState([]) - const [quant, setQuant] = useState("Q4_K_M") - const [msg, setMsg] = useState("") - const [q, setQ] = useState("") - const [results, setResults] = useState<{ repo: string; downloads: number }[]>([]) - - async function loadQuants(r?: string) { - const rr = r ?? repo - if (!rr.trim()) return - setMsg("Analysiere HuggingFace Repository...") - try { - const d = await api<{ repo: string; quants: string[] }>(`/api/hf/quants?repo=${encodeURIComponent(rr)}`) - setRepo(d.repo) - setQuants(d.quants) - if (d.quants.length) setQuant(d.quants.includes("Q4_K_M") ? "Q4_K_M" : d.quants[0]) - setMsg(d.quants.length ? "" : "Keine GGUF-Dateien in diesem Repository gefunden.") - } catch (e) { - setMsg(`Fehler: ${e}`) - } - } - - async function search() { - if (!q.trim()) return - setMsg("Durchsuche HuggingFace...") - try { - const d = await api<{ results: { repo: string; downloads: number }[] }>(`/api/hf/search?q=${encodeURIComponent(q)}`) - setResults(d.results) - setMsg(d.results.length ? "" : "Keine Ergebnisse gefunden.") - } catch (e) { - setMsg(`Suche fehlgeschlagen: ${e}`) - } - } - - async function install() { - if (!repo.trim()) return - setMsg("Download-Job wird initiiert...") - try { - await api("/api/models/install", { - method: "POST", - body: JSON.stringify({ repo, quant, jinja: true }), - }) - setMsg(`Download gestartet: ${repo} (${quant}). Fortschritt wird oben angezeigt.`) - } catch (e) { - setMsg(`Download-Fehler: ${e}`) - } - } - - return ( -
-
HF Download & Suche
- -
- setRepo(e.target.value)} - placeholder="HF-URL oder org/repo (z.B. unsloth/Qwen2.5-Coder-7B-Instruct-GGUF)" - className="flex-1 h-9 rounded-lg border border-border/60 bg-background/40 px-3 text-xs outline-none focus:ring-1 focus:ring-primary/50 text-foreground" - /> -
- - {quants.length > 0 && ( - <> - - - - )} -
-
- -
-
- setQ(e.target.value)} - onKeyDown={(e) => e.key === "Enter" && search()} - placeholder="HuggingFace durchsuchen (z.B. Llama-3.1)..." - className="w-full h-9 pl-9 pr-3 rounded-lg border border-border/60 bg-background/40 text-xs outline-none focus:ring-1 focus:ring-primary/50 text-foreground" - /> - -
- -
- - {results.length > 0 && ( -
- {results.map((r) => ( - - ))} -
- )} - - {msg &&
{msg}
} -
- ) -} - -const ROLE_METADATA: Record = { - vision: { - title: "Bilder & Vision", - desc: "Verarbeitet Bilder, Screenshots und visuelle Diagramme in multimodalen Chats.", - icon: Eye - }, - coder: { - title: "Coden & Entwicklung", - desc: "Autovervollständigung, Refactoring und Codegenerierung direkt in deiner IDE.", - icon: Code - }, - reasoning: { - title: "Logik & Nachdenken", - desc: "Komplexe logische Gedankengänge, Mathematik und tiefgründiges Planen (Reasoning).", - icon: Brain - }, - agent: { - title: "Autonomer Agent (Hermes)", - desc: "Führt selbstständig Terminalbefehle aus und interagiert mit deinem Homelab.", - icon: Bot - }, - scout: { - title: "Allrounder & Chat", - desc: "Schnelle Antworten, Zusammenfassungen, Übersetzungen und alltägliche Fragen.", - icon: Compass - } -} - -function Discover() { - const { data, isLoading: loading, error: loadErr } = useDiscover() - const { data: modelsResp } = useModels() - const { data: updates } = useUpdates() - const models = modelsResp?.models ?? [] - const error = loadErr ? String(loadErr) : "" - const [installing, setInstalling] = useState>({}) - const [expandedAlternatives, setExpandedAlternatives] = useState>({}) - const [showExpert, setShowExpert] = useState(false) - - async function install(repo: string, role: string, quant: string, toolCapable: boolean) { - setInstalling((s) => ({ ...s, [repo]: "Starte..." })) - try { - await api("/api/models/install", { - method: "POST", - body: JSON.stringify({ repo, role, quant, jinja: toolCapable }), - }) - setInstalling((s) => ({ ...s, [repo]: "Download läuft" })) - } catch (e) { - setInstalling((s) => ({ ...s, [repo]: "Fehler" })) - } - } - - if (loading) return
Analysiere Hardware und suche passende GGUF-Empfehlungen…
- if (error || !data) - return ( -
- Empfehlungsdienst temporär nicht erreichbar ({error}). -
- ) - - return ( -
- {/* Informational Header */} -
-
- Modell-Registry geladen für {data.sys_ram_gb} GB System-RAM. -
-
- - Empfehlungen sind automatisch auf deine Box-Hardware optimiert. -
-
- - {/* Sockets/Slots Grid */} -
- {data.categories.map((cat) => { - const meta = ROLE_METADATA[cat.role] || { - title: cat.title || cat.role, - desc: "Spezifisches Modell für diese Systemrolle.", - icon: Layers - } - const IconComponent = meta.icon - - // Check if a model is installed for this role - const installedModel = models.find((m) => m.role === cat.role) - - // Check if an upgrade is available for this role - const hasUpgrade = updates?.model_list.find((u) => u.role === cat.role) - - // Get the primary recommended model - const recommendedModel = cat.models.find((m) => m.repo === cat.recommended) || cat.models[0] - if (!recommendedModel) return null - - const isInstallingRecommended = installing[recommendedModel.repo] - const alternativeModels = cat.models.filter((m) => m.repo !== cat.recommended) - const isExpanded = !!expandedAlternatives[cat.role] - - return ( -
-
- {/* Socket Header */} -
-
-
- -
-
-

{meta.title}

- - Rolle: {cat.role} - -
-
- - {/* Status Badges */} - {installedModel ? ( - - - Aktiviert - - ) : ( - - Frei - - )} -
- - {/* Role Description */} -

- {meta.desc} -

- - {/* Current vs Recommended model card */} -
- {installedModel ? ( -
-
Aktive GGUF-Belegung
-
- {installedModel.name.split("/").pop()} -
-
- Größe: {fmtBytes(installedModel.size_bytes || 0)} - - Quant: {installedModel.quant || "GGUF"} -
-
- ) : ( -
-
Empfohlenes Modell
-
- {recommendedModel.name} -
-
- Ersteller: {recommendedModel.author} - - Quant: {recommendedModel.quant} -
-
- -
-
- )} -
- - {/* Main Action Button */} -
- {installedModel ? ( - hasUpgrade ? ( -
-
- - Bessere Version in der Registry: {hasUpgrade.repo.split("/").pop()} -
- -
- ) : ( -
- Auf neuestem Stand -
- ) - ) : ( - - )} -
-
- - {/* Collapsible alternatives list */} - {alternativeModels.length > 0 && ( -
- - - {isExpanded && ( -
- {alternativeModels.map((alt) => ( -
-
-
- {alt.name} -
-
- Quant: {alt.quant} - - {alt.fit.text} -
-
- -
- ))} -
- )} -
- )} -
- ) - })} -
- - {/* Collapsible Custom Hugging Face Downloader */} -
- - {showExpert && ( -
- -
- )} -
-
- ) -} +import { Cockpit } from "./models/Cockpit" +import { Discover } from "./models/Discover" export function ModelsView() { const [tab, setTab] = useState<"cockpit" | "discover">("cockpit") @@ -1434,8 +25,8 @@ export function ModelsView() { onClick={() => setTab(t)} className={cn( "rounded-lg px-4 py-1.5 text-xs font-semibold tracking-wide uppercase transition-all cursor-pointer", - tab === t - ? "bg-primary text-primary-foreground shadow-md shadow-primary/10" + tab === t + ? "bg-primary text-primary-foreground shadow-md shadow-primary/10" : "text-muted-foreground hover:text-foreground", )} > diff --git a/frontend/src/views/models/AddModel.tsx b/frontend/src/views/models/AddModel.tsx new file mode 100644 index 0000000..078c597 --- /dev/null +++ b/frontend/src/views/models/AddModel.tsx @@ -0,0 +1,131 @@ +import { useState } from "react" +import { Download, Search } from "lucide-react" +import { api } from "@/lib/api" + +export function AddModel() { + const [repo, setRepo] = useState("") + const [quants, setQuants] = useState([]) + const [quant, setQuant] = useState("Q4_K_M") + const [msg, setMsg] = useState("") + const [q, setQ] = useState("") + const [results, setResults] = useState<{ repo: string; downloads: number }[]>([]) + + async function loadQuants(r?: string) { + const rr = r ?? repo + if (!rr.trim()) return + setMsg("Analysiere HuggingFace Repository...") + try { + const d = await api<{ repo: string; quants: string[] }>(`/api/hf/quants?repo=${encodeURIComponent(rr)}`) + setRepo(d.repo) + setQuants(d.quants) + if (d.quants.length) setQuant(d.quants.includes("Q4_K_M") ? "Q4_K_M" : d.quants[0]) + setMsg(d.quants.length ? "" : "Keine GGUF-Dateien in diesem Repository gefunden.") + } catch (e) { + setMsg(`Fehler: ${e}`) + } + } + + async function search() { + if (!q.trim()) return + setMsg("Durchsuche HuggingFace...") + try { + const d = await api<{ results: { repo: string; downloads: number }[] }>(`/api/hf/search?q=${encodeURIComponent(q)}`) + setResults(d.results) + setMsg(d.results.length ? "" : "Keine Ergebnisse gefunden.") + } catch (e) { + setMsg(`Suche fehlgeschlagen: ${e}`) + } + } + + async function install() { + if (!repo.trim()) return + setMsg("Download-Job wird initiiert...") + try { + await api("/api/models/install", { + method: "POST", + body: JSON.stringify({ repo, quant, jinja: true }), + }) + setMsg(`Download gestartet: ${repo} (${quant}). Fortschritt wird oben angezeigt.`) + } catch (e) { + setMsg(`Download-Fehler: ${e}`) + } + } + + return ( +
+
HF Download & Suche
+ +
+ setRepo(e.target.value)} + placeholder="HF-URL oder org/repo (z.B. unsloth/Qwen2.5-Coder-7B-Instruct-GGUF)" + className="flex-1 h-9 rounded-lg border border-border/60 bg-background/40 px-3 text-xs outline-none focus:ring-1 focus:ring-primary/50 text-foreground" + /> +
+ + {quants.length > 0 && ( + <> + + + + )} +
+
+ +
+
+ setQ(e.target.value)} + onKeyDown={(e) => e.key === "Enter" && search()} + placeholder="HuggingFace durchsuchen (z.B. Llama-3.1)..." + className="w-full h-9 pl-9 pr-3 rounded-lg border border-border/60 bg-background/40 text-xs outline-none focus:ring-1 focus:ring-primary/50 text-foreground" + /> + +
+ +
+ + {results.length > 0 && ( +
+ {results.map((r) => ( + + ))} +
+ )} + + {msg &&
{msg}
} +
+ ) +} diff --git a/frontend/src/views/models/Cockpit.tsx b/frontend/src/views/models/Cockpit.tsx new file mode 100644 index 0000000..84b7d50 --- /dev/null +++ b/frontend/src/views/models/Cockpit.tsx @@ -0,0 +1,1008 @@ +import { useState, useRef, useCallback } from "react" +import { Download, Trash2, Edit3, Activity, HardDrive, X, Check, Copy } from "lucide-react" +import { api } from "@/lib/api" +import { useModels, useRouting, useConnect, useUpdates, useQueryClient, qk } from "@/lib/queries" +import { useDialog } from "@/lib/useDialog" +import { CapsChips } from "@/components/CapsChips" +import { cn } from "@/lib/utils" +import { fmtSize, fmtCtx } from "@/lib/format" +import { getBrandInfo, ROLES } from "@/components/models/ModelBadges" + +export function Cockpit() { + const qc = useQueryClient() + const { data: modelsResp, isLoading: loading, error: loadErr } = useModels(4_000) + const { data: routing } = useRouting(4_000) + const { data: connectData } = useConnect() + const { data: updates } = useUpdates(4_000) + const { showAlert, showConfirm, showPrompt, dialogElement } = useDialog() + const models = modelsResp?.models ?? [] + const running = modelsResp?.running ?? [] + const error = loadErr ? String(loadErr) : "" + const reload = () => { + qc.invalidateQueries({ queryKey: qk.models }) + qc.invalidateQueries({ queryKey: qk.routing }) + } + + // UI state + const [activeClient, setActiveClient] = useState<"roocode" | "cursor" | "opencode" | "zed" | "continue" | null>(null) + const [activeRoleForAssign, setActiveRoleForAssign] = useState(null) + const [copied, setCopied] = useState(false) + const [hoveredNode, setHoveredNode] = useState(null) + const [viewMode, setViewMode] = useState<"grid" | "list">("grid") + const [filterMode, setFilterMode] = useState<"all" | "in_use">("all") + + const filteredModels = models.filter((m) => { + if (filterMode === "in_use") { + return !!m.role || running.includes(m.name) + } + return true + }) + + // Canvas pixel tracking for pixel-perfect connection graph without non-uniform scaling + const [dimensions, setDimensions] = useState({ width: 800, height: 360 }) + const observerRef = useRef(null) + + const containerRef = useCallback((node: HTMLDivElement | null) => { + if (observerRef.current) { + observerRef.current.disconnect() + observerRef.current = null + } + if (node) { + const observer = new ResizeObserver((entries) => { + if (!entries || entries.length === 0) return + const rect = entries[0].contentRect + setDimensions({ width: rect.width, height: rect.height }) + }) + observer.observe(node) + observerRef.current = observer + } + }, []) + + const w = dimensions.width + const h = dimensions.height + + // Helper to generate curve from client to gateway + const getClientPath = (yPercent: number) => { + const startX = w * 0.1 + const startY = h * yPercent + const endX = w * 0.5 + const endY = h * 0.5 + const cp1X = w * 0.3 + const cp1Y = startY + const cp2X = w * 0.3 + const cp2Y = endY + return `M ${startX} ${startY} C ${cp1X} ${cp1Y}, ${cp2X} ${cp2Y}, ${endX} ${endY}` + } + + // Helper to generate curve from gateway to role + const getRolePath = (yPercent: number) => { + const startX = w * 0.5 + const startY = h * 0.5 + const endX = w * 0.9 + const endY = h * yPercent + const cp1X = w * 0.7 + const cp1Y = startY + const cp2X = w * 0.7 + const cp2Y = endY + return `M ${startX} ${startY} C ${cp1X} ${cp1Y}, ${cp2X} ${cp2Y}, ${endX} ${endY}` + } + + async function handleLoadModel(name: string) { + try { + await api(`/api/models/${encodeURIComponent(name)}/load`, { method: "POST" }) + reload() + } catch (e: any) { + showAlert("Fehler", `Fehler beim Laden des Modells: ${e.message}`) + } + } + + async function handleUnloadModel(name: string) { + try { + await api(`/api/models/${encodeURIComponent(name)}/unload`, { method: "POST" }) + reload() + } catch (e: any) { + showAlert("Fehler", `Fehler beim Entladen des Modells: ${e.message}`) + } + } + + async function handleUnloadAll() { + try { + await api("/api/models/unload", { method: "POST" }) + reload() + } catch (e: any) { + showAlert("Fehler", `Fehler beim Entladen aller Modelle: ${e.message}`) + } + } + + async function handleRoleChange(role: string, modelName: string) { + try { + await api(`/api/models/${encodeURIComponent(modelName)}/role`, { + method: "POST", + body: JSON.stringify({ role: role || null }), + }) + reload() + } catch (e: any) { + showAlert("Fehler", `Fehler beim Zuweisen der Rolle: ${e.message || e}`) + } + } + + async function handleSetCtx(name: string, cur: number | null) { + showPrompt( + "Kontextlänge anpassen", + "Gib die gewünschte Kontextlänge in Tokens an:", + String(cur || 32768), + async (v) => { + if (!v) return + try { + await api(`/api/models/${encodeURIComponent(name)}/ctx`, { + method: "POST", + body: JSON.stringify({ ctx: parseInt(v, 10) }), + }) + reload() + } catch (e: any) { + showAlert("Fehler", `Fehler beim Setzen des Kontexts: ${e.message || e}`) + } + } + ) + } + + async function handleDelete(name: string) { + showConfirm( + "Modell löschen?", + `Modell '${name}' und alle zugehörigen GGUF-Dateien unwiderruflich von der Box löschen?`, + async () => { + try { + await api(`/api/models/${encodeURIComponent(name)}`, { method: "DELETE" }) + reload() + } catch (e: any) { + showAlert("Fehler", `Fehler beim Löschen: ${e.message || e}`) + } + } + ) + } + + async function handleSmartUpgrade(repo: string, role: string, quant: string, toolCapable: boolean) { + try { + await api("/api/models/install", { + method: "POST", + body: JSON.stringify({ repo, role, quant, jinja: toolCapable }), + }) + showAlert("Herunterladen gestartet", `Download für '${repo}' gestartet! Der Fortschritt wird oben angezeigt.`) + } catch (e: any) { + showAlert("Fehler", `Fehler beim Starten des Upgrades: ${e.message || e}`) + } + } + + async function copySnippet(snippet?: string) { + if (!snippet) return + await navigator.clipboard.writeText(snippet) + setCopied(true) + setTimeout(() => setCopied(false), 1500) + } + + if (loading) return
Initialisiere HUD Cockpit…
+ if (error) { + return ( +
+ Gateway oder Engine nicht erreichbar ({error}). +
+ ) + } + + // VRAM calculation: APU fallback 16GB if sysfs returns 0 + const runningWithInfo = models.filter((m) => running.includes(m.name)) + const totalRunningSize = runningWithInfo.reduce((acc, m) => acc + (m.size_bytes || 0), 0) + const virtualMax = 16 * 1024 ** 3 // 16 GB Default + const capacity = totalRunningSize > virtualMax ? totalRunningSize * 1.2 : virtualMax + + // Find model by role + const getModelForRole = (role: string) => models.find((m) => m.role === role) + const isRoleRunning = (role: string) => { + const m = getModelForRole(role) + return m ? running.includes(m.name) : false + } + + return ( +
+ {/* Styles inside Cockpit for dash flow animations */} + + + {/* ZONE A: Widescreen VRAM HUD */} +
+
+
+ + VRAM / Memory Belegung +
+
+ + Llama Swap VRAM-Pool: {fmtSize(totalRunningSize)} / {fmtSize(capacity)} geladen + + {running.length > 0 && ( + + )} +
+
+ + {/* The memory bar */} +
+ {runningWithInfo.length === 0 ? ( +
+ VRAM Leer — Auto-Swap lädt Modelle bei Anfrage +
+ ) : ( + runningWithInfo.map((m, idx) => { + const widthPct = ((m.size_bytes || 0) / capacity) * 100 + const bgClass = [ + "from-teal-500 to-emerald-500", + "from-indigo-500 to-blue-500", + "from-purple-500 to-pink-500", + "from-cyan-500 to-sky-500" + ][idx % 4] + return ( +
+ + {m.role ? `[${m.role}] ` : ""}{m.name.split("/").pop()?.replace(".gguf", "")} + + {fmtSize(m.size_bytes)} +
+ ) + }) + )} +
+
+ + {/* ZONE B: SVG Node Router */} +
+
+ Interactive Gateway Graph +

+ Klicke links auf Editoren, um Configs zu kopieren. Klicke rechts auf Rollen, um GGUF-Zuweisungen live zu ändern. +

+
+ + {/* The Graph Canvas Area */} +
+ {/* SVG Overlay behind HTML Nodes */} + + {/* Gradients */} + + + + + + + + + + + + {/* Bezier Curves: Clients to Gateway (10% -> 50%) */} + {/* Roo Code (y=10) */} + + {(hoveredNode === "roocode" || activeClient === "roocode") && ( + + )} + + {/* Cursor (y=30) */} + + {(hoveredNode === "cursor" || activeClient === "cursor") && ( + + )} + + {/* OpenCode (y=50) */} + + {(hoveredNode === "opencode" || activeClient === "opencode") && ( + + )} + + {/* Zed (y=70) */} + + {(hoveredNode === "zed" || activeClient === "zed") && ( + + )} + + {/* Continue (y=90) */} + + {(hoveredNode === "continue" || activeClient === "continue") && ( + + )} + + {/* Bezier Curves: Gateway to Roles (50% -> 90%) */} + {/* fast (y=12) */} + + {isRoleRunning("fast") && ( + + )} + + {/* heavy (y=31) */} + + {isRoleRunning("heavy") && ( + + )} + + {/* coder (y=50) */} + + {isRoleRunning("coder") && ( + + )} + + {/* vision (y=69) */} + + {isRoleRunning("vision") && ( + + )} + + {/* scout (y=88) */} + + {isRoleRunning("scout") && ( + + )} + + + {/* HTML Nodes */} + {/* COLUMN 1: Client nodes */} +
setHoveredNode("roocode")} + onMouseLeave={() => setHoveredNode(null)} + onClick={() => setActiveClient(c => c === "roocode" ? null : "roocode")} + > + + Roo Code +
+ +
setHoveredNode("cursor")} + onMouseLeave={() => setHoveredNode(null)} + onClick={() => setActiveClient(c => c === "cursor" ? null : "cursor")} + > + + Cursor IDE +
+ +
setHoveredNode("opencode")} + onMouseLeave={() => setHoveredNode(null)} + onClick={() => setActiveClient(c => c === "opencode" ? null : "opencode")} + > + + OpenCode +
+ +
setHoveredNode("zed")} + onMouseLeave={() => setHoveredNode(null)} + onClick={() => setActiveClient(c => c === "zed" ? null : "zed")} + > + + Zed +
+ +
setHoveredNode("continue")} + onMouseLeave={() => setHoveredNode(null)} + onClick={() => setActiveClient(c => c === "continue" ? null : "continue")} + > + + Continue +
+ + {/* COLUMN 2: Central Gateway Node */} +
+
Gateway Auto
+
+ Schwelle: > {routing?.heavy_threshold_chars ? (routing.heavy_threshold_chars / 1000) : "4"}k Zeichen +
+
+ Auto-Swap +
+
+ + {/* COLUMN 3: Role nodes (fast, heavy, coder, vision, scout) */} + {ROLES.map((role) => { + const yPositions = ["12%", "31%", "50%", "69%", "88%"] + const activeModel = getModelForRole(role) + const isWarm = activeModel ? running.includes(activeModel.name) : false + + // Skip "reasoning" & "agent" to keep layout neat and identical to canonical roles + if (role === "reasoning" || role === "agent") return null + const indexMap = { fast: 0, heavy: 1, coder: 2, vision: 3, scout: 4 }[role] as number + + return ( +
setActiveRoleForAssign(role)} + > +
+ {role} + {isWarm && } +
+
+ {activeModel ? activeModel.name.split("/").pop()?.replace(".gguf", "") : "Keine Zuweisung"} +
+
+ ) + })} + + {/* CLIENT SETUP MODAL WINDOW */} + {activeClient && connectData && ( +
+
+ {/* Modal Header */} +
+ + {activeClient === "roocode" && "Roo Code Setup"} + {activeClient === "cursor" && "Cursor Setup"} + {activeClient === "opencode" && "OpenCode Setup"} + {activeClient === "zed" && "Zed Setup"} + {activeClient === "continue" && "Continue Setup"} + + +
+ + {/* Modal Guide Steps */} +
+ {activeClient === "roocode" && ( +
    +
  • Suche in VS Code nach der Erweiterung Roo Code und installiere sie.
  • +
  • Wähle in den Roo Code Einstellungen: Provider: OpenAI Compatible.
  • +
  • Füge das untenstehende JSON-Snippet in die settings.json ein.
  • +
+ )} + {activeClient === "cursor" && ( +
    +
  • Öffne Cursor Settings ➔ Models.
  • +
  • Deaktiviere Cloud-Modelle, klappe OpenAI API auf.
  • +
  • Trage die Base URL unten ein und aktiviere das Modell auto.
  • +
+ )} + {activeClient === "opencode" && ( +
    +
  • Öffne die opencode.jsonc Konfigurationsdatei.
  • +
  • Ersetze den Provider-Eintrag unter provider mit dem Snippet unten.
  • +
+ )} + {activeClient === "zed" && ( +
    +
  • Öffne die Zed Settings (ctrl+,).
  • +
  • Füge das untenstehende JSON-Segment unter language_models ein.
  • +
+ )} + {activeClient === "continue" && ( +
    +
  • Klicke auf das Zahnrad-Symbol in der Continue-Erweiterung.
  • +
  • Füge den Gateway-Eintrag zum models-Array hinzu.
  • +
+ )} +
+ + {/* Snippet box */} + {connectData.tools && ( +
+
+ JSON Config + +
+
+                      
+                        {activeClient === "roocode" && connectData.tools.cline?.snippet}
+                        {activeClient === "cursor" && connectData.tools.cursor?.snippet}
+                        {activeClient === "opencode" && connectData.tools.opencode?.snippet}
+                        {activeClient === "zed" && connectData.tools.zed?.snippet}
+                        {activeClient === "continue" && connectData.tools.continue?.snippet}
+                      
+                    
+
+ )} + + +
+
+ )} +
+ + {/* Legend for the connection graph */} +
+ + + Cyan-Fluss: Client-Anfrage an Gateway + + + + Grüner Puls: Aktive Verbindung / Warmes Modell geladen + + + + VRAM-Verlauf: Modellspezifischer Speicheranteil + +
+
+ + {/* ZONE B.5: Slot-Belegung */} +
+
+ Gateway Steckplatz-Belegung (Slot-Zuweisung) +
+
+ {["fast", "heavy", "coder", "reasoning", "vision", "scout"].map((role) => { + const m = models.find((x) => x.role === role) + const isWarm = m ? running.includes(m.name) : false + + return ( +
setActiveRoleForAssign(role)} + className={cn( + "rounded-xl border p-3 flex flex-col justify-between gap-2.5 transition-all cursor-pointer select-none text-left bg-background/25 hover:border-primary/45 hover:bg-background/40 group min-h-[90px]", + isWarm + ? "border-emerald-500/40 shadow-sm shadow-emerald-500/5" + : m + ? "border-primary/20 bg-primary/5" + : "border-border/30 border-dashed opacity-75" + )} + > +
+ {role} + {isWarm && } +
+ +
+ {m ? m.name.split("/").pop()?.replace(/\.gguf$/i, "") : "nicht zugewiesen"} +
+ +
+ Ändern ➔ +
+
+ ) + })} +
+
+ + {/* ZONE C: Library list cards & Upgrade Radar */} +
+
+
+ Installierte Modell-Bibliothek ({filteredModels.length} von {models.length}) +
+ +
+ {/* Filter mode selector */} +
+ + +
+ + {/* Grid/List layout selector */} +
+ + +
+
+
+ + {viewMode === "grid" ? ( +
+ {filteredModels.length === 0 ? ( +
+ {filterMode === "in_use" + ? "Keine Modelle in Benutzung (keine Zuweisung oder warm geladene Modelle)." + : "Keine Modelle konfiguriert. Verwende den Tab \"Modelle finden\" zum Herunterladen."} +
+ ) : ( + filteredModels.map((m) => { + const isRunning = running.includes(m.name) + const hasUpgrade = updates?.model_list.find((u) => u.role === m.role) + const brand = getBrandInfo(m.name) + + return ( +
+
+
+
+ {/* Brand Icon Badge */} +
+ {brand.initial} +
+ +
+

+ {m.name.split("/").pop()} +

+
+ + {m.quant || "GGUF"} + + {isRunning && ( + + Warm + + )} + {m.role && ( + + {m.role} + + )} + {m.prompt_cache && ( + + PC + + )} + {m.spec_draft_model && ( + + SPEC + + )} + {m.parallel_slots > 1 && ( + + SLOTS: {m.parallel_slots} + + )} +
+
+
+
+ +
+ +
+
+ +
+
+
+ +
+
Größe
+
{fmtSize(m.size_bytes)}
+
+
+ +
+ +
+
Kontext
+
{fmtCtx(m.ctx)}
+
+
+
+ + {/* Smart Upgrade radar trigger banner */} + {hasUpgrade && ( +
+
+ + Upgrade verfügbar: {hasUpgrade.repo.split("/").pop()} +
+ +
+ )} + + {/* Actions row at the bottom of Grid Card */} +
+ + + +
+
+
+ ) + }) + )} +
+ ) : ( +
+ {filteredModels.length === 0 ? ( +
+ {filterMode === "in_use" + ? "Keine Modelle in Benutzung (keine Zuweisung oder warm geladene Modelle)." + : "Keine Modelle konfiguriert. Verwende den Tab \"Modelle finden\" zum Herunterladen."} +
+ ) : ( + filteredModels.map((m) => { + const isRunning = running.includes(m.name) + const brand = getBrandInfo(m.name) + + return ( +
+
+ {/* Brand Icon */} +
+ {brand.initial} +
+ +
+
+

+ {m.name.split("/").pop()} +

+ {m.role && ( + + {m.role} + + )} + {m.prompt_cache && ( + + PC + + )} + {m.spec_draft_model && ( + + SPEC + + )} + {m.parallel_slots > 1 && ( + + SLOTS: {m.parallel_slots} + + )} + {isRunning && ( + + warm + + )} +
+
+ Größe: {fmtSize(m.size_bytes)} + + Kontext: {fmtCtx(m.ctx)} + + {m.quant || "GGUF"} +
+
+
+ + {/* Chips and Actions */} +
+
+ +
+ +
+ + + +
+
+
+ ) + }) + )} +
+ )} +
+ + {/* Role Assignment Modal */} + {activeRoleForAssign && ( +
+
+
+

+ Rolle '{activeRoleForAssign}' konfigurieren +

+ +
+

+ Wähle ein Modell aus deiner Bibliothek für die Rolle {activeRoleForAssign}: +

+ +
+ + {models.map((m) => ( + + ))} +
+
+
+ )} + + {dialogElement} +
+ ) +} diff --git a/frontend/src/views/models/Discover.tsx b/frontend/src/views/models/Discover.tsx new file mode 100644 index 0000000..b3942f2 --- /dev/null +++ b/frontend/src/views/models/Discover.tsx @@ -0,0 +1,285 @@ +import { useState } from "react" +import { Download, Search, Star, Layers, Check, Bot, Eye, Code, Brain, Compass, ChevronDown, ChevronUp } from "lucide-react" +import { api } from "@/lib/api" +import { useModels, useUpdates, useDiscover } from "@/lib/queries" +import { cn } from "@/lib/utils" +import { fmtBytes } from "@/lib/format" +import { FitBadge } from "@/components/models/ModelBadges" +import { AddModel } from "./AddModel" + +const ROLE_METADATA: Record = { + vision: { + title: "Bilder & Vision", + desc: "Verarbeitet Bilder, Screenshots und visuelle Diagramme in multimodalen Chats.", + icon: Eye + }, + coder: { + title: "Coden & Entwicklung", + desc: "Autovervollständigung, Refactoring und Codegenerierung direkt in deiner IDE.", + icon: Code + }, + reasoning: { + title: "Logik & Nachdenken", + desc: "Komplexe logische Gedankengänge, Mathematik und tiefgründiges Planen (Reasoning).", + icon: Brain + }, + agent: { + title: "Autonomer Agent (Hermes)", + desc: "Führt selbstständig Terminalbefehle aus und interagiert mit deinem Homelab.", + icon: Bot + }, + scout: { + title: "Allrounder & Chat", + desc: "Schnelle Antworten, Zusammenfassungen, Übersetzungen und alltägliche Fragen.", + icon: Compass + } +} + +export function Discover() { + const { data, isLoading: loading, error: loadErr } = useDiscover() + const { data: modelsResp } = useModels() + const { data: updates } = useUpdates() + const models = modelsResp?.models ?? [] + const error = loadErr ? String(loadErr) : "" + const [installing, setInstalling] = useState>({}) + const [expandedAlternatives, setExpandedAlternatives] = useState>({}) + const [showExpert, setShowExpert] = useState(false) + + async function install(repo: string, role: string, quant: string, toolCapable: boolean) { + setInstalling((s) => ({ ...s, [repo]: "Starte..." })) + try { + await api("/api/models/install", { + method: "POST", + body: JSON.stringify({ repo, role, quant, jinja: toolCapable }), + }) + setInstalling((s) => ({ ...s, [repo]: "Download läuft" })) + } catch (e) { + setInstalling((s) => ({ ...s, [repo]: "Fehler" })) + } + } + + if (loading) return
Analysiere Hardware und suche passende GGUF-Empfehlungen…
+ if (error || !data) + return ( +
+ Empfehlungsdienst temporär nicht erreichbar ({error}). +
+ ) + + return ( +
+ {/* Informational Header */} +
+
+ Modell-Registry geladen für {data.sys_ram_gb} GB System-RAM. +
+
+ + Empfehlungen sind automatisch auf deine Box-Hardware optimiert. +
+
+ + {/* Sockets/Slots Grid */} +
+ {data.categories.map((cat) => { + const meta = ROLE_METADATA[cat.role] || { + title: cat.title || cat.role, + desc: "Spezifisches Modell für diese Systemrolle.", + icon: Layers + } + const IconComponent = meta.icon + + // Check if a model is installed for this role + const installedModel = models.find((m) => m.role === cat.role) + + // Check if an upgrade is available for this role + const hasUpgrade = updates?.model_list.find((u) => u.role === cat.role) + + // Get the primary recommended model + const recommendedModel = cat.models.find((m) => m.repo === cat.recommended) || cat.models[0] + if (!recommendedModel) return null + + const isInstallingRecommended = installing[recommendedModel.repo] + const alternativeModels = cat.models.filter((m) => m.repo !== cat.recommended) + const isExpanded = !!expandedAlternatives[cat.role] + + return ( +
+
+ {/* Socket Header */} +
+
+
+ +
+
+

{meta.title}

+ + Rolle: {cat.role} + +
+
+ + {/* Status Badges */} + {installedModel ? ( + + + Aktiviert + + ) : ( + + Frei + + )} +
+ + {/* Role Description */} +

+ {meta.desc} +

+ + {/* Current vs Recommended model card */} +
+ {installedModel ? ( +
+
Aktive GGUF-Belegung
+
+ {installedModel.name.split("/").pop()} +
+
+ Größe: {fmtBytes(installedModel.size_bytes || 0)} + + Quant: {installedModel.quant || "GGUF"} +
+
+ ) : ( +
+
Empfohlenes Modell
+
+ {recommendedModel.name} +
+
+ Ersteller: {recommendedModel.author} + + Quant: {recommendedModel.quant} +
+
+ +
+
+ )} +
+ + {/* Main Action Button */} +
+ {installedModel ? ( + hasUpgrade ? ( +
+
+ + Bessere Version in der Registry: {hasUpgrade.repo.split("/").pop()} +
+ +
+ ) : ( +
+ Auf neuestem Stand +
+ ) + ) : ( + + )} +
+
+ + {/* Collapsible alternatives list */} + {alternativeModels.length > 0 && ( +
+ + + {isExpanded && ( +
+ {alternativeModels.map((alt) => ( +
+
+
+ {alt.name} +
+
+ Quant: {alt.quant} + + {alt.fit.text} +
+
+ +
+ ))} +
+ )} +
+ )} +
+ ) + })} +
+ + {/* Collapsible Custom Hugging Face Downloader */} +
+ + {showExpert && ( +
+ +
+ )} +
+
+ ) +}