corrected admin view
This commit is contained in:
parent
c59ad6cb70
commit
25c768d013
|
|
@ -19,6 +19,7 @@
|
||||||
- **authentik client auth method**: Admin OIDC settings now include an advanced `client_secret_basic` / `client_secret_post` token endpoint authentication method selector. The default remains `client_secret_basic`, matching the previous `openid-client` behavior.
|
- **authentik client auth method**: Admin OIDC settings now include an advanced `client_secret_basic` / `client_secret_post` token endpoint authentication method selector. The default remains `client_secret_basic`, matching the previous `openid-client` behavior.
|
||||||
- **Admin user role management**: Admin Users table now lets an admin promote another user to `admin` or demote an admin back to `user`, with protections against changing your own role or removing the last admin account.
|
- **Admin user role management**: Admin Users table now lets an admin promote another user to `admin` or demote an admin back to `user`, with protections against changing your own role or removing the last admin account.
|
||||||
- **Single-user mode recovery**: User Settings now shows a Login Mode section while single-user mode is active, allowing the default user to restore multi-user login without needing access to Admin routes.
|
- **Single-user mode recovery**: User Settings now shows a Login Mode section while single-user mode is active, allowing the default user to restore multi-user login without needing access to Admin routes.
|
||||||
|
- **Admin navigation parity**: Admin users now keep the normal app navigation and get an Admin link after Status; `/admin` uses the same top nav so admins can return to Tracker/Bills/Categories/Profile/Settings/Status without typing a URL. Backend `/admin` protection remains unchanged.
|
||||||
- **Admin-controlled auth method toggles** in Admin panel (Authentication Methods card):
|
- **Admin-controlled auth method toggles** in Admin panel (Authentication Methods card):
|
||||||
- `local_login_enabled` — enable/disable local username/password login (default: enabled)
|
- `local_login_enabled` — enable/disable local username/password login (default: enabled)
|
||||||
- `oidc_login_enabled` — enable/disable OIDC/authentik login (default: disabled)
|
- `oidc_login_enabled` — enable/disable OIDC/authentik login (default: disabled)
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,10 @@ function RequireAuth({ children, role }) {
|
||||||
return <Navigate to="/login" state={{ from: location }} replace />;
|
return <Navigate to="/login" state={{ from: location }} replace />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const roleAllowed = !role || user.role === role || (role === 'user' && user.role === 'admin');
|
||||||
|
|
||||||
// Role mismatch
|
// Role mismatch
|
||||||
if (role && user.role !== role) {
|
if (!roleAllowed) {
|
||||||
return <Navigate to={user.role === 'admin' ? '/admin' : '/'} replace />;
|
return <Navigate to={user.role === 'admin' ? '/admin' : '/'} replace />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -98,14 +98,16 @@ function UserMenu({ adminMode = false }) {
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="end" className="w-52">
|
<DropdownMenuContent align="end" className="w-52">
|
||||||
<DropdownMenuLabel className="truncate">{name}</DropdownMenuLabel>
|
<DropdownMenuLabel className="truncate">{name}</DropdownMenuLabel>
|
||||||
{!adminMode && (
|
|
||||||
<>
|
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem onSelect={() => navigate('/profile')}>
|
<DropdownMenuItem onSelect={() => navigate('/profile')}>
|
||||||
<User className="h-4 w-4" />
|
<User className="h-4 w-4" />
|
||||||
Profile
|
Profile
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</>
|
{user?.role === 'admin' && !adminMode && (
|
||||||
|
<DropdownMenuItem onSelect={() => navigate('/admin')}>
|
||||||
|
<ShieldCheck className="h-4 w-4" />
|
||||||
|
Admin
|
||||||
|
</DropdownMenuItem>
|
||||||
)}
|
)}
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem destructive onSelect={handleLogout}>
|
<DropdownMenuItem destructive onSelect={handleLogout}>
|
||||||
|
|
@ -119,7 +121,10 @@ function UserMenu({ adminMode = false }) {
|
||||||
|
|
||||||
export default function Sidebar({ adminMode = false }) {
|
export default function Sidebar({ adminMode = false }) {
|
||||||
const [mobileOpen, setMobileOpen] = useState(false);
|
const [mobileOpen, setMobileOpen] = useState(false);
|
||||||
const items = adminMode ? adminNavItems : userNavItems;
|
const { user } = useAuth();
|
||||||
|
const items = user?.role === 'admin'
|
||||||
|
? [...userNavItems, ...adminNavItems]
|
||||||
|
: userNavItems;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="sticky top-0 z-40 border-b border-border/70 bg-background/85 shadow-sm shadow-foreground/5 backdrop-blur-xl supports-[backdrop-filter]:bg-background/70">
|
<header className="sticky top-0 z-40 border-b border-border/70 bg-background/85 shadow-sm shadow-foreground/5 backdrop-blur-xl supports-[backdrop-filter]:bg-background/70">
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ function requireAuth(req, res, next) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function requireUser(req, res, next) {
|
function requireUser(req, res, next) {
|
||||||
if (req.user?.role !== 'user') {
|
if (!['user', 'admin'].includes(req.user?.role)) {
|
||||||
return res.status(403).json({ error: 'Access denied: user account required' });
|
return res.status(403).json({ error: 'Access denied: user account required' });
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue