fc3h(ui): BackupConfirmModal.vue — typed-token confirmation for restore + delete

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-24 23:05:04 -04:00
parent 102c21feaa
commit 1e34b1b428
@@ -0,0 +1,87 @@
<template>
<v-dialog v-model="modelValue" max-width="520" persistent>
<v-card>
<v-card-title>
{{ action === 'restore' ? 'Restore' : 'Delete' }}
{{ kind === 'db' ? 'database' : 'images' }} backup #{{ runId }}
</v-card-title>
<v-card-text>
<v-alert
:type="action === 'restore' ? 'warning' : 'error'"
variant="tonal" density="compact" class="mb-3"
>
<strong>{{ warningText }}</strong>
<div class="mt-1">{{ description }}</div>
</v-alert>
<div class="text-body-2 mb-2">
Type the following to confirm:
</div>
<div class="fc-token mb-3">{{ expectedToken }}</div>
<v-text-field
v-model="typed"
variant="outlined" density="compact" hide-details
autofocus
placeholder="paste the token above"
/>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn variant="text" @click="onCancel">Cancel</v-btn>
<v-btn
:color="action === 'restore' ? 'warning' : 'error'"
variant="flat" rounded="pill"
:disabled="typed !== expectedToken"
@click="onConfirm"
>
{{ action === 'restore' ? 'Restore' : 'Delete' }}
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script setup>
import { computed, ref, watch } from 'vue'
const props = defineProps({
modelValue: { type: Boolean, required: true },
action: { type: String, required: true }, // 'restore' | 'delete'
kind: { type: String, required: true }, // 'db' | 'images'
runId: { type: Number, required: true },
description: { type: String, default: '' },
})
const emit = defineEmits(['update:modelValue', 'confirm'])
const typed = ref('')
const expectedToken = computed(
() => `${props.action}-${props.kind}-${props.runId}`,
)
const warningText = computed(() => (
props.action === 'restore'
? 'This replaces current state with the backup. There is no undo.'
: 'This deletes the backup record + on-disk files. Cannot be recovered.'
))
watch(() => props.modelValue, (open) => {
if (open) typed.value = ''
})
function onCancel() {
emit('update:modelValue', false)
}
function onConfirm() {
emit('confirm', expectedToken.value)
emit('update:modelValue', false)
}
</script>
<style scoped>
.fc-token {
font-family: 'JetBrains Mono', monospace;
background: rgb(var(--v-theme-surface-light));
padding: 6px 10px; border-radius: 4px;
font-size: 14px; word-break: break-all;
}
</style>