<template>
<GnAlert variant="danger" role="alert">
<strong>{{ title }}</strong>
<p v-if="displayMessage">{{ displayMessage }}</p>
<div v-if="error" class="error-meta">
<GnBadge v-if="error.type" variant="secondary">{{ error.type }}</GnBadge>
<GnBadge v-if="error.statusCode" variant="secondary">HTTP {{ error.statusCode }}</GnBadge>
<GnBadge v-if="error.errorAlias" variant="warning">{{ error.errorAlias }}</GnBadge>
</div>
<div class="error-actions">
<GnCopyButton
v-if="error"
:text="formattedDetails"
label="Copy error details"
size="sm"
/>
<GnButton v-if="retry" variant="danger" @click="retry">Retry</GnButton>
</div>
</GnAlert>
</template>
<script setup>
import { computed } from "vue";
import { GnAlert, GnBadge, GnButton, GnCopyButton } from "gnexus-ui-kit/vue";
const props = defineProps({
title: {
type: String,
default: "Request failed",
},
message: {
type: String,
default: "",
},
retry: {
type: Function,
default: null,
},
error: {
type: Object,
default: null,
},
});
const displayMessage = computed(() => props.message || props.error?.message || "");
const formattedDetails = computed(() => {
if (!props.error) return "";
try {
return JSON.stringify(props.error, null, 2);
} catch {
return String(props.error);
}
});
</script>
<style scoped>
.error-meta {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 8px;
}
.error-actions {
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: center;
margin-top: 12px;
}
</style>