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>
This commit is contained in:
parent
88e9e88f46
commit
1c1c43d28b
23 changed files with 521 additions and 50 deletions
|
|
@ -1,8 +1,17 @@
|
|||
import React from 'react';
|
||||
import React, { useCallback } from 'react';
|
||||
import { useWindowManager } from '../../contexts/WindowManagerContext';
|
||||
import { useCurrentUser } from '../../hooks/useCurrentUser';
|
||||
import { logout } from '../../api/endpoints';
|
||||
|
||||
export const SidebarWindowButtons: React.FC = () => {
|
||||
const { openWindow } = useWindowManager();
|
||||
const { user } = useCurrentUser();
|
||||
const isAdmin = !!user?.is_admin;
|
||||
|
||||
const onLogout = useCallback(async () => {
|
||||
if (!confirm('Log out?')) return;
|
||||
try { await logout(); } catch { window.location.href = '/login'; }
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="ml-tool-links">
|
||||
|
|
@ -18,6 +27,18 @@ export const SidebarWindowButtons: React.FC = () => {
|
|||
onClick={() => openWindow('vitalsharing', 'Vital Sharing')}>🤝 Vitals</span>
|
||||
<span className="ml-tool-link" style={{ cursor: 'pointer' }}
|
||||
onClick={() => openWindow('combatpicker', 'Combat Stats')}>⚔️ Combat</span>
|
||||
{isAdmin && (
|
||||
<span className="ml-tool-link" style={{ cursor: 'pointer' }}
|
||||
onClick={() => openWindow('adminusers', 'Admin · Users')}>🛡️ Admin</span>
|
||||
)}
|
||||
<span
|
||||
className="ml-tool-link ml-tool-link-logout"
|
||||
style={{ cursor: 'pointer' }}
|
||||
onClick={onLogout}
|
||||
title={user ? `Logged in as ${user.username}` : 'Log out'}
|
||||
>
|
||||
🚪 Log out{user ? ` (${user.username})` : ''}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue