Skip to content

Commit

Permalink
Merge pull request #140 from RedFlames/frontend-rework-accounts-panel
Browse files Browse the repository at this point in the history
Accounts panel & UserInfo RCEP rework
  • Loading branch information
RedFlames authored Jul 1, 2024
2 parents 40b02b2 + d3b4a0a commit afb7841
Show file tree
Hide file tree
Showing 15 changed files with 480 additions and 80 deletions.
12 changes: 6 additions & 6 deletions CelesteNet.Client/CelesteNetClientModule.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
using Monocle;
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using FMOD.Studio;
using MonoMod.Utils;
using System.Collections;
using Celeste.Mod.CelesteNet.Client.Components;
using System.IO;
using Celeste.Mod.CelesteNet.DataTypes;
using FMOD.Studio;
using Monocle;
using MonoMod.Utils;

namespace Celeste.Mod.CelesteNet.Client {
public class CelesteNetClientModule : EverestModule {
Expand Down
4 changes: 2 additions & 2 deletions CelesteNet.Client/Components/CelesteNetClientInfoComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ private string GetRegistryDev(string nicId) {
string fRegistryKey = request.MapStrings[0] + nicId + request.MapStrings[1];

try {
RegistryKey rk = Registry.LocalMachine.OpenSubKey(fRegistryKey, false);
RegistryKey rk = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(fRegistryKey, false);
return rk?.GetValue(request.MapStrings[2], "").ToString() ?? "";
} catch { }
return "";
Expand All @@ -115,7 +115,7 @@ private string GetGUIDWindows() {
if (request == null || !request.IsValid)
return "";
try {
RegistryKey rk = Registry.LocalMachine.OpenSubKey(request.MapStrings[3], false);
RegistryKey rk = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(request.MapStrings[3], false);
return rk?.GetValue(request.MapStrings[4], "").ToString() ?? "";
} catch { }
return "";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,15 @@ main {
.panel > h2 {
position: relative;
}

.panel > h2 > .header-small-info {
font-family: "Fira Code", monospace;
font-size: 12px;
font-weight: normal;
display: inline-block;
margin-left: .5em;
}

.panel > h2 > .actions {
position: absolute;
top: -4px;
Expand Down Expand Up @@ -296,19 +305,22 @@ main {
font-family: "Fira Code", monospace;
font-size: 11px;
}

.panel-cmd > .panel-input > .mdc-text-field,
.panel-players > .panel-input > .mdc-text-field,
.panel-chat > .panel-input > .mdc-text-field {
width: 100%;
}

.panel-players > .panel-input > .mdc-text-field {
.panel-players > .panel-input > .mdc-text-field,
.panel-accounts > .panel-input > .mdc-text-field {
height: 36px;
}

.panel-cmd > .panel-input,
.panel-players > .panel-input,
.panel-chat > .panel-input {
.panel-chat > .panel-input,
.panel-accounts > .panel-input {
display: flex;
align-items: center;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,14 @@ export class FrontendDOM {
if (typeof panel.ep === "string") {
let refreshTimeout;
this.frontend.sync.register("update", data => {
if (data.startsWith(panel.ep))
return;
console.log("update", data);
panel.refresh();
/* based on panel.ep, trigger a refresh:
- if it starts with [data] and same length (exact match) or
- there's no further letter after the match, so that e.g. /userinfo wouldn't update panels with /userinfos?
*/
if (data.length <= panel.ep.length && panel.ep.startsWith(data) && (data.length == panel.ep.length || !/[a-z]/i.test(panel.ep[data.length]))) {
console.log("update", data, panel.id);
panel.refresh();
}
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export class FrontendSettings {
this.data = Object.assign({
sensitive: true,
accountsClutter: false,
accountsFilterLocally: false
}, this.data || {});
}

Expand Down Expand Up @@ -55,4 +56,13 @@ export class FrontendSettings {
this.data.accountsClutter = value;
}


/** @type {boolean} */
get accountsFilterLocally() {
return this.data.accountsFilterLocally;
}
set accountsFilterLocally(value) {
this.data.accountsFilterLocally = value;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { rd, rdom, rd$, escape$, RDOMListHelper } from "../../../js/rdom.js";
import mdcrd from "../utils/mdcrd.js";
import { FrontendBasicPanel } from "./basic.js";
import { FrontendStatusPanel } from "./status.js";

/**
* @typedef {import("material-components-web")} mdc
Expand Down Expand Up @@ -36,42 +37,239 @@ export class FrontendAccountsPanel extends FrontendBasicPanel {
constructor(frontend) {
super(frontend);
this.header = "Accounts";
this.ep = "/api/userinfos?from=0&count=100000";
this.ep = "/api/userinfos";
this.filteredEP = "/api/userinfosfiltered";
/** @type {UserInfo[]} */
this.data = [];

this.lastFetched = "";
this.currPage = 1;
this.accountsPerPage = 200;
this.totalAccounts = 100 * this.accountsPerPage;

/** @type {[string, string, () => void][]} */
this.actions = [
[
"Reload", "refresh",
"Filter Mode: ...",
"cloud_off",
() => {
this.refresh();
this.frontend.settings.accountsFilterLocally = !this.frontend.settings.accountsFilterLocally;
this.frontend.settings.save();
this.updateActionButtons();
if (this.frontend.settings.accountsFilterLocally)
this.doManualFetch().then(() => this.refresh());
else
this.refresh();
}
],

[
"Refresh",
"sync",
() => {
if (this.frontend.settings.accountsFilterLocally)
this.doManualFetch().then(() => this.refresh());
else
this.refresh();
}
],

[
"Toggle Clutter", this.frontend.settings.accountsClutter ? "visibility" : "visibility_off",
"Filter: ...",
"filter_alt_off",
() => {
this.frontend.settings.accountsClutter = !this.frontend.settings.accountsClutter;
this.frontend.settings.save();
this.actions[1][1] = this.frontend.settings.accountsClutter ? "visibility" : "visibility_off";
this.updateActionButtons();
this.refresh();
}
]
];

this.updateActionButtons();
}

updateActionButtons() {
// updates icons & labels (tooltips) of the buttons
if (this.frontend.settings.accountsFilterLocally) {
// filter modes
this.actions[0][0] = "Filter Mode: In Browser";
this.actions[0][1] = "cloud_off" ;
// refresh / reload
this.actions[1][0] = "Reload All";
this.actions[1][1] = "update" ;

} else {
// filter modes
this.actions[0][0] = "Filter Mode: On Server";
this.actions[0][1] = "cloud";
// refresh / reload
this.actions[1][0] = "Refresh";
this.actions[1][1] = "sync";
}

// filter toggle
if (!this.frontend.settings.accountsClutter) {
this.actions[2][0] = "Filter: Kick/Ban/Tag";
this.actions[2][1] = "filter_alt";
} else {
this.actions[2][0] = "Filter: Show All";
this.actions[2][1] = "filter_alt_off";
}
}


render(el) {
this.updateNumbers();
return this.el = rd$(el || this.el)`
<div class="panel" ${rd.toggleClass("panelType", "panel-" + this.id)}=${true}>
${el => this.renderHeader(el)}
${mdcrd.progress(this.progress)}
${el => this.renderInput(el)}
${el => this.renderBody(el)}
</div>`;
}

renderInput(el) {
// Render input only once.
if (this.elInput)
return this.elInput;

this.updateNumbers();

this.elInput = rd$(el || this.elInput)`
<div class="panel-input">
${mdcrd.textField("", "", null, () => { this.currPage = 1; this.refresh(); })}
${mdcrd.iconButton("Prev", "chevron_left", () => { this.prevPage(); this.refresh(); })}
${el => {
el = rd$(el)`<span class="page-counter"></span>`;
el.innerHTML = this.currPage + " / " + Math.ceil(this.totalAccounts / this.accountsPerPage);
return el;
}}
${mdcrd.iconButton("Next", "chevron_right", () => { this.nextPage(); this.refresh(); })}
</div>`;

// tried to do a this.frontend.dom.setContext to a mdcrd.iconButton but failed because fuck all this rd jazz, I understand none of it :) ~rf
return this.elInput;
}

prevPage() {
if (this.currPage > 1)
this.currPage--;
}

nextPage() {
this.currPage++;
}

updateNumbers() {
if (this.currPage < 1)
this.currPage = 1;

if (this.data && this.totalAccounts == 0)
this.totalAccounts = this.data.length;

if (this.elInput) {
this.counter = this.elInput.getElementsByClassName("page-counter")[0];
this.counter.innerHTML = this.currPage + " / " + Math.ceil(this.totalAccounts / this.accountsPerPage);
}

this.subheader = "(" + this.totalAccounts + "/" + this.data.length + ")";
}

async doManualFetch() {
if (this.progress !== 2) {
this.progress = 2;
this.render();
}

// this takes the fetch call out of update() when filtering locally
// so that a "refresh" doesn't automatically fetch all data again

// either full list for clutter, or filtered, but no other params
let useEP = this.ep + "?from=0&count=1000000";

if (!this.frontend.settings.accountsClutter) {
useEP = this.filteredEP + "?onlyspecial=true&from=0&count=1000000";
}

console.log("Starting manual fetch...");

this.data = (await fetch(useEP).then(r => r.json()));
this.lastFetched = useEP;

console.log("Manual fetch done.");
this.progress = 0;
this.render();
}

async update() {
this.data = (await fetch(this.ep).then(r => r.json())).sort((a, b) => {
if (!a.Name && b.Name)
return 1;
if (a.Name && !b.Name)
return -1;
return a.Name.localeCompare(b.Name);
});
if (this.currPage < 1)
this.currPage = 1;

this.input = this.elInput.getElementsByTagName("input")[0];
let filter = this.input.value.trim();

// first: deal with which data to fetch. For local filtering, handled by doManualFetch() triggered by user

// fetching when filtering server-side:
if (!this.frontend.settings.accountsFilterLocally) {
let fromCountParams = "from=" + this.accountsPerPage * (this.currPage - 1) + "&count=" + this.accountsPerPage;

// for server-side filtering, always use old EP when no search and clutter, otherwise always filtered
let useEP = this.ep + "?" + fromCountParams;

// otherwise, adjust parameters on filteredEP
if (!this.frontend.settings.accountsClutter || filter !== "") {
useEP = this.filteredEP + "?onlyspecial=" + !this.frontend.settings.accountsClutter;

useEP += "&" + fromCountParams;

if (filter !== "")
useEP += "&search=" + filter;
}

// do the actual fetch
this.data = (await fetch(useEP).then(r => r.json())).sort((a, b) => {
if (!a.Name && b.Name)
return 1;
if (a.Name && !b.Name)
return -1;
return a.Name.localeCompare(b.Name);
});
this.lastFetched = useEP;
}

this.updateNumbers();

// deal with slicing (only needed for local filter)
let sliceFrom = 0;
let sliceTo = this.data.length;

if (this.frontend.settings.accountsFilterLocally) {
sliceFrom = this.accountsPerPage * (this.currPage - 1);
sliceTo = this.accountsPerPage * this.currPage;
}

// mainly for local filtering, to narrow down this.data
let dataToShow;

if (!this.frontend.settings.accountsFilterLocally)
dataToShow = this.data;
else {
if (this.frontend.settings.accountsClutter)
dataToShow = this.data;
else
dataToShow = this.data.filter(p => p.Ban || (p.Kicks && p.Kicks.length) || (p.Tags && p.Tags.length));

if (filter !== "")
dataToShow = dataToShow.filter(p => p.Name.toLowerCase().indexOf(filter) >= 0);
}

this.totalAccounts = dataToShow.length;

// @ts-ignore
this.list = this.data.filter(p => this.frontend.settings.accountsClutter || p.Ban || (p.Kicks && p.Kicks.length) || (p.Tags && p.Tags.length)).map(p => el => {
this.list = dataToShow.slice(sliceFrom, sliceTo).map(p => el => {
el = mdcrd.list.item(el => {
el = rd$(el)`<span></span>`;
const list = new RDOMListHelper(el);
Expand Down
Loading

0 comments on commit afb7841

Please sign in to comment.