88 lines
2.6 KiB
Vue
88 lines
2.6 KiB
Vue
<template>
|
|
<v-dialog :model-value="modelValue" max-width="900"
|
|
@update:model-value="$emit('update:modelValue', $event)">
|
|
<v-card>
|
|
<v-card-title class="d-flex align-center" style="gap: 12px;">
|
|
<v-icon icon="mdi-alert-circle-outline" color="error" />
|
|
<span>{{ title }}</span>
|
|
<v-spacer />
|
|
<v-btn icon variant="text" size="small" @click="close">
|
|
<v-icon>mdi-close</v-icon>
|
|
</v-btn>
|
|
</v-card-title>
|
|
<v-card-text>
|
|
<pre class="fc-err-pre">{{ message || '(no error message)' }}</pre>
|
|
</v-card-text>
|
|
<v-card-actions>
|
|
<v-btn
|
|
variant="text" rounded="pill" size="small"
|
|
:prepend-icon="copied ? 'mdi-check' : 'mdi-content-copy'"
|
|
@click="onCopy"
|
|
>{{ copied ? 'Copied' : 'Copy' }}</v-btn>
|
|
<v-spacer />
|
|
<v-btn variant="text" rounded="pill" @click="close">Close</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, watch } from 'vue'
|
|
|
|
const props = defineProps({
|
|
modelValue: { type: Boolean, default: false },
|
|
title: { type: String, default: 'Error details' },
|
|
message: { type: String, default: '' },
|
|
})
|
|
|
|
const emit = defineEmits(['update:modelValue'])
|
|
|
|
const copied = ref(false)
|
|
let copiedTimer = null
|
|
|
|
watch(() => props.modelValue, (open) => {
|
|
if (!open) {
|
|
copied.value = false
|
|
if (copiedTimer) { clearTimeout(copiedTimer); copiedTimer = null }
|
|
}
|
|
})
|
|
|
|
function close() {
|
|
emit('update:modelValue', false)
|
|
}
|
|
|
|
async function onCopy() {
|
|
try {
|
|
await navigator.clipboard.writeText(props.message || '')
|
|
copied.value = true
|
|
if (copiedTimer) clearTimeout(copiedTimer)
|
|
copiedTimer = setTimeout(() => { copied.value = false }, 1500)
|
|
} catch (e) {
|
|
window.__fcToast?.({ text: `Copy failed: ${e.message}`, type: 'error' })
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
/* The full error often contains a SQLAlchemy statement + parameters
|
|
block + multi-line traceback. Pre-wrap keeps long lines readable;
|
|
monospace + tabular layout keeps the structure scannable. The
|
|
max-height + overflow-auto prevents a 50-line traceback from
|
|
pushing the Close button off-screen. Operator-flagged 2026-05-26:
|
|
the prior :title="..." tooltip was unusable for content this long. */
|
|
.fc-err-pre {
|
|
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
font-size: 12px;
|
|
line-height: 1.5;
|
|
white-space: pre-wrap;
|
|
word-break: break-word;
|
|
background: rgb(var(--v-theme-surface-variant, 38 36 41));
|
|
color: rgb(var(--v-theme-on-surface));
|
|
padding: 12px 14px;
|
|
border-radius: 6px;
|
|
max-height: 60vh;
|
|
overflow: auto;
|
|
margin: 0;
|
|
}
|
|
</style>
|