22import { ref , onMounted , onUnmounted , computed , watch } from ' vue'
33import { useI18n } from ' vue-i18n'
44import { Button } from ' @/components/ui/button'
5- import {
6- Breadcrumb ,
7- BreadcrumbItem ,
8- BreadcrumbLink ,
9- BreadcrumbList ,
10- BreadcrumbPage ,
11- BreadcrumbSeparator ,
12- } from ' @/components/ui/breadcrumb'
135import { Alert , AlertDescription } from ' @/components/ui/alert'
6+ import { ProgressBars } from ' @/components/ui/progress-bars'
147import { FileText , Github , Code , Zap , CheckCircle , Loader2 } from ' lucide-vue-next'
158import { McpCatalogService } from ' @/services/mcpCatalogService'
169import { useEventBus } from ' @/composables/useEventBus'
@@ -82,6 +75,68 @@ const steps = [
8275 }
8376]
8477
78+ // Progress steps for ProgressBars component
79+ const progressSteps = computed (() => {
80+ return steps .map ((step , index ) => {
81+ let status: ' completed' | ' current' | ' pending' | ' error' = ' pending'
82+
83+ if (index < currentStep .value ) {
84+ status = ' completed'
85+ } else if (index === currentStep .value ) {
86+ status = ' current'
87+ }
88+
89+ // Check for errors
90+ if (index === 0 && githubFetchError .value ) {
91+ status = ' error'
92+ }
93+
94+ return {
95+ id: step .key ,
96+ label: step .label ,
97+ status ,
98+ clickable: index < currentStep .value // Only completed steps are clickable
99+ }
100+ })
101+ })
102+
103+ // Calculate progress percentage
104+ const progressPercentage = computed (() => {
105+ // Progress should match visual step positions:
106+ // For 5 steps: 0%, 25%, 50%, 75%, 100%
107+ const totalSteps = steps .length
108+ if (totalSteps <= 1 ) return 0
109+
110+ const progressIncrement = 100 / (totalSteps - 1 )
111+ return currentStep .value * progressIncrement
112+ })
113+
114+ // Progress title based on current step
115+ const progressTitle = computed (() => {
116+ if (isSubmitting .value ) {
117+ return props .mode === ' edit'
118+ ? t (' mcpCatalog.form.navigation.updating' )
119+ : t (' mcpCatalog.form.navigation.creating' )
120+ }
121+ if (isFetchingGitHub .value ) {
122+ return t (' mcpCatalog.form.navigation.fetching' )
123+ }
124+ if (githubFetchError .value ) {
125+ return t (' mcpCatalog.form.errors.githubFetch' )
126+ }
127+
128+ const currentStepData = steps [currentStep .value ]
129+ return ` ${currentStepData .label } - ${t (' mcpCatalog.form.steps.configuring' )} `
130+ })
131+
132+ // Progress variant based on state
133+ const progressVariant = computed (() => {
134+ if (githubFetchError .value || submitError .value ) return ' destructive'
135+ if (isSubmitting .value ) return ' default' // Keep default while submitting
136+ // Only show success after actual completion (would need to be handled by parent component)
137+ return ' default'
138+ })
139+
85140// State
86141const currentStep = ref (0 )
87142const isSubmitting = ref (false )
@@ -194,6 +249,13 @@ const goToStep = (stepIndex: number) => {
194249 }
195250}
196251
252+ // Handle step click from ProgressBars
253+ const handleStepClick = (step : any , index : number ) => {
254+ if (step .clickable ) {
255+ goToStep (index )
256+ }
257+ }
258+
197259const nextStep = () => {
198260 if (canGoNext .value ) {
199261 const oldStep = currentStep .value
@@ -363,7 +425,6 @@ const loadFormData = () => {
363425 // For now, we'll keep the default empty form
364426}
365427
366-
367428// Form submission
368429const submitForm = async () => {
369430 try {
@@ -392,39 +453,17 @@ onUnmounted(() => {
392453
393454<template >
394455 <div class =" space-y-6" >
395- <!-- Breadcrumb Navigation -->
396- <Breadcrumb >
397- <BreadcrumbList >
398- <template v-for =" (step , index ) in steps " :key =" index " >
399- <BreadcrumbItem >
400- <!-- Current Step -->
401- <BreadcrumbPage v-if =" index === currentStep" class =" flex items-center gap-2" >
402- <component :is =" step.icon" class =" h-4 w-4" />
403- <span >{{ step.label }}</span >
404- </BreadcrumbPage >
405-
406- <!-- Completed Steps (clickable) -->
407- <BreadcrumbLink
408- v-else-if =" index < currentStep"
409- @click =" goToStep(index)"
410- class =" flex items-center gap-2 cursor-pointer hover:text-foreground"
411- >
412- <component :is =" step.icon" class =" h-4 w-4" />
413- <span >{{ step.label }}</span >
414- </BreadcrumbLink >
415-
416- <!-- Future Steps (disabled) -->
417- <span v-else class =" flex items-center gap-2 text-muted-foreground" >
418- <component :is =" step.icon" class =" h-4 w-4" />
419- <span >{{ step.label }}</span >
420- </span >
421- </BreadcrumbItem >
422-
423- <!-- Separator -->
424- <BreadcrumbSeparator v-if =" index < steps.length - 1" />
425- </template >
426- </BreadcrumbList >
427- </Breadcrumb >
456+ <!-- Progress Bar Navigation -->
457+ <ProgressBars
458+ :steps =" progressSteps"
459+ :progress =" progressPercentage"
460+ :title =" progressTitle"
461+ :variant =" progressVariant"
462+ size =" md"
463+ interactive
464+ styled
465+ @step-click =" handleStepClick"
466+ />
428467
429468 <!-- Error Message -->
430469 <Alert v-if =" submitError" variant =" destructive" >
@@ -433,7 +472,6 @@ onUnmounted(() => {
433472 </AlertDescription >
434473 </Alert >
435474
436-
437475 <!-- Step Content -->
438476 <div class =" bg-white rounded-lg border p-6" >
439477 <component
@@ -477,7 +515,7 @@ onUnmounted(() => {
477515 class =" min-w-[120px]"
478516 >
479517 <Loader2 v-if =" isFetchingGitHub" class =" h-4 w-4 animate-spin mr-2" />
480- {{ isFetchingGitHub ? 'Fetching...' : t('mcpCatalog.form.navigation.next') }}
518+ {{ isFetchingGitHub ? t('mcpCatalog.form.navigation.fetching') : t('mcpCatalog.form.navigation.next') }}
481519 </Button >
482520
483521 <!-- Normal next button for other steps -->
@@ -504,7 +542,7 @@ onUnmounted(() => {
504542 <AlertDescription >
505543 {{ githubFetchError }}
506544 <br >
507- <span class =" text-sm" >Please check the URL and try again. </span >
545+ <span class =" text-sm" >{{ t('mcpCatalog.validation.githubUrlInvalid') }} </span >
508546 </AlertDescription >
509547 </Alert >
510548 </div >
0 commit comments