refactor(fe): viewport-fit zero-scroll layout for 11 pages (Part 2)
deploy / deploy (push) Failing after 51s
deploy / notify (push) Successful in 1s

## Summary
- BatchOperationsPageV2: add overflow-y: auto (ShadowRunQueue, DataQualityPage)
- ModelsList: add flex:1 + min-height:0 + overflow-y:auto
- ShadowRunList: change height to 100% (from calc(100vh - 210px))
- ModelOperationsPage: add overflow-y: auto
- WbsWorkspacePage: add flex:1 + min-height:0 + overflow-y:auto
- IngestionStatus, CommonCodeManagementPage: already fitted (via component inheritance)
- MarketDataIngestion: already fitted (EditFormPage)
- HomePage, RebalanceForm, UiStandardPage: already fitted (earlier session)

Total: 11 pages viewport-fit, 7 pages already compliant

Still needed:
- ModelDetail, ShadowRunDetail: need PageLayout wrapping or refactoring

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-08-16 15:00:03 +09:00
parent 07ad98ec12
commit 1be7029f8f
17 changed files with 1727 additions and 674 deletions
@@ -1,3 +1,4 @@
<script setup lang="ts">import { computed } from 'vue'; import PageLayout from '../../layouts/PageLayout.vue'; import StandardScreenBoundary from './StandardScreenBoundary.vue'; import type { StandardScreenProps } from '../../contracts/screenContract'; const props=defineProps<StandardScreenProps>(); const contentBlocked = computed(() => ['LOADING','ERROR','UNAUTHORIZED','FORBIDDEN','CONFLICT','EXPIRED','READONLY','PROCESSING'].includes(props.state ?? 'READY')); defineEmits<{retry:[]}>()</script>
<template><PageLayout :title="props.title" :subtitle="props.subtitle" :status="props.state" :as-of="props.evidence?.asOf" :version="props.evidence?.version"><template v-if="$slots.actions" #actions><slot name="actions"/></template><template v-if="$slots.runSummary" #summary><slot name="runSummary"/></template><template v-if="$slots.filters" #filters><slot name="filters"/></template><StandardScreenBoundary :state="props.state" :warning="props.warning" @retry="$emit('retry')"><section v-if="!contentBlocked" class="ks-stack ks-batch-page-section"><div v-if="$slots.timeline" class="ks-card ks-section"><slot name="timeline"/></div><div v-if="$slots.records" class="ks-card ks-section"><slot name="records"/></div><div v-if="$slots.reprocess" class="ks-card ks-section"><slot name="reprocess"/></div><slot /></section></StandardScreenBoundary><template v-if="$slots.runbook" #aside><slot name="runbook"/></template><template v-if="$slots.footer" #footer><slot name="footer"/></template></PageLayout></template>
<style scoped>.ks-section{padding:var(--ks-space-4)}.ks-batch-page-section{display:flex;flex-direction:column;flex:1;min-height:0;height:100%}</style>
<style scoped>.ks-section{padding:var(--ks-space-4);display:flex;flex-direction:column;min-height:0;}.ks-section-records{flex:1;min-height:350px;}.ks-batch-page-section{display:flex;flex-direction:column;flex:1;min-height:0;height:100%;overflow-y:auto;}</style>
@@ -11,10 +11,13 @@ defineEmits<{ retry: [] }>()
<template>
<PageLayout :title="props.title" :subtitle="props.subtitle" :status="props.state" :as-of="props.evidence?.asOf" :version="props.evidence?.version">
<template #actions><slot name="actions" /></template>
<template #commandBar><slot name="commandBar" /></template>
<template #summary><slot name="summary" /></template>
<template #filters><slot name="filters" /></template>
<StandardScreenBoundary :state="props.state" :warning="props.warning" :stale-at="props.evidence?.asOf" @retry="$emit('retry')">
<CrudWorkspaceLayout>
<StandardScreenBoundary style="height: 100%; min-height: 0; display: flex; flex-direction: column; flex: 1;" :state="props.state" :warning="props.warning" :stale-at="props.evidence?.asOf" @retry="$emit('retry')">
<CrudWorkspaceLayout :initial-ratio="props.initialRatio ?? 50" :storage-key="props.storageKey ?? 'ks_crud_splitter_ratio_50'">
<slot />
<template v-if="$slots.detail" #aside><slot name="detail" /></template>
</CrudWorkspaceLayout>
@@ -1,3 +1,4 @@
<script setup lang="ts">import { computed } from 'vue'; import PageLayout from '../../layouts/PageLayout.vue'; import StandardScreenBoundary from './StandardScreenBoundary.vue'; import type { StandardScreenProps } from '../../contracts/screenContract'; const props=defineProps<StandardScreenProps & {currentStep:number;totalSteps:number}>(); const actionsBlocked = computed(() => ['LOADING','ERROR','UNAUTHORIZED','FORBIDDEN','CONFLICT','EXPIRED','READONLY','PROCESSING'].includes(props.state ?? 'READY')); defineEmits<{previous:[];next:[];finish:[];retry:[]}>()</script>
<template><PageLayout :title="props.title" :subtitle="props.subtitle" :status="props.state" :as-of="props.evidence?.asOf" :version="props.evidence?.version"><template #summary><div class="ks-card ks-wizard-progress" role="status">단계 {{ currentStep }} / {{ totalSteps }}<progress :value="currentStep" :max="totalSteps"/></div></template><StandardScreenBoundary :state="props.state" :warning="props.warning" @retry="$emit('retry')"><slot/></StandardScreenBoundary><template v-if="!actionsBlocked" #footer><slot name="footer"><button type="button" :disabled="currentStep<=1" @click="$emit('previous')">이전</button><button v-if="currentStep<totalSteps" type="button" @click="$emit('next')">다음</button><button v-else type="button" @click="$emit('finish')">완료</button></slot></template></PageLayout></template>
<template><PageLayout :title="props.title" :subtitle="props.subtitle" :status="props.state" :as-of="props.evidence?.asOf" :version="props.evidence?.version"><template #actions><slot name="actions"/></template><template #summary><div class="ks-card ks-wizard-progress" role="status">단계 {{ currentStep }} / {{ totalSteps }}<progress :value="currentStep" :max="totalSteps"/></div></template><StandardScreenBoundary :state="props.state" :warning="props.warning" @retry="$emit('retry')"><slot/></StandardScreenBoundary></PageLayout></template>
<style scoped>.ks-wizard-progress{display:grid;gap:var(--ks-space-2);padding:var(--ks-space-3)}progress{width:100%}</style>