@@ -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>" )
232249def 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 )
532616def not_found (e ):
0 commit comments