mm-front/src/components/common/ApiKeyRevealDialog.vue
2026-06-23 11:27:28 +09:00

104 lines
No EOL
3.2 KiB
Vue

<template>
<v-dialog
:model-value="modelValue"
max-width="520"
persistent
@update:model-value="$emit('update:modelValue', $event)"
>
<v-card rounded="lg">
<v-card-title class="pa-4 d-flex align-center ga-2">
<v-icon color="success">mdi-key-variant</v-icon>
APIキーが発行されました
</v-card-title>
<v-divider />
<v-card-text class="pa-4">
<v-alert
type="warning"
variant="tonal"
class="mb-4"
text="このキーは一度しか表示されません。必ずコピーして安全な場所に保存してください。"
/>
<div class="d-flex align-center ga-2">
<v-text-field
:model-value="apiKey"
variant="outlined"
density="compact"
readonly
hide-details
class="flex-grow-1"
:type="show ? 'text' : 'password'"
>
<template #append-inner>
<v-btn
icon
size="small"
variant="text"
@click="show = !show"
>
<v-icon size="18">
{{ show ? "mdi-eye-off" : "mdi-eye" }}
</v-icon>
</v-btn>
</template>
</v-text-field>
<v-btn
icon
variant="tonal"
color="primary"
size="small"
@click="copyKey"
>
<v-icon size="18">
{{ copied ? "mdi-check" : "mdi-content-copy" }}
</v-icon>
<v-tooltip activator="parent" location="top">
{{ copied ? "コピー済み" : "コピー" }}
</v-tooltip>
</v-btn>
</div>
</v-card-text>
<v-divider />
<v-card-actions class="pa-4">
<v-spacer />
<v-btn
color="primary"
variant="tonal"
@click="$emit('update:modelValue', false)"
>
閉じる
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script setup lang="ts">
import { ref } from "vue";
const props = defineProps<{
modelValue: boolean;
apiKey: string | null;
}>();
defineEmits<{
"update:modelValue": [value: boolean];
}>();
const show = ref(false);
const copied = ref(false);
const copyKey = async () => {
if (!props.apiKey) return;
await navigator.clipboard.writeText(props.apiKey);
copied.value = true;
setTimeout(() => {
copied.value = false;
}, 2000);
};
</script>