From e1d484fd28beb4c7cd597ec884e7d56c750f683a Mon Sep 17 00:00:00 2001 From: Nystik <236107-Nystik@users.noreply.gitlab.com> Date: Wed, 18 Mar 2026 18:52:38 +0100 Subject: [PATCH] improve vault manager, refactor vault operations into shared service. --- services/vault-service.js | 118 +++++++++++++++++++ shims/electron/ipc-renderer.js | 27 +---- shims/loader.js | 10 +- shims/ui/vault-manager.js => ui/bootstrap.js | 3 + ui/views/VaultManager.svelte | 69 +++++------ 5 files changed, 159 insertions(+), 68 deletions(-) create mode 100644 services/vault-service.js rename shims/ui/vault-manager.js => ui/bootstrap.js (71%) diff --git a/services/vault-service.js b/services/vault-service.js new file mode 100644 index 0000000..974bfde --- /dev/null +++ b/services/vault-service.js @@ -0,0 +1,118 @@ +const API_BASE = "/api/vault"; + +async function fetchJson(url, options) { + const res = await fetch(url, options); + + if (!res.ok) { + const data = await res.json().catch(() => ({ error: res.statusText })); + throw new Error(data.error || "Request failed"); + } + + return res.json(); +} + +export const vaultService = { + getCurrentVaultId() { + return window.__currentVaultId || ""; + }, + + async listVaults() { + const list = await fetchJson(API_BASE + "/list"); + + window.__vaultList = list; + + return list; + }, + + listVaultsSync() { + const xhr = new XMLHttpRequest(); + + xhr.open("GET", API_BASE + "/list", false); + xhr.send(); + + if (xhr.status === 200) { + const list = JSON.parse(xhr.responseText); + + window.__vaultList = list; + + return list; + } + + return []; + }, + + async createVault(name) { + await fetchJson(API_BASE + "/create", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ name }), + }); + + return this.listVaults(); + }, + + createVaultSync(name) { + const xhr = new XMLHttpRequest(); + + xhr.open("POST", API_BASE + "/create", false); + xhr.setRequestHeader("Content-Type", "application/json"); + xhr.send(JSON.stringify({ name })); + + if (xhr.status >= 400) { + return null; + } + + return true; + }, + + async renameVault(id, newName) { + await fetchJson(API_BASE + "/rename", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ vault: id, name: newName }), + }); + + if (id === this.getCurrentVaultId()) { + window.__currentVaultId = newName; + + if (window.__vaultConfig) { + window.__vaultConfig.id = newName; + } + } + + return this.listVaults(); + }, + + async deleteVault(id) { + await fetchJson( + API_BASE + "/remove?vault=" + encodeURIComponent(id), + { method: "DELETE" }, + ); + + const wasCurrentVault = id === this.getCurrentVaultId(); + + await this.listVaults(); + + return { wasCurrentVault }; + }, + + deleteVaultSync(id) { + const xhr = new XMLHttpRequest(); + + xhr.open( + "DELETE", + API_BASE + "/remove?vault=" + encodeURIComponent(id), + false, + ); + + xhr.send(); + + return xhr.status < 400; + }, + + openVault(id) { + const target = window.parent !== window ? window.parent : window; + + target.location.href = "/?vault=" + encodeURIComponent(id); + }, +}; diff --git a/shims/electron/ipc-renderer.js b/shims/electron/ipc-renderer.js index c979727..c2a0f9e 100644 --- a/shims/electron/ipc-renderer.js +++ b/shims/electron/ipc-renderer.js @@ -1,4 +1,5 @@ -import { showVaultManager } from "../ui/vault-manager.js"; +import { showVaultManager } from "../../ui/bootstrap.js"; +import { vaultService } from "../../services/vault-service.js"; const listeners = new Map(); @@ -44,7 +45,7 @@ const syncHandlers = { result[v.id] = { path: "/" + v.id, ts: Date.now(), - open: v.id === (window.__currentVaultId || ""), + open: v.id === vaultService.getCurrentVaultId(), }; } @@ -56,36 +57,20 @@ const syncHandlers = { const vault = (window.__vaultList || []).find((v) => v.id === id); if (!vault && id) { - const xhr = new XMLHttpRequest(); - - xhr.open("POST", "/api/vault/create", false); - xhr.setRequestHeader("Content-Type", "application/json"); - xhr.send(JSON.stringify({ name: id })); - - if (xhr.status >= 400) { + if (!vaultService.createVaultSync(id)) { return "Failed to create vault"; } } - const target = window.parent !== window ? window.parent : window; - target.location.href = "/?vault=" + encodeURIComponent(id); + vaultService.openVault(id); return true; }, "vault-remove": (vaultPath) => { const id = (vaultPath || "").replace(/^\/+/, ""); - const xhr = new XMLHttpRequest(); - xhr.open( - "DELETE", - "/api/vault/remove?vault=" + encodeURIComponent(id), - false, - ); - - xhr.send(); - - return xhr.status < 400; + return vaultService.deleteVaultSync(id); }, "vault-move": (oldPath, newPath) => { diff --git a/shims/loader.js b/shims/loader.js index 09cd108..32a41fc 100644 --- a/shims/loader.js +++ b/shims/loader.js @@ -15,6 +15,7 @@ import * as eventsShim from "./node/events.js"; import * as osShim from "./node/os.js"; import * as netShim from "./node/net.js"; import * as httpShim from "./node/http.js"; +import { vaultService } from "../services/vault-service.js"; const DEBUG = true; const _accessLog = new Map(); // "module.property" -> count @@ -217,14 +218,7 @@ window.__currentVaultId = _urlParams.get("vault") || ""; (function initVaultList() { try { - const xhr = new XMLHttpRequest(); - - xhr.open("GET", "/api/vault/list", false); - xhr.send(); - - if (xhr.status === 200) { - window.__vaultList = JSON.parse(xhr.responseText); - } + vaultService.listVaultsSync(); } catch (e) { window.__vaultList = []; } diff --git a/shims/ui/vault-manager.js b/ui/bootstrap.js similarity index 71% rename from shims/ui/vault-manager.js rename to ui/bootstrap.js index bc3990a..bb12d90 100644 --- a/shims/ui/vault-manager.js +++ b/ui/bootstrap.js @@ -1,8 +1,11 @@ +import { vaultService } from "../services/vault-service.js"; + export function showVaultManager() { if (!document.querySelector(".workspace")) return; if (document.querySelector(".vault-manager-overlay")) return; new window.IgnisUI.VaultManager({ target: document.body, + props: { vaultService }, }); } diff --git a/ui/views/VaultManager.svelte b/ui/views/VaultManager.svelte index b548c0d..1f7c85c 100644 --- a/ui/views/VaultManager.svelte +++ b/ui/views/VaultManager.svelte @@ -17,6 +17,8 @@ import ListItem from "../components/display/ListItem.svelte"; import PopoverMenu from "../components/menu/PopoverMenu.svelte"; + export let vaultService; + let vaults = []; let searchQuery = ""; let openMenuId = null; @@ -31,7 +33,8 @@ { id: "delete", label: "Delete", danger: true }, ]; - $: currentVaultId = window.__currentVaultId || ""; + let currentVaultId = vaultService.getCurrentVaultId(); + $: deleteMessage = targetVault ? 'Are you sure you want to delete "' + targetVault.name + '"?' : ""; @@ -41,10 +44,9 @@ ) : vaults; - async function fetchVaults() { + async function refreshVaults() { try { - const res = await fetch("/api/vault/list"); - vaults = res.ok ? await res.json() : []; + vaults = await vaultService.listVaults(); } catch { vaults = []; } @@ -55,7 +57,7 @@ modalRef.dismiss(); return; } - window.location.href = "/?vault=" + encodeURIComponent(vault.id); + vaultService.openVault(vault.id); } function toggleMenu(vaultId) { @@ -104,21 +106,14 @@ return; } - const res = await fetch("/api/vault/create", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ name }), - }); - - if (!res.ok) { - const data = await res.json(); - alert("Failed to create vault: " + (data.error || "Unknown error")); + try { + vaults = await vaultService.createVault(name); + } catch (err) { + alert("Failed to create vault: " + err.message); return; } closeDialog(); - - window.location.href = "/?vault=" + encodeURIComponent(name); } async function onRenameConfirm(e) { @@ -129,41 +124,37 @@ return; } - const res = await fetch("/api/vault/rename", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ vault: targetVault.id, name: trimmed }), - }); + const wasCurrentVault = targetVault.id === currentVaultId; - if (!res.ok) { - const data = await res.json(); - alert("Failed to rename vault: " + (data.error || "Unknown error")); + try { + vaults = await vaultService.renameVault(targetVault.id, trimmed); + } catch (err) { + alert("Failed to rename vault: " + err.message); return; } closeDialog(); - if (targetVault.id === currentVaultId) { - window.location.href = "/?vault=" + encodeURIComponent(trimmed); - } else { - await fetchVaults(); + if (wasCurrentVault) { + currentVaultId = vaultService.getCurrentVaultId(); } } async function onDeleteConfirm() { - const wasCurrentVault = targetVault.id === currentVaultId; + try { + const { wasCurrentVault } = await vaultService.deleteVault( + targetVault.id, + ); - await fetch( - "/api/vault/remove?vault=" + encodeURIComponent(targetVault.id), - { method: "DELETE" }, - ); + closeDialog(); - closeDialog(); + vaults = await vaultService.listVaults(); - await fetchVaults(); - - if (wasCurrentVault) { - window.location.href = "/"; + if (wasCurrentVault) { + vaultService.openVault(""); + } + } catch (err) { + alert("Failed to delete vault: " + err.message); } } @@ -176,7 +167,7 @@ } onMount(() => { - fetchVaults(); + refreshVaults(); });