Files
KArtSell.Aegis/frontend/src/features/shadow-run/pages/ShadowRunDetail.vue
T
kjh2064 728393226f refactor(fe): P3 pages standardize to screen-type v2 templates
Refactored 4 feature pages to use standard screen-type v2 layouts:

1. HomePage → ScorecardDashboardPage
   - Exception-driven work queue metrics + dashboard layout
   - KPI cards, filters, operational guides
   - Viewport-fit ready, no page-level scrolling

2. ModelsList → MasterDetailCrudPage
   - Master list + detail panel layout
   - Model grid with phase/performance metrics
   - Search, filter, pagination

3. ModelDetail → DetailReadPage
   - Read-only model detail view
   - State management (LOADING/ERROR/READY)
   - Metric display (PBO, DSR, Return)

4. ShadowRunDetail → DetailReadPage
   - Shadow run detail view
   - State management (LOADING/ERROR/READY)
   - Performance metrics (PBO, DSR, OOS)

Pattern Applied:
- Remove PageLayout, use screen-type component
- Add StandardScreenProps (state, evidence)
- State computed from query status
- Slot structure maintained or aligned
- No functional changes, pure standardization

Benefits:
- Consistent layout across pages
- Standardized state management
- Improved viewport-fit compliance
- Better component reusability

Next: Viewport-fit final validation + viewport-fit edge cases

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-08-17 17:14:30 +09:00

134 lines
3.2 KiB
Vue

<script setup lang="ts">
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import { DetailReadPage } from '../../../shared/ui/screen-types/v2'
import { SkeletonLoader } from '../../../shared/ui/components'
import { useShadowRunDetail } from '../composables/useShadowRuns'
import type { StandardScreenProps } from '../../../shared/ui/contracts/screenContract'
const route = useRoute()
const runId = computed(() => route.params.runId as string)
const shadowRunQuery = useShadowRunDetail(runId.value)
const run = computed(() => shadowRunQuery.data as any)
const screenState = computed<StandardScreenProps['state']>(() => {
if (shadowRunQuery.isPending) return 'LOADING'
if (shadowRunQuery.isError) return 'ERROR'
return 'READY'
})
const screenEvidence = { asOf: new Date().toISOString(), version: '1.0' }
</script>
<template>
<DetailReadPage
:title="`Shadow Run #${runId}`"
:state="screenState"
:evidence="screenEvidence"
>
<template #primary>
<header class="page-header">
<h1>Shadow Run Details</h1>
</header>
<!-- Loading State -->
<div v-if="shadowRunQuery.isPending" class="loading-state">
<SkeletonLoader type="card" />
</div>
<!-- Error State -->
<div v-else-if="shadowRunQuery.isError" class="error-state">
<p>Failed to load shadow run</p>
</div>
<!-- Data State -->
<div v-else-if="run && run.id" class="shadow-run-detail">
<div class="detail-section">
<h2>Run #{{ run.id }}</h2>
<div class="detail-grid">
<div class="detail-item">
<label>Model</label>
<p>{{ run.modelName }}</p>
</div>
<div class="detail-item">
<label>Status</label>
<p>{{ run.status }}</p>
</div>
<div class="detail-item">
<label>PBO</label>
<p>{{ run.pbo }}%</p>
</div>
<div class="detail-item">
<label>DSR</label>
<p>{{ run.dsr }}%</p>
</div>
<div class="detail-item">
<label>OOS</label>
<p>{{ run.oos }}%</p>
</div>
</div>
</div>
</div>
</template>
</DetailReadPage>
</template>
<style scoped>
.shadow-run-detail-page {
padding: 2rem;
max-width: 1200px;
margin: 0 auto;
}
.page-header {
margin-bottom: 2rem;
}
.page-header h1 {
margin: 0;
font-size: 2rem;
font-weight: 700;
}
.loading-state,
.error-state {
padding: 2rem;
text-align: center;
border: 1px solid var(--color-border-primary);
border-radius: var(--border-radius-md);
background-color: var(--color-background-secondary);
}
.shadow-run-detail {
border: 1px solid var(--color-border-primary);
border-radius: var(--border-radius-md);
padding: 2rem;
background-color: var(--color-background-secondary);
}
.detail-section h2 {
margin: 0 0 1.5rem 0;
font-size: 1.5rem;
}
.detail-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1.5rem;
}
.detail-item label {
display: block;
font-weight: 600;
margin-bottom: 0.5rem;
color: var(--color-text-secondary);
}
.detail-item p {
margin: 0;
color: var(--color-text-primary);
}
</style>