Initial commit: Brass & Sigil monorepo
Self-hosted Minecraft modpack distribution + administration system.
- launcher/ Avalonia 12 desktop client; single-file win-x64 publish.
Microsoft auth via XboxAuthNet, manifest+SHA-1 mod sync,
portable install path, sidecar settings.
- server/ brass-sigil-server daemon (.NET 8, linux-x64). Wraps the
MC subprocess, embedded Kestrel admin panel with cookie
auth + rate limiting, RCON bridge, scheduled backups,
BlueMap CLI integration with player markers + skin proxy,
friend-side whitelist request flow, world wipe with seed
selection (keep current / random / custom).
- pack/ pack.lock.json (Modrinth + manual CurseForge entries),
data-only tweak source under tweaks/, build outputs in
overrides/ (gitignored).
- scripts/ Build-Pack / Build-Tweaks / Update-Pack / Check-Updates
plus Deploy-Brass.ps1 unified one-shot deploy with
version-bump pre-flight and daemon-state detection.
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
// Whitelist add / remove via the API; refreshes the panel display shortly after
|
||||
// each action (server takes ~1-2 s to look up UUID via Mojang and write whitelist.json).
|
||||
"use strict";
|
||||
|
||||
import { api, apiJson, escapeHtml } from "./api.js";
|
||||
|
||||
export function setupWhitelistActions(refreshSoon) {
|
||||
const wlInput = document.getElementById("wlInput");
|
||||
document.getElementById("wlAdd").addEventListener("click", () => addWhitelisted(refreshSoon));
|
||||
wlInput.addEventListener("keydown", e => { if (e.key === "Enter") addWhitelisted(refreshSoon); });
|
||||
|
||||
// Delegated removal -- list items are re-rendered each tick, no static binding.
|
||||
document.getElementById("whitelist").addEventListener("click", async e => {
|
||||
const btn = e.target.closest(".wl-remove");
|
||||
if (!btn) return;
|
||||
const name = btn.dataset.name;
|
||||
if (!name) return;
|
||||
if (!confirm(`Remove ${name} from whitelist?`)) return;
|
||||
try {
|
||||
await apiJson("/api/whitelist/remove", { name });
|
||||
refreshSoon();
|
||||
} catch (err) { alert(err.message); }
|
||||
});
|
||||
|
||||
// Pending whitelist requests from friends. Approve adds to whitelist + clears
|
||||
// the request; Deny just marks denied so the friend's launcher knows.
|
||||
const reqsList = document.getElementById("wlRequests");
|
||||
const reqsBlock = document.getElementById("wlRequestsBlock");
|
||||
const reqsBadge = document.getElementById("wlReqBadge");
|
||||
|
||||
reqsList?.addEventListener("click", async e => {
|
||||
const btn = e.target.closest("button[data-req-action]");
|
||||
if (!btn) return;
|
||||
const name = btn.dataset.name;
|
||||
const action = btn.dataset.reqAction; // "approve" | "deny"
|
||||
if (!name || !action) return;
|
||||
if (action === "deny" && !confirm(`Deny ${name}'s request?`)) return;
|
||||
try {
|
||||
await apiJson(`/api/whitelist/requests/${action}`, { name });
|
||||
await refreshRequests();
|
||||
// Approving fires /whitelist add via stdin -- let the server-side write
|
||||
// ~1-2 s of grace before re-reading whitelist.json.
|
||||
if (action === "approve") refreshSoon();
|
||||
} catch (err) { alert(err.message); }
|
||||
});
|
||||
|
||||
async function refreshRequests() {
|
||||
if (!reqsList || !reqsBlock || !reqsBadge) return;
|
||||
let data;
|
||||
try { data = await api("/api/whitelist/requests"); }
|
||||
catch { return; }
|
||||
const reqs = data.requests || [];
|
||||
if (reqs.length === 0) {
|
||||
reqsBlock.hidden = true;
|
||||
reqsBadge.hidden = true;
|
||||
return;
|
||||
}
|
||||
reqsBlock.hidden = false;
|
||||
reqsBadge.hidden = false;
|
||||
reqsBadge.textContent = String(reqs.length);
|
||||
reqsList.innerHTML = reqs.map(r => `
|
||||
<li>
|
||||
<div class="wl-req-meta">${escapeHtml(r.username)}</div>
|
||||
${r.message ? `<div class="wl-req-msg">"${escapeHtml(r.message)}"</div>` : ""}
|
||||
<div class="wl-req-actions">
|
||||
<button data-req-action="approve" data-name="${escapeHtml(r.username)}">Approve</button>
|
||||
<button class="ghost-btn" data-req-action="deny" data-name="${escapeHtml(r.username)}">Deny</button>
|
||||
</div>
|
||||
</li>
|
||||
`).join("");
|
||||
}
|
||||
|
||||
refreshRequests();
|
||||
setInterval(refreshRequests, 15000);
|
||||
}
|
||||
|
||||
async function addWhitelisted(refreshSoon) {
|
||||
const inp = document.getElementById("wlInput");
|
||||
const name = inp.value.trim();
|
||||
if (!name) return;
|
||||
try {
|
||||
await apiJson("/api/whitelist/add", { name });
|
||||
inp.value = "";
|
||||
refreshSoon();
|
||||
} catch (e) { alert(e.message); }
|
||||
}
|
||||
Reference in New Issue
Block a user