Playtime from PlaytimeHistory's database (SAW_PT_DSN)
A public Playtime tab and player-drawer playtime, and staff-only figures (who's on, staff activity, disconnect reasons, countries, names, sessions) for @css/generic on the staff panel and on the public site when signed in. Hidden unless SAW_PT_DSN is set and its tables are there.
This commit is contained in:
parent
daa7ec2dbc
commit
6d0fc6e463
18 changed files with 2238 additions and 12 deletions
|
|
@ -1,14 +1,18 @@
|
|||
// Public, read-only site: the live server, bans, gags/mutes, and staff with their rank changes. The
|
||||
// API leaves out who issued penalties and IPs; nothing here can change anything.
|
||||
// Public, read-only site: the live server, bans, gags/mutes, staff with their rank changes, and
|
||||
// playtime (playtime.js). The API leaves out who issued penalties and IPs; nothing here can change
|
||||
// anything. Signed-in staff with @css/generic also see staff playtime figures here.
|
||||
|
||||
const PAGES = [
|
||||
{ id: "server", label: "Server" },
|
||||
{ id: "bans", label: "Bans" },
|
||||
{ id: "comms", label: "Gags & mutes" },
|
||||
{ id: "staff", label: "Staff" },
|
||||
// Once PlaytimeHistory has recorded something, or for staff who see its staff figures.
|
||||
{ id: "playtime", label: "Playtime", show: () => state.me?.playtime === "on" || !!state.me?.playtimeStaff },
|
||||
];
|
||||
|
||||
const state = { page: "server", banFilter: "active", commFilter: "active", query: "", num: 1 };
|
||||
// me is null until /api/me answers.
|
||||
const state = { page: "server", banFilter: "active", commFilter: "active", query: "", num: 1, me: null };
|
||||
|
||||
function siteName(title) {
|
||||
const i = title.indexOf(".");
|
||||
|
|
@ -242,6 +246,7 @@ async function openPlayer(sid) {
|
|||
${now.length || p.online || p.verified ? `<section>
|
||||
<div class="chips">${p.verified ? VERIFIED_TAG : ""}${p.online ? '<span class="tag">On the server</span>' : ""}${now.map((h) => `<span class="tag ${h.kind === "ban" ? "red" : "amber"}">${h.kind === "ban" ? "Banned" : COMM_HELP[h.type]}${h.duration ? `, ${fmtLeft(served(h).left)}` : ", permanently"}</span>`).join("")}</div>
|
||||
</section>` : ""}
|
||||
${ptDrawer(p.playtime, p.online)}
|
||||
<section>
|
||||
<h3>History</h3>
|
||||
${history.length ? `<ul class="history">${history.map((h) => `<li>
|
||||
|
|
@ -256,11 +261,20 @@ async function openPlayer(sid) {
|
|||
|
||||
/* ---------- Routing & events ---------- */
|
||||
|
||||
const RENDER = { server, bans, comms, staff };
|
||||
function playtime() {
|
||||
if (!state.me) { $("#view").innerHTML = loading(); return; }
|
||||
ptPage(state.me, () => state.page === "playtime");
|
||||
}
|
||||
|
||||
const RENDER = { server, bans, comms, staff, playtime };
|
||||
|
||||
// A page is shown if it has no condition, or (once /api/me has answered) meets it.
|
||||
const pageShown = (p) => !p.show || p.show();
|
||||
|
||||
function route() {
|
||||
const [page, query] = location.hash.slice(1).split("?");
|
||||
state.page = RENDER[page] ? page : "server";
|
||||
const def = PAGES.find((p) => p.id === page);
|
||||
state.page = def && (pageShown(def) || !state.me) ? page : "server";
|
||||
// A link like #bans?q=<steamid> (from a staff notification) opens the list searching for that
|
||||
// player, showing every status so lifted and expired ones are there too.
|
||||
const q = new URLSearchParams(query || "").get("q");
|
||||
|
|
@ -269,7 +283,7 @@ function route() {
|
|||
state.num = 1;
|
||||
state[state.page === "bans" ? "banFilter" : "commFilter"] = "all";
|
||||
}
|
||||
$("#nav-links").innerHTML = PAGES.map((p) => `<li><a href="#${p.id}" ${p.id === state.page ? 'aria-current="page"' : ""}>${p.label}</a></li>`).join("");
|
||||
$("#nav-links").innerHTML = PAGES.filter(pageShown).map((p) => `<li><a href="#${p.id}" ${p.id === state.page ? 'aria-current="page"' : ""}>${p.label}</a></li>`).join("");
|
||||
RENDER[state.page]();
|
||||
}
|
||||
|
||||
|
|
@ -283,6 +297,7 @@ document.addEventListener("input", (e) => {
|
|||
document.addEventListener("click", (e) => {
|
||||
const t = e.target;
|
||||
const seg = t.closest("[data-seg] button");
|
||||
if (seg && seg.parentElement.dataset.seg.startsWith("pt")) return; // playtime.js
|
||||
if (seg) {
|
||||
state[seg.parentElement.dataset.seg] = seg.dataset.value;
|
||||
state.num = 1;
|
||||
|
|
@ -303,10 +318,15 @@ document.addEventListener("keydown", (e) => {
|
|||
});
|
||||
|
||||
api("/api/me").then((me) => {
|
||||
state.me = me;
|
||||
$("#site-name").innerHTML = siteName(me.site);
|
||||
document.title = `${me.site} bans and staff`;
|
||||
if (me.staff) $(".signin").innerHTML = "Staff panel";
|
||||
}).catch(() => {});
|
||||
}).catch(() => { state.me = {}; }).finally(() => {
|
||||
// The Playtime tab depends on /api/me, so draw the nav (and a Playtime page) again.
|
||||
if (state.page === "playtime") route();
|
||||
else $("#nav-links").innerHTML = PAGES.filter(pageShown).map((p) => `<li><a href="#${p.id}" ${p.id === state.page ? 'aria-current="page"' : ""}>${p.label}</a></li>`).join("");
|
||||
});
|
||||
|
||||
// Keep the scoreboard current while it's on screen.
|
||||
setInterval(() => { if (state.page === "server" && !document.hidden && !$("#drawer-root").innerHTML) server(); }, 15000);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue