@@ -22,12 +22,14 @@ interface Props {
2222 initialData? : Partial <McpServerFormData >
2323 submitButtonText? : string
2424 cancelButtonText? : string
25+ serverId? : string
2526}
2627
2728const props = withDefaults (defineProps <Props >(), {
2829 mode: ' create' ,
2930 submitButtonText: ' ' ,
30- cancelButtonText: ' '
31+ cancelButtonText: ' ' ,
32+ serverId: ' '
3133})
3234
3335// Emits
@@ -41,6 +43,10 @@ const emit = defineEmits<{
4143const { t } = useI18n ()
4244const eventBus = useEventBus ()
4345
46+ // Storage key for form drafts
47+ const FORM_DRAFTS_KEY = ' mcp_edit_drafts'
48+ const DRAFT_EXPIRY_HOURS = 24
49+
4450// Form steps configuration
4551const steps = [
4652 {
@@ -155,7 +161,8 @@ const formData = ref<McpServerFormData>({
155161 author_contact: ' ' ,
156162 organization: ' ' ,
157163 license: ' ' ,
158- tags: []
164+ tags: [],
165+ featured: false
159166 },
160167 repository: {
161168 github_url: ' ' ,
@@ -337,7 +344,8 @@ const autoPopulateFromGitHub = (githubData: any) => {
337344 author_contact: githubData .owner ?.email || githubData .author_contact || ' ' ,
338345 organization: githubData .owner ?.type === ' Organization' ? githubData .owner .login : (githubData .organization || ' ' ),
339346 license: githubData .license ?.spdx_id || githubData .license || ' ' ,
340- tags: githubData .topics || githubData .tags || []
347+ tags: githubData .topics || githubData .tags || [],
348+ featured: formData .value .basic .featured // Keep user selection for featured status
341349 },
342350 repository: {
343351 github_url: githubData .html_url || githubData .github_url || formData .value .github .github_url ,
@@ -404,20 +412,118 @@ const parseInstallationMethods = (githubData: any): string[] => {
404412 return methods .length > 0 ? methods : [' manual' ]
405413}
406414
407- // Form persistence using event bus
408- const saveFormData = () => {
409- eventBus .emit (' mcp-form-data-updated' , {
410- step: currentStep .value ,
411- data: formData .value
415+ // Draft management functions with proper typing
416+ interface FormDraft {
417+ data: McpServerFormData
418+ lastModified: string
419+ currentStep: number
420+ }
421+
422+ interface FormDrafts {
423+ [serverId : string ]: FormDraft
424+ }
425+
426+ const getDrafts = (): FormDrafts => {
427+ return eventBus .getState <FormDrafts >(FORM_DRAFTS_KEY , {}) || {}
428+ }
429+
430+ const saveDraft = () => {
431+ if (! props .serverId ) return
432+
433+ const drafts = getDrafts ()
434+ drafts [props .serverId ] = {
435+ data: formData .value ,
436+ lastModified: new Date ().toISOString (),
437+ currentStep: currentStep .value
438+ }
439+
440+ eventBus .setState (FORM_DRAFTS_KEY , drafts )
441+
442+ // Emit specific events for real-time updates
443+ eventBus .emit (' mcp-edit-draft-updated' , {
444+ serverId: props .serverId ,
445+ data: formData .value ,
446+ step: currentStep .value
412447 })
413448}
414449
415- const loadFormData = () => {
416- // Try to load persisted form data
417- // This would be implemented with localStorage or session storage
418- // For now, we'll keep the default empty form
450+ const loadDraft = (): boolean => {
451+ if (! props .serverId ) return false
452+
453+ const drafts = getDrafts ()
454+ const draft = drafts [props .serverId ]
455+
456+ if (draft ) {
457+ // Check if draft is not expired
458+ const draftAge = Date .now () - new Date (draft .lastModified ).getTime ()
459+ const maxAge = DRAFT_EXPIRY_HOURS * 60 * 60 * 1000
460+
461+ if (draftAge < maxAge ) {
462+ formData .value = draft .data
463+ currentStep .value = draft .currentStep || 0
464+ return true
465+ } else {
466+ // Remove expired draft
467+ clearDraft ()
468+ }
469+ }
470+
471+ return false
472+ }
473+
474+ const clearDraft = () => {
475+ if (! props .serverId ) return
476+
477+ const drafts = getDrafts ()
478+ if (drafts [props .serverId ]) {
479+ delete drafts [props .serverId ]
480+ eventBus .setState (FORM_DRAFTS_KEY , drafts )
481+
482+ eventBus .emit (' mcp-edit-draft-cleared' , {
483+ serverId: props .serverId
484+ })
485+ }
486+ }
487+
488+ const cleanupExpiredDrafts = () => {
489+ const drafts = getDrafts ()
490+ const maxAge = DRAFT_EXPIRY_HOURS * 60 * 60 * 1000
491+ let hasChanges = false
492+
493+ Object .keys (drafts ).forEach (serverId => {
494+ const draft = drafts [serverId ]
495+ if (draft && draft .lastModified ) {
496+ const draftAge = Date .now () - new Date (draft .lastModified ).getTime ()
497+
498+ if (draftAge >= maxAge ) {
499+ delete drafts [serverId ]
500+ hasChanges = true
501+ }
502+ }
503+ })
504+
505+ if (hasChanges ) {
506+ eventBus .setState (FORM_DRAFTS_KEY , drafts )
507+ }
419508}
420509
510+ // Enhanced form data watcher for real-time storage
511+ watch (
512+ formData ,
513+ () => {
514+ saveDraft ()
515+ },
516+ { deep: true }
517+ )
518+
519+ // Watch current step changes
520+ watch (
521+ currentStep ,
522+ () => {
523+ saveDraft ()
524+ }
525+ )
526+
421527// Form submission
422528const submitForm = async () => {
423529 try {
@@ -436,11 +542,28 @@ const submitForm = async () => {
436542
437543// Lifecycle
438544onMounted (() => {
439- loadFormData ()
545+ // Clean up expired drafts on mount
546+ cleanupExpiredDrafts ()
547+
548+ // In edit mode, check for existing draft and clear it before loading initial data
549+ if (props .mode === ' edit' && props .serverId ) {
550+ clearDraft () // Clear any existing draft for this server
551+ }
552+
553+ // Try to load draft (mainly for create mode or if user refreshed page)
554+ const draftLoaded = loadDraft ()
555+
556+ // If no draft was loaded and we have initial data, use it
557+ if (! draftLoaded && props .initialData ) {
558+ // The initialData watcher will handle this
559+ }
440560})
441561
442562onUnmounted (() => {
443- saveFormData ()
563+ // Save current state as draft when component unmounts (unless submitting)
564+ if (! isSubmitting .value ) {
565+ saveDraft ()
566+ }
444567})
445568 </script >
446569
@@ -478,6 +601,7 @@ onUnmounted(() => {
478601 v-else
479602 v-model =" formData[currentStepData.key]"
480603 :form-data =" formData"
604+ @update:modelValue =" (newValue: any) => formData[currentStepData.key] = newValue"
481605 />
482606 </div >
483607
0 commit comments