feat: compose T01 search list workspace (V13-FE-011)
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import SearchListCrudPage from '../v2/SearchListCrudPage.vue'
|
||||
|
||||
describe('SearchListCrudPage', () => {
|
||||
it('keeps the T01 list body and optional detail in the shared responsive workspace', () => {
|
||||
const wrapper = mount(SearchListCrudPage, {
|
||||
props: {
|
||||
title: '고객 목록',
|
||||
state: 'READY',
|
||||
evidence: { asOf: '2026-08-09T00:00:00Z', version: 'v1' }
|
||||
},
|
||||
slots: {
|
||||
default: '<section data-test="list">목록</section>',
|
||||
detail: '<section data-test="detail">상세</section>'
|
||||
}
|
||||
})
|
||||
|
||||
expect(wrapper.get('.ks-crud-workspace__body').classes()).toContain('has-aside')
|
||||
expect(wrapper.get('main [data-test="list"]').text()).toBe('목록')
|
||||
expect(wrapper.get('aside [data-test="detail"]').text()).toBe('상세')
|
||||
})
|
||||
|
||||
it('does not render an empty detail region when the T01 caller has no selection', () => {
|
||||
const wrapper = mount(SearchListCrudPage, {
|
||||
props: { title: '고객 목록', state: 'READY' },
|
||||
slots: { default: '<section>목록</section>' }
|
||||
})
|
||||
|
||||
expect(wrapper.find('.ks-crud-workspace__body').classes()).not.toContain('has-aside')
|
||||
expect(wrapper.find('.ks-crud-workspace aside').exists()).toBe(false)
|
||||
})
|
||||
})
|
||||
@@ -1,2 +1,24 @@
|
||||
<script setup lang="ts">import PageLayout from '../../layouts/PageLayout.vue'; import StandardScreenBoundary from './StandardScreenBoundary.vue'; import type { StandardScreenProps } from '../../contracts/screenContract'; const props=defineProps<StandardScreenProps>(); defineEmits<{retry:[]}>()</script>
|
||||
<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><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')"><slot/></StandardScreenBoundary><template v-if="$slots.detail" #aside><slot name="detail"/></template><template v-if="$slots.footer" #footer><slot name="footer"/></template></PageLayout></template>
|
||||
<script setup lang="ts">
|
||||
import PageLayout from '../../layouts/PageLayout.vue'
|
||||
import CrudWorkspaceLayout from '../../layouts/CrudWorkspaceLayout.vue'
|
||||
import StandardScreenBoundary from './StandardScreenBoundary.vue'
|
||||
import type { StandardScreenProps } from '../../contracts/screenContract'
|
||||
|
||||
const props = defineProps<StandardScreenProps>()
|
||||
defineEmits<{ retry: [] }>()
|
||||
</script>
|
||||
|
||||
<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><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>
|
||||
<slot />
|
||||
<template v-if="$slots.detail" #aside><slot name="detail" /></template>
|
||||
</CrudWorkspaceLayout>
|
||||
</StandardScreenBoundary>
|
||||
<template v-if="$slots.footer" #footer><slot name="footer" /></template>
|
||||
</PageLayout>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user