Skip to content

Commit b021ddb

Browse files
author
Lasim
committed
feat(frontend): add success and error toasts for user configuration updates
1 parent 468967d commit b021ddb

File tree

2 files changed

+86
-56
lines changed

2 files changed

+86
-56
lines changed

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

Lines changed: 79 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
44
import { ref, computed, onMounted } from 'vue'
55
import { useI18n } from 'vue-i18n'
6+
import { toast } from 'vue-sonner'
67
import { Settings, Eye, EyeOff, AlertTriangle, Monitor } from 'lucide-vue-next'
78
import { McpCatalogService } from '@/services/mcpCatalogService'
89
import { McpInstallationService } from '@/services/mcpInstallationService'
@@ -167,10 +168,9 @@ const currentUserEnv = computed(() => {
167168
168169
// Prepare user arguments with current values
169170
const userArgsWithData = computed(() => {
170-
return userArgsSchema.value.map((argSchema: any, index: number) => ({
171+
return userArgsSchema.value.map((argSchema: any) => ({
171172
...argSchema,
172-
index,
173-
currentValue: currentUserArgs.value[index] || ''
173+
currentValue: currentUserEnv.value[argSchema.name] || ''
174174
}))
175175
})
176176
@@ -202,11 +202,8 @@ const getDeviceValue = (item: any, deviceId: string, type: 'arg' | 'env') => {
202202
const userConfig = userConfigurations.value.find(config => config.device_id === deviceId)
203203
if (!userConfig) return ''
204204
205-
if (type === 'arg') {
206-
return userConfig.user_args?.[item.index] || ''
207-
} else {
208-
return userConfig.user_env?.[item.name] || ''
209-
}
205+
// Both args and env are stored in user_env (args are named env vars)
206+
return userConfig.user_env?.[item.name] || ''
210207
}
211208
212209
// Modal functions
@@ -264,64 +261,88 @@ const handleEdit = async () => {
264261
isSubmitting.value = true
265262
266263
try {
267-
// Find existing user config for this device or create new one
264+
// Find existing user config for this device
268265
let userConfig = userConfigurations.value.find(config => config.device_id === editingDevice.value.id)
269266
270267
if (!userConfig) {
271-
// Create new user configuration for this device
272-
const initialArgs = new Array(userArgsSchema.value.length).fill('')
273-
const initialEnv: Record<string, string> = {}
268+
// Create new user configuration for this device with only the specific field
269+
const createData: any = {
270+
device_id: editingDevice.value.id
271+
}
272+
273+
if (editingType.value === 'arg') {
274+
// Create env object with the named argument (args are actually env vars)
275+
createData.user_env = {
276+
[editingItem.value.name]: editingValue.value
277+
}
278+
} else {
279+
// Create env object with only the specific variable set
280+
createData.user_env = {
281+
[editingItem.value.name]: editingValue.value
282+
}
283+
}
274284
275285
userConfig = await McpInstallationService.createUserConfiguration(
276286
props.teamId,
277287
props.installation.id,
278-
{
279-
device_id: editingDevice.value.id,
280-
user_args: initialArgs,
281-
user_env: initialEnv
282-
}
288+
createData
283289
)
284290
285291
userConfigurations.value.push(userConfig)
286-
}
287-
288-
// Update the specific field
289-
let updatedArgs = [...(userConfig.user_args || [])]
290-
let updatedEnv = { ...(userConfig.user_env || {}) }
291-
292-
if (editingType.value === 'arg') {
293-
// Ensure array is large enough
294-
while (updatedArgs.length <= editingItem.value.index) {
295-
updatedArgs.push('')
296-
}
297-
updatedArgs[editingItem.value.index] = editingValue.value
298292
} else {
299-
updatedEnv[editingItem.value.name] = editingValue.value
300-
}
301-
302-
// Update the configuration
303-
const updatedConfig = await McpInstallationService.updateUserConfiguration(
304-
props.teamId,
305-
props.installation.id,
306-
userConfig.id,
307-
{
308-
device_id: editingDevice.value.id,
309-
user_args: updatedArgs,
310-
user_env: updatedEnv
293+
// Update existing configuration with only the specific field
294+
const updateData: any = {
295+
device_id: editingDevice.value.id
311296
}
312-
)
313-
314-
// Update local state
315-
const configIndex = userConfigurations.value.findIndex(c => c.id === userConfig!.id)
316-
if (configIndex >= 0) {
317-
userConfigurations.value[configIndex] = updatedConfig
297+
298+
if (editingType.value === 'arg') {
299+
// Update only the env vars object (args are actually env vars)
300+
const updatedEnv = { ...(userConfig.user_env || {}) }
301+
updatedEnv[editingItem.value.name] = editingValue.value
302+
updateData.user_env = updatedEnv
303+
} else {
304+
// Update only the env vars object
305+
const updatedEnv = { ...(userConfig.user_env || {}) }
306+
updatedEnv[editingItem.value.name] = editingValue.value
307+
updateData.user_env = updatedEnv
308+
}
309+
310+
// Update the configuration
311+
const updatedConfig = await McpInstallationService.updateUserConfiguration(
312+
props.teamId,
313+
props.installation.id,
314+
userConfig.id,
315+
updateData
316+
)
317+
318+
// Update local state
319+
const configIndex = userConfigurations.value.findIndex(c => c.id === userConfig!.id)
320+
if (configIndex >= 0) {
321+
userConfigurations.value[configIndex] = updatedConfig
322+
}
323+
324+
userConfig = updatedConfig
318325
}
319326
320-
emit('configuration-updated', updatedConfig)
327+
emit('configuration-updated', userConfig)
328+
329+
// Show success toast
330+
toast.success(t('mcpInstallations.userConfiguration.editModal.messages.saveSuccess'), {
331+
description: t('mcpInstallations.userConfiguration.editModal.messages.saveSuccessDescription', {
332+
item: editingItem.value.name,
333+
device: editingDevice.value.device_name
334+
})
335+
})
321336
322337
closeEditModal()
323338
} catch (error) {
324339
console.error('Error updating user configuration:', error)
340+
341+
// Show error toast
342+
toast.error(t('mcpInstallations.userConfiguration.editModal.messages.saveError'), {
343+
description: error instanceof Error ? error.message : t('mcpInstallations.userConfiguration.editModal.messages.saveErrorDescription')
344+
})
345+
325346
formErrors.value.general = error instanceof Error ? error.message : 'Failed to update configuration'
326347
} finally {
327348
isSubmitting.value = false
@@ -331,9 +352,7 @@ const handleEdit = async () => {
331352
const modalTitle = computed(() => {
332353
if (!editingItem.value || !editingDevice.value) return ''
333354
334-
const itemName = editingType.value === 'arg'
335-
? t('mcpInstallations.userConfiguration.table.values.argumentNumber', { number: editingItem.value.index + 1 })
336-
: editingItem.value.name
355+
const itemName = editingItem.value.name
337356
338357
return t('mcpInstallations.userConfiguration.editModal.title', {
339358
item: itemName,
@@ -380,12 +399,12 @@ const modalTitle = computed(() => {
380399
</div>
381400

382401
<ul role="list" class="space-y-3">
383-
<li v-for="arg in userArgsWithData" :key="arg.index" class="bg-muted/50 rounded-lg px-4 py-5">
402+
<li v-for="arg in userArgsWithData" :key="arg.name" class="bg-muted/50 rounded-lg px-4 py-5">
384403
<div class="flex items-center justify-between gap-x-6 mb-4">
385404
<div class="min-w-0 flex-1">
386405
<div class="flex items-start gap-x-3">
387406
<p class="text-sm/6 font-semibold text-gray-900 font-mono">
388-
{{ t('mcpInstallations.userConfiguration.table.values.argumentNumber', { number: arg.index + 1 }) }}
407+
{{ arg.name }}
389408
</p>
390409
</div>
391410
<div class="mt-1 text-xs/5 text-gray-700">
@@ -579,7 +598,7 @@ const modalTitle = computed(() => {
579598
{{ editingType === 'arg' ? t('mcpInstallations.userConfiguration.editModal.form.labels.argument') : t('mcpInstallations.userConfiguration.editModal.form.labels.variable') }}
580599
</span>
581600
<code class="bg-gray-200 text-gray-800 px-2 py-1 rounded font-mono text-xs font-semibold">
582-
{{ editingType === 'arg' ? t('mcpInstallations.userConfiguration.table.values.argumentNumber', { number: editingItem.index + 1 }) : editingItem.name }}
601+
{{ editingItem.name }}
583602
</code>
584603
<Badge v-if="editingItem.required" variant="default" class="text-xs">
585604
{{ t('mcpInstallations.userConfiguration.table.values.required') }}
@@ -652,8 +671,12 @@ const modalTitle = computed(() => {
652671
<Button type="button" variant="outline" @click="closeEditModal">
653672
{{ t('mcpInstallations.userConfiguration.editModal.form.buttons.cancel') }}
654673
</Button>
655-
<Button type="submit" :disabled="isSubmitting">
656-
{{ isSubmitting ? t('mcpInstallations.userConfiguration.editModal.form.buttons.saving') : t('mcpInstallations.userConfiguration.editModal.form.buttons.save') }}
674+
<Button
675+
type="submit"
676+
:loading="isSubmitting"
677+
:loadingText="t('mcpInstallations.userConfiguration.editModal.form.buttons.saving')"
678+
>
679+
{{ t('mcpInstallations.userConfiguration.editModal.form.buttons.save') }}
657680
</Button>
658681
</AlertDialogFooter>
659682
</form>

services/frontend/src/i18n/locales/en/mcp-installations.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,13 @@ export default {
484484
updateFailed: 'Failed to update configuration. Please try again.'
485485
},
486486

487+
messages: {
488+
saveSuccess: 'Configuration saved',
489+
saveSuccessDescription: 'Updated {item} for {device}',
490+
saveError: 'Failed to save configuration',
491+
saveErrorDescription: 'Please try again or contact support'
492+
},
493+
487494
success: {
488495
updated: 'Updated {item}',
489496
description: 'Your configuration has been updated successfully'

0 commit comments

Comments
 (0)