1import{j as e,a5 as S,a9 as l,ac as E,a7 as k,ao as u,a8 as M,ab as h,ad as $,aI as N,aq as R,aA as y}from"./mantine-CGEClQ3v.js";import{r as t}from"./vendor-D6eLTwOz.js";import{u as G,A as z,I as v,a7 as H,c as J,M as V}from"./app-IRs7ANyC.js";import{T as r}from"./Table-Zp2sxSz8.js";import{I as Y}from"./IconBan-WBs1OlEs.js";import"./IconBrain-RWha6D0u.js";import"./chunk-reload-CTWyn8eB.js";const se=()=>{const{user:K,impersonating:a,realUser:c}=G(),[B,g]=t.useState([]),[D,A]=t.useState(!0),[w,m]=t.useState(null),[T,F]=t.useState(""),[x,L]=t.useState((a==null?void 0:a.id)||null),[d,p]=t.useState(null),[C,f]=t.useState(null);t.useEffect(()=>{L((a==null?void 0:a.id)||null)},[a]),t.useEffect(()=>{fetch("/api/admin/users",{credentials:"include"}).then(s=>{if(!s.ok)throw s.status===403?new Error("Admin access required"):new Error("Failed to fetch users");return s.json()}).then(s=>{g(s.users),A(!1)}).catch(s=>{m(s.message),A(!1)})},[]);const O=async s=>{try{const n=await fetch(`/api/admin/impersonate/${s}`,{method:"POST",credentials:"include"});if(!n.ok){const i=await n.json();throw new Error(i.error||"Failed to impersonate")}window.location.reload()}catch(n){m(n instanceof Error?n.message:"Failed to impersonate")}},b=async()=>{try{const s=await fetch("/api/admin/stop-impersonation",{method:"POST",credentials:"include"});if(!s.ok){const n=await s.json();throw new Error(n.error||"Failed to stop impersonation")}window.location.reload()}catch(s){m(s instanceof Error?s.message:"Failed to stop impersonation")}},P=async s=>{try{const n=await fetch(`/api/admin/users/${s}/ban`,{method:"POST",credentials:"include"});if(!n.ok){const o=await n.json();throw new Error(o.error||"Failed to update ban status")}const i=await n.json();g(o=>o.map(j=>j.id===s?{...j,isBanned:i.isBanned,bannedAt:i.isBanned?new Date().toISOString():null}:j))}catch(n){m(n instanceof Error?n.message:"Failed to update ban status")}},q=async s=>{try{f(null);const n=await fetch(`/api/admin/users/${s}`,{method:"DELETE",credentials:"include"}),i=await n.json();if(!n.ok){const o=i.reasons?i.reasons.join(", "):i.error;f(o);return}g(o=>o.filter(j=>j.id!==s)),p(null)}catch(n){f(n instanceof Error?n.message:"Failed to delete user")}},I=B.filter(s=>{var n;return s.email.toLowerCase().includes(T.toLowerCase())||((n=s.name)==null?void 0:n.toLowerCase().includes(T.toLowerCase()))});return D?e.jsx(z,{children:e.jsx(S,{size:"lg",py:"xl",children:e.jsx(l,{children:"Loading..."})})}):w==="Admin access required"?e.jsx(z,{children:e.jsx(S,{size:"lg",py:"xl",children:e.jsx(E,{icon:e.jsx(v,{size:16}),title:"Access Denied",color:"red",children:"You do not have admin access to view this page."})})}):e.jsx(z,{children:e.jsxs(S,{size:"lg",py:"xl",children:[e.jsxs(k,{gap:"lg",children:[e.jsxs(u,{justify:"space-between",children:[e.jsxs("div",{children:[e.jsx(M,{order:2,children:"User Management"}),e.jsx(l,{c:"dimmed",size:"sm",children:"View and impersonate users for debugging"})]}),x&&e.jsx(h,{color:"orange",onClick:b,children:"Stop Impersonating"})]}),w&&e.jsx(E,{icon:e.jsx(v,{size:16}),title:"Error",color:"red",children:w}),e.jsx($,{placeholder:"Search by name or email...",leftSection:e.jsx(N,{size:16}),value:T,onChange:s=>F(s.target.value)}),e.jsxs(r,{striped:!0,highlightOnHover:!0,children:[e.jsx(r.Thead,{children:e.jsxs(r.Tr,{children:[e.jsx(r.Th,{children:"User"}),e.jsx(r.Th,{children:"Email"}),e.jsx(r.Th,{children:"Role"}),e.jsx(r.Th,{children:"Joined"}),e.jsx(r.Th,{children:"Actions"})]})}),e.jsx(r.Tbody,{children:I.map(s=>{var n;return e.jsxs(r.Tr,{children:[e.jsx(r.Td,{children:e.jsxs(u,{gap:"sm",children:[e.jsx(R,{src:s.avatarUrl,radius:"xl",size:"sm",children:((n=s.name)==null?void 0:n.charAt(0))||s.email.charAt(0)}),e.jsx(l,{size:"sm",fw:500,children:s.name||"No name"})]})}),e.jsx(r.Td,{children:e.jsx(l,{size:"sm",children:s.email})}),e.jsx(r.Td,{children:e.jsxs(u,{gap:"xs",children:[s.isAdmin?e.jsx(y,{color:"blue",children:"Admin"}):e.jsx(y,{color:"gray",children:"User"}),s.isBanned&&e.jsx(y,{color:"red",children:"Banned"})]})}),e.jsx(r.Td,{children:e.jsx(l,{size:"sm",c:"dimmed",children:new Date(s.createdAt).toLocaleDateString()})}),e.jsx(r.Td,{children:e.jsxs(u,{gap:"xs",children:[e.jsx(h,{size:"xs",variant:x===s.id?"filled":"light",color:x===s.id?"orange":"blue",leftSection:e.jsx(H,{size:14}),onClick:()=>x===s.id?b():O(s.id),disabled:s.id===(c==null?void 0:c.id),children:x===s.id?"Stop":"Impersonate"}),!s.isAdmin&&s.id!==(c==null?void 0:c.id)&&e.jsxs(e.Fragment,{children:[e.jsx(h,{size:"xs",variant:"light",color:s.isBanned?"green":"red",leftSection:e.jsx(Y,{size:14}),onClick:()=>P(s.id),children:s.isBanned?"Unban":"Ban"}),e.jsx(h,{size:"xs",variant:"light",color:"red",leftSection:e.jsx(J,{size:14}),onClick:()=>{f(null),p(s)},children:"Delete"})]})]})})]},s.id)})})]}),I.length===0&&e.jsx(l,{ta:"center",c:"dimmed",py:"xl",children:"No users found"})]}),e.jsx(V,{opened:!!d,onClose:()=>p(null),title:"Delete User",centered:!0,children:e.jsxs(k,{gap:"md",children:[e.jsxs(l,{size:"sm",children:["This will permanently delete ",e.jsx("strong",{children:d==null?void 0:d.email})," and their organization. This only works for simple users with no environments, integrations, or other members."]}),C&&e.jsx(E,{color:"red",title:"Cannot delete",children:C}),e.jsxs(u,{justify:"flex-end",children:[e.jsx(h,{variant:"default",onClick:()=>p(null),children:"Cancel"}),e.jsx(h,{color:"red",onClick:()=>d&&q(d.id),children:"Delete User"})]})]})})]})})};export{se as AdminPage};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.