Argon2id password hashing, JWT access tokens with rotating HttpOnly refresh cookies and reuse detection, login rate limiting, auth audit log, bootstrap admin, admin-only user CRUD and password reset, OpenAPI spec. Vue login page, auth store with automatic token refresh, route guards, sidebar shell with toasts and placeholder pages, user management page. All tests green: 40 backend, 12 Vitest, 4 Playwright. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
50 lines
1.6 KiB
Vue
50 lines
1.6 KiB
Vue
<script setup lang="ts">
|
|
import { useRouter } from 'vue-router'
|
|
import { useAuthStore } from '../stores/auth'
|
|
|
|
const auth = useAuthStore()
|
|
const router = useRouter()
|
|
const nav = [
|
|
{ to: '/', label: 'Dashboard' },
|
|
{ to: '/updates', label: 'Updates' },
|
|
{ to: '/vulnerabilities', label: 'Vulnerabilities' },
|
|
{ to: '/backups', label: 'Backups' },
|
|
{ to: '/users', label: 'Users', admin: true },
|
|
{ to: '/settings', label: 'Settings' },
|
|
]
|
|
|
|
async function signOut() {
|
|
await auth.logout()
|
|
router.push('/login')
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="flex min-h-screen bg-gray-50 text-gray-900">
|
|
<aside class="flex w-56 flex-col border-r border-gray-200 bg-white">
|
|
<div class="px-5 py-4 text-lg font-semibold">SoftVisor Monitoring</div>
|
|
<nav class="flex-1 space-y-1 px-3">
|
|
<template v-for="item in nav" :key="item.to">
|
|
<RouterLink
|
|
v-if="!item.admin || auth.isAdmin"
|
|
:to="item.to"
|
|
class="block rounded-md px-3 py-2 text-sm hover:bg-gray-100"
|
|
active-class="bg-gray-100 font-medium"
|
|
:exact-active-class="item.to === '/' ? 'bg-gray-100 font-medium' : undefined"
|
|
>
|
|
{{ item.label }}
|
|
</RouterLink>
|
|
</template>
|
|
</nav>
|
|
<div class="border-t border-gray-200 px-5 py-4 text-sm">
|
|
<div class="truncate font-medium">{{ auth.user?.display_name }}</div>
|
|
<div class="truncate text-gray-500">{{ auth.user?.email }}</div>
|
|
<button class="mt-2 text-blue-600 hover:underline" @click="signOut">Sign out</button>
|
|
</div>
|
|
</aside>
|
|
<main class="flex-1 p-8">
|
|
<RouterView />
|
|
</main>
|
|
</div>
|
|
</template>
|