feat: initial Racecraft web client v0.1.0
Vue 3 + TypeScript + Vite web client for rusty-telemetry. - Dashboard with system status, live feeds, quick actions - Live telemetry view with real-time gauges (speed/RPM/gear) - Session management (create, run, complete, analyze) - Shift point analysis with Chart.js visualizations - Track map with Canvas 2D boundary rendering - Typed API client for all 19 REST endpoints - Dark theme, network-accessible via Vite 0.0.0.0 bind
This commit is contained in:
commit
cf9af73281
27 changed files with 5123 additions and 0 deletions
118
src/api/client.ts
Normal file
118
src/api/client.ts
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
import axios from 'axios'
|
||||
import type {
|
||||
LiveTelemetryResponse,
|
||||
RecordingManifest,
|
||||
StartRecordingRequest,
|
||||
UseCaseSession,
|
||||
CreateSessionRequest,
|
||||
StartRunRequest,
|
||||
SessionRun,
|
||||
UseCase,
|
||||
Game,
|
||||
} from '@/types'
|
||||
|
||||
const api = axios.create({
|
||||
baseURL: '/api',
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
|
||||
// ── Live Telemetry ──
|
||||
|
||||
export async function getLiveTelemetry(): Promise<LiveTelemetryResponse> {
|
||||
const res = await api.get<LiveTelemetryResponse>('/live')
|
||||
return res.data
|
||||
}
|
||||
|
||||
// ── Recordings ──
|
||||
|
||||
export async function listRecordings(): Promise<RecordingManifest[]> {
|
||||
const res = await api.get<RecordingManifest[]>('/recordings')
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function getRecording(id: string): Promise<RecordingManifest> {
|
||||
const res = await api.get<RecordingManifest>(`/recordings/${id}`)
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function startRecording(req?: StartRecordingRequest): Promise<RecordingManifest> {
|
||||
const res = await api.post<RecordingManifest>('/recordings', req ?? {})
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function stopActiveRecording(): Promise<RecordingManifest> {
|
||||
const res = await api.post<RecordingManifest>('/recordings/stop')
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function stopRecording(id: string): Promise<RecordingManifest> {
|
||||
const res = await api.post<RecordingManifest>(`/recordings/${id}/stop`)
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function deleteRecording(id: string): Promise<void> {
|
||||
await api.delete(`/recordings/${id}`)
|
||||
}
|
||||
|
||||
// ── Sessions ──
|
||||
|
||||
export async function listSessions(): Promise<UseCaseSession[]> {
|
||||
const res = await api.get<UseCaseSession[]>('/sessions')
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function getSession(id: string): Promise<UseCaseSession> {
|
||||
const res = await api.get<UseCaseSession>(`/sessions/${id}`)
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function createSession(req: CreateSessionRequest): Promise<UseCaseSession> {
|
||||
const res = await api.post<UseCaseSession>('/sessions', req)
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function deleteSession(id: string): Promise<void> {
|
||||
await api.delete(`/sessions/${id}`)
|
||||
}
|
||||
|
||||
export async function startRun(sessionId: string, req: StartRunRequest): Promise<SessionRun> {
|
||||
const res = await api.post<SessionRun>(`/sessions/${sessionId}/runs`, req)
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function stopRun(sessionId: string, runId: string): Promise<SessionRun> {
|
||||
const res = await api.post<SessionRun>(`/sessions/${sessionId}/runs/${runId}/stop`)
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function completeSession(id: string): Promise<UseCaseSession> {
|
||||
const res = await api.post<UseCaseSession>(`/sessions/${id}/complete`)
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function getAnalysis(id: string): Promise<Record<string, unknown>> {
|
||||
const res = await api.get<Record<string, unknown>>(`/sessions/${id}/analysis`)
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function reAnalyze(id: string): Promise<Record<string, unknown>> {
|
||||
const res = await api.post<Record<string, unknown>>(`/sessions/${id}/analyze`)
|
||||
return res.data
|
||||
}
|
||||
|
||||
// ── Metadata ──
|
||||
|
||||
export async function getUseCases(): Promise<UseCase[]> {
|
||||
const res = await api.get<UseCase[]>('/use-cases')
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function getGames(): Promise<Game[]> {
|
||||
const res = await api.get<Game[]>('/games')
|
||||
return res.data
|
||||
}
|
||||
|
||||
export default api
|
||||
Loading…
Add table
Add a link
Reference in a new issue