diff --git a/web/src/router/index.ts b/web/src/router/index.ts
index b6a0df6..91cc984 100644
--- a/web/src/router/index.ts
+++ b/web/src/router/index.ts
@@ -1,25 +1,49 @@
import { createRouter, createWebHashHistory } from 'vue-router'
-import LabelView from '../views/LabelView.vue'
-// Views are lazy-loaded to keep initial bundle small
-const FetchView = () => import('../views/FetchView.vue')
-const StatsView = () => import('../views/StatsView.vue')
-const BenchmarkView = () => import('../views/BenchmarkView.vue')
-const SettingsView = () => import('../views/SettingsView.vue')
-const CorrectionsView = () => import('../views/CorrectionsView.vue')
-const ModelsView = () => import('../views/ModelsView.vue')
-const ImitateView = () => import('../views/ImitateView.vue')
+// Lazy-loaded views
+const DashboardView = () => import('../views/DashboardView.vue')
+const LabelView = () => import('../views/LabelView.vue')
+const FetchView = () => import('../views/FetchView.vue')
+const CorrectionsView = () => import('../views/CorrectionsView.vue')
+const ImitateView = () => import('../views/ImitateView.vue')
+const BenchmarkView = () => import('../views/BenchmarkView.vue')
+const CompareView = () => import('../views/CompareView.vue')
+const TrainJobsView = () => import('../views/TrainJobsView.vue')
+const TrainResultsView = () => import('../views/TrainResultsView.vue')
+const ModelsView = () => import('../views/ModelsView.vue')
+const SettingsView = () => import('../views/SettingsView.vue')
+
+export const routes = [
+ // ── Top-level ────────────────────────────────────────────
+ { path: '/', component: DashboardView, meta: { title: 'Dashboard' } },
+ { path: '/fleet', component: ModelsView, meta: { title: 'Fleet' } },
+ { path: '/settings', component: SettingsView, meta: { title: 'Settings' } },
+
+ // ── Data domain ──────────────────────────────────────────
+ { path: '/data/label', component: LabelView, meta: { title: 'Label' } },
+ { path: '/data/fetch', component: FetchView, meta: { title: 'Fetch' } },
+ { path: '/data/corrections', component: CorrectionsView, meta: { title: 'Corrections' } },
+ { path: '/data/imitate', component: ImitateView, meta: { title: 'Imitate' } },
+
+ // ── Eval domain ──────────────────────────────────────────
+ { path: '/eval/benchmark', component: BenchmarkView, meta: { title: 'Benchmark' } },
+ { path: '/eval/compare', component: CompareView, meta: { title: 'Compare' } },
+
+ // ── Train domain ─────────────────────────────────────────
+ { path: '/train/jobs', component: TrainJobsView, meta: { title: 'Training Jobs' } },
+ { path: '/train/results', component: TrainResultsView, meta: { title: 'Training Results' } },
+
+ // ── Backward-compat redirects ────────────────────────────
+ { path: '/benchmark', redirect: '/eval/benchmark' },
+ { path: '/models', redirect: '/fleet' },
+ { path: '/stats', redirect: '/' },
+ { path: '/label', redirect: '/data/label' },
+ { path: '/fetch', redirect: '/data/fetch' },
+ { path: '/corrections', redirect: '/data/corrections' },
+ { path: '/imitate', redirect: '/data/imitate' },
+]
export const router = createRouter({
history: createWebHashHistory(),
- routes: [
- { path: '/', component: LabelView, meta: { title: 'Label' } },
- { path: '/fetch', component: FetchView, meta: { title: 'Fetch' } },
- { path: '/stats', component: StatsView, meta: { title: 'Stats' } },
- { path: '/benchmark', component: BenchmarkView, meta: { title: 'Benchmark' } },
- { path: '/models', component: ModelsView, meta: { title: 'Models' } },
- { path: '/imitate', component: ImitateView, meta: { title: 'Imitate' } },
- { path: '/corrections', component: CorrectionsView, meta: { title: 'Corrections' } },
- { path: '/settings', component: SettingsView, meta: { title: 'Settings' } },
- ],
+ routes,
})
diff --git a/web/src/router/router.test.ts b/web/src/router/router.test.ts
new file mode 100644
index 0000000..60b6ea7
--- /dev/null
+++ b/web/src/router/router.test.ts
@@ -0,0 +1,94 @@
+import { describe, it, expect } from 'vitest'
+import { createRouter, createWebHashHistory } from 'vue-router'
+
+// Import the raw routes array so we can test structure without mounting App
+import { routes } from './index'
+
+describe('router routes', () => {
+ it('exports a routes array', () => {
+ expect(Array.isArray(routes)).toBe(true)
+ })
+
+ it('has / pointing to DashboardView', () => {
+ const root = routes.find(r => r.path === '/')
+ expect(root).toBeDefined()
+ // Component should be async (lazy) or have a name
+ expect(root?.component).toBeDefined()
+ })
+
+ it('has /fleet route', () => {
+ const r = routes.find(r => r.path === '/fleet')
+ expect(r).toBeDefined()
+ })
+
+ it('has /data/label route', () => {
+ const r = routes.find(r => r.path === '/data/label')
+ expect(r).toBeDefined()
+ })
+
+ it('has /data/fetch route', () => {
+ const r = routes.find(r => r.path === '/data/fetch')
+ expect(r).toBeDefined()
+ })
+
+ it('has /data/corrections route', () => {
+ const r = routes.find(r => r.path === '/data/corrections')
+ expect(r).toBeDefined()
+ })
+
+ it('has /data/imitate route', () => {
+ const r = routes.find(r => r.path === '/data/imitate')
+ expect(r).toBeDefined()
+ })
+
+ it('has /eval/benchmark route', () => {
+ const r = routes.find(r => r.path === '/eval/benchmark')
+ expect(r).toBeDefined()
+ })
+
+ it('has /eval/compare route', () => {
+ const r = routes.find(r => r.path === '/eval/compare')
+ expect(r).toBeDefined()
+ })
+
+ it('has /train/jobs route', () => {
+ const r = routes.find(r => r.path === '/train/jobs')
+ expect(r).toBeDefined()
+ })
+
+ it('has /train/results route', () => {
+ const r = routes.find(r => r.path === '/train/results')
+ expect(r).toBeDefined()
+ })
+
+ it('has /settings route', () => {
+ const r = routes.find(r => r.path === '/settings')
+ expect(r).toBeDefined()
+ })
+
+ it('has backward-compat redirect from /benchmark to /eval/benchmark', () => {
+ const r = routes.find(r => r.path === '/benchmark')
+ expect(r).toBeDefined()
+ expect((r as { redirect?: string }).redirect).toBe('/eval/benchmark')
+ })
+
+ it('has backward-compat redirect from /models to /fleet', () => {
+ const r = routes.find(r => r.path === '/models')
+ expect(r).toBeDefined()
+ expect((r as { redirect?: string }).redirect).toBe('/fleet')
+ })
+
+ it('has backward-compat redirect from /stats to /', () => {
+ const r = routes.find(r => r.path === '/stats')
+ expect(r).toBeDefined()
+ expect((r as { redirect?: string }).redirect).toBe('/')
+ })
+
+ it('can create a functional router instance', () => {
+ const router = createRouter({
+ history: createWebHashHistory(),
+ routes,
+ })
+ expect(router).toBeDefined()
+ })
+})
diff --git a/web/src/views/CompareView.vue b/web/src/views/CompareView.vue
new file mode 100644
index 0000000..3e7acda
--- /dev/null
+++ b/web/src/views/CompareView.vue
@@ -0,0 +1,10 @@
+
+
+
CompareView
+
Coming soon.
+
+
+
+
diff --git a/web/src/views/DashboardView.vue b/web/src/views/DashboardView.vue
new file mode 100644
index 0000000..62db590
--- /dev/null
+++ b/web/src/views/DashboardView.vue
@@ -0,0 +1,10 @@
+
+
+
DashboardView
+
Coming soon.
+
+
+
+
diff --git a/web/src/views/TrainJobsView.vue b/web/src/views/TrainJobsView.vue
new file mode 100644
index 0000000..bd271a2
--- /dev/null
+++ b/web/src/views/TrainJobsView.vue
@@ -0,0 +1,10 @@
+
+
+
TrainJobsView
+
Coming soon.
+
+
+
+
diff --git a/web/src/views/TrainResultsView.vue b/web/src/views/TrainResultsView.vue
new file mode 100644
index 0000000..450c434
--- /dev/null
+++ b/web/src/views/TrainResultsView.vue
@@ -0,0 +1,10 @@
+
+
+
TrainResultsView
+
Coming soon.
+
+
+
+