Changeset 505f39a for lan-frontend/src/App.jsx
- Timestamp:
- 01/21/26 13:35:44 (6 months ago)
- Branches:
- master
- Children:
- d42aac3
- Parents:
- 2058e5c
- File:
-
- 1 edited
-
lan-frontend/src/App.jsx (modified) (11 diffs)
Legend:
- Unmodified
- Added
- Removed
-
lan-frontend/src/App.jsx
r2058e5c r505f39a 1 import React from "react"; 2 import {useEffect, useMemo, useState} from "react"; 1 import React, {useEffect, useMemo, useState} from "react"; 3 2 import "./styles/theme.css"; 4 3 4 import Login from "./components/Login"; 5 5 import TopBar from "./components/TopBar"; 6 6 import ComputerCard from "./components/ComputerCard"; … … 22 22 const [selectedEnv, setSelectedEnv] = useState("default"); 23 23 24 const [me, setMe] = useState(null); 25 const [meLoading, setMeLoading] = useState(true); 26 27 // const [openAI, setOpenAI] = useState(false); 28 // const [scope, setScope] = useState(null); 29 30 31 async function loadMe() { 32 setMeLoading(true); 33 try { 34 const r = await fetch("/api/me", {credentials: "include"}); 35 if (r.ok) { 36 const data = await r.json(); 37 setMe(data.user); 38 } else { 39 setMe(null); 40 } 41 } catch (e) { 42 console.error("loadMe error", e); 43 setMe(null); 44 } finally { 45 setMeLoading(false); 46 } 47 } 48 24 49 async function refresh() { 25 50 try { 26 51 setLoading(true); 27 52 const [s, c] = await Promise.all([ 28 fetch("/api/stats" ).then((r) => r.json()),53 fetch("/api/stats", {credentials: "include"}).then((r) => r.json()), 29 54 fetch("/api/computers", { 55 credentials: "include", 30 56 headers: {"X-Env": selectedEnv}, 31 57 }).then((r) => r.json()), 32 58 ]); 59 33 60 setStats(s); 34 61 setComputers(Array.isArray(c) ? c : []); … … 41 68 } 42 69 70 // on mount: check session 43 71 useEffect(() => { 44 refresh(); 45 }, [selectedEnv]); 72 loadMe(); 73 }, []); 74 75 // when logged in OR env changed, refresh data 76 useEffect(() => { 77 if (me) refresh(); 78 // eslint-disable-next-line react-hooks/exhaustive-deps 79 }, [me, selectedEnv]); 46 80 47 81 const filtered = useMemo(() => { … … 51 85 .filter((c) => { 52 86 if (!q) return true; 53 const hay = [c.name, c.user, c.ip, c.os, c.status].filter(Boolean).join(" ").toLowerCase(); 87 const hay = [c.name, c.user, c.ip, c.os, c.status] 88 .filter(Boolean) 89 .join(" ") 90 .toLowerCase(); 54 91 return hay.includes(q); 55 92 }); 56 93 }, [computers, query, status]); 94 95 // Gate UI 96 if (meLoading) return <div style={{padding: 20}}>Loading…</div>; 97 if (!me) return <Login onDone={loadMe}/>; 57 98 58 99 return ( … … 64 105 onEnvChange={(env) => setSelectedEnv(env)} 65 106 selectedEnv={selectedEnv} 107 me={me} 108 onLoggedOut={loadMe} 66 109 /> 110 67 111 68 112 {/* STATS */} … … 104 148 /> 105 149 106 <select className="select" value={status} onChange={(e) => setStatus(e.target.value)}> 150 <select 151 className="select" 152 value={status} 153 onChange={(e) => setStatus(e.target.value)} 154 > 107 155 <option value="">All status</option> 108 156 <option value="online">Online</option> … … 111 159 </select> 112 160 113 <button className="btn primary" onClick={refresh}>Refresh</button> 161 <button className="btn primary" onClick={refresh}> 162 Refresh 163 </button> 114 164 </div> 115 165 </div> … … 122 172 <div style={{display: "flex", gap: 10, alignItems: "center"}}> 123 173 <span className="pill">{filtered.length} computers</span> 124 <button className="btn" onClick={() => { 125 setQuery(""); 126 setStatus(""); 127 }}>Reset 174 <button 175 className="btn" 176 onClick={() => { 177 setQuery(""); 178 setStatus(""); 179 }} 180 > 181 Reset 128 182 </button> 129 183 </div> … … 142 196 ))} 143 197 {filtered.length === 0 && ( 144 <div style={{color: "var(--dim)"}}>No computers match filter.</div> 198 <div style={{color: "var(--dim)"}}> 199 No computers match filter. 200 </div> 145 201 )} 146 202 </div> … … 160 216 161 217 {/* AI DRAWER */} 218 {/*<button onClick={() => setOpenAI(true)}>AI</button>*/} 219 220 {/*<AIAssistantDrawer*/} 221 {/* open={openAI}*/} 222 {/* onClose={() => setOpenAI(false)}*/} 223 {/* computers={computers}*/} 224 {/* scope={scope}*/} 225 {/* setScope={setScope}*/} 226 {/* apiBase={import.meta.env.VITE_API_BASE}*/} 227 {/*/>*/} 228 162 229 <AIAssistantDrawer 163 230 open={aiOpen} … … 166 233 scope={aiScope} 167 234 setScope={setAiScope} 235 apiBase={import.meta.env.VITE_API_BASE} 168 236 /> 237 238 169 239 </div> 170 240 );
Note:
See TracChangeset
for help on using the changeset viewer.
