diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 7b1e977..326738f 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -40,6 +40,7 @@ const query = ref(""); const selected = ref(null); const revealed = ref(null); +const revealedVisibleFields = ref(new Set()); const versions = ref([]); const revealedVersion = ref(null); const auditEvents = ref([]); @@ -130,7 +131,8 @@ ]; }); const revealedFieldItems = computed(() => - (revealed.value?.fields || []).map((field) => ({ + (revealed.value?.fields || []).map((field, index) => ({ + key: `${field.name}:${index}`, title: field.name, subtitle: field.encrypted ? "encrypted" : "plain", raw: field @@ -379,16 +381,33 @@ async function reveal(secret) { revealed.value = await api.revealSecret(secret.id); + revealedVisibleFields.value = new Set(); } -async function copyField(secret, field) { - const payload = revealed.value?.id === secret.id ? revealed.value : await api.revealSecret(secret.id); - const full = payload.fields.find((item) => item.name === field.name); - if (full?.value) { - await navigator.clipboard.writeText(full.value); +async function copyValue(value) { + if (value) { + await navigator.clipboard.writeText(value); } } +function maskValue(value) { + return "*".repeat(Math.max(8, String(value || "").length)); +} + +function isRevealedFieldVisible(key) { + return revealedVisibleFields.value.has(key); +} + +function toggleRevealedField(key) { + const next = new Set(revealedVisibleFields.value); + if (next.has(key)) { + next.delete(key); + } else { + next.add(key); + } + revealedVisibleFields.value = next; +} + async function loadVersions(secret) { selected.value = secret; activeTab.value = "history"; @@ -675,13 +694,20 @@
- + diff --git a/frontend/src/styles.css b/frontend/src/styles.css index b0c5101..f4944fa 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -243,6 +243,36 @@ overflow: auto; } +.revealed-fields-list.list-actions { + max-width: none; + gap: 0; +} + +.revealed-fields-list.list-actions .list-item { + display: grid; + grid-template-columns: minmax(160px, 240px) minmax(260px, 1fr); + align-items: center; + gap: 18px; +} + +.revealed-fields-list .list-controls { + display: flex; + align-items: center; + justify-content: flex-start; + gap: 8px; + min-width: 0; +} + +.secret-value { + display: inline-flex; + align-items: center; + min-height: 32px; + min-width: 220px; + max-width: min(520px, 100%); + padding: 0 8px; + white-space: nowrap; +} + .error { margin: 0; color: #f7768e;