Skip to content

playerstats to go with infra#3520

Merged
evanpelle merged 5 commits intomainfrom
playerstats
Mar 27, 2026
Merged

playerstats to go with infra#3520
evanpelle merged 5 commits intomainfrom
playerstats

Conversation

@ryanbarlow97
Copy link
Copy Markdown
Contributor

@ryanbarlow97 ryanbarlow97 commented Mar 26, 2026

Description:

https://github.com/openfrontio/infra/pull/279 to go with this, splits out 1v1

Please complete the following:

  • I have added screenshots for all UI updates
  • I process any text displayed to the user through translateText() and I've added it to the en.json file
  • I have added relevant tests to the test directory
  • I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced

Please put your Discord username so you can be contacted if a bug or regression is found:

w.o.n

Copilot AI review requested due to automatic review settings March 26, 2026 23:32
@openfrontio openfrontio Bot had a problem deploying to staging March 26, 2026 23:32 Failure
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 26, 2026

Walkthrough

Adds a Ranked branch to player stats: i18n entries, UI support for selecting Ranked and its subtypes, and an API schema change to store Ranked stats keyed by RankedType.

Changes

Cohort / File(s) Summary
Translation
resources/lang/en.json
Added player_stats_tree.ranked"Ranked" and player_stats_tree.ranked_1v1"1v1".
UI Component
src/client/components/baseComponents/stats/PlayerStatsTree.ts
Expanded selection to include "Ranked": selectedType now accepts `GameType
API Schema / Types
src/core/ApiSchemas.ts
Replaced generic nested partial-record with an explicit PlayerStatsTreeSchema object: optional Singleplayer, Public, Private (partial records of GameMode→Difficulty→leaf) and an optional Ranked subtree as Partial<Record<RankedType, PlayerStatsLeaf>>, updating the inferred PlayerStatsTree type.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Poem

A ranked branch sprouts on the stats tree, 🌱
Buttons, types, and schema now agree,
Two new keys give names that fit,
UI picks subtypes nice and lit,
A tidy leaf for ranked to be. ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is vague and does not clearly describe the main changes; 'to go with infra' is unclear without external context. Use a more specific title that describes the actual change, such as 'Add ranked player stats support with 1v1 subcategory' or similar.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed The description references an infrastructure PR and mentions splitting out 1v1, which relates to the ranked stats additions and schema changes in the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ryanbarlow97 ryanbarlow97 marked this pull request as draft March 26, 2026 23:33
@ryanbarlow97 ryanbarlow97 added this to the v30 milestone Mar 26, 2026
@ryanbarlow97 ryanbarlow97 added Backend Server-side features and systems - lobbies, matchmaking, accounts, APIs, etc. UI/UX UI/UX changes including assets, menus, QoL, etc. Feature labels Mar 26, 2026

This comment was marked as resolved.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/client/components/baseComponents/stats/PlayerStatsTree.ts (1)

67-69: Avoid hard-coding RankedType.OneVOne here.

src/core/ApiSchemas.ts:101-116 exposes ranked stats as a record keyed by RankedType, and src/core/game/Game.ts:225-240 already models the queue as an enum. This branch will silently ignore the next ranked type added there. Please keep a selected ranked type, or at least derive the first available ranked key from statsTree.Ranked.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/client/components/baseComponents/stats/PlayerStatsTree.ts` around lines
67 - 69, The branch is hard-coded to use RankedType.OneVOne; update the logic to
use a maintained selected ranked key (e.g., this.selectedRankedType) or derive
the first available key from statsTree.Ranked instead of the literal
RankedType.OneVOne. Modify the getter to return
this.statsTree?.Ranked?.[this.selectedRankedType ??
(Object.keys(this.statsTree?.Ranked || {})[0] as unknown as RankedType)] ?? null
and ensure selectedRankedType is initialized/kept in component state and typed
as RankedType so newly added ranked types are honored automatically.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/client/components/baseComponents/stats/PlayerStatsTree.ts`:
- Around line 67-69: The branch is hard-coded to use RankedType.OneVOne; update
the logic to use a maintained selected ranked key (e.g.,
this.selectedRankedType) or derive the first available key from statsTree.Ranked
instead of the literal RankedType.OneVOne. Modify the getter to return
this.statsTree?.Ranked?.[this.selectedRankedType ??
(Object.keys(this.statsTree?.Ranked || {})[0] as unknown as RankedType)] ?? null
and ensure selectedRankedType is initialized/kept in component state and typed
as RankedType so newly added ranked types are honored automatically.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1845eef0-b274-4427-9fa2-38963d6b1763

📥 Commits

Reviewing files that changed from the base of the PR and between 23150f0 and 71c9258.

📒 Files selected for processing (3)
  • resources/lang/en.json
  • src/client/components/baseComponents/stats/PlayerStatsTree.ts
  • src/core/ApiSchemas.ts

coderabbitai[bot]
coderabbitai Bot previously approved these changes Mar 26, 2026
@github-project-automation github-project-automation Bot moved this from Triage to Final Review in OpenFront Release Management Mar 26, 2026
@ryanbarlow97 ryanbarlow97 marked this pull request as ready for review March 26, 2026 23:56
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/client/components/baseComponents/stats/PlayerStatsTree.ts (1)

116-130: Remove the misleading type cast.

Line 118 casts selectedType as GameType, but selectedType can be "Ranked" which is not a GameType. The cast is unnecessary since types is (GameType | "Ranked")[] and includes accepts the union type directly. The cast hides the actual type and could mask future type errors.

♻️ Suggested fix
-    if (types.length && !types.includes(this.selectedType as GameType)) {
+    if (types.length && !types.includes(this.selectedType)) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/client/components/baseComponents/stats/PlayerStatsTree.ts` around lines
116 - 130, In syncSelection(), remove the misleading cast "selectedType as
GameType" and call includes with the actual this.selectedType value (since
availableTypes is (GameType | "Ranked")[] and includes accepts that union);
update the check to use this.selectedType directly so the runtime check and
TypeScript types align (refer to syncSelection, selectedType, and
availableTypes).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/client/components/baseComponents/stats/PlayerStatsTree.ts`:
- Around line 302-314: In PlayerStatsTree replace the raw enum label output (the
${r} inside the rankedTypes map) with a call to the translation helper so
displayed ranked type labels go through i18n; e.g., change the button body to
use translateText(`player_stats_tree.ranked_type.${r}`) (or a small mapping
function) while keeping the click handler setRankedType(r) and the
selectedRankedType comparison unchanged, and add corresponding keys like
player_stats_tree.ranked_type.1v1 to your locale JSON.

---

Nitpick comments:
In `@src/client/components/baseComponents/stats/PlayerStatsTree.ts`:
- Around line 116-130: In syncSelection(), remove the misleading cast
"selectedType as GameType" and call includes with the actual this.selectedType
value (since availableTypes is (GameType | "Ranked")[] and includes accepts that
union); update the check to use this.selectedType directly so the runtime check
and TypeScript types align (refer to syncSelection, selectedType, and
availableTypes).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c4a6a1fe-f13a-4c65-8006-4388901a2a3c

📥 Commits

Reviewing files that changed from the base of the PR and between b3ec04f and 53304d3.

📒 Files selected for processing (1)
  • src/client/components/baseComponents/stats/PlayerStatsTree.ts

Comment thread src/client/components/baseComponents/stats/PlayerStatsTree.ts
@github-project-automation github-project-automation Bot moved this from Final Review to Development in OpenFront Release Management Mar 26, 2026
@openfrontio openfrontio Bot had a problem deploying to staging March 26, 2026 23:57 Failure
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/client/components/baseComponents/stats/PlayerStatsTree.ts (1)

38-82: Consolidate RankedType metadata into a single source of truth.

The code currently distributes Ranked subtype knowledge across three places: availableRankedTypes() filters keys, labelForRankedType() maps types to translation keys via switch, and availableTypes() checks raw key count. If one place changes alone, the UI can drift—for example, a Ranked tab visible with no subtype buttons, or a subtype with no label.

Additionally, labelForRankedType() lacks a default case and can return undefined if called with an unexpected value.

Define a single Record<RankedType, string> for all Ranked metadata:

♻️ Proposed refactor
+  private readonly rankedTypeLabels: Record<RankedType, string> = {
+    [RankedType.OneVOne]: "player_stats_tree.ranked_1v1",
+  };
+
   private get availableTypes(): (GameType | "Ranked")[] {
     if (!this.statsTree) return [];
     const types: (GameType | "Ranked")[] = Object.keys(this.statsTree).filter(
       (k): k is GameType =>
         isGameType(k) &&
         Object.keys(this.statsTree![k as GameType] ?? {}).length > 0,
     );
-    if (
-      this.statsTree.Ranked &&
-      Object.keys(this.statsTree.Ranked).length > 0
-    ) {
+    if (this.availableRankedTypes.length > 0) {
       types.push("Ranked");
     }
     return types;
   }

   private get availableRankedTypes(): RankedType[] {
     if (!this.statsTree?.Ranked) return [];
-    return Object.keys(this.statsTree.Ranked).filter((k): k is RankedType =>
-      Object.values(RankedType).includes(k as RankedType),
-    );
+    return Object.keys(this.statsTree.Ranked).filter(
+      (k): k is RankedType => k in this.rankedTypeLabels,
+    );
   }

   private labelForRankedType(r: RankedType) {
-    switch (r) {
-      case RankedType.OneVOne:
-        return translateText("player_stats_tree.ranked_1v1");
-    }
+    return translateText(this.rankedTypeLabels[r]);
   }

All current RankedType members (OneVOne) have matching translation keys (player_stats_tree.ranked_1v1) in resources/lang/en.json.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/client/components/baseComponents/stats/PlayerStatsTree.ts` around lines
38 - 82, Consolidate RankedType logic by introducing a single Record constant
(e.g., RANKED_METADATA: Record<RankedType, string>) mapping each RankedType to
its translation key and then update availableRankedTypes, labelForRankedType,
and availableTypes to derive behavior from that map: have availableRankedTypes
return keys present in statsTree.Ranked filtered against
Object.keys(RANKED_METADATA), change availableTypes to check for any keys from
RANKED_METADATA instead of raw key count, and rewrite labelForRankedType to look
up the translation key in RANKED_METADATA and return a safe fallback if missing
(avoid a missing default/undefined). Use the existing symbols
availableRankedTypes, labelForRankedType, availableTypes, and RankedType to
locate and replace the logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/client/components/baseComponents/stats/PlayerStatsTree.ts`:
- Around line 38-82: Consolidate RankedType logic by introducing a single Record
constant (e.g., RANKED_METADATA: Record<RankedType, string>) mapping each
RankedType to its translation key and then update availableRankedTypes,
labelForRankedType, and availableTypes to derive behavior from that map: have
availableRankedTypes return keys present in statsTree.Ranked filtered against
Object.keys(RANKED_METADATA), change availableTypes to check for any keys from
RANKED_METADATA instead of raw key count, and rewrite labelForRankedType to look
up the translation key in RANKED_METADATA and return a safe fallback if missing
(avoid a missing default/undefined). Use the existing symbols
availableRankedTypes, labelForRankedType, availableTypes, and RankedType to
locate and replace the logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2b824325-7ca8-465a-bac7-519f182a5758

📥 Commits

Reviewing files that changed from the base of the PR and between 53304d3 and 7a23c9a.

📒 Files selected for processing (2)
  • resources/lang/en.json
  • src/client/components/baseComponents/stats/PlayerStatsTree.ts
✅ Files skipped from review due to trivial changes (1)
  • resources/lang/en.json

@github-project-automation github-project-automation Bot moved this from Development to Final Review in OpenFront Release Management Mar 27, 2026
@evanpelle evanpelle merged commit 14a5128 into main Mar 27, 2026
11 checks passed
@github-project-automation github-project-automation Bot moved this from Final Review to Complete in OpenFront Release Management Mar 27, 2026
@evanpelle evanpelle deleted the playerstats branch March 27, 2026 02:04
evanpelle pushed a commit that referenced this pull request Mar 27, 2026
## Description:

openfrontio/infra#279 to go with this, splits
out 1v1

## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced

## Please put your Discord username so you can be contacted if a bug or
regression is found:

w.o.n
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Backend Server-side features and systems - lobbies, matchmaking, accounts, APIs, etc. Feature UI/UX UI/UX changes including assets, menus, QoL, etc.

Projects

Status: Complete

Development

Successfully merging this pull request may close these issues.

3 participants