Skip to content

Commit eb7944c

Browse files
feat: 优化面板布局与Markdown查看器组件
- GitHubMarkdownViewer 添加 showHeader 属性支持隐藏头部 - PipelineSnapshotPanel 使用可调整大小的分割面板 - 分割比例支持 localStorage 持久化 - 小屏幕自动切换为堆叠布局
1 parent a1c4a45 commit eb7944c

File tree

6 files changed

+210
-87
lines changed

6 files changed

+210
-87
lines changed

dashboard/src/components/extension/mod-manager/PluginChangelogPanel.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ watch(
9999

100100
<div v-else-if="content" class="changelog-scroll__content">
101101
<div class="changelog-scroll__container">
102-
<GitHubMarkdownViewer :content="content" header-icon="mdi-history" header-label="CHANGELOG.md" />
102+
<GitHubMarkdownViewer :content="content" header-icon="mdi-history" header-label="CHANGELOG.md" :show-header="false" />
103103
</div>
104104
</div>
105105

dashboard/src/components/extension/mod-manager/PluginOverviewPanel.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,12 @@ watch(
126126

127127
<div v-else-if="content" class="readme-scroll__content">
128128
<div class="readme-scroll__container">
129-
<GitHubMarkdownViewer :content="content" header-icon="mdi-book-open-outline" header-label="README.md" />
129+
<GitHubMarkdownViewer
130+
:content="content"
131+
header-icon="mdi-book-open-outline"
132+
header-label="README.md"
133+
:show-header="false"
134+
/>
130135
</div>
131136
</div>
132137

dashboard/src/components/extension/mod-manager/PluginWelcomePanel.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ onMounted(() => {
123123

124124
<div v-else-if="content" class="welcome-readme">
125125
<div class="welcome-readme__container">
126-
<GitHubMarkdownViewer :content="content" header-icon="mdi-book-open-outline" header-label="README.md" />
126+
<GitHubMarkdownViewer :content="content" header-icon="mdi-book-open-outline" header-label="README.md" :show-header="false" />
127127

128128
<v-alert type="info" variant="tonal" density="comfortable" class="mt-8">
129129
<div class="text-body-2">

dashboard/src/components/extension/mod-manager/pipeline/PipelineSnapshotPanel.vue

Lines changed: 197 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup lang="ts">
22
import { computed, ref, watch } from 'vue'
3+
import { useDisplay } from 'vuetify'
34
import { useModuleI18n } from '@/i18n/composables'
45
import { usePipelineSnapshot } from '@/composables/usePipelineSnapshot'
56
import type { EffectTarget, PipelineSnapshot, PipelineStageId, SnapshotScopeMode, StageParticipant } from './pipelineSnapshotTypes'
@@ -14,6 +15,8 @@ import ConflictListPanel from './ConflictListPanel.vue'
1415
import TraceImpactDetailPanel from './TraceImpactDetailPanel.vue'
1516
import PromptPreviewDialog from './PromptPreviewDialog.vue'
1617
18+
import ResizableSplitPane from '../ResizableSplitPane.vue'
19+
1720
type SnapshotPanelMode = 'pipeline' | 'trace'
1821
type RightTab = 'detail' | 'conflicts'
1922
@@ -51,6 +54,9 @@ const props = withDefaults(
5154
5255
const { tm } = useModuleI18n('features/extension')
5356
57+
const display = useDisplay()
58+
const isSmallScreen = computed(() => display.width.value <= 960)
59+
5460
const scopeMode = ref<SnapshotScopeMode>('global')
5561
const sessionUmo = ref<string>('')
5662
@@ -60,6 +66,27 @@ const selectedParticipantId = ref<string | null>(null)
6066
6167
const showAllStages = ref(false)
6268
69+
const SPLIT_RATIO_KEY = 'psp-split-ratio'
70+
71+
function parseStoredRatio(raw: string | null): number | null {
72+
if (!raw) return null
73+
const num = Number(raw)
74+
if (!Number.isFinite(num)) return null
75+
if (num <= 0 || num >= 1) return null
76+
return num
77+
}
78+
79+
const splitRatio = ref(parseStoredRatio(localStorage.getItem(SPLIT_RATIO_KEY)) ?? 0.67)
80+
81+
watch(
82+
splitRatio,
83+
(val) => {
84+
if (!Number.isFinite(val)) return
85+
localStorage.setItem(SPLIT_RATIO_KEY, String(val))
86+
},
87+
{ flush: 'post' }
88+
)
89+
6390
const traceSelectedTarget = ref<'__all__' | EffectTarget>('__all__')
6491
const traceSelectedImpactKey = ref<string | null>(null)
6592
@@ -381,88 +408,179 @@ const scopeItems = computed(() => [
381408
<v-progress-linear v-if="loading" indeterminate color="primary" />
382409

383410
<div class="psp__content d-flex flex-grow-1" style="min-height: 0">
384-
<div class="psp__left">
385-
<TraceFishboneView
386-
v-if="props.mode === 'trace'"
387-
class="psp__fishbone"
388-
:groups="traceRootGroupsAll"
389-
:active-stage-id="selectedStageId"
390-
:active-target="traceActiveTarget"
391-
:active-impact-key="traceSelectedImpactKey"
392-
@select-stage="handleSelectStage"
393-
@select-target="(t) => (traceSelectedTarget = t)"
394-
@select-impact="selectImpactKey"
395-
/>
396-
<PipelineFishboneView
397-
v-else
398-
class="psp__fishbone"
399-
:snapshot="displaySnapshot"
400-
:selected-stage-id="selectedStageId"
401-
:selected-participant-id="selectedParticipantId"
402-
:show-all-stages="showAllStages"
403-
@select-stage="handleSelectStage"
404-
@select-participant="handleSelectParticipant"
405-
/>
406-
</div>
407-
408-
<div class="psp__right">
409-
<div v-if="props.mode === 'pipeline'" class="psp__right-tabs">
410-
<v-btn-toggle v-model="rightTab" mandatory density="compact" class="psp__right-toggle w-100">
411-
<v-btn value="detail" variant="text" class="psp__right-toggle-btn flex-1">
412-
{{ tm('pipeline.rightTabs.detail') }}
413-
</v-btn>
414-
<v-btn value="conflicts" variant="text" class="psp__right-toggle-btn flex-1">
415-
{{ tm('pipeline.rightTabs.conflicts') }}
416-
</v-btn>
417-
</v-btn-toggle>
418-
419-
<v-divider />
411+
<template v-if="isSmallScreen">
412+
<div class="psp__left">
413+
<TraceFishboneView
414+
v-if="props.mode === 'trace'"
415+
class="psp__fishbone"
416+
:groups="traceRootGroupsAll"
417+
:active-stage-id="selectedStageId"
418+
:active-target="traceActiveTarget"
419+
:active-impact-key="traceSelectedImpactKey"
420+
@select-stage="handleSelectStage"
421+
@select-target="(t) => (traceSelectedTarget = t)"
422+
@select-impact="selectImpactKey"
423+
/>
424+
<PipelineFishboneView
425+
v-else
426+
class="psp__fishbone"
427+
:snapshot="displaySnapshot"
428+
:selected-stage-id="selectedStageId"
429+
:selected-participant-id="selectedParticipantId"
430+
:show-all-stages="showAllStages"
431+
@select-stage="handleSelectStage"
432+
@select-participant="handleSelectParticipant"
433+
/>
420434
</div>
421435

422-
<div class="psp__right-body">
423-
<v-window
424-
v-if="props.mode === 'pipeline'"
425-
v-model="rightTab"
426-
class="psp__window flex-grow-1"
427-
style="min-height: 0"
428-
>
429-
<v-window-item value="detail" class="h-100">
430-
<StageDetailPanel
431-
:snapshot="displaySnapshot"
432-
:stage-id="selectedStageId"
433-
:selected-participant-id="selectedParticipantId"
434-
@select-participant="handleSelectParticipant"
435-
@select-plugin="handleSelectPlugin"
436-
@view-impact-chain="handleViewImpactChain"
437-
/>
438-
</v-window-item>
436+
<div class="psp__right">
437+
<div v-if="props.mode === 'pipeline'" class="psp__right-tabs">
438+
<v-btn-toggle v-model="rightTab" mandatory density="compact" class="psp__right-toggle w-100">
439+
<v-btn value="detail" variant="text" class="psp__right-toggle-btn flex-1">
440+
{{ tm('pipeline.rightTabs.detail') }}
441+
</v-btn>
442+
<v-btn value="conflicts" variant="text" class="psp__right-toggle-btn flex-1">
443+
{{ tm('pipeline.rightTabs.conflicts') }}
444+
</v-btn>
445+
</v-btn-toggle>
446+
447+
<v-divider />
448+
</div>
439449

440-
<v-window-item value="conflicts" class="h-100">
441-
<ConflictListPanel
442-
:snapshot="displaySnapshot"
443-
@select-stage="handleSelectStage"
444-
@select-participant="handleSelectParticipant"
450+
<div class="psp__right-body">
451+
<v-window
452+
v-if="props.mode === 'pipeline'"
453+
v-model="rightTab"
454+
class="psp__window flex-grow-1"
455+
style="min-height: 0"
456+
>
457+
<v-window-item value="detail" class="h-100">
458+
<StageDetailPanel
459+
:snapshot="displaySnapshot"
460+
:stage-id="selectedStageId"
461+
:selected-participant-id="selectedParticipantId"
462+
@select-participant="handleSelectParticipant"
463+
@select-plugin="handleSelectPlugin"
464+
@view-impact-chain="handleViewImpactChain"
465+
/>
466+
</v-window-item>
467+
468+
<v-window-item value="conflicts" class="h-100">
469+
<ConflictListPanel
470+
:snapshot="displaySnapshot"
471+
@select-stage="handleSelectStage"
472+
@select-participant="handleSelectParticipant"
473+
@select-plugin="handleSelectPlugin"
474+
/>
475+
</v-window-item>
476+
</v-window>
477+
478+
<div v-else class="h-100 d-flex flex-column" style="min-height: 0">
479+
<TraceImpactDetailPanel
480+
class="flex-grow-1"
481+
:row="traceSelectedRow"
445482
@select-plugin="handleSelectPlugin"
483+
@navigate-pipeline="handleNavigatePipeline"
446484
/>
447-
</v-window-item>
448-
</v-window>
449-
450-
<div v-else class="h-100 d-flex flex-column" style="min-height: 0">
451-
<TraceImpactDetailPanel
452-
class="flex-grow-1"
453-
:row="traceSelectedRow"
454-
@select-plugin="handleSelectPlugin"
455-
@navigate-pipeline="handleNavigatePipeline"
485+
</div>
486+
487+
<div v-if="error" class="psp__error px-4 py-3">
488+
<v-alert type="error" variant="tonal" density="comfortable">
489+
{{ error }}
490+
</v-alert>
491+
</div>
492+
</div>
493+
</div>
494+
</template>
495+
496+
<ResizableSplitPane v-else v-model="splitRatio" direction="horizontal" class="psp__split">
497+
<template #first>
498+
<div class="psp__left">
499+
<TraceFishboneView
500+
v-if="props.mode === 'trace'"
501+
class="psp__fishbone"
502+
:groups="traceRootGroupsAll"
503+
:active-stage-id="selectedStageId"
504+
:active-target="traceActiveTarget"
505+
:active-impact-key="traceSelectedImpactKey"
506+
@select-stage="handleSelectStage"
507+
@select-target="(t) => (traceSelectedTarget = t)"
508+
@select-impact="selectImpactKey"
509+
/>
510+
<PipelineFishboneView
511+
v-else
512+
class="psp__fishbone"
513+
:snapshot="displaySnapshot"
514+
:selected-stage-id="selectedStageId"
515+
:selected-participant-id="selectedParticipantId"
516+
:show-all-stages="showAllStages"
517+
@select-stage="handleSelectStage"
518+
@select-participant="handleSelectParticipant"
456519
/>
457520
</div>
521+
</template>
458522

459-
<div v-if="error" class="psp__error px-4 py-3">
460-
<v-alert type="error" variant="tonal" density="comfortable">
461-
{{ error }}
462-
</v-alert>
523+
<template #second>
524+
<div class="psp__right">
525+
<div v-if="props.mode === 'pipeline'" class="psp__right-tabs">
526+
<v-btn-toggle v-model="rightTab" mandatory density="compact" class="psp__right-toggle w-100">
527+
<v-btn value="detail" variant="text" class="psp__right-toggle-btn flex-1">
528+
{{ tm('pipeline.rightTabs.detail') }}
529+
</v-btn>
530+
<v-btn value="conflicts" variant="text" class="psp__right-toggle-btn flex-1">
531+
{{ tm('pipeline.rightTabs.conflicts') }}
532+
</v-btn>
533+
</v-btn-toggle>
534+
535+
<v-divider />
536+
</div>
537+
538+
<div class="psp__right-body">
539+
<v-window
540+
v-if="props.mode === 'pipeline'"
541+
v-model="rightTab"
542+
class="psp__window flex-grow-1"
543+
style="min-height: 0"
544+
>
545+
<v-window-item value="detail" class="h-100">
546+
<StageDetailPanel
547+
:snapshot="displaySnapshot"
548+
:stage-id="selectedStageId"
549+
:selected-participant-id="selectedParticipantId"
550+
@select-participant="handleSelectParticipant"
551+
@select-plugin="handleSelectPlugin"
552+
@view-impact-chain="handleViewImpactChain"
553+
/>
554+
</v-window-item>
555+
556+
<v-window-item value="conflicts" class="h-100">
557+
<ConflictListPanel
558+
:snapshot="displaySnapshot"
559+
@select-stage="handleSelectStage"
560+
@select-participant="handleSelectParticipant"
561+
@select-plugin="handleSelectPlugin"
562+
/>
563+
</v-window-item>
564+
</v-window>
565+
566+
<div v-else class="h-100 d-flex flex-column" style="min-height: 0">
567+
<TraceImpactDetailPanel
568+
class="flex-grow-1"
569+
:row="traceSelectedRow"
570+
@select-plugin="handleSelectPlugin"
571+
@navigate-pipeline="handleNavigatePipeline"
572+
/>
573+
</div>
574+
575+
<div v-if="error" class="psp__error px-4 py-3">
576+
<v-alert type="error" variant="tonal" density="comfortable">
577+
{{ error }}
578+
</v-alert>
579+
</div>
580+
</div>
463581
</div>
464-
</div>
465-
</div>
582+
</template>
583+
</ResizableSplitPane>
466584
</div>
467585

468586
<PromptPreviewDialog v-model:show="promptDialog" :preview="displaySnapshot?.llm_prompt_preview ?? null" />
@@ -499,10 +617,13 @@ const scopeItems = computed(() => [
499617
min-width: 0;
500618
}
501619
620+
.psp__split {
621+
flex: 1 1 auto;
622+
min-height: 0;
623+
min-width: 0;
624+
}
625+
502626
.psp__right {
503-
width: clamp(360px, 42vw, 760px);
504-
max-width: 60%;
505-
min-width: 360px;
506627
min-height: 0;
507628
display: flex;
508629
flex-direction: column;
@@ -580,11 +701,5 @@ const scopeItems = computed(() => [
580701
border-right: 0;
581702
border-bottom: 1px solid rgba(var(--v-theme-on-surface), 0.08);
582703
}
583-
584-
.psp__right {
585-
width: 100%;
586-
max-width: 100%;
587-
min-width: 0;
588-
}
589704
}
590705
</style>

dashboard/src/components/shared/GitHubMarkdownViewer.vue

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,20 @@ type Props = {
77
headerIcon?: string
88
headerLabel?: string
99
typewriter?: boolean
10+
showHeader?: boolean
1011
}
1112
1213
withDefaults(defineProps<Props>(), {
1314
headerIcon: 'mdi-book-open-outline',
1415
headerLabel: 'README.md',
15-
typewriter: false
16+
typewriter: false,
17+
showHeader: true
1618
})
1719
</script>
1820

1921
<template>
2022
<div class="github-style-container">
21-
<div class="github-style-header">
23+
<div v-if="showHeader" class="github-style-header">
2224
<v-icon size="16" class="mr-2">{{ headerIcon }}</v-icon>
2325
<span class="text-caption font-weight-bold">{{ headerLabel }}</span>
2426
</div>

dashboard/src/components/shared/ReadmeDialog.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ const _show = computed({
197197
:content="content"
198198
:header-icon="mode === 'changelog' ? 'mdi-history' : 'mdi-book-open-outline'"
199199
:header-label="mode === 'changelog' ? 'CHANGELOG.md' : 'README.md'"
200+
:show-header="false"
200201
/>
201202
</div>
202203
</div>

0 commit comments

Comments
 (0)