from flask import Flask, render_template_string, request, redirect, url_for, flash, jsonify import json import os # Added os import from src.config_manager import ConfigManager from src.default_api import DefaultAPI app = Flask(__name__) app.secret_key = os.urandom(24) # Needed for flash messages config_manager = ConfigManager() default_api = DefaultAPI() CONFIG_PAGE_TEMPLATE = """ LED Matrix Config

LED Matrix Configuration

{% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {% endif %} {% endwith %}

Main Configuration ({{ main_config_path }})

Secrets Configuration ({{ secrets_config_path }})

Display & Service Actions


Action Output:

No action run yet.
""" @app.route('/') def display_config_route(): active_tab = request.args.get('tab', 'main') # Default to 'main' tab main_config_data = {} secrets_config_data = {} error_message = None try: main_config_data = config_manager.get_raw_file_content('main') except Exception as e: flash(f"Error loading main config: {str(e)}", "error") try: secrets_config_data = config_manager.get_raw_file_content('secrets') except Exception as e: flash(f"Error loading secrets config: {str(e)}", "error") main_config_json = json.dumps(main_config_data, indent=4) secrets_config_json = json.dumps(secrets_config_data, indent=4) return render_template_string(CONFIG_PAGE_TEMPLATE, main_config_json=main_config_json, secrets_config_json=secrets_config_json, active_tab=active_tab, main_config_path=config_manager.get_config_path(), secrets_config_path=config_manager.get_secrets_path()) @app.route('/save', methods=['POST']) def save_config_route(): config_type = request.form.get('config_type', 'main') data_to_save_str = "" if config_type == 'main': data_to_save_str = request.form['main_config_data'] elif config_type == 'secrets': data_to_save_str = request.form['secrets_config_data'] else: flash("Invalid configuration type specified for saving.", "error") return redirect(url_for('display_config_route')) try: new_data = json.loads(data_to_save_str) config_manager.save_raw_file_content(config_type, new_data) flash(f"{config_type.capitalize()} configuration saved successfully!", "success") except json.JSONDecodeError: flash(f"Error: Invalid JSON format submitted for {config_type} config.", "error") except Exception as e: flash(f"Error saving {config_type} configuration: {str(e)}", "error") return redirect(url_for('display_config_route', tab=config_type)) # Redirect back to the same tab @app.route('/run_action', methods=['POST']) def run_action_route(): data = request.get_json() action = data.get('action') command = None explanation_msg = "" if action == 'start_display': command = "bash start_display.sh" explanation_msg = "Starting the LED matrix display via start_display.sh." elif action == 'stop_display': command = "bash stop_display.sh" explanation_msg = "Stopping the LED matrix display via stop_display.sh." elif action == 'enable_autostart': command = "sudo systemctl enable ledmatrix.service" explanation_msg = "Enabling the LED matrix service to start on boot." elif action == 'disable_autostart': command = "sudo systemctl disable ledmatrix.service" explanation_msg = "Disabling the LED matrix service from starting on boot." else: return jsonify({"status": "error", "message": "Invalid action specified.", "error": "Unknown action"}), 400 try: # This will propose the command to the user for approval via the IDE extension. # The actual command execution happens after user approval. tool_output = default_api.run_terminal_cmd(command=command, is_background=False, explanation=explanation_msg) # Process the tool_output. The structure of tool_output depends on the tool's implementation. # We expect it to contain stdout, stderr, and an indication of success/failure (e.g., exit_code). # For this example, we'll assume tool_output might look like: # {"stdout": "...", "stderr": "...", "exit_code": 0, "command_id": "..."} # or it might directly be the stdout if the command was simple and successful without error. stdout_content = tool_output.get("stdout", "") stderr_content = tool_output.get("stderr", "") # Infer success if stderr is empty, this is a common convention but not always true. # A more robust check might involve an explicit exit_code if the tool provides it. if stderr_content: status = "error" message = f"Action '{action}' may have encountered issues." else: status = "success" message = f"Action '{action}' proposed and likely executed. Check output." # If the tool just returns a string (e.g. command_id or simple stdout), adapt as needed. if isinstance(tool_output, str): stdout_content = tool_output # Or interpret as a command ID or status message message = f"Action '{action}' proposed. Tool response: {tool_output}" if not stderr_content: # if stderr was not in a dict status = "success" else: status = "error" return jsonify({ "status": status, "message": message, "stdout": stdout_content, "stderr": stderr_content, "raw_tool_response": tool_output # For debugging if needed }) except Exception as e: return jsonify({"status": "error", "message": f"Failed to execute or process action: {action}", "error": str(e)}), 500 if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=5000)