Skip to content

Commit ac4a0d8

Browse files
committed
Ref(viewer): Split up main templates in smaller templates
1 parent c3e22c9 commit ac4a0d8

10 files changed

Lines changed: 800 additions & 525 deletions

File tree

.cursor/rules/viewer.mdc

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,24 @@ two AI agent in a round-based game against each other.
1919
* Organize JavaScript into logical modules: clipboard.js, experiment.js, readme.js, json-editors.js, etc.
2020
* The application consists of two main pages: the viewer and the game picker
2121

22+
### Template Organization
23+
24+
* **Main templates**: `index.html`, `picker.html`, `no_logs.html` are in the templates root
25+
* **Sub-templates**: All partial/include templates are organized in `templates/includes/` directory
26+
* **Template structure**: Use Jinja includes to break down complex templates into manageable sub-templates
27+
* **Include naming**: Sub-templates should be named descriptively (e.g., `header.html`, `folder_path.html`, `trajectory.html`)
28+
* **Template hierarchy**: Main templates include sub-templates using `{% include 'includes/template_name.html' %}`
29+
30+
#### Current Include Templates
31+
32+
* `includes/header.html` - Navigation controls and theme toggle
33+
* `includes/folder_path.html` - Current folder display with actions
34+
* `includes/readme.html` - Editable readme section
35+
* `includes/setup.html` - Agent info, metadata, and tournament log foldouts
36+
* `includes/overview.html` - Results summary table with round navigation
37+
* `includes/trajectory.html` - Player trajectory display with messages, diffs, and files
38+
* `includes/rounds.html` - Main rounds section that includes trajectories and simulation logs
39+
2240
## Input folder
2341

2442
The input folders are all subfolders of `logs/`
@@ -314,18 +332,21 @@ Note that he last round only has the `round_n.log`, but there's no more trajecto
314332

315333
#### Trajectory view
316334

317-
This should be its own jinja template.
318-
319-
First show the following properties from the `info` section
335+
This is implemented as its own jinja template (`includes/trajectory.html`) that is included by the rounds template.
320336

321-
* Number of LM calls (api calls)
322-
* Cost (instance cost)
337+
The trajectory template displays:
323338

324-
Then, show all the messages. Each message should be its own block together with the role.
325-
Because the content can be long, make sure to have a foldout for the content.
339+
* **Trajectory Stats**: API calls, cost, and exit status from the `info` section
340+
* **Messages Foldout**: All trajectory messages with role badges and content preview/expand functionality
341+
* **Diff Foldouts**: Full diff and incremental diff sections (if available)
342+
* **Modified Files**: Changed files during the trajectory (if available)
343+
* **Submission**: Final submission content (if available)
344+
* **Memory**: Memory state content (if available)
326345

327346
**Message Role Badges**: Each message displays a small role badge (e.g., "User #1", "Assistant #2") in the top-right corner. These badges automatically hide on hover over the message block to improve readability and allow users to see text that might be obscured by the badge.
328347

348+
**Content Preview**: Long message content (>5 lines) shows a preview with expand/collapse functionality to keep the interface manageable.
349+
329350
### Important
330351

331352
* Always use the player name from the metadata.json file, do not assume players are called p1, p2, etc.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<!-- Current Folder Path -->
2+
<section class="folder-path-section">
3+
<div class="folder-path-container">
4+
<h3>📁 Current Folder:</h3>
5+
<div class="path-display">
6+
<code class="folder-path">{{ selected_folder_path }}</code>
7+
<button class="copy-path-btn" data-path="{{ selected_folder_path }}" title="Copy folder path">
8+
📋 Copy path
9+
</button>
10+
<button class="delete-experiment-btn" data-folder-path="{{ selected_folder_path }}" title="Delete this experiment">
11+
🗑️ Delete
12+
</button>
13+
</div>
14+
</div>
15+
</section>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<header class="header">
2+
<div class="header-content">
3+
<h1>🎮 CodeClash Trajectory Viewer</h1>
4+
5+
<div class="controls">
6+
<!-- Game Selection Buttons -->
7+
<div class="control-group">
8+
<button id="pick-game-btn" class="pick-game-button" title="Pick Game (Press p) - Middle-click or Ctrl+click for new tab">
9+
🎮 Pick Game <kbd>p</kbd>
10+
</button>
11+
<button id="pick-game-new-tab-btn" class="pick-game-new-tab-button" title="Pick Game in New Tab (Press P)">
12+
13+
</button>
14+
</div>
15+
16+
<!-- Dark Mode Toggle -->
17+
<div class="control-group">
18+
<button id="theme-toggle" aria-label="Toggle dark mode">
19+
<span class="theme-icon">🌙</span>
20+
</button>
21+
</div>
22+
</div>
23+
</div>
24+
</header>
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<!-- Overview Section -->
2+
<section class="overview-section">
3+
<h2>📊 Overview</h2>
4+
5+
<div class="overview-summary">
6+
<table class="results-table">
7+
<thead>
8+
<tr>
9+
<th>Round</th>
10+
<th>Winner</th>
11+
<th>Results</th>
12+
{% for trajectory in trajectories_by_round.get(1, []) %}
13+
<th>Player {{ trajectory.player_id }} Steps</th>
14+
{% endfor %}
15+
<th>Actions</th>
16+
</tr>
17+
</thead>
18+
<tbody>
19+
{% for round_data in metadata.rounds %}
20+
<tr>
21+
<td>{{ round_data.round_num }}</td>
22+
<td>
23+
{% if round_data.results and round_data.results.winner %}
24+
<span class="winner-badge">{{ round_data.results.winner }}</span>
25+
{% if round_data.results.winner_percentage %}
26+
<span class="winner-percentage">({{ round_data.results.winner_percentage }}%)</span>
27+
{% endif %}
28+
{% if round_data.results.p_value is not none %}
29+
<span class="p-value">(p={{ "%.2f"|format(round_data.results.p_value) }})</span>
30+
{% endif %}
31+
{% else %}
32+
<span class="no-result">-</span>
33+
{% endif %}
34+
</td>
35+
<td>
36+
{% if round_data.results and round_data.results.sorted_scores %}
37+
<div class="score-breakdown">
38+
{% for player, score in round_data.results.sorted_scores %}
39+
<span class="score-item">{{ player }}: {{ score }}</span>
40+
{% endfor %}
41+
</div>
42+
{% else %}
43+
<span class="no-result">-</span>
44+
{% endif %}
45+
</td>
46+
{% if trajectories_by_round.get(round_data.round_num) %}
47+
{% for trajectory in trajectories_by_round[round_data.round_num] %}
48+
<td>
49+
<span class="steps-count">{{ trajectory.api_calls }}</span>
50+
</td>
51+
{% endfor %}
52+
{% else %}
53+
{% for trajectory in trajectories_by_round.get(1, []) %}
54+
<td><span class="no-result">-</span></td>
55+
{% endfor %}
56+
{% endif %}
57+
<td>
58+
{% if metadata.agent_info %}
59+
<div class="models-cell">
60+
{% for agent in metadata.agent_info %}
61+
{% if agent.model_name %}
62+
<span class="model-tag">{{ agent.model_name }}</span>
63+
{% endif %}
64+
{% endfor %}
65+
</div>
66+
{% else %}
67+
<span class="no-result">-</span>
68+
{% endif %}
69+
</td>
70+
<td>
71+
<button class="nav-to-round-btn" data-round="{{ round_data.round_num }}" title="Jump to Round {{ round_data.round_num }} details">
72+
<span class="nav-arrow"></span>
73+
</button>
74+
</td>
75+
</tr>
76+
{% endfor %}
77+
</tbody>
78+
</table>
79+
</div>
80+
</section>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<!-- Readme Section -->
2+
<section class="readme-section">
3+
<h2>📝 Readme</h2>
4+
<div class="readme-container">
5+
<textarea id="readme-textarea" class="readme-textarea" placeholder="Add notes about this experiment..."></textarea>
6+
<div class="readme-status" id="readme-status">Loading...</div>
7+
</div>
8+
</section>
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<!-- Rounds Section -->
2+
<section class="rounds-section">
3+
<h2>🎯 Detailed Rounds</h2>
4+
5+
{% for round_data in metadata.rounds %}
6+
{% set round_num = round_data.round_num %}
7+
8+
<!-- Round Anchor for Navigation -->
9+
<div id="round-{{ round_num }}" class="round-anchor"></div>
10+
11+
<!-- Player Trajectories for this round -->
12+
{% if round_num in trajectories_by_round %}
13+
{% for trajectory in trajectories_by_round[round_num] %}
14+
{% include 'includes/trajectory.html' %}
15+
{% endfor %}
16+
{% endif %}
17+
18+
<!-- Round Simulation Logs -->
19+
<details class="foldout round-foldout">
20+
<summary>🎮 Round {{ round_num }} Simulation Logs ({{ round_data.sim_logs|length }} sims)</summary>
21+
<div class="log-content">
22+
{% for sim_log in round_data.sim_logs %}
23+
<details class="foldout sim-foldout">
24+
<summary>
25+
{{ sim_log.filename }}
26+
<button class="copy-path-btn-small" data-path="{{ sim_log.full_path }}" title="Copy file path">
27+
📋 Copy path
28+
</button>
29+
</summary>
30+
<div class="log-content">
31+
<pre><code>{{ sim_log.content }}</code></pre>
32+
</div>
33+
</details>
34+
{% endfor %}
35+
</div>
36+
</details>
37+
38+
<!-- Round Results (if available) -->
39+
{% if round_data.results %}
40+
<details class="foldout round-foldout">
41+
<summary>
42+
🏆 Round {{ round_num }} Results
43+
{% if round_data.results.winner and round_data.results.scores %}
44+
{%- set total_games = round_data.results.scores.values() | sum -%}
45+
{%- set winner = round_data.results.winner -%}
46+
{%- if winner != 'Tie' -%}
47+
{%- set winner_wins = round_data.results.scores.get(winner, 0) -%}
48+
{%- set ties = round_data.results.scores.get('Tie', 0) -%}
49+
{%- set win_percentage = ((winner_wins + 0.5 * ties) / total_games * 100) | round(1) -%}
50+
- Winner: {{ winner }} with {{ win_percentage }}%
51+
{%- if round_data.results.p_value is not none %} (p={{ "%.2f"|format(round_data.results.p_value) }}){% endif %} (
52+
{%- for player, score in round_data.results.scores.items() -%}
53+
{{- score -}}
54+
{%- if not loop.last -%}-{%- endif -%}
55+
{%- endfor -%})
56+
{%- else -%}
57+
- Winner: Tie
58+
{%- if round_data.results.p_value is not none %} (p={{ "%.2f"|format(round_data.results.p_value) }}){% endif %} (
59+
{%- for player, score in round_data.results.scores.items() -%}
60+
{{- score -}}
61+
{%- if not loop.last -%}-{%- endif -%}
62+
{%- endfor -%})
63+
{% endif %}
64+
{% endif %}
65+
</summary>
66+
<div class="log-content">
67+
<div id="round-{{ round_num }}-results-jsoneditor" class="json-viewer"></div>
68+
</div>
69+
</details>
70+
{% endif %}
71+
72+
<!-- Round separator (except after the last round) -->
73+
{% if not loop.last %}
74+
<div class="round-separator"></div>
75+
{% endif %}
76+
77+
{% endfor %}
78+
</section>
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<!-- Setup Section -->
2+
<section class="setup-section">
3+
<h2>⚙️ Setup</h2>
4+
5+
<!-- Agent Information -->
6+
<div class="agent-info">
7+
{% if metadata.agent_info %}
8+
<div class="agents-grid">
9+
{% for agent in metadata.agent_info %}
10+
<div class="agent-card">
11+
<div class="agent-name">{{ agent.name }}</div>
12+
{% if agent.model_name %}
13+
<div class="agent-model">Model: {{ agent.model_name }}</div>
14+
{% endif %}
15+
{% if agent.agent_class %}
16+
<div class="agent-class">Class: {{ agent.agent_class }}</div>
17+
{% endif %}
18+
</div>
19+
{% endfor %}
20+
</div>
21+
{% else %}
22+
<p>No agent information available</p>
23+
{% endif %}
24+
</div>
25+
26+
<!-- Metadata Foldout -->
27+
<details class="foldout">
28+
<summary>
29+
📋 Metadata
30+
{% if metadata.metadata_file_path %}
31+
<button class="copy-path-btn-small" data-path="{{ metadata.metadata_file_path }}" title="Copy metadata file path">
32+
📋 Copy path
33+
</button>
34+
{% endif %}
35+
</summary>
36+
<div class="metadata-display">
37+
<div id="metadata-jsoneditor" class="json-viewer"></div>
38+
</div>
39+
</details>
40+
41+
<!-- Main Log Foldout -->
42+
<details class="foldout">
43+
<summary>
44+
📝 Tournament Log
45+
{% if metadata.main_log_path %}
46+
<button class="copy-path-btn-small" data-path="{{ metadata.main_log_path }}" title="Copy file path">
47+
📋 Copy path
48+
</button>
49+
{% endif %}
50+
</summary>
51+
<div class="log-content">
52+
<pre><code>{{ metadata.main_log }}</code></pre>
53+
</div>
54+
</details>
55+
</section>

0 commit comments

Comments
 (0)