<script setup>
import { computed } from "vue";
import {
GnActionList,
GnBadge,
GnCopyButton,
GnDescriptionList,
GnDropdown,
GnIconButton,
GnPageHeader,
GnToolbar,
GnTooltip
} from "gnexus-ui-kit/vue";
import { t } from "../i18n";
const props = defineProps({
secret: { type: Object, required: true },
fields: { type: Array, default: null },
showHeader: { type: Boolean, default: true },
showBack: { type: Boolean, default: false },
showActions: { type: Boolean, default: true },
// false when the panel renders a historical version: metadata rows would
// read as "the version's metadata", but they come from the current secret
showDetails: { type: Boolean, default: true },
visibleFieldKeys: { type: Set, default: () => new Set() }
});
const emit = defineEmits([
"back",
"reveal",
"hide",
"edit-metadata",
"toggle-field-visibility",
"status-change",
"archive",
"delete",
"navigate"
]);
// notes are optional — the row only appears when the secret carries one
const details = computed(() => [
{ label: t("detail.purpose"), value: props.secret.purpose || t("common.notSet") },
{ label: t("detail.category"), value: props.secret.category || t("common.notSet") },
...(props.secret.notes
? [{ label: t("detail.notes"), value: props.secret.notes }]
: []),
{ label: t("detail.tags"), value: props.secret.tags?.join(", ") || t("detail.noTags") },
{
label: t("detail.access"),
value: t("detail.accessState", {
ui: props.secret.allow_ui ? t("detail.on") : t("detail.off"),
rest: props.secret.allow_rest_api ? t("detail.on") : t("detail.off"),
mcp: props.secret.allow_mcp ? t("detail.on") : t("detail.off")
})
}
]);
const fieldItems = computed(() =>
(props.fields || []).map((field, index) => ({
key: `${field.name}:${index}`,
title: field.name,
subtitle: field.encrypted ? t("detail.encrypted") : t("detail.plain"),
raw: field
}))
);
const actionItems = computed(() => [
{
label: t("detail.versions"),
icon: "ph ph-clock-counter-clockwise",
onSelect: () => emit("navigate", "history")
},
{
label: t("nav.audit"),
icon: "ph ph-list-checks",
onSelect: () => emit("navigate", "audit")
},
{
label: t("detail.editFields"),
icon: "ph ph-list-plus",
onSelect: () => emit("navigate", "edit-fields")
},
{
label: props.secret.status === "actual" ? t("detail.markOutdated") : t("detail.markActual"),
icon: "ph ph-arrows-clockwise",
onSelect: () =>
emit("status-change", props.secret.status === "actual" ? "outdated" : "actual")
},
{ label: t("detail.archive"), icon: "ph ph-archive", onSelect: () => emit("archive") },
{
label: t("detail.deleteAction"),
icon: "ph ph-trash",
danger: true,
onSelect: () => emit("delete")
}
]);
function maskValue(value) {
return "*".repeat(Math.max(8, String(value || "").length));
}
function isVisible(key) {
return props.visibleFieldKeys.has(key);
}
</script>
<template>
<GnPageHeader
v-if="showHeader"
:title="secret.title"
compact
>
<template #kicker>
<GnIconButton
v-if="showBack"
icon="ph ph-arrow-left"
:label="t('detail.backToList')"
@click="emit('back')"
/>
</template>
<template #actions>
<div v-if="showActions" class="detail-actions">
<GnBadge :variant="secret.status === 'actual' ? 'success' : 'warning'">
{{ secret.status }}
</GnBadge>
<GnTooltip :text="fields ? t('detail.maskValues') : t('detail.showValues')">
<GnIconButton
:icon="fields ? 'ph ph-eye-slash' : 'ph ph-eye'"
:label="fields ? t('detail.hideSecret') : t('detail.revealSecret')"
@click="fields ? emit('hide') : emit('reveal')"
/>
</GnTooltip>
<GnTooltip :text="t('detail.editMetadata')">
<GnIconButton
icon="ph ph-pencil-simple"
:label="t('detail.editMetadata')"
@click="emit('edit-metadata')"
/>
</GnTooltip>
<GnDropdown :items="actionItems" class="secret-dropdown">
<template #trigger="{ toggle }">
<GnIconButton
icon="ph ph-dots-three-outline"
:label="t('detail.secretActions')"
@click="toggle"
/>
</template>
</GnDropdown>
</div>
</template>
</GnPageHeader>
<GnDescriptionList v-if="showDetails" :items="details" />
<section v-if="fields?.length" class="workspace-surface inset-surface">
<GnToolbar :title="t('detail.revealedFields')" />
<GnActionList :items="fieldItems" class="revealed-fields-list">
<template #controls="{ item }">
<code class="secret-value">
{{ isVisible(item.key) ? item.raw.value : maskValue(item.raw.value) }}
</code>
<GnTooltip :text="isVisible(item.key) ? t('detail.hideValue') : t('detail.showValue')">
<GnIconButton
:icon="isVisible(item.key) ? 'ph ph-eye-slash' : 'ph ph-eye'"
:label="isVisible(item.key) ? t('detail.hideFieldValue') : t('detail.showFieldValue')"
@click="emit('toggle-field-visibility', item.key)"
/>
</GnTooltip>
<GnCopyButton :text="item.raw.value" :label="t('common.copy')" size="sm" />
</template>
</GnActionList>
</section>
</template>