Skip to content

Fixed playerPanel doesnt show flag | Added flag name on hover#3851

Open
Boostry123 wants to merge 5 commits intoopenfrontio:mainfrom
Boostry123:fix/playerPanelFlag
Open

Fixed playerPanel doesnt show flag | Added flag name on hover#3851
Boostry123 wants to merge 5 commits intoopenfrontio:mainfrom
Boostry123:fix/playerPanelFlag

Conversation

@Boostry123
Copy link
Copy Markdown
Contributor

@Boostry123 Boostry123 commented May 5, 2026

Description:

Noticed the playerPanel should have had a flag, but it wasn't working.
Fixed plus added flag name when hovering.
Before:
noFLag

After:
withFlagAndName

Please complete the following:

  • [ x] Linked the relevant issue (e.g., Resolves #123).
  • [ x] Added screenshots for any UI changes.
  • [ x] Processed text through translateText() and added strings to en.json.
  • [ x] Added/Updated tests in the tests/ directory.
  • [ x] Verified that npm test passes.
  • [ x] Provided your Discord username in the PR description for communication.

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

Boostry

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 5, 2026

Review Change Stack

Walkthrough

renderIdentityRow now reads the flag path from other.cosmetics.flag, extracts a flagCode via regex, resolves country metadata with Countries.find(...), and renders the flag using the path directly while preferring country.name for alt/title. The render() identity wrapper was reformatted to multiple lines but still calls this.renderIdentityRow(other, my).

Changes

Player Panel Flag Rendering

Layer / File(s) Summary
Flag selection and country lookup
src/client/graphics/layers/PlayerPanel.ts
renderIdentityRow now derives activeFlagPath from other.cosmetics.flag, extracts flagCode using a regex, and looks up country via Countries.find(...) with a fallback to the parsed string.
Flag image attributes
src/client/graphics/layers/PlayerPanel.ts
The identity <img> uses activeFlagPath directly for src. title and alt are set from country.name when country is an object, otherwise from country as a string.
Render call-site formatting
src/client/graphics/layers/PlayerPanel.ts
The identity section in render() was reformatted to a multi-line <div> but still invokes this.renderIdentityRow(other, my) unchanged.

Estimated Code Review Effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🚩 A small refactor, flags now read with care,
Paths parsed, countries found, alt text placed where,
The image points straight at the path you see,
Render stays the same, just tidied to be. 🌍

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR addresses fixing a player panel flag display issue, but the linked issue #123 is about debouncing a join button to prevent lag - these are unrelated topics. Remove the unrelated issue #123 from the PR, or link the correct issue about the player panel flag display if one exists.
Out of Scope Changes check ⚠️ Warning The changes in PlayerPanel.ts focus on flag display refactoring, but the linked issue #123 concerns join button debouncing - the changes are out of scope for the linked issue. Either link the correct issue related to player panel flag display, or remove issue #123 from this PR and create a separate PR for the debouncer work.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main changes: fixing a missing flag display in the player panel and adding flag name on hover.
Description check ✅ Passed The description is related to the changeset, explaining the flag display issue and showing before/after screenshots demonstrating the fix.
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.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/client/graphics/layers/PlayerPanel.ts (1)

499-524: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Broken regex makes the flag never appear for most path formats.

The regex /\/([^.]+)\./ at line 500 does not exclude / inside [^.]+, so it greedily matches from the first slash in the path. For any path like /images/flags/us.svg, it captures images/flags/us, and then flagCode.split("/")[1] yields "flags" — not a country code — so Countries.find() returns undefined. Because line 514 guards on country &&, the <img> is suppressed entirely, which defeats this PR's main goal.

Two fixes are needed:

  1. Correct the regex to extract just the filename stem (no slashes, no extension).
  2. Separate the render guard from country resolution: use activeFlagPath alone to decide whether to show the image, and use the country result only as a tooltip/alt fallback.
🐛 Proposed fix
- const flagCode = activeFlagPath?.match(/\/([^.]+)\./)?.[1];
+ // Extract the bare filename stem: e.g. "us" from "/images/flags/us.svg"
+ const flagCode = activeFlagPath?.match(/\/([^/.]+)\.[^/]*$/)?.[1];

  // Find the country based on that code
  const country = flagCode
-   ? Countries.find((c) => c.code === flagCode.split("/")[1])
+   ? Countries.find((c) => c.code === flagCode)
    : flagCode;
- ${country && activeFlagPath
+ ${activeFlagPath
    ? html`<img
        src=${activeFlagPath}
-       title=${typeof country !== "string" ? country.name : country}
-       alt=${typeof country !== "string" ? country.name : country}
+       title=${(country && typeof country !== "string") ? country.name : (flagCode ?? "")}
+       alt=${(country && typeof country !== "string") ? country.name : (flagCode ?? "")}
        class="h-10 w-10 rounded-full object-cover"
        `@error`=${(e: Event) => {
          (e.target as HTMLImageElement).style.display = "none";
        }}
      />`
    : ""}

Run this to confirm actual flag path formats stored in cosmetics.flag:

#!/bin/bash
# Find how cosmetics.flag values are set/formatted in the codebase
rg -n "\.flag\s*=" --type ts -C 2
rg -n "cosmetics" src/core/CosmeticSchemas.ts -A 3 2>/dev/null || true
rg -n "flag.*assetUrl\|assetUrl.*flag" --type ts -C 2
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/graphics/layers/PlayerPanel.ts` around lines 499 - 524, The flag
extraction regex and render guard are incorrect: update the flag filename
extraction so flagCode pulls only the filename stem (no slashes or extension)
from activeFlagPath (fix the regex used in flagCode), then change the rendering
condition to rely solely on activeFlagPath (not on country) so the <img> is
shown whenever activeFlagPath exists; keep Countries.find(...) (used to build
tooltip/alt) as a separate lookup and fall back to displaying the raw flagCode
or a sensible string when Countries.find(...) returns undefined (adjust uses of
flagCode, Countries.find, and the img title/alt accordingly in PlayerPanel).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/client/graphics/layers/PlayerPanel.ts`:
- Around line 517-518: The Prettier error is caused by missing spaces around the
strict inequality in the template attributes for title and alt in PlayerPanel
(the expressions `typeof country!== "string"`); update those expressions to
include spaces around `!==` (e.g., `typeof country !== "string"`) for both title
and alt, then run `npx prettier --write
src/client/graphics/layers/PlayerPanel.ts` to reformat the file and fix the CI
check.

---

Outside diff comments:
In `@src/client/graphics/layers/PlayerPanel.ts`:
- Around line 499-524: The flag extraction regex and render guard are incorrect:
update the flag filename extraction so flagCode pulls only the filename stem (no
slashes or extension) from activeFlagPath (fix the regex used in flagCode), then
change the rendering condition to rely solely on activeFlagPath (not on country)
so the <img> is shown whenever activeFlagPath exists; keep Countries.find(...)
(used to build tooltip/alt) as a separate lookup and fall back to displaying the
raw flagCode or a sensible string when Countries.find(...) returns undefined
(adjust uses of flagCode, Countries.find, and the img title/alt accordingly in
PlayerPanel).
🪄 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: eb40bb54-33ad-439d-9e5f-748ebff273b2

📥 Commits

Reviewing files that changed from the base of the PR and between 8d1614d and 00715c0.

📒 Files selected for processing (1)
  • src/client/graphics/layers/PlayerPanel.ts

Comment thread src/client/graphics/layers/PlayerPanel.ts Outdated
@github-project-automation github-project-automation Bot moved this from Triage to Development in OpenFront Release Management May 5, 2026
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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/client/graphics/layers/PlayerPanel.ts`:
- Around line 505-507: The flag image is being suppressed when
Countries.find(...) fails and the else branch widens country to string; update
the logic in PlayerPanel.ts so the image src/rendering depends only on
activeFlagPath (render if activeFlagPath is truthy) and set the else branch for
country to undefined (not flagCode) so country remains Country|undefined; keep
country (from Countries.find(flagCode.split("/")[1])) only for title/alt (use
country?.name or conditional to supply labels) and remove the unnecessary typeof
country !== "string" runtime guard.
- Around line 502-506: The flag extraction logic around activeFlagPath and
flagCode in PlayerPanel.ts fails for hashed build asset names; update the
matching to extract the 2-letter country code before any hash instead of
splitting on "/"—for example run a case-insensitive regex match like
/([a-z]{2})(?:-[a-f0-9]+)?\.svg$/i against activeFlagPath and use the captured
group as the flagCode, then pass that flagCode directly into Countries.find((c)
=> c.code === flagCode); keep the safe fallback when no match is found so
country can be undefined.
🪄 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: e046b928-e3c5-4b81-bc5b-473329ce0f38

📥 Commits

Reviewing files that changed from the base of the PR and between 00715c0 and fc2c239.

📒 Files selected for processing (1)
  • src/client/graphics/layers/PlayerPanel.ts

Comment on lines +502 to +506
const flagCode = activeFlagPath?.match(/\/([^.]+)\./)?.[1];

// Find the country based on that code
const country = flagCode
? Countries.find((c) => c.code === flagCode.split("/")[1])
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find where cosmetics.flag is assigned or read to understand the path format
rg -n "cosmetics[.\[]" --type ts -A 2 -B 2 | grep -i flag | head -40

# Also check cosmetics.json for flag entry shapes
fd "cosmetics.json" --exec cat {}

Repository: openfrontio/OpenFrontIO

Length of output: 2640


🏁 Script executed:

# Check how the flag is used after extraction in PlayerPanel.ts
rg -n "flagCode" src/client/graphics/layers/PlayerPanel.ts -A 5 -B 2

# Check if there's validation for custom URLs elsewhere
rg -n "cosmetics.flag" src/client/graphics/layers/ -A 3 -B 1 | head -50

Repository: openfrontio/OpenFrontIO

Length of output: 2042


🏁 Script executed:

# Find Countries definition and what codes it contains
rg -n "Countries\s*=" src/client --type ts -A 5 | head -30

# See how 'country' variable is used after line 506 in PlayerPanel.ts
rg -n "const country = " src/client/graphics/layers/PlayerPanel.ts -A 10

Repository: openfrontio/OpenFrontIO

Length of output: 418


🏁 Script executed:

# Find the Countries import in PlayerPanel.ts
rg -n "^import|^from|Countries" src/client/graphics/layers/PlayerPanel.ts | head -20

# Find Countries definition in the entire codebase
rg -n "const Countries|export.*Countries" src/client --type ts -B 2 -A 3

Repository: openfrontio/OpenFrontIO

Length of output: 939


🏁 Script executed:

# Read the countries.json file to see code structure
cat resources/countries.json | head -50

Repository: openfrontio/OpenFrontIO

Length of output: 913


🏁 Script executed:

# Check GameView.ts flagAssignment and asset generation
rg -n "flag:" src/core/game/GameView.ts -B 3 -A 3

# Check if assetUrl or asset hashing changes the path before reaching PlayerPanel
rg -n "assetUrl|flagAssignments" src/client/graphics/layers/PlayerPanel.ts -B 2 -A 2

# Check core/AssetUrls to see how flag paths are transformed
cat src/core/AssetUrls.ts | head -40

Repository: openfrontio/OpenFrontIO

Length of output: 2500


Flag code extraction breaks for hashed asset paths—improve regex to handle hash suffixes.

The current regex /\/([^.]+)\./ incorrectly handles bundled assets. For /_assets/flags/us-abc123.svg (which appears after build hashing), it captures _assets/flags/us-abc123, then split("/")[1] yields flags instead of the country code us. The Countries.find() silently fails because no entry has code "flags".

The proposed regex /([^/]+)\.[^.]+$/ extracts just the filename but still includes the hash suffix: for us-abc123.svg it captures us-abc123, which also fails the country lookup. Strip the hash portion using a pattern like /([a-z]{2})(?:-[a-f0-9]+)?\.svg$/ to extract the 2-letter code before any hash:

Suggested refactor
-    const flagCode = activeFlagPath?.match(/\/([^.]+)\./)?.[1];
-
-    // Find the country based on that code
-    const country = flagCode
-      ? Countries.find((c) => c.code === flagCode.split("/")[1])
-      : flagCode;
+    // Extract the 2-letter code from paths like "/flags/us.svg" or "/_assets/flags/us-hash.svg"
+    const flagCode = activeFlagPath?.match(/([a-z]{2})(?:-[a-f0-9]+)?\.svg$/)?.[1];
+    const country = flagCode
+      ? Countries.find((c) => c.code === flagCode)
+      : undefined;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/graphics/layers/PlayerPanel.ts` around lines 502 - 506, The flag
extraction logic around activeFlagPath and flagCode in PlayerPanel.ts fails for
hashed build asset names; update the matching to extract the 2-letter country
code before any hash instead of splitting on "/"—for example run a
case-insensitive regex match like /([a-z]{2})(?:-[a-f0-9]+)?\.svg$/i against
activeFlagPath and use the captured group as the flagCode, then pass that
flagCode directly into Countries.find((c) => c.code === flagCode); keep the safe
fallback when no match is found so country can be undefined.

Comment thread src/client/graphics/layers/PlayerPanel.ts
my: PlayerView,
myPanelClicked: boolean = false,
) {
const activeFlagPath = myPanelClicked
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

why can't we alwasy use other? if you click on yourself wont other be yourself? then we dont' need myPanelClicked?

Comment on lines +505 to +506
const country = flagCode
? Countries.find((c) => c.code === flagCode.split("/")[1])
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

why do we need to do this lookup? Can we do what NameLayer.ts does?

@CLAassistant
Copy link
Copy Markdown

CLAassistant commented May 8, 2026

CLA assistant check
All committers have signed the CLA.

@Boostry123 Boostry123 force-pushed the fix/playerPanelFlag branch from 184d922 to 79a3dad Compare May 8, 2026 18:39
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

♻️ Duplicate comments (1)
src/client/graphics/layers/PlayerPanel.ts (1)

499-504: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Flag code extraction still breaks for hashed/bundled asset paths.

The regex /\/([^.]+)\./ on a path like /_assets/flags/us-abc123.svg captures _assets/flags/us-abc123, so flagCode.split("/")[1] gives "flags" — which matches nothing in Countries.

The else branch also still assigns flagCode (a string | undefined) to country, widening its type to string | Country | undefined and making the typeof country !== "string" guard necessary even though it is always true at runtime (when flagCode is falsy it is undefined, not "").

Both problems are fixed together:

🛠️ Proposed fix
-    const activeFlagPath = other.cosmetics.flag;
-    const flagCode = activeFlagPath?.match(/\/([^.]+)\./)?.[1];
-
-    // Find the country based on that code
-    const country = flagCode
-      ? Countries.find((c) => c.code === flagCode.split("/")[1])
-      : flagCode;
+    const activeFlagPath = other.cosmetics.flag;
+    // Extract 2-letter code from "/flags/us.svg" or "/_assets/flags/us-abc123.svg"
+    const flagCode = activeFlagPath?.match(/\/([a-z]{2})(?:-[a-f0-9]+)?\.svg$/i)?.[1];
+    const country = flagCode
+      ? Countries.find((c) => c.code === flagCode.toLowerCase())
+      : undefined;

Then in the template the typeof guard can be dropped:

-              title=${typeof country !== "string" ? country?.name : country}
-              alt=${typeof country !== "string" ? country?.name : country}
+              title=${country?.name ?? flagCode ?? ""}
+              alt=${country?.name ?? flagCode ?? ""}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/graphics/layers/PlayerPanel.ts` around lines 499 - 504,
activeFlagPath handling extracts the wrong segment and can produce a string in
country; instead derive the basename and the short country code before extension
and hyphenation, then look up Countries by that short code and set country to
undefined when no code exists. Concretely, replace the regex-based flagCode
extraction so it first obtains the path basename from activeFlagPath (last
segment after "/"), strips the file extension, then splits on "-" and takes the
first token as the flagCode; then compute country = flagCode ? Countries.find(c
=> c.code === flagCode) : undefined (using the existing Countries lookup and the
existing country variable), and remove the unnecessary typeof country !==
"string" guard in the template.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/client/graphics/layers/PlayerPanel.ts`:
- Line 498: The declaration for activeFlagPath in PlayerPanel.ts is missing a
trailing semicolon which breaks Prettier CI; add the semicolon to the const
declaration (the identifier activeFlagPath where it is set to
other.cosmetics.flag) and then run npx prettier --write
src/client/graphics/layers/PlayerPanel.ts (or your repo-wide prettier) to
reformat and ensure no other formatting issues remain before merging.

---

Duplicate comments:
In `@src/client/graphics/layers/PlayerPanel.ts`:
- Around line 499-504: activeFlagPath handling extracts the wrong segment and
can produce a string in country; instead derive the basename and the short
country code before extension and hyphenation, then look up Countries by that
short code and set country to undefined when no code exists. Concretely, replace
the regex-based flagCode extraction so it first obtains the path basename from
activeFlagPath (last segment after "/"), strips the file extension, then splits
on "-" and takes the first token as the flagCode; then compute country =
flagCode ? Countries.find(c => c.code === flagCode) : undefined (using the
existing Countries lookup and the existing country variable), and remove the
unnecessary typeof country !== "string" guard in the template.
🪄 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: ed76ec06-48e3-4504-a7ea-d24109ab2f2e

📥 Commits

Reviewing files that changed from the base of the PR and between 79a3dad and cc1b2b8.

📒 Files selected for processing (1)
  • src/client/graphics/layers/PlayerPanel.ts

other: PlayerView,
my: PlayerView,
) {
const activeFlagPath = other.cosmetics.flag
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Missing semicolon on activeFlagPath declaration is still breaking Prettier CI.

Line 498 has no semicolon:

-    const activeFlagPath = other.cosmetics.flag
+    const activeFlagPath = other.cosmetics.flag;

Run npx prettier --write src/client/graphics/layers/PlayerPanel.ts to confirm all remaining formatting issues are cleared before merging.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const activeFlagPath = other.cosmetics.flag
const activeFlagPath = other.cosmetics.flag;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/graphics/layers/PlayerPanel.ts` at line 498, The declaration for
activeFlagPath in PlayerPanel.ts is missing a trailing semicolon which breaks
Prettier CI; add the semicolon to the const declaration (the identifier
activeFlagPath where it is set to other.cosmetics.flag) and then run npx
prettier --write src/client/graphics/layers/PlayerPanel.ts (or your repo-wide
prettier) to reformat and ensure no other formatting issues remain before
merging.

@evanpelle
Copy link
Copy Markdown
Collaborator

looks like ci is failing

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

Labels

None yet

Projects

Status: Development

Development

Successfully merging this pull request may close these issues.

3 participants