diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index fc71bcb..2efd4d1 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -30,13 +30,18 @@
const selected = ref(null);
const revealed = ref(null);
const versions = ref([]);
+const revealedVersion = ref(null);
const auditEvents = ref([]);
+const auditMode = ref("all");
const tokens = ref([]);
const newToken = ref(null);
const showDeleteConfirm = ref(false);
const editing = ref(false);
const editFields = ref(false);
const pendingDeleteSecret = ref(null);
+const importFile = ref(null);
+const importPreview = ref(null);
+const importError = ref("");
const form = reactive({
title: "",
@@ -128,6 +133,7 @@
function selectSecret(secret) {
selected.value = secret;
revealed.value = null;
+ revealedVersion.value = null;
editing.value = false;
editFields.value = false;
fillEditForm(secret);
@@ -247,12 +253,22 @@
async function loadVersions(secret) {
selected.value = secret;
activeTab.value = "history";
+ revealedVersion.value = null;
versions.value = await api.versions(secret.id);
}
+async function revealVersion(version) {
+ if (!selected.value) return;
+ revealedVersion.value = await api.revealVersion(selected.value.id, version.id);
+}
+
async function loadAudit() {
activeTab.value = "audit";
- auditEvents.value = (await api.audit()).items;
+ if (auditMode.value === "secret" && selected.value) {
+ auditEvents.value = (await api.secretAudit(selected.value.id)).items;
+ } else {
+ auditEvents.value = (await api.audit()).items;
+ }
}
async function loadTokens() {
@@ -291,6 +307,32 @@
URL.revokeObjectURL(url);
}
+async function handleImportFile(event) {
+ importError.value = "";
+ importPreview.value = null;
+ const file = event.target.files?.[0];
+ importFile.value = file || null;
+ if (!file) return;
+ try {
+ const text = await file.text();
+ const payload = JSON.parse(text);
+ if (payload.format !== "gnexus-creds-export" || payload.version !== 1) {
+ throw new Error("Unsupported import file");
+ }
+ importPreview.value = payload;
+ } catch (err) {
+ importError.value = err.message;
+ }
+}
+
+async function importData() {
+ if (!importPreview.value) return;
+ await api.importData(importPreview.value);
+ importFile.value = null;
+ importPreview.value = null;
+ await loadSecrets();
+}
+
async function deleteAllData() {
await api.deleteAccountData();
showDeleteConfirm.value = false;
@@ -504,11 +546,33 @@
{{ selected?.title || "Select a secret first" }} {{ selected?.title || "Select a secret first from the Secrets tab" }}Version history
- Version history
+ Version {{ revealedVersion.version_number }}
+ {{ field.value }}
+
{{ JSON.stringify(event.metadata) }}
{{ importError }}
++ {{ importPreview.secrets?.length || 0 }} secrets ready to import from + {{ importFile?.name }} +
+