|
| 1 | +<template> |
| 2 | + <form |
| 3 | + class="credentials-form" |
| 4 | + novalidate |
| 5 | + @submit.prevent="submit" |
| 6 | + > |
| 7 | + <p>{{ $t('migrate.credentials.description', {name: migratorName}) }}</p> |
| 8 | + <Message |
| 9 | + v-if="error" |
| 10 | + variant="danger" |
| 11 | + class="mbe-4" |
| 12 | + > |
| 13 | + {{ error }} |
| 14 | + </Message> |
| 15 | + <FormField |
| 16 | + id="migration-url" |
| 17 | + v-model="credentials.url" |
| 18 | + v-focus |
| 19 | + :label="$t('migrate.credentials.url', {name: migratorName})" |
| 20 | + :placeholder="urlPlaceholder" |
| 21 | + :error="credentialsErrors.url" |
| 22 | + type="url" |
| 23 | + autocomplete="url" |
| 24 | + /> |
| 25 | + <fieldset class="field"> |
| 26 | + <legend class="label"> |
| 27 | + {{ $t('migrate.credentials.authMethod') }} |
| 28 | + </legend> |
| 29 | + <div class="control auth-method"> |
| 30 | + <label class="radio"> |
| 31 | + <input |
| 32 | + v-model="authMethod" |
| 33 | + type="radio" |
| 34 | + name="auth-method" |
| 35 | + value="token" |
| 36 | + > |
| 37 | + {{ $t('migrate.credentials.apiKey') }} |
| 38 | + </label> |
| 39 | + <label class="radio"> |
| 40 | + <input |
| 41 | + v-model="authMethod" |
| 42 | + type="radio" |
| 43 | + name="auth-method" |
| 44 | + value="password" |
| 45 | + > |
| 46 | + {{ $t('migrate.credentials.authPassword') }} |
| 47 | + </label> |
| 48 | + </div> |
| 49 | + </fieldset> |
| 50 | + <template v-if="authMethod === 'token'"> |
| 51 | + <FormField |
| 52 | + id="migration-token" |
| 53 | + v-model="credentials.token" |
| 54 | + :label="$t('migrate.credentials.apiKey')" |
| 55 | + :error="credentialsErrors.token" |
| 56 | + type="password" |
| 57 | + autocomplete="off" |
| 58 | + :aria-describedby="apiKeyHelp ? 'migration-token-help' : undefined" |
| 59 | + /> |
| 60 | + <p |
| 61 | + v-if="apiKeyHelp" |
| 62 | + id="migration-token-help" |
| 63 | + class="help" |
| 64 | + > |
| 65 | + {{ apiKeyHelp }} |
| 66 | + </p> |
| 67 | + </template> |
| 68 | + <template v-else> |
| 69 | + <FormField |
| 70 | + id="migration-username" |
| 71 | + v-model="credentials.username" |
| 72 | + :label="$t('user.auth.usernameEmail')" |
| 73 | + :error="credentialsErrors.username" |
| 74 | + type="text" |
| 75 | + autocomplete="off" |
| 76 | + /> |
| 77 | + <FormField |
| 78 | + id="migration-password" |
| 79 | + v-model="credentials.password" |
| 80 | + :label="$t('user.auth.password')" |
| 81 | + :error="credentialsErrors.password" |
| 82 | + type="password" |
| 83 | + autocomplete="off" |
| 84 | + :aria-describedby="passwordHelp ? 'migration-password-help' : undefined" |
| 85 | + /> |
| 86 | + <p |
| 87 | + v-if="passwordHelp" |
| 88 | + id="migration-password-help" |
| 89 | + class="help" |
| 90 | + > |
| 91 | + {{ passwordHelp }} |
| 92 | + </p> |
| 93 | + </template> |
| 94 | + <XButton |
| 95 | + type="submit" |
| 96 | + :loading="loading" |
| 97 | + :disabled="loading || undefined" |
| 98 | + > |
| 99 | + {{ $t('migrate.credentials.start') }} |
| 100 | + </XButton> |
| 101 | + </form> |
| 102 | +</template> |
| 103 | + |
| 104 | +<script setup lang="ts"> |
| 105 | +import {computed, reactive, ref} from 'vue' |
| 106 | +import {useI18n} from 'vue-i18n' |
| 107 | +
|
| 108 | +import FormField from '@/components/input/FormField.vue' |
| 109 | +import Message from '@/components/misc/Message.vue' |
| 110 | +
|
| 111 | +import type {MigrationConfig} from '@/services/migrator/abstractMigration' |
| 112 | +
|
| 113 | +const props = withDefaults(defineProps<{ |
| 114 | + migratorName: string, |
| 115 | + loading: boolean, |
| 116 | + error: string, |
| 117 | + apiKeyHelp?: string, |
| 118 | + passwordHelp?: string, |
| 119 | +}>(), { |
| 120 | + apiKeyHelp: '', |
| 121 | + passwordHelp: '', |
| 122 | +}) |
| 123 | +
|
| 124 | +const emit = defineEmits<{ |
| 125 | + submit: [config: MigrationConfig], |
| 126 | + clearError: [], |
| 127 | +}>() |
| 128 | +
|
| 129 | +const {t} = useI18n({useScope: 'global'}) |
| 130 | +
|
| 131 | +const urlPlaceholder = computed(() => `https://${props.migratorName.toLowerCase()}.example.com`) |
| 132 | +
|
| 133 | +const authMethod = ref<'token' | 'password'>('token') |
| 134 | +const credentials = reactive({url: '', token: '', username: '', password: ''}) |
| 135 | +const credentialsErrors = reactive<{ |
| 136 | + url: string | null, |
| 137 | + token: string | null, |
| 138 | + username: string | null, |
| 139 | + password: string | null, |
| 140 | +}>({url: null, token: null, username: null, password: null}) |
| 141 | +
|
| 142 | +function submit() { |
| 143 | + emit('clearError') |
| 144 | +
|
| 145 | + const url = credentials.url.trim() |
| 146 | + credentialsErrors.url = url === '' ? t('apiConfig.urlRequired') : null |
| 147 | +
|
| 148 | + if (authMethod.value === 'token') { |
| 149 | + credentialsErrors.token = credentials.token.trim() === '' ? t('migrate.credentials.apiKeyRequired') : null |
| 150 | + credentialsErrors.username = null |
| 151 | + credentialsErrors.password = null |
| 152 | + } else { |
| 153 | + credentialsErrors.token = null |
| 154 | + credentialsErrors.username = credentials.username.trim() === '' ? t('user.auth.usernameRequired') : null |
| 155 | + credentialsErrors.password = credentials.password === '' ? t('user.auth.passwordRequired') : null |
| 156 | + } |
| 157 | +
|
| 158 | + if (credentialsErrors.url || credentialsErrors.token || credentialsErrors.username || credentialsErrors.password) { |
| 159 | + return |
| 160 | + } |
| 161 | +
|
| 162 | + emit('submit', authMethod.value === 'token' |
| 163 | + ? {url, token: credentials.token.trim()} |
| 164 | + : {url, username: credentials.username.trim(), password: credentials.password}) |
| 165 | +} |
| 166 | +</script> |
| 167 | + |
| 168 | +<style lang="scss" scoped> |
| 169 | +.credentials-form { |
| 170 | + max-inline-size: 500px; |
| 171 | +} |
| 172 | +
|
| 173 | +fieldset { |
| 174 | + border: 0; |
| 175 | + margin: 0; |
| 176 | + padding: 0; |
| 177 | +} |
| 178 | +
|
| 179 | +.auth-method { |
| 180 | + display: flex; |
| 181 | + flex-wrap: wrap; |
| 182 | + gap: 1rem; |
| 183 | +} |
| 184 | +</style> |
0 commit comments