From 5bdb0952359e70200c3922e6717fc397c6609256 Mon Sep 17 00:00:00 2001 From: pyr0ball Date: Sat, 2 May 2026 13:00:04 -0700 Subject: [PATCH] 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 --- web/src/router/index.ts | 62 ++++++++++++++------ web/src/router/router.test.ts | 94 ++++++++++++++++++++++++++++++ web/src/views/CompareView.vue | 10 ++++ web/src/views/DashboardView.vue | 10 ++++ web/src/views/TrainJobsView.vue | 10 ++++ web/src/views/TrainResultsView.vue | 10 ++++ 6 files changed, 177 insertions(+), 19 deletions(-) create mode 100644 web/src/router/router.test.ts create mode 100644 web/src/views/CompareView.vue create mode 100644 web/src/views/DashboardView.vue create mode 100644 web/src/views/TrainJobsView.vue create mode 100644 web/src/views/TrainResultsView.vue 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 @@ + + + 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 @@ + + + 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 @@ + + + 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 @@ + + +