Skip to content

Commit 89f2d74

Browse files
committed
Ref(viewer): In progress: moving to react
1 parent a360910 commit 89f2d74

22 files changed

Lines changed: 1832 additions & 44 deletions

viewer_react/backend.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,23 @@ def api_folders():
228228
return jsonify({"success": False, "error": str(e)}), 500
229229

230230

231+
def get_navigation_info(selected_folder: str) -> dict:
232+
"""Get previous and next game folders for navigation"""
233+
game_folders = find_all_game_folders()
234+
game_names = [folder["name"] for folder in game_folders if folder["is_game"]]
235+
game_names.sort()
236+
237+
try:
238+
current_index = game_names.index(selected_folder)
239+
except ValueError:
240+
return {"previous": None, "next": None}
241+
242+
previous_game = game_names[current_index - 1] if current_index > 0 else None
243+
next_game = game_names[current_index + 1] if current_index < len(game_names) - 1 else None
244+
245+
return {"previous": previous_game, "next": next_game}
246+
247+
231248
@app.route("/api/game/<path:folder_path>")
232249
def api_game(folder_path):
233250
"""Get game metadata and overview"""
@@ -274,12 +291,16 @@ def api_game(folder_path):
274291

275292
rounds.sort(key=lambda x: x["round_num"])
276293

294+
# Get navigation info
295+
navigation = get_navigation_info(folder_path)
296+
277297
return jsonify(
278298
{
279299
"success": True,
280300
"metadata": metadata,
281301
"agents": agents,
282302
"rounds": rounds,
303+
"navigation": navigation,
283304
}
284305
)
285306

@@ -527,6 +548,69 @@ def api_delete_folder():
527548
return jsonify({"success": False, "error": str(e)}), 500
528549

529550

551+
@app.route("/api/move-folder", methods=["POST"])
552+
def api_move_folder():
553+
"""Move/rename a folder"""
554+
try:
555+
data = request.get_json()
556+
old_path = data.get("old_path", "")
557+
new_path = data.get("new_path", "")
558+
559+
if not old_path or not new_path:
560+
return jsonify({"success": False, "error": "Both old_path and new_path are required"}), 400
561+
562+
old_full_path = LOG_BASE_DIR / old_path
563+
new_full_path = LOG_BASE_DIR / new_path
564+
565+
if not old_full_path.exists():
566+
return jsonify({"success": False, "error": "Source folder does not exist"}), 404
567+
568+
if new_full_path.exists():
569+
return jsonify({"success": False, "error": "Target path already exists"}), 400
570+
571+
# Security checks
572+
try:
573+
old_full_path.relative_to(LOG_BASE_DIR)
574+
new_full_path.relative_to(LOG_BASE_DIR)
575+
except ValueError:
576+
return jsonify({"success": False, "error": "Invalid path"}), 403
577+
578+
# Create parent directory if needed
579+
new_full_path.parent.mkdir(parents=True, exist_ok=True)
580+
581+
# Perform the move
582+
old_full_path.rename(new_full_path)
583+
584+
return jsonify({"success": True, "message": "Folder moved successfully", "new_path": new_path})
585+
586+
except Exception as e:
587+
logger.error(f"Error moving folder: {e}", exc_info=True)
588+
return jsonify({"success": False, "error": str(e)}), 500
589+
590+
591+
@app.route("/api/readme", methods=["GET", "POST"])
592+
def api_readme():
593+
"""Get or save readme content"""
594+
folder_path = request.args.get("folder") if request.method == "GET" else request.get_json().get("folder")
595+
596+
if not folder_path:
597+
return jsonify({"success": False, "error": "No folder specified"}), 400
598+
599+
folder = LOG_BASE_DIR / folder_path
600+
if not folder.exists() or not folder.is_dir():
601+
return jsonify({"success": False, "error": "Invalid folder"}), 404
602+
603+
readme_file = folder / "readme.txt"
604+
605+
if request.method == "GET":
606+
content = readme_file.read_text() if readme_file.exists() else ""
607+
return jsonify({"success": True, "content": content})
608+
else:
609+
content = request.get_json().get("content", "")
610+
readme_file.write_text(content)
611+
return jsonify({"success": True, "message": "Readme saved successfully"})
612+
613+
530614
# Catch-all route for React Router (must be last)
531615
@app.errorhandler(404)
532616
def not_found(e):

viewer_react/frontend/package-lock.json

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

viewer_react/frontend/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
"react": "^18.2.0",
1313
"react-dom": "^18.2.0",
1414
"react-router-dom": "^6.20.0",
15-
"axios": "^1.6.2"
15+
"axios": "^1.6.2",
16+
"chart.js": "^4.4.1",
17+
"react-chartjs-2": "^5.2.0"
1618
},
1719
"devDependencies": {
1820
"@types/react": "^18.2.43",

viewer_react/frontend/src/App.tsx

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,6 @@ function App() {
77
return (
88
<Router>
99
<div className="app">
10-
<header className="header">
11-
<div className="header-content">
12-
<h1>🎮 CodeClash Trajectory Viewer</h1>
13-
</div>
14-
</header>
15-
1610
<Routes>
1711
<Route path="/" element={<GamePicker />} />
1812
<Route path="/game/*" element={<GameViewer />} />

viewer_react/frontend/src/components/Analysis.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export function Analysis({ folderPath }: AnalysisProps) {
3333
};
3434

3535
return (
36-
<div className="card">
36+
<div className="card analysis-section">
3737
<div className="card-header" onClick={() => setIsExpanded(!isExpanded)} style={{ cursor: 'pointer' }}>
3838
<h2>
3939
Analysis
@@ -110,16 +110,11 @@ export function Analysis({ folderPath }: AnalysisProps) {
110110
}
111111

112112
function generateAsciiChart(data: SimWinsData): string {
113-
const width = 60;
114-
const height = 20;
115113
let chart = '';
116114

117115
chart += 'Win Rate (%) vs Round\n';
118116
chart += '100% ┤\n';
119117

120-
const maxRound = Math.max(...data.rounds);
121-
const minRound = Math.min(...data.rounds);
122-
123118
// Generate chart lines
124119
for (let y = 90; y >= 10; y -= 10) {
125120
let line = y.toString().padStart(4, ' ') + '% ┤';

0 commit comments

Comments
 (0)