theseus: drop Community section from Settings > Extensions

Discovery of new community extensions belongs on theseus.x/extensions,
which has room to describe each one and lists them by publisher. Settings
just shows what's installed on this machine — one card per extension,
whether bundled or community. The Install button on the web page invokes
the same addons-install-community IPC, and Theseus refreshes the
installed list after each install, so the two lists were mirroring the
same state with a docx-editor card appearing on both sides.

Removes the Community h2, its list container, the Refresh catalog
button, loadCommunity() and its wiring — kept only the trust warning as
a note directly under the installed list.
This commit is contained in:
Local Dev 2026-09-21 03:28:04 +02:00
parent 0684906f13
commit 9fbba50999

View file

@ -606,14 +606,12 @@
<div id="addonsUpdStatus" class="pmuted" style="font-size:12.5px;margin-top:6px;text-align:right"></div>
<h2 class="sub" style="border-top:0;padding-top:0;margin-top:1.5rem">Installed</h2>
<div id="addonsList"><div class="d" style="color:var(--dim)">Loading…</div></div>
<h2 class="sub" style="margin-top:1.5rem">Community</h2>
<p class="lede" style="margin-top:0">Extensions anyone can publish from <a href="https://theseus.x/extensions/" target="_blank" rel="noopener">theseus.x/extensions</a>
by signing the package with the wallet that holds a BCDN name. Before installing, Theseus checks that signature
against the name's current owner in its own chain index — the relay can't substitute code under a trusted name.</p>
<div class="row" style="justify-content:flex-end;gap:8px"><button id="communityRefresh" class="btn" type="button">Refresh catalog</button></div>
<div id="communityList"><div class="d" style="color:var(--dim)">Loading…</div></div>
<div class="note">Extensions run with full app access — treat installing one like installing an unsigned executable.
Only load extensions whose source you trust.</div>
<div class="note" style="margin-top:1.5rem">To install a new extension, browse the catalogue at
<a href="https://theseus.x/extensions/" target="_blank" rel="noopener">theseus.x/extensions</a>
and use the Install button there. Theseus checks each publisher's signature against the name's current
owner on chain before installing — the relay can't substitute code under a trusted name. Extensions run
with full app access — treat installing one like installing an unsigned executable, and only load
extensions whose source you trust.</div>
</section>
</div>
</div>
@ -1349,44 +1347,10 @@
btn.addEventListener("click", () => C.revealAddon(btn.dataset.reveal));
});
}
// ---- community catalog (theseus.x/extensions) ----
const communityList = document.getElementById("communityList");
async function loadCommunity() {
communityList.innerHTML = '<div class="d" style="color:var(--dim)">Loading…</div>';
let r;
try { r = await C.communityCatalog(); } catch (e) { r = { ok: false, error: e?.message || String(e), extensions: [] }; }
if (!r.ok) { communityList.innerHTML = '<div class="d" style="color:#f6768a">Catalog unavailable: ' + escapeHtml(r.error) + '</div>'; return; }
// Hide extensions already shown in the Installed list above — the
// Community list's job is to surface things you DON'T have. Updates to
// installed extensions come through the poll + "Check for updates" flow
// in the Installed list, not through a second card for the same id here.
const catalog = r.extensions.filter((e) => !e.installedVersion);
if (!catalog.length) { communityList.innerHTML = '<div class="d" style="color:var(--dim)">' + (r.extensions.length ? "All catalog extensions are already installed." : "Nothing published yet. Be the first — see theseus.x/extensions.") + '</div>'; return; }
communityList.innerHTML = catalog.map((e) => {
const state = e.installedVersion
? (e.canUpdate ? '<button class="btn" data-install="' + escapeAttr(e.id) + '">Update to ' + escapeHtml(e.latest) + '</button>'
: '<span style="color:var(--acid);font-size:12.5px">Installed v' + escapeHtml(e.installedVersion) + '</span>')
: '<button class="btn" data-install="' + escapeAttr(e.id) + '">Install</button>';
return '<div class="row"><div class="txt"><div class="t">' + escapeHtml(e.icon || "🧩") + ' ' + escapeHtml(e.name)
+ ' <span style="color:var(--dim);font-weight:400">v' + escapeHtml(e.latest) + '</span></div>'
+ '<div class="d">' + escapeHtml(e.description || "") + '</div>'
+ '<div class="d" style="color:var(--dim);font-size:12px">Published by <b>' + escapeHtml(e.publisher) + '</b> · ' + escapeHtml(String(e.versions || 1)) + ' version' + (e.versions === 1 ? "" : "s")
+ (e.capabilities && e.capabilities.length ? ' · ' + escapeHtml(e.capabilities.join(", ")) : "") + '</div>'
+ '<div class="d" data-status="' + escapeAttr(e.id) + '"></div></div><div>' + state + '</div></div>';
}).join("");
communityList.querySelectorAll("button[data-install]").forEach((btn) => {
btn.addEventListener("click", async () => {
const id = btn.dataset.install;
const status = communityList.querySelector('[data-status="' + CSS.escape(id) + '"]');
btn.disabled = true; const orig = btn.textContent; btn.textContent = "Verifying…";
let res;
try { res = await C.installCommunity(id); } catch (e) { res = { ok: false, error: e?.message || String(e) }; }
if (res && res.ok) { status.style.color = "var(--acid)"; status.textContent = "✓ Installed v" + res.version + " (signed by " + res.publisher + ")"; loadAddons(); loadCommunity(); }
else { status.style.color = "#f6768a"; status.textContent = "✗ " + (res?.error || "install failed"); btn.disabled = false; btn.textContent = orig; }
});
});
}
document.getElementById("communityRefresh").addEventListener("click", loadCommunity);
// Discovery of new community extensions happens at theseus.x/extensions —
// Settings only shows what's installed on this machine. The install button
// on that page invokes the same "addons-install-community" IPC and Theseus
// refreshes the installed list on its own.
function escapeHtml(s) { return String(s || "").replace(/[&<>"']/g, (c) => ({ "&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;" })[c]); }
function escapeAttr(s) { return escapeHtml(s); }
async function loadAddons() {
@ -1407,7 +1371,7 @@
});
document.getElementById("addonsOpenDir").addEventListener("click", () => C.openAddonsDir());
document.querySelector('.side a[data-sec="addons"]').addEventListener("click", async () => {
await loadAddonUpdates(); loadAddons(); loadCommunity();
await loadAddonUpdates(); loadAddons();
});
// Plug-ins tab: refresh Ariadne's live daemon state on every visit so it
// doesn't display stale "checking…" text if the background poll finished
@ -1463,7 +1427,7 @@
}
});
// Populate on first paint so the tab is ready when the user clicks in.
(async () => { await loadAddonUpdates(); loadAddons(); loadCommunity(); })();
(async () => { await loadAddonUpdates(); loadAddons(); })();
</script>
</body>
</html>