Skip to content

Commit 96923ed

Browse files
committed
refactor(frontend): clean up code and improve readability in components
1 parent 4d2e332 commit 96923ed

File tree

10 files changed

+78
-158
lines changed

10 files changed

+78
-158
lines changed

services/frontend/src/components/admin/mcp-catalog/BasicInfoStep.vue

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* This component uses storage-first architecture where:
55
* - All form data is stored in localStorage via the event bus
6-
* - Component reads/writes directly to storage, not through v-model props
6+
* - Component reads/writes directly to storage, not through v-model props
77
* - Real-time synchronization across all wizard steps
88
* - No v-model props or emit patterns
99
*
@@ -137,14 +137,8 @@ const handleTagKeydown = (event: KeyboardEvent) => {
137137
}
138138
}
139139
140-
// Debug function to check storage state
141-
const debugStorageState = () => {
142-
const currentData = eventBus.getState<BasicInfoFormData>(STORAGE_KEY)
143-
console.log('[BasicInfoStep] Current storage state:', currentData)
144-
console.log('[BasicInfoStep] Featured value:', currentData?.featured)
145-
}
146-
147140
// Storage change handler
141+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
148142
const handleStorageChange = (data: { key: string; oldValue: any; newValue: any }) => {
149143
if (data.key === STORAGE_KEY) {
150144
// Storage changed externally, update local reactive data
@@ -155,13 +149,13 @@ const handleStorageChange = (data: { key: string; oldValue: any; newValue: any }
155149
// Lifecycle
156150
onMounted(() => {
157151
loadCategories()
158-
152+
159153
// Load initial data from storage
160154
loadFromStorage()
161-
155+
162156
// Listen for storage changes from other components
163157
eventBus.on('storage-changed', handleStorageChange)
164-
158+
165159
// Initialize from props in edit mode if storage is empty
166160
if (props.mode === 'edit' && props.modelValue) {
167161
const currentData = eventBus.getState<BasicInfoFormData>(STORAGE_KEY)

services/frontend/src/components/admin/mcp-catalog/McpServerAddFormWizard.vue

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script setup lang="ts">
2+
/* eslint-disable @typescript-eslint/no-explicit-any */
23
import { ref, onMounted, onUnmounted, computed } from 'vue'
34
import { useI18n } from 'vue-i18n'
45
import { Button } from '@/components/ui/button'
@@ -27,7 +28,7 @@ const props = withDefaults(defineProps<Props>(), {
2728
2829
// Emits
2930
const emit = defineEmits<{
30-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
31+
3132
submit: [formData: any] // Use any to avoid circular type dependencies, parent view defines the final type
3233
cancel: []
3334
stepChanged: [data: { step: number; stepKey: string }]
@@ -43,7 +44,7 @@ interface McpServerAddFormData {
4344
github_url: string
4445
git_branch: string
4546
auto_populated: boolean
46-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
47+
4748
repo_data?: any
4849
}
4950
claudeConfig: {
@@ -262,7 +263,7 @@ const goToStep = (stepIndex: number) => {
262263
}
263264
264265
// Handle step click from ProgressBars
265-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
266+
266267
const handleStepClick = (step: any, index: number) => {
267268
if (step.clickable) {
268269
goToStep(index)
@@ -342,7 +343,7 @@ const handleGitHubStepNext = async () => {
342343
}
343344
344345
// Auto-population function for GitHub data
345-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
346+
346347
const autoPopulateFromGitHub = (githubData: any) => {
347348
// Update GitHub data
348349
formData.value.github = {

services/frontend/src/components/admin/mcp-catalog/steps/ConfigurationSchemaEnvironmentSection.vue

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
<!--
22
* SHARED ENVIRONMENT VARIABLES CONFIGURATION SECTION
3-
*
3+
*
44
* This component extracts ONLY the duplicated template code for environment variables.
55
* No logic duplication - just the UI template that was identical in both components.
66
-->
77

88
<script setup lang="ts">
9-
import { computed } from 'vue'
10-
import { useI18n } from 'vue-i18n'
119
import { Button } from '@/components/ui/button'
1210
import {
1311
DropdownMenu,
@@ -34,19 +32,18 @@ interface Props {
3432
items: EnvItem[]
3533
getCategoryInfo: (category: string) => {
3634
label: string
35+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
3736
icon: any
3837
color: string
3938
}
4039
}
4140
42-
const props = defineProps<Props>()
41+
defineProps<Props>()
4342
const emit = defineEmits<{
4443
'add': []
4544
'edit': [index: number]
4645
'delete': [index: number]
4746
}>()
48-
49-
const { t } = useI18n()
5047
</script>
5148

5249
<template>

services/frontend/src/components/mcp-server/installation/TeamConfiguration.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script setup lang="ts">
2+
/* eslint-disable @typescript-eslint/no-explicit-any */
23
34
import { ref, computed, onMounted } from 'vue'
45
import { useI18n } from 'vue-i18n'

services/frontend/src/composables/useDevices.ts

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,17 @@ export function useDevices() {
2121

2222
// Computed
2323
const sortedDevices = computed<DeviceTableItem[]>(() => {
24-
return devices.value.map(device => ({
25-
...device,
26-
statusBadgeVariant: device.is_active ? 'default' : 'secondary' as const,
27-
osDisplayName: getOSDisplayName(device.os_type),
28-
lastActivityDisplay: formatLastActivity(device.last_activity_at || device.last_login_at),
29-
trustStatusDisplay: device.is_trusted ? t('devices.status.trusted') : t('devices.status.untrusted')
30-
})).sort((a, b) => {
24+
return devices.value.map(device => {
25+
const statusBadgeVariant: 'default' | 'secondary' | 'destructive' | 'outline' = device.is_active ? 'default' : 'secondary'
26+
27+
return {
28+
...device,
29+
statusBadgeVariant,
30+
osDisplayName: getOSDisplayName(device.os_type),
31+
lastActivityDisplay: formatLastActivity(device.last_activity_at || device.last_login_at),
32+
trustStatusDisplay: device.is_trusted ? t('devices.status.trusted') : t('devices.status.untrusted')
33+
}
34+
}).sort((a, b) => {
3135
// Sort by last activity, then by device name
3236
const aTime = new Date(a.last_activity_at || a.last_login_at || a.created_at).getTime()
3337
const bTime = new Date(b.last_activity_at || b.last_login_at || b.created_at).getTime()
@@ -43,44 +47,44 @@ export function useDevices() {
4347
const active = devices.value.filter(d => d.is_active).length
4448
const trusted = devices.value.filter(d => d.is_trusted).length
4549
const inactive = total - active
46-
50+
4751
return { total, active, trusted, inactive }
4852
})
4953

5054
// Helper functions
5155
function getOSDisplayName(osType: string | null): string {
5256
if (!osType) return t('devices.os.unknown')
53-
57+
5458
const osMap: Record<string, string> = {
5559
'windows': t('devices.os.windows'),
5660
'darwin': t('devices.os.macos'),
5761
'macos': t('devices.os.macos'),
5862
'linux': t('devices.os.linux')
5963
}
60-
64+
6165
return osMap[osType.toLowerCase()] || osType
6266
}
6367

6468
function formatLastActivity(timestamp: string | null): string {
6569
if (!timestamp) return t('devices.time.never')
66-
70+
6771
const now = new Date()
6872
const activityTime = new Date(timestamp)
6973
const diffMs = now.getTime() - activityTime.getTime()
7074
const diffMinutes = Math.floor(diffMs / (1000 * 60))
71-
75+
7276
if (diffMinutes < 1) return t('devices.time.justNow')
7377
if (diffMinutes < 60) return t('devices.time.minutesAgo', { minutes: diffMinutes })
74-
78+
7579
const diffHours = Math.floor(diffMinutes / 60)
7680
if (diffHours < 24) return t('devices.time.hoursAgo', { hours: diffHours })
77-
81+
7882
const diffDays = Math.floor(diffHours / 24)
7983
if (diffDays < 7) return t('devices.time.daysAgo', { days: diffDays })
80-
84+
8185
const diffWeeks = Math.floor(diffDays / 7)
8286
if (diffWeeks < 4) return t('devices.time.weeksAgo', { weeks: diffWeeks })
83-
87+
8488
const diffMonths = Math.floor(diffDays / 30)
8589
return t('devices.time.monthsAgo', { months: diffMonths })
8690
}
@@ -106,19 +110,19 @@ export function useDevices() {
106110
try {
107111
isUpdating.value = true
108112
const updatedDevice = await DeviceService.updateDevice(deviceId, updates)
109-
113+
110114
// Update local state
111115
const index = devices.value.findIndex(d => d.id === deviceId)
112116
if (index !== -1) {
113117
devices.value[index] = updatedDevice
114118
}
115-
119+
116120
// Show success message
117121
toast.success(t('devices.messages.deviceUpdated'))
118-
122+
119123
// Emit event for other components
120124
eventBus.emit('device-updated', { device: updatedDevice })
121-
125+
122126
return updatedDevice
123127
} catch (error) {
124128
console.error('Failed to update device:', error)
@@ -135,17 +139,16 @@ export function useDevices() {
135139
try {
136140
isRemoving.value = true
137141
await DeviceService.removeDevice(deviceId)
138-
142+
139143
// Remove from local state
140-
const deviceName = devices.value.find(d => d.id === deviceId)?.device_name
141144
devices.value = devices.value.filter(d => d.id !== deviceId)
142-
145+
143146
// Show success message
144147
toast.success(t('devices.messages.deviceRemoved'))
145-
148+
146149
// Emit event for other components
147150
eventBus.emit('device-removed', { deviceId })
148-
151+
149152
} catch (error) {
150153
console.error('Failed to remove device:', error)
151154
toast.error(t('devices.errors.removeDevice'), {
@@ -165,7 +168,7 @@ export function useDevices() {
165168
isLoading,
166169
isUpdating,
167170
isRemoving,
168-
171+
169172
// Methods
170173
fetchDevices,
171174
updateDevice,

services/frontend/src/composables/useEventBus.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ export type EventBusEvents = {
3030
'mcp-github-data-populated': any
3131
'mcp-form-step-changed': { from: number; to: number; stepKey: string }
3232
'technical-env-vars-updated': { envVars: string[] }
33-
33+
'device-loaded': { device: any }
34+
'devices-loaded': { devices: any[] }
35+
'device-updated': { device: any }
36+
'device-removed': { deviceId: string }
3437
'mcp-edit-draft-updated': { serverId: string; data: any; step: number }
3538
'mcp-edit-draft-cleared': { serverId: string }
3639
'icons-cache-loaded': { count: number }

services/frontend/src/views/admin/mcp-server-catalog/edit/[id].vue

Lines changed: 5 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup lang="ts">
2-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2+
/* eslint-disable @typescript-eslint/no-explicit-any */
3+
34
import { ref, onMounted } from 'vue'
45
import { useI18n } from 'vue-i18n'
56
import { useRouter, useRoute } from 'vue-router'
@@ -63,7 +64,7 @@ const loadServerData = async () => {
6364
}
6465
6566
// Helper function to parse JSON fields with proper error handling
66-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
67+
6768
const parseJsonField = (fieldValue: any, defaultValue: any) => {
6869
if (!fieldValue || fieldValue === '' || (typeof fieldValue === 'string' && fieldValue.trim() === '')) {
6970
return defaultValue
@@ -79,42 +80,10 @@ const parseJsonField = (fieldValue: any, defaultValue: any) => {
7980
}
8081
}
8182
82-
// Helper function to parse environment variables with robust handling
83-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
84-
const parseEnvironmentVariables = (envVars: any): any[] => {
85-
// Handle null/undefined (service returns null as fallback)
86-
if (!envVars || envVars === null || envVars === undefined) return []
87-
88-
// Handle arrays (expected format from API)
89-
if (Array.isArray(envVars)) {
90-
return envVars
91-
}
92-
93-
// Handle JSON strings (legacy format)
94-
if (typeof envVars === 'string') {
95-
try {
96-
const parsed = JSON.parse(envVars)
97-
return Array.isArray(parsed) ? parsed : []
98-
} catch {
99-
return []
100-
}
101-
}
102-
103-
// Handle objects (in case service parsing changes)
104-
if (typeof envVars === 'object') {
105-
// If it's an object with array-like properties, try to convert
106-
if (Object.keys(envVars).every(key => !isNaN(Number(key)))) {
107-
return Object.values(envVars)
108-
}
109-
}
110-
111-
return []
112-
}
113-
11483
// Convert server data to form data format
11584
const convertServerToFormData = (server: McpServer): Partial<McpServerFormData> => {
11685
// Convert installation methods to new format
117-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
86+
11887
const convertedInstallationMethods = (server.installation_methods || []).map((method: any) => {
11988
// Handle old format: {type, command, description}
12089
if (method.type && method.command && !method.client) {
@@ -138,7 +107,7 @@ const convertServerToFormData = (server: McpServer): Partial<McpServerFormData>
138107
args: method.args || [],
139108
env: method.env || {}
140109
}
141-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
110+
142111
}).filter((method: any) =>
143112
// Filter out git clone template entries and any invalid entries
144113
method.command &&
@@ -149,11 +118,6 @@ const convertServerToFormData = (server: McpServer): Partial<McpServerFormData>
149118
// Parse tags with proper handling
150119
const parsedTags = parseJsonField(server.tags, [])
151120
152-
// Parse tools, resources, and prompts with proper handling
153-
const parsedTools = parseJsonField(server.tools, [])
154-
const parsedResources = parseJsonField(server.resources, [])
155-
const parsedPrompts = parseJsonField(server.prompts, [])
156-
157121
// Convert three-tier schema fields from API response
158122
const parseSchemaField = (field: any, defaultValue: any) => {
159123
if (!field) return defaultValue

0 commit comments

Comments
 (0)