Skip to content

Commit 16f8117

Browse files
committed
Enh(viewer): Improve game session dropdown
Add warning sign next to probably failed; add # rounds; alphabetical sort
1 parent cbeaf1f commit 16f8117

2 files changed

Lines changed: 39 additions & 6 deletions

File tree

codeclash/viewer/app.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,25 @@ def set_log_base_directory(directory: str | Path):
2222
LOG_BASE_DIR = Path(directory).resolve()
2323

2424

25+
def is_probably_failed_run(log_dir: Path) -> bool:
26+
"""Check if a run probably failed by checking if metadata.json is missing"""
27+
metadata_file = log_dir / "metadata.json"
28+
return not metadata_file.exists()
29+
30+
31+
def get_round_count_from_metadata(log_dir: Path) -> Optional[int]:
32+
"""Extract round count from metadata.json if it exists"""
33+
metadata_file = log_dir / "metadata.json"
34+
if not metadata_file.exists():
35+
return None
36+
37+
try:
38+
metadata = json.loads(metadata_file.read_text())
39+
return metadata.get("config", {}).get("game", {}).get("rounds")
40+
except (json.JSONDecodeError, KeyError):
41+
return None
42+
43+
2544
@dataclass
2645
class GameMetadata:
2746
"""Metadata about a game session"""
@@ -150,9 +169,22 @@ def index():
150169
"""Main viewer page"""
151170
# Get available log directories
152171
logs_dir = LOG_BASE_DIR
153-
log_folders = []
172+
log_folders_info = []
154173
if logs_dir.exists():
155-
log_folders = [d.name for d in logs_dir.iterdir() if d.is_dir()]
174+
for d in logs_dir.iterdir():
175+
if d.is_dir():
176+
folder_info = {
177+
"name": d.name,
178+
"is_failed": is_probably_failed_run(d),
179+
"round_count": get_round_count_from_metadata(d),
180+
}
181+
log_folders_info.append(folder_info)
182+
183+
# Sort folders alphabetically by name
184+
log_folders_info.sort(key=lambda x: x["name"])
185+
186+
# Extract just the names for backwards compatibility
187+
log_folders = [folder["name"] for folder in log_folders_info]
156188

157189
selected_folder = request.args.get(
158190
"folder", log_folders[0] if log_folders else None
@@ -178,6 +210,7 @@ def index():
178210
return render_template(
179211
"index.html",
180212
log_folders=log_folders,
213+
log_folders_info=log_folders_info,
181214
selected_folder=selected_folder,
182215
metadata=metadata,
183216
trajectories_by_round=trajectories_by_round,

codeclash/viewer/templates/index.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ <h1>🎮 CodeClash Trajectory Viewer</h1>
1616
<div class="control-group">
1717
<label for="folder-select">Game Session:</label>
1818
<select id="folder-select" onchange="changeFolder()">
19-
{% for folder in log_folders %}
20-
<option value="{{ folder }}"
21-
{% if folder == selected_folder %}selected{% endif %}>
22-
{{ folder }}
19+
{% for folder_info in log_folders_info %}
20+
<option value="{{ folder_info.name }}"
21+
{% if folder_info.name == selected_folder %}selected{% endif %}>
22+
{{ folder_info.name }}{% if folder_info.is_failed %} ⚠️{% endif %}{% if folder_info.round_count %} ({{ folder_info.round_count }} rounds){% endif %}
2323
</option>
2424
{% endfor %}
2525
</select>

0 commit comments

Comments
 (0)