WP-00: project skeleton with three-level test harness
Cargo workspace (domain, application, infrastructure, api), axum health endpoint with SPA fallback, Vue 3 + Tailwind frontend, Vitest, Playwright, Makefile, Gitea Actions CI and README. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
5
frontend/src/App.vue
Normal file
5
frontend/src/App.vue
Normal file
@ -0,0 +1,5 @@
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<RouterView />
|
||||
</template>
|
||||
14
frontend/src/components/StatusBadge.test.ts
Normal file
14
frontend/src/components/StatusBadge.test.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import StatusBadge from './StatusBadge.vue'
|
||||
|
||||
describe('StatusBadge', () => {
|
||||
it('renders the label and an ok style', () => {
|
||||
const w = mount(StatusBadge, { props: { status: 'ok', label: 'Backend' } })
|
||||
expect(w.text()).toContain('Backend')
|
||||
expect(w.classes().join(' ')).toContain('green')
|
||||
})
|
||||
it('renders an error style', () => {
|
||||
const w = mount(StatusBadge, { props: { status: 'error', label: 'Backend' } })
|
||||
expect(w.classes().join(' ')).toContain('red')
|
||||
})
|
||||
})
|
||||
17
frontend/src/components/StatusBadge.vue
Normal file
17
frontend/src/components/StatusBadge.vue
Normal file
@ -0,0 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{ status: 'ok' | 'error' | 'unknown'; label: string }>()
|
||||
const styles = {
|
||||
ok: 'bg-green-100 text-green-800',
|
||||
error: 'bg-red-100 text-red-800',
|
||||
unknown: 'bg-gray-100 text-gray-700',
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span
|
||||
class="inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium"
|
||||
:class="styles[status]"
|
||||
>
|
||||
{{ label }}
|
||||
</span>
|
||||
</template>
|
||||
7
frontend/src/main.ts
Normal file
7
frontend/src/main.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { createApp } from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
import App from './App.vue'
|
||||
import { router } from './router'
|
||||
import './style.css'
|
||||
|
||||
createApp(App).use(createPinia()).use(router).mount('#app')
|
||||
24
frontend/src/pages/HealthPage.vue
Normal file
24
frontend/src/pages/HealthPage.vue
Normal file
@ -0,0 +1,24 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import StatusBadge from '../components/StatusBadge.vue'
|
||||
|
||||
const status = ref<'ok' | 'error' | 'unknown'>('unknown')
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const res = await fetch('/healthz')
|
||||
status.value = res.ok ? 'ok' : 'error'
|
||||
} catch {
|
||||
status.value = 'error'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="mx-auto max-w-2xl p-8">
|
||||
<h1 class="text-2xl font-semibold">SoftVisor Monitoring</h1>
|
||||
<p class="mt-4 text-gray-600">
|
||||
Backend:
|
||||
<span data-testid="backend-status"><StatusBadge :status="status" :label="status" /></span>
|
||||
</p>
|
||||
</main>
|
||||
</template>
|
||||
7
frontend/src/router.ts
Normal file
7
frontend/src/router.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import HealthPage from './pages/HealthPage.vue'
|
||||
|
||||
export const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: [{ path: '/', component: HealthPage }],
|
||||
})
|
||||
1
frontend/src/style.css
Normal file
1
frontend/src/style.css
Normal file
@ -0,0 +1 @@
|
||||
@import 'tailwindcss';
|
||||
1
frontend/src/vite-env.d.ts
vendored
Normal file
1
frontend/src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
Reference in New Issue
Block a user