improve vault manager, refactor vault operations into shared service.
This commit is contained in:
parent
408eb7fb54
commit
e1d484fd28
5 changed files with 159 additions and 68 deletions
118
services/vault-service.js
Normal file
118
services/vault-service.js
Normal file
|
|
@ -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);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -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();
|
const listeners = new Map();
|
||||||
|
|
||||||
|
|
@ -44,7 +45,7 @@ const syncHandlers = {
|
||||||
result[v.id] = {
|
result[v.id] = {
|
||||||
path: "/" + v.id,
|
path: "/" + v.id,
|
||||||
ts: Date.now(),
|
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);
|
const vault = (window.__vaultList || []).find((v) => v.id === id);
|
||||||
|
|
||||||
if (!vault && id) {
|
if (!vault && id) {
|
||||||
const xhr = new XMLHttpRequest();
|
if (!vaultService.createVaultSync(id)) {
|
||||||
|
|
||||||
xhr.open("POST", "/api/vault/create", false);
|
|
||||||
xhr.setRequestHeader("Content-Type", "application/json");
|
|
||||||
xhr.send(JSON.stringify({ name: id }));
|
|
||||||
|
|
||||||
if (xhr.status >= 400) {
|
|
||||||
return "Failed to create vault";
|
return "Failed to create vault";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const target = window.parent !== window ? window.parent : window;
|
vaultService.openVault(id);
|
||||||
target.location.href = "/?vault=" + encodeURIComponent(id);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
"vault-remove": (vaultPath) => {
|
"vault-remove": (vaultPath) => {
|
||||||
const id = (vaultPath || "").replace(/^\/+/, "");
|
const id = (vaultPath || "").replace(/^\/+/, "");
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
|
|
||||||
xhr.open(
|
return vaultService.deleteVaultSync(id);
|
||||||
"DELETE",
|
|
||||||
"/api/vault/remove?vault=" + encodeURIComponent(id),
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
xhr.send();
|
|
||||||
|
|
||||||
return xhr.status < 400;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"vault-move": (oldPath, newPath) => {
|
"vault-move": (oldPath, newPath) => {
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import * as eventsShim from "./node/events.js";
|
||||||
import * as osShim from "./node/os.js";
|
import * as osShim from "./node/os.js";
|
||||||
import * as netShim from "./node/net.js";
|
import * as netShim from "./node/net.js";
|
||||||
import * as httpShim from "./node/http.js";
|
import * as httpShim from "./node/http.js";
|
||||||
|
import { vaultService } from "../services/vault-service.js";
|
||||||
|
|
||||||
const DEBUG = true;
|
const DEBUG = true;
|
||||||
const _accessLog = new Map(); // "module.property" -> count
|
const _accessLog = new Map(); // "module.property" -> count
|
||||||
|
|
@ -217,14 +218,7 @@ window.__currentVaultId = _urlParams.get("vault") || "";
|
||||||
|
|
||||||
(function initVaultList() {
|
(function initVaultList() {
|
||||||
try {
|
try {
|
||||||
const xhr = new XMLHttpRequest();
|
vaultService.listVaultsSync();
|
||||||
|
|
||||||
xhr.open("GET", "/api/vault/list", false);
|
|
||||||
xhr.send();
|
|
||||||
|
|
||||||
if (xhr.status === 200) {
|
|
||||||
window.__vaultList = JSON.parse(xhr.responseText);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
window.__vaultList = [];
|
window.__vaultList = [];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
3
shims/ui/vault-manager.js → ui/bootstrap.js
vendored
3
shims/ui/vault-manager.js → ui/bootstrap.js
vendored
|
|
@ -1,8 +1,11 @@
|
||||||
|
import { vaultService } from "../services/vault-service.js";
|
||||||
|
|
||||||
export function showVaultManager() {
|
export function showVaultManager() {
|
||||||
if (!document.querySelector(".workspace")) return;
|
if (!document.querySelector(".workspace")) return;
|
||||||
if (document.querySelector(".vault-manager-overlay")) return;
|
if (document.querySelector(".vault-manager-overlay")) return;
|
||||||
|
|
||||||
new window.IgnisUI.VaultManager({
|
new window.IgnisUI.VaultManager({
|
||||||
target: document.body,
|
target: document.body,
|
||||||
|
props: { vaultService },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -17,6 +17,8 @@
|
||||||
import ListItem from "../components/display/ListItem.svelte";
|
import ListItem from "../components/display/ListItem.svelte";
|
||||||
import PopoverMenu from "../components/menu/PopoverMenu.svelte";
|
import PopoverMenu from "../components/menu/PopoverMenu.svelte";
|
||||||
|
|
||||||
|
export let vaultService;
|
||||||
|
|
||||||
let vaults = [];
|
let vaults = [];
|
||||||
let searchQuery = "";
|
let searchQuery = "";
|
||||||
let openMenuId = null;
|
let openMenuId = null;
|
||||||
|
|
@ -31,7 +33,8 @@
|
||||||
{ id: "delete", label: "Delete", danger: true },
|
{ id: "delete", label: "Delete", danger: true },
|
||||||
];
|
];
|
||||||
|
|
||||||
$: currentVaultId = window.__currentVaultId || "";
|
let currentVaultId = vaultService.getCurrentVaultId();
|
||||||
|
|
||||||
$: deleteMessage = targetVault
|
$: deleteMessage = targetVault
|
||||||
? 'Are you sure you want to delete "' + targetVault.name + '"?'
|
? 'Are you sure you want to delete "' + targetVault.name + '"?'
|
||||||
: "";
|
: "";
|
||||||
|
|
@ -41,10 +44,9 @@
|
||||||
)
|
)
|
||||||
: vaults;
|
: vaults;
|
||||||
|
|
||||||
async function fetchVaults() {
|
async function refreshVaults() {
|
||||||
try {
|
try {
|
||||||
const res = await fetch("/api/vault/list");
|
vaults = await vaultService.listVaults();
|
||||||
vaults = res.ok ? await res.json() : [];
|
|
||||||
} catch {
|
} catch {
|
||||||
vaults = [];
|
vaults = [];
|
||||||
}
|
}
|
||||||
|
|
@ -55,7 +57,7 @@
|
||||||
modalRef.dismiss();
|
modalRef.dismiss();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
window.location.href = "/?vault=" + encodeURIComponent(vault.id);
|
vaultService.openVault(vault.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleMenu(vaultId) {
|
function toggleMenu(vaultId) {
|
||||||
|
|
@ -104,21 +106,14 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await fetch("/api/vault/create", {
|
try {
|
||||||
method: "POST",
|
vaults = await vaultService.createVault(name);
|
||||||
headers: { "Content-Type": "application/json" },
|
} catch (err) {
|
||||||
body: JSON.stringify({ name }),
|
alert("Failed to create vault: " + err.message);
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
const data = await res.json();
|
|
||||||
alert("Failed to create vault: " + (data.error || "Unknown error"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
closeDialog();
|
closeDialog();
|
||||||
|
|
||||||
window.location.href = "/?vault=" + encodeURIComponent(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onRenameConfirm(e) {
|
async function onRenameConfirm(e) {
|
||||||
|
|
@ -129,41 +124,37 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await fetch("/api/vault/rename", {
|
const wasCurrentVault = targetVault.id === currentVaultId;
|
||||||
method: "POST",
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify({ vault: targetVault.id, name: trimmed }),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) {
|
try {
|
||||||
const data = await res.json();
|
vaults = await vaultService.renameVault(targetVault.id, trimmed);
|
||||||
alert("Failed to rename vault: " + (data.error || "Unknown error"));
|
} catch (err) {
|
||||||
|
alert("Failed to rename vault: " + err.message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
closeDialog();
|
closeDialog();
|
||||||
|
|
||||||
if (targetVault.id === currentVaultId) {
|
if (wasCurrentVault) {
|
||||||
window.location.href = "/?vault=" + encodeURIComponent(trimmed);
|
currentVaultId = vaultService.getCurrentVaultId();
|
||||||
} else {
|
|
||||||
await fetchVaults();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onDeleteConfirm() {
|
async function onDeleteConfirm() {
|
||||||
const wasCurrentVault = targetVault.id === currentVaultId;
|
try {
|
||||||
|
const { wasCurrentVault } = await vaultService.deleteVault(
|
||||||
await fetch(
|
targetVault.id,
|
||||||
"/api/vault/remove?vault=" + encodeURIComponent(targetVault.id),
|
|
||||||
{ method: "DELETE" },
|
|
||||||
);
|
);
|
||||||
|
|
||||||
closeDialog();
|
closeDialog();
|
||||||
|
|
||||||
await fetchVaults();
|
vaults = await vaultService.listVaults();
|
||||||
|
|
||||||
if (wasCurrentVault) {
|
if (wasCurrentVault) {
|
||||||
window.location.href = "/";
|
vaultService.openVault("");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
alert("Failed to delete vault: " + err.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,7 +167,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
fetchVaults();
|
refreshVaults();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue