Skip to content

Commit fb1fc66

Browse files
committed
Enh(viewer): Show models in picker
1 parent 78ab590 commit fb1fc66

3 files changed

Lines changed: 99 additions & 12 deletions

File tree

β€Žcodeclash/viewer/app.pyβ€Ž

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,38 @@ def get_round_count_from_metadata(log_dir: Path) -> int | None:
4141
return None
4242

4343

44+
def get_models_from_metadata(log_dir: Path) -> list[str]:
45+
"""Extract model names from metadata.json if it exists"""
46+
metadata_file = log_dir / "metadata.json"
47+
if not metadata_file.exists():
48+
return []
49+
50+
try:
51+
metadata = json.loads(metadata_file.read_text())
52+
models = []
53+
players_config = metadata.get("config", {}).get("players", [])
54+
55+
# Handle both list and dict formats
56+
if isinstance(players_config, list):
57+
# If players is a list, iterate through each player
58+
for player_config in players_config:
59+
if isinstance(player_config, dict):
60+
model_name = player_config.get("config", {}).get("model", {}).get("model_name")
61+
if model_name and model_name not in models:
62+
models.append(model_name)
63+
elif isinstance(players_config, dict):
64+
# If players is a dict, iterate through player keys (p1, p2, etc.)
65+
for _player_key, player_config in players_config.items():
66+
if isinstance(player_config, dict):
67+
model_name = player_config.get("config", {}).get("model", {}).get("model_name")
68+
if model_name and model_name not in models:
69+
models.append(model_name)
70+
71+
return models
72+
except (json.JSONDecodeError, KeyError, AttributeError):
73+
return []
74+
75+
4476
def find_all_game_folders(base_dir: Path) -> list[dict[str, Any]]:
4577
"""Recursively find all folders and mark which ones contain metadata.json"""
4678
all_folders = []
@@ -60,12 +92,14 @@ def scan_directory(directory: Path, relative_path: str = ""):
6092
# Check if this directory is a game folder
6193
if is_game_folder(item):
6294
round_count = get_round_count_from_metadata(item)
95+
models = get_models_from_metadata(item)
6396
game_folders.add(current_relative)
6497
all_folders.append(
6598
{
6699
"name": current_relative,
67100
"full_path": str(item),
68101
"round_count": round_count,
102+
"models": models,
69103
"is_game": True,
70104
"depth": depth,
71105
"parent": relative_path if relative_path else None,
@@ -78,6 +112,7 @@ def scan_directory(directory: Path, relative_path: str = ""):
78112
"name": current_relative,
79113
"full_path": str(item),
80114
"round_count": None,
115+
"models": [],
81116
"is_game": False,
82117
"depth": depth,
83118
"parent": relative_path if relative_path else None,

β€Žcodeclash/viewer/static/css/picker.cssβ€Ž

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* Game Picker Styles */
22

33
.picker-container {
4-
max-width: 1000px;
4+
max-width: 1400px;
55
margin: 2rem auto;
66
padding: 0 1rem;
77
}
@@ -56,15 +56,15 @@
5656
padding: 1rem;
5757
border-bottom: 1px solid var(--border-color);
5858
display: grid;
59-
grid-template-columns: 1fr auto auto;
59+
grid-template-columns: 1fr 100px 180px 140px;
6060
gap: 1rem;
6161
font-weight: 600;
6262
color: var(--text-primary);
6363
}
6464

6565
.game-row {
6666
display: grid;
67-
grid-template-columns: 1fr auto auto;
67+
grid-template-columns: 1fr 100px 180px 140px;
6868
gap: 1rem;
6969
padding: 0.75rem 1rem;
7070
border-bottom: 1px solid var(--border-color);
@@ -145,7 +145,7 @@
145145
display: flex;
146146
align-items: center;
147147
justify-content: center;
148-
min-width: 80px;
148+
width: 100px;
149149
}
150150

151151
.rounds-count {
@@ -165,8 +165,38 @@
165165
font-style: italic;
166166
}
167167

168+
.models-cell {
169+
display: flex;
170+
align-items: center;
171+
justify-content: flex-start;
172+
gap: 0.25rem;
173+
width: 180px;
174+
flex-wrap: wrap;
175+
padding: 0.25rem;
176+
}
177+
178+
.model-tag {
179+
background-color: var(--success-color);
180+
color: white;
181+
padding: 0.125rem 0.375rem;
182+
border-radius: 0.75rem;
183+
font-size: 0.7rem;
184+
font-weight: 500;
185+
white-space: nowrap;
186+
max-width: 120px;
187+
overflow: hidden;
188+
text-overflow: ellipsis;
189+
flex-shrink: 0;
190+
}
191+
192+
.models-unknown {
193+
color: var(--text-muted);
194+
font-size: 0.8rem;
195+
font-style: italic;
196+
}
197+
168198
.action-cell {
169-
min-width: 120px;
199+
width: 140px;
170200
display: flex;
171201
justify-content: center;
172202
gap: 0.5rem;
@@ -236,18 +266,29 @@
236266

237267
.table-header,
238268
.game-row {
239-
grid-template-columns: 1fr auto;
269+
grid-template-columns: 1fr 80px 120px;
240270
gap: 0.5rem;
241271
}
242272

243273
.rounds-cell {
244-
min-width: 60px;
274+
width: 80px;
275+
}
276+
277+
.models-cell {
278+
width: 120px;
279+
justify-content: flex-start;
245280
}
246281

247282
.action-cell {
248283
display: none; /* Hide action buttons on mobile, click row instead */
249284
}
250285

286+
.model-tag {
287+
font-size: 0.6rem;
288+
padding: 0.1rem 0.25rem;
289+
max-width: 80px;
290+
}
291+
251292
.game-name {
252293
font-size: 0.85rem;
253294
}

β€Žcodeclash/viewer/templates/picker.htmlβ€Ž

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,12 @@ <h3>πŸ“ Base Directory:</h3>
2828

2929
{% if game_folders %}
3030
<div class="games-table">
31-
<div class="table-header">
32-
<div>πŸ“ Game Session</div>
33-
<div>🎯 Rounds</div>
34-
<div>Action</div>
35-
</div>
31+
<div class="table-header">
32+
<div>πŸ“ Game Session</div>
33+
<div>🎯 Rounds</div>
34+
<div>πŸ€– Models</div>
35+
<div>Action</div>
36+
</div>
3637
{% for game in game_folders %}
3738
{% set depth = game.name.count('/') %}
3839
{% set folder_name = game.name.split('/')[-1] %}
@@ -69,6 +70,16 @@ <h3>πŸ“ Base Directory:</h3>
6970
{% endif %}
7071
</div>
7172

73+
<div class="models-cell">
74+
{% if game.is_game and game.models %}
75+
{% for model in game.models %}
76+
<span class="model-tag">{{ model }}</span>
77+
{% endfor %}
78+
{% else %}
79+
<span class="models-unknown">-</span>
80+
{% endif %}
81+
</div>
82+
7283
<div class="action-cell">
7384
{% if game.is_game %}
7485
<button class="open-button" onmousedown="event.stopPropagation(); handleGameClick(event, '{{ game.name }}')">

0 commit comments

Comments
Β (0)