fix: make bms/pms use normal sorting on tables (#1519)

This commit is contained in:
zk
2026-05-20 02:13:10 +01:00
committed by GitHub
parent 9be4426ab5
commit de1947573a
7 changed files with 46 additions and 18 deletions
+3
View File
@@ -86,6 +86,9 @@ RUN apt-get update \
gh \
# MinIO CLI (binary is `minio-client`, not Midnight Commander's `mc`)
minio-client \
# `xdg-open` so the client vite plugin can launch a browser without
# crashing on missing binary (see typescript/client/vite.config.ts).
xdg-utils \
&& rm -rf /var/lib/apt/lists/*
ENV DEBIAN_FRONTEND=readline
@@ -123,9 +123,9 @@ export default function TableEvolutionReplay({
const folderSlugOrder = useMemo(
() =>
scope.kind === "table"
? tableFolderSlugsDisplayOrder(scope.table)
? tableFolderSlugsDisplayOrder(scope.table, game)
: [scope.folder.slug],
[scope],
[scope, game],
);
const scrubRef = useRef(0);
@@ -45,7 +45,7 @@ export default function TableFolderList({
const dataset = useMemo(() => {
const arr = [];
for (const folder of tableFolderSlugsDisplayOrder(table)) {
for (const folder of tableFolderSlugsDisplayOrder(table, game)) {
const data = dataMap.get(folder);
if (!data) {
@@ -56,7 +56,7 @@ export default function TableFolderList({
}
return arr;
}, [dataMap, table]);
}, [dataMap, table, game]);
const { user } = useContext(UserContext);
@@ -1,5 +1,6 @@
import type { FolderStatsInfo, TableEvolutionEventAPI } from "#types/api-returns";
import { GPT_CLIENT_IMPLEMENTATIONS } from "#lib/game-implementations";
import {
type FolderDocument,
type GameConfig,
@@ -20,9 +21,18 @@ export interface UGPTFolderStats {
stats: FolderStatsInfo;
}
/** API `table.folders` is ascending (e.g. Level 1 … 12); show highest folder / level first in chart + table. */
export function tableFolderSlugsDisplayOrder(table: TableDocument): string[] {
return [...table.folders].reverse();
/**
* Resolve the order folder slugs should be rendered for `table` in `game`.
*
* `table.folders` is ascending (e.g. Level 1 … 12), and by default we reverse so the
* highest folder / level renders first. Games can opt out via `reverseFolderOrder` on
* their GPT client impl, in which case we reverse again — i.e. render in the table's
* declared order (currently used for BMS/PMS).
*/
export function tableFolderSlugsDisplayOrder(table: TableDocument, game: V3Game): string[] {
const reverseAgain = GPT_CLIENT_IMPLEMENTATIONS[game].reverseFolderOrder ?? false;
return reverseAgain ? [...table.folders] : [...table.folders].reverse();
}
export function evoEventTimeMs(ev: TableEvolutionEventAPI): number {
@@ -14,6 +14,7 @@ import { bgc, CreateRatingSys } from "./_util";
const BASE_IMPL: GPTClientImplementation<GamesForGroup["bms" | "pms"]> = {
sessionImportantScoreCount: 20,
reverseFolderOrder: true,
difficultyColours: {
CHART: COLOUR_SET.gray, // lol
},
+8
View File
@@ -148,4 +148,12 @@ export interface GPTClientImplementation<GPT extends V3Game = V3Game> {
* display?
*/
sessionImportantScoreCount: integer;
/**
* By default folders are rendered in reverse of `table.folders` (so the highest
* level / hardest folder shows first). Set this to flip that back — folders will
* then be rendered in the order declared by the table. Used for games like BMS/PMS
* where the table is already authored in the order the UI should display.
*/
reverseFolderOrder?: boolean;
}
+17 -11
View File
@@ -21,6 +21,8 @@ function openLoopbackInBrowserPlugin(): Plugin {
useHttps: boolean,
) => {
if (!httpServer) return;
// Opt out for headless dev containers / CI where no browser opener exists.
if (process.env.TACHI_NO_OPEN === "1" || process.env.CI) return;
const run = () => {
const addr = httpServer.address();
const port =
@@ -29,17 +31,21 @@ function openLoopbackInBrowserPlugin(): Plugin {
: (portFallback ?? 3000);
const protocol = useHttps ? "https" : "http";
const url = `${protocol}://localhost:${port}/`;
if (process.platform === "darwin") {
spawn("open", [url], { detached: true, stdio: "ignore" }).unref();
} else if (process.platform === "win32") {
spawn("cmd", ["/c", "start", "", url], {
detached: true,
stdio: "ignore",
shell: false,
}).unref();
} else {
spawn("xdg-open", [url], { detached: true, stdio: "ignore" }).unref();
}
const [cmd, args]: [string, string[]] =
process.platform === "darwin"
? ["open", [url]]
: process.platform === "win32"
? ["cmd", ["/c", "start", "", url]]
: ["xdg-open", [url]];
const child = spawn(cmd, args, {
detached: true,
stdio: "ignore",
shell: false,
});
// Without this, a missing opener binary (e.g. no xdg-open in a dev
// container) emits an unhandled 'error' event and crashes vite.
child.on("error", () => {});
child.unref();
};
if (httpServer.listening) run();
else httpServer.once("listening", run);