Skip to content

Commit fe038d9

Browse files
author
Lasim
committed
feat(credentials): add edit name functionality and modal for credential management
1 parent 56d58be commit fe038d9

File tree

2 files changed

+186
-3
lines changed

2 files changed

+186
-3
lines changed

services/frontend/src/i18n/locales/en/credentials.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ export default {
8181
editName: 'Edit Name',
8282
updateSecrets: 'Update Secrets'
8383
},
84+
editName: {
85+
title: 'Edit Name',
86+
description: 'Edit the name and comment for "{credentialName}"'
87+
},
8488
updateSecrets: {
8589
title: 'Update Secrets',
8690
description: 'Update secret values for "{credentialName}"',

services/frontend/src/views/credentials/[id].vue

Lines changed: 182 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { Badge } from '@/components/ui/badge'
77
import { Alert, AlertDescription } from '@/components/ui/alert'
88
import { Input } from '@/components/ui/input'
99
import { Label } from '@/components/ui/label'
10+
import { Textarea } from '@/components/ui/textarea'
1011
import {
1112
AlertDialog,
1213
AlertDialogAction,
@@ -53,6 +54,16 @@ const secretsErrors = ref<Record<string, string>>({})
5354
const isUpdatingSecrets = ref(false)
5455
const updateSecretsError = ref<string | null>(null)
5556
57+
// Edit Name modal state
58+
const showEditNameModal = ref(false)
59+
const editNameForm = ref({
60+
name: '',
61+
comment: ''
62+
})
63+
const editNameErrors = ref<Record<string, string>>({})
64+
const isUpdatingName = ref(false)
65+
const updateNameError = ref<string | null>(null)
66+
5667
// Success message state for main page
5768
const showSuccessMessage = ref(false)
5869
const successMessage = ref<string | null>(null)
@@ -159,6 +170,19 @@ const isSecretsFormValid = computed(() => {
159170
return hasAnyValue
160171
})
161172
173+
// Edit Name computed properties
174+
const isEditNameFormValid = computed(() => {
175+
// Check if there are any validation errors
176+
if (Object.keys(editNameErrors.value).length > 0) return false
177+
178+
// Name is required and must be different from current name or comment must be different
179+
const nameChanged = editNameForm.value.name.trim() !== credential.value?.name
180+
const commentChanged = editNameForm.value.comment.trim() !== (credential.value?.comment || '')
181+
182+
// Must have a valid name and at least one field changed
183+
return editNameForm.value.name.trim() !== '' && (nameChanged || commentChanged)
184+
})
185+
162186
const formatDate = (dateString: string) => {
163187
return new Date(dateString).toLocaleDateString('en-US', {
164188
year: 'numeric',
@@ -334,10 +358,88 @@ const cancelUpdateSecrets = () => {
334358
initializeSecretsForm()
335359
}
336360
337-
// Placeholder function for edit name
361+
// Edit Name functionality
362+
const initializeEditNameForm = () => {
363+
if (!credential.value) return
364+
365+
editNameForm.value = {
366+
name: credential.value.name,
367+
comment: credential.value.comment || ''
368+
}
369+
editNameErrors.value = {}
370+
updateNameError.value = null
371+
}
372+
373+
const validateEditNameForm = () => {
374+
const errors: Record<string, string> = {}
375+
376+
// Name validation
377+
if (!editNameForm.value.name.trim()) {
378+
errors.name = t('credentials.form.fields.name.required')
379+
} else if (editNameForm.value.name.length > 100) {
380+
errors.name = t('credentials.form.fields.name.maxLength')
381+
}
382+
383+
// Comment validation
384+
if (editNameForm.value.comment.length > 500) {
385+
errors.comment = t('credentials.form.fields.comment.maxLength')
386+
}
387+
388+
editNameErrors.value = errors
389+
return Object.keys(errors).length === 0
390+
}
391+
338392
const handleEditName = () => {
339-
console.log('Edit Name clicked - functionality to be implemented')
340-
// TODO: Implement edit name functionality
393+
if (!credential.value) return
394+
395+
initializeEditNameForm()
396+
showEditNameModal.value = true
397+
}
398+
399+
const handleSubmitEditName = async () => {
400+
if (!validateEditNameForm() || !selectedTeam.value || !credential.value) return
401+
402+
try {
403+
isUpdatingName.value = true
404+
updateNameError.value = null
405+
406+
// Prepare update data
407+
const updateData = {
408+
name: editNameForm.value.name.trim(),
409+
comment: editNameForm.value.comment.trim() || undefined
410+
}
411+
412+
// Call the update API with name and comment only
413+
const updatedCredential = await CredentialsService.updateCredential(
414+
selectedTeam.value.id,
415+
credential.value.id,
416+
updateData
417+
)
418+
419+
// Update local credential data
420+
credential.value = updatedCredential
421+
422+
// Close modal immediately after successful API call
423+
showEditNameModal.value = false
424+
425+
// Show success message on main page
426+
showSuccessMessage.value = true
427+
successMessage.value = t('credentials.form.messages.success.update', { name: updatedCredential.name })
428+
429+
// Emit success event
430+
eventBus.emit('credentials-updated')
431+
432+
} catch (err) {
433+
console.error('Error updating credential name:', err)
434+
updateNameError.value = err instanceof Error ? err.message : t('credentials.form.messages.error.update')
435+
} finally {
436+
isUpdatingName.value = false
437+
}
438+
}
439+
440+
const cancelEditName = () => {
441+
showEditNameModal.value = false
442+
initializeEditNameForm()
341443
}
342444
</script>
343445

@@ -663,5 +765,82 @@ const handleEditName = () => {
663765
</AlertDialogFooter>
664766
</AlertDialogContent>
665767
</AlertDialog>
768+
769+
<!-- Edit Name Modal -->
770+
<AlertDialog v-model:open="showEditNameModal">
771+
<AlertDialogContent class="sm:max-w-[500px]">
772+
<AlertDialogHeader>
773+
<AlertDialogTitle class="flex items-center gap-2">
774+
<Edit class="h-5 w-5" />
775+
{{ t('credentials.editName.title') }}
776+
</AlertDialogTitle>
777+
<AlertDialogDescription class="text-left">
778+
{{ t('credentials.editName.description', { credentialName: credential?.name || '' }) }}
779+
</AlertDialogDescription>
780+
</AlertDialogHeader>
781+
782+
<!-- Error Display -->
783+
<Alert v-if="updateNameError" variant="destructive" class="mx-6">
784+
<AlertTriangle class="h-4 w-4" />
785+
<AlertDescription>
786+
{{ updateNameError }}
787+
</AlertDescription>
788+
</Alert>
789+
790+
<!-- Form Content -->
791+
<div class="px-6 space-y-4">
792+
<form @submit.prevent="handleSubmitEditName" class="space-y-4">
793+
<!-- Name Field -->
794+
<div class="space-y-2">
795+
<Label for="edit-name">{{ t('credentials.form.fields.name.label') }}</Label>
796+
<Input
797+
id="edit-name"
798+
v-model="editNameForm.name"
799+
:placeholder="t('credentials.form.fields.name.placeholder')"
800+
:class="{ 'border-destructive': editNameErrors.name }"
801+
@input="validateEditNameForm"
802+
required
803+
/>
804+
<div v-if="editNameErrors.name" class="text-sm text-destructive">
805+
{{ editNameErrors.name }}
806+
</div>
807+
</div>
808+
809+
<!-- Comment Field -->
810+
<div class="space-y-2">
811+
<Label for="edit-comment">{{ t('credentials.form.fields.comment.label') }}</Label>
812+
<Textarea
813+
id="edit-comment"
814+
v-model="editNameForm.comment"
815+
:placeholder="t('credentials.form.fields.comment.placeholder')"
816+
:class="{ 'border-destructive': editNameErrors.comment }"
817+
@input="validateEditNameForm"
818+
rows="3"
819+
/>
820+
<div v-if="editNameErrors.comment" class="text-sm text-destructive">
821+
{{ editNameErrors.comment }}
822+
</div>
823+
</div>
824+
</form>
825+
</div>
826+
827+
<AlertDialogFooter class="flex gap-2">
828+
<AlertDialogCancel
829+
@click="cancelEditName"
830+
:disabled="isUpdatingName"
831+
>
832+
{{ t('credentials.form.buttons.cancel') }}
833+
</AlertDialogCancel>
834+
<AlertDialogAction
835+
@click="handleSubmitEditName"
836+
:disabled="!isEditNameFormValid || isUpdatingName"
837+
>
838+
<Edit v-if="!isUpdatingName" class="h-4 w-4 mr-2" />
839+
<div v-else class="h-4 w-4 mr-2 animate-spin rounded-full border-2 border-white border-t-transparent"></div>
840+
{{ isUpdatingName ? t('credentials.form.buttons.saving') : t('credentials.form.buttons.save') }}
841+
</AlertDialogAction>
842+
</AlertDialogFooter>
843+
</AlertDialogContent>
844+
</AlertDialog>
666845
</DashboardLayout>
667846
</template>

0 commit comments

Comments
 (0)