MosswartOverlord/static/assets/PlayerDashboardWindow-qdSQRhha.js
Erik 1c1c43d28b feat(dashboard): logout button + admin user-management window
Logout: new sidebar link 'Log out (username)' that POSTs /api/logout
(clears session cookie) and navigates to /login. Visible to everyone.
Replaces 'no logout functionality' state where users could only get
out by deleting cookies manually.

Admin window: new 'Admin · Users' window (only shown when current
user.is_admin) lists all users in a table with:
  - Add user (username + password + admin checkbox)
  - Reset password inline per row
  - Toggle admin per row
  - Delete user per row (blocked for self)
Wraps the existing /api-admin/users CRUD endpoints in main.py.

Plumbing: useCurrentUser hook fetches /me on mount; apiPatch+apiDelete
helpers added to api/client.ts; new endpoint wrappers exported from
api/endpoints.ts; AdminUsersWindow.tsx registered in WindowRenderer
under id prefix 'adminusers'; CSS for admin table/form/buttons and
the muted-red logout link.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-15 20:10:10 +02:00

1 line
5.1 KiB
JavaScript

import{r as d,j as t,D as y}from"./index-3SHiQu4l.js";import"./react-yfL0ty4i.js";const A=({id:u,zIndex:f,characters:h})=>{const[o,k]=d.useState("kph"),[c,x]=d.useState(!1),p=d.useMemo(()=>{const e=Array.from(h.values()).filter(r=>r.telemetry).map(r=>{var i,g,m;const s=r.telemetry;return{name:r.name,kills:s.kills??0,kph:parseInt(s.kills_per_hour)||0,totalKills:s.total_kills??0,rares:s.total_rares??0,sessionRares:s.session_rares??0,deaths:parseInt(s.deaths)||0,totalDeaths:parseInt(s.total_deaths)||0,uptime:((i=s.onlinetime)==null?void 0:i.replace(/^00\./,""))??"",state:s.vt_state??"idle",tapers:parseInt(s.prismatic_taper_count)||0,hp:((g=r.vitals)==null?void 0:g.health_percentage)??0,vitae:((m=r.vitals)==null?void 0:m.vitae)??0}});return e.sort((r,s)=>{let i=0;switch(o){case"name":i=r.name.localeCompare(s.name);break;case"kills":i=r.kills-s.kills;break;case"kph":i=r.kph-s.kph;break;case"rares":i=r.rares-s.rares;break;case"deaths":i=r.totalDeaths-s.totalDeaths;break;case"uptime":i=r.uptime.localeCompare(s.uptime);break;case"state":i=r.state.localeCompare(s.state);break}return c?i:-i}),e},[h,o,c]),l=e=>{o===e?x(!c):(k(e),x(!1))},a=e=>({padding:"4px 6px",cursor:"pointer",userSelect:"none",color:o===e?"#6af":"#888",fontSize:"0.65rem",fontWeight:600,whiteSpace:"nowrap",borderBottom:"1px solid #444"}),n=e=>o===e?c?" ▲":" ▼":"";return t.jsx(y,{id:u,title:"Player Dashboard",zIndex:f,width:850,height:500,children:t.jsxs("div",{style:{flex:1,overflow:"auto",fontSize:"0.73rem"},children:[t.jsxs("table",{style:{width:"100%",borderCollapse:"collapse"},children:[t.jsx("thead",{children:t.jsxs("tr",{style:{position:"sticky",top:0,background:"#1a1a1a",zIndex:1},children:[t.jsxs("th",{style:{...a("name"),textAlign:"left"},onClick:()=>l("name"),children:["Character",n("name")]}),t.jsxs("th",{style:{...a("state"),textAlign:"center"},onClick:()=>l("state"),children:["State",n("state")]}),t.jsxs("th",{style:{...a("kph"),textAlign:"right"},onClick:()=>l("kph"),children:["KPH",n("kph")]}),t.jsxs("th",{style:{...a("kills"),textAlign:"right"},onClick:()=>l("kills"),children:["Session",n("kills")]}),t.jsx("th",{style:{textAlign:"right",padding:"4px 6px",color:"#888",fontSize:"0.65rem",fontWeight:600,borderBottom:"1px solid #444"},children:"Total"}),t.jsxs("th",{style:{...a("rares"),textAlign:"right"},onClick:()=>l("rares"),children:["Rares",n("rares")]}),t.jsxs("th",{style:{...a("deaths"),textAlign:"right"},onClick:()=>l("deaths"),children:["Deaths",n("deaths")]}),t.jsxs("th",{style:{...a("uptime"),textAlign:"right"},onClick:()=>l("uptime"),children:["Uptime",n("uptime")]}),t.jsx("th",{style:{textAlign:"right",padding:"4px 6px",color:"#888",fontSize:"0.65rem",fontWeight:600,borderBottom:"1px solid #444"},children:"HP%"}),t.jsx("th",{style:{textAlign:"right",padding:"4px 6px",color:"#888",fontSize:"0.65rem",fontWeight:600,borderBottom:"1px solid #444"},children:"Vitae"}),t.jsx("th",{style:{textAlign:"right",padding:"4px 6px",color:"#888",fontSize:"0.65rem",fontWeight:600,borderBottom:"1px solid #444"},children:"Tapers"})]})}),t.jsx("tbody",{children:p.map(e=>{const r=e.state.toLowerCase(),s=r==="combat"||r==="hunt";return t.jsxs("tr",{style:{borderBottom:"1px solid #1a1a1a"},children:[t.jsx("td",{style:{padding:"3px 6px",color:"#ccc",fontWeight:500,maxWidth:180,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.name}),t.jsx("td",{style:{textAlign:"center",padding:"3px 6px"},children:t.jsx("span",{style:{fontSize:"0.6rem",padding:"1px 6px",borderRadius:3,background:s?"rgba(68,204,68,0.15)":r==="idle"||r==="default"?"rgba(100,100,100,0.2)":"rgba(204,68,68,0.15)",color:s?"#4c4":r==="idle"||r==="default"?"#888":"#c44"},children:e.state})}),t.jsx("td",{style:{textAlign:"right",padding:"3px 6px",color:"#4c4",fontVariantNumeric:"tabular-nums"},children:e.kph.toLocaleString()}),t.jsx("td",{style:{textAlign:"right",padding:"3px 6px",color:"#ccc",fontVariantNumeric:"tabular-nums"},children:e.kills.toLocaleString()}),t.jsx("td",{style:{textAlign:"right",padding:"3px 6px",color:"#888",fontVariantNumeric:"tabular-nums"},children:e.totalKills.toLocaleString()}),t.jsxs("td",{style:{textAlign:"right",padding:"3px 6px",color:"#fc0",fontVariantNumeric:"tabular-nums"},children:[e.rares,e.sessionRares>0?` (${e.sessionRares})`:""]}),t.jsx("td",{style:{textAlign:"right",padding:"3px 6px",color:e.totalDeaths>0?"#c66":"#555",fontVariantNumeric:"tabular-nums"},children:e.totalDeaths}),t.jsx("td",{style:{textAlign:"right",padding:"3px 6px",color:"#888",fontVariantNumeric:"tabular-nums"},children:e.uptime}),t.jsxs("td",{style:{textAlign:"right",padding:"3px 6px",fontVariantNumeric:"tabular-nums",color:e.hp>80?"#4c4":e.hp>40?"#ca0":"#c44"},children:[e.hp.toFixed(0),"%"]}),t.jsx("td",{style:{textAlign:"right",padding:"3px 6px",fontVariantNumeric:"tabular-nums",color:e.vitae>0?"#f66":"#333"},children:e.vitae>0?`${e.vitae}%`:""}),t.jsx("td",{style:{textAlign:"right",padding:"3px 6px",color:"#888",fontVariantNumeric:"tabular-nums"},children:e.tapers.toLocaleString()})]},e.name)})})]}),p.length===0&&t.jsx("div",{style:{padding:20,color:"#666",textAlign:"center"},children:"No characters online"})]})})};export{A as PlayerDashboardWindow};