feat: restructure router into /data/* /eval/* /train/* domains with backward-compat redirects
- Export named `routes` array from router/index.ts for testability - Move label/fetch/corrections/imitate under /data/* namespace - Move benchmark/compare under /eval/* namespace - Add /train/jobs and /train/results under /train/* namespace - Add / -> DashboardView and /fleet -> ModelsView (replaces old / -> LabelView) - Add backward-compat redirects for all old flat paths (/benchmark, /models, /stats, /label, /fetch, /corrections, /imitate) - Add stub views for DashboardView, CompareView, TrainJobsView, TrainResultsView (implemented in later tasks) - Add router.test.ts: 16 tests covering route structure and redirect targets
This commit is contained in:
parent
0904967320
commit
5bdb095235
6 changed files with 177 additions and 19 deletions
|
|
@ -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,
|
||||
})
|
||||
|
|
|
|||
94
web/src/router/router.test.ts
Normal file
94
web/src/router/router.test.ts
Normal file
|
|
@ -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()
|
||||
})
|
||||
})
|
||||
10
web/src/views/CompareView.vue
Normal file
10
web/src/views/CompareView.vue
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<template>
|
||||
<div class="view-placeholder">
|
||||
<h2>CompareView</h2>
|
||||
<p>Coming soon.</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// Stub — will be implemented in a later task
|
||||
</script>
|
||||
10
web/src/views/DashboardView.vue
Normal file
10
web/src/views/DashboardView.vue
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<template>
|
||||
<div class="view-placeholder">
|
||||
<h2>DashboardView</h2>
|
||||
<p>Coming soon.</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// Stub — will be implemented in a later task
|
||||
</script>
|
||||
10
web/src/views/TrainJobsView.vue
Normal file
10
web/src/views/TrainJobsView.vue
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<template>
|
||||
<div class="view-placeholder">
|
||||
<h2>TrainJobsView</h2>
|
||||
<p>Coming soon.</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// Stub — will be implemented in a later task
|
||||
</script>
|
||||
10
web/src/views/TrainResultsView.vue
Normal file
10
web/src/views/TrainResultsView.vue
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<template>
|
||||
<div class="view-placeholder">
|
||||
<h2>TrainResultsView</h2>
|
||||
<p>Coming soon.</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// Stub — will be implemented in a later task
|
||||
</script>
|
||||
Loading…
Reference in a new issue