97 lines
3.1 KiB
JavaScript
97 lines
3.1 KiB
JavaScript
// views/remotes.js — connector-tile grid of configured remotes with CRUD.
|
|
|
|
import { post } from "../rc.js?v=security-fixes-1";
|
|
import { escapeHtml, getState, setState, toast } from "../state.js?v=security-fixes-1";
|
|
import { t } from "../i18n.js?v=security-fixes-1";
|
|
|
|
export async function renderRemotes() {
|
|
const app = document.getElementById("app");
|
|
if (!app) return;
|
|
|
|
app.innerHTML = `
|
|
<div class="section-head">
|
|
<div>
|
|
<h2>${t("remotes.title")}</h2>
|
|
<p class="subtitle">${t("remotes.subtitle")}</p>
|
|
</div>
|
|
<a class="btn btn-primary btn-sm" href="#/configure/new">${t("remotes.new_remote")}</a>
|
|
</div>
|
|
<div id="remote-grid" class="connector-grid">
|
|
<p class="empty" style="grid-column:1/-1">${t("remotes.loading")}</p>
|
|
</div>
|
|
`;
|
|
|
|
const grid = document.getElementById("remote-grid");
|
|
|
|
try {
|
|
const [listRes, dumpRes] = await Promise.all([
|
|
post("config/listremotes"),
|
|
post("config/dump"),
|
|
]);
|
|
const names = (listRes && listRes.remotes) || [];
|
|
const dump = dumpRes || {};
|
|
const remotes = names.map((name) => ({
|
|
name,
|
|
type: (dump[name] && dump[name].type) || "unknown",
|
|
}));
|
|
|
|
setState({ remotes });
|
|
|
|
if (remotes.length === 0) {
|
|
grid.innerHTML = `
|
|
<div class="empty" style="grid-column:1/-1">
|
|
<h3>${t("remotes.empty_title")}</h3>
|
|
<p>${t("remotes.empty_body")}</p>
|
|
</div>
|
|
`;
|
|
return;
|
|
}
|
|
|
|
grid.innerHTML = remotes
|
|
.map(
|
|
(r) => `
|
|
<a class="connector-tile tile-with-actions" href="#/browse/${encodeURIComponent(r.name)}">
|
|
<span class="tile-name">${escapeHtml(r.name)}</span>
|
|
<span class="badge">${escapeHtml(r.type)}</span>
|
|
<div class="tile-actions">
|
|
<button type="button" title="${t("browser.rename")}" data-edit="${escapeHtml(r.name)}">✎</button>
|
|
<button type="button" title="${t("browser.delete")}" class="danger" data-delete="${escapeHtml(r.name)}">🗑</button>
|
|
</div>
|
|
</a>
|
|
`,
|
|
)
|
|
.join("");
|
|
|
|
grid.querySelectorAll("[data-edit]").forEach((btn) => {
|
|
btn.addEventListener("click", (e) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
location.hash = `#/configure/edit/${encodeURIComponent(btn.dataset.edit)}`;
|
|
});
|
|
});
|
|
grid.querySelectorAll("[data-delete]").forEach((btn) => {
|
|
btn.addEventListener("click", async (e) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
const name = btn.dataset.delete;
|
|
if (!confirm(t("remotes.delete_confirm", name))) return;
|
|
try {
|
|
await post("config/delete", { name });
|
|
toast(t("remotes.deleted", name), "success");
|
|
await renderRemotes();
|
|
} catch (err) {
|
|
toast(`${t("remotes.delete_failed")}: ${err.message}`, "error");
|
|
}
|
|
});
|
|
});
|
|
} catch (e) {
|
|
grid.innerHTML = `
|
|
<div class="empty" style="grid-column:1/-1">
|
|
<h3>${t("error.couldnt_reach")}</h3>
|
|
<p>${escapeHtml(e.message)}</p>
|
|
</div>
|
|
`;
|
|
toast(`${t("remotes.load_failed")}: ${e.message}`, "error");
|
|
}
|
|
}
|