diff --git a/backend/autometabuilder/data/routes/context.py b/backend/autometabuilder/data/routes/context.py deleted file mode 100644 index 090315e..0000000 --- a/backend/autometabuilder/data/routes/context.py +++ /dev/null @@ -1,62 +0,0 @@ -"""Context routes for dashboard state and logs.""" -from __future__ import annotations - -import os - -from flask import Blueprint - -from autometabuilder.data import ( - get_env_vars, - get_navigation_items, - get_prompt_content, - get_recent_logs, - get_ui_messages, - get_workflow_content, - list_translations, - load_metadata, - load_workflow_packages, - summarize_workflow_packages, -) -from autometabuilder.data.run_state import bot_process, current_run_config, mock_running -from autometabuilder.roadmap_utils import is_mvp_reached - -context_bp = Blueprint("context", __name__) - - -def build_context() -> dict[str, object]: - lang = os.environ.get("APP_LANG", "en") - metadata = load_metadata() - packages = load_workflow_packages() - return { - "logs": get_recent_logs(), - "env_vars": get_env_vars(), - "translations": list_translations(), - "metadata": metadata, - "navigation": get_navigation_items(), - "prompt_content": get_prompt_content(), - "workflow_content": get_workflow_content(), - "workflow_packages": summarize_workflow_packages(packages), - "workflow_packages_raw": packages, - "messages": get_ui_messages(lang), - "lang": lang, - "status": { - "is_running": bot_process is not None or mock_running, - "mvp_reached": is_mvp_reached(), - "config": current_run_config, - }, - } - - -@context_bp.route("/api/context") -def api_context() -> tuple[dict[str, object], int]: - return build_context(), 200 - - -@context_bp.route("/api/status") -def api_status() -> tuple[dict[str, object], int]: - return build_context()["status"], 200 - - -@context_bp.route("/api/logs") -def api_logs() -> tuple[dict[str, str], int]: - return {"logs": get_recent_logs()}, 200 diff --git a/backend/autometabuilder/data/routes/navigation.py b/backend/autometabuilder/data/routes/navigation.py deleted file mode 100644 index 89481f2..0000000 --- a/backend/autometabuilder/data/routes/navigation.py +++ /dev/null @@ -1,39 +0,0 @@ -"""Navigation and workflow metadata routes.""" -from __future__ import annotations - -from flask import Blueprint - -from autometabuilder.data import get_navigation_items, load_metadata, load_workflow_packages, summarize_workflow_packages -from autometabuilder.data.workflow_graph import build_workflow_graph - -navigation_bp = Blueprint("navigation", __name__) - - -@navigation_bp.route("/api/navigation") -def api_navigation() -> tuple[dict[str, object], int]: - return {"items": get_navigation_items()}, 200 - - -@navigation_bp.route("/api/workflow/packages") -def api_workflow_packages() -> tuple[dict[str, object], int]: - packages = load_workflow_packages() - return {"packages": summarize_workflow_packages(packages)}, 200 - - -@navigation_bp.route("/api/workflow/packages/") -def api_get_workflow_package(package_id: str) -> tuple[dict[str, object], int]: - packages = load_workflow_packages() - for pkg in packages: - if pkg.get("id") == package_id: - return pkg, 200 - return {"error": "package not found"}, 404 - - -@navigation_bp.route("/api/workflow/plugins") -def api_workflow_plugins() -> tuple[dict[str, object], int]: - return {"plugins": load_metadata().get("workflow_plugins", {})}, 200 - - -@navigation_bp.route("/api/workflow/graph") -def api_workflow_graph() -> tuple[dict[str, object], int]: - return build_workflow_graph(), 200 diff --git a/backend/autometabuilder/data/routes/prompt.py b/backend/autometabuilder/data/routes/prompt.py deleted file mode 100644 index 53563d5..0000000 --- a/backend/autometabuilder/data/routes/prompt.py +++ /dev/null @@ -1,30 +0,0 @@ -"""Prompt and workflow editing routes.""" -from __future__ import annotations - -from flask import Blueprint, request - -from autometabuilder.data import build_prompt_yaml, write_prompt, write_workflow - -prompt_bp = Blueprint("prompt", __name__) - - -@prompt_bp.route("/api/prompt", methods=["POST"]) -def api_prompt() -> tuple[dict[str, str], int]: - payload = request.get_json(force=True) - content = payload.get("content") - system = payload.get("system_content") - user = payload.get("user_content") - model = payload.get("model") - mode = payload.get("prompt_mode", "builder") - if mode == "raw" and content is not None: - write_prompt(content) - else: - write_prompt(build_prompt_yaml(system, user, model)) - return {"status": "ok"}, 200 - - -@prompt_bp.route("/api/workflow", methods=["POST"]) -def api_workflow() -> tuple[dict[str, str], int]: - payload = request.get_json(force=True) - write_workflow(payload.get("content", "")) - return {"status": "saved"}, 200 diff --git a/backend/autometabuilder/data/routes/run.py b/backend/autometabuilder/data/routes/run.py deleted file mode 100644 index 968edc8..0000000 --- a/backend/autometabuilder/data/routes/run.py +++ /dev/null @@ -1,19 +0,0 @@ -"""Run route for triggering the bot.""" -from __future__ import annotations - -from flask import Blueprint, request - -from autometabuilder.data.run_state import start_bot - -run_bp = Blueprint("run", __name__) - - -@run_bp.route("/api/run", methods=["POST"]) -def api_run() -> tuple[dict[str, object], int]: - payload = request.get_json(silent=True) or {} - mode = payload.get("mode", "once") - iterations = int(payload.get("iterations", 1)) - yolo = bool(payload.get("yolo", True)) - stop_at_mvp = bool(payload.get("stop_at_mvp", False)) - started = start_bot(mode, iterations, yolo, stop_at_mvp) - return {"started": started}, 202 if started else 409 diff --git a/backend/autometabuilder/data/routes/settings.py b/backend/autometabuilder/data/routes/settings.py deleted file mode 100644 index 4f344c9..0000000 --- a/backend/autometabuilder/data/routes/settings.py +++ /dev/null @@ -1,16 +0,0 @@ -"""Settings persistence route.""" -from __future__ import annotations - -from flask import Blueprint, request - -from autometabuilder.data import persist_env_vars - -settings_bp = Blueprint("settings", __name__) - - -@settings_bp.route("/api/settings", methods=["POST"]) -def api_settings() -> tuple[dict[str, str], int]: - payload = request.get_json(force=True) or {} - entries = payload.get("env", {}) or {} - persist_env_vars(entries) - return {"status": "ok"}, 200 diff --git a/backend/autometabuilder/data/routes/translations.py b/backend/autometabuilder/data/routes/translations.py deleted file mode 100644 index 9304c73..0000000 --- a/backend/autometabuilder/data/routes/translations.py +++ /dev/null @@ -1,47 +0,0 @@ -"""Translation management routes.""" -from __future__ import annotations - -from flask import Blueprint, request - -from autometabuilder.data import create_translation, delete_translation, load_metadata, load_translation, list_translations, update_translation - -translations_bp = Blueprint("translations", __name__) - - -@translations_bp.route("/api/translation-options") -def api_translation_options() -> tuple[dict[str, dict[str, str]], int]: - return {"translations": list_translations()}, 200 - - -@translations_bp.route("/api/translations", methods=["POST"]) -def api_create_translation() -> tuple[dict[str, str], int]: - payload = request.get_json(force=True) - lang = payload.get("lang") - if not lang: - return {"error": "lang required"}, 400 - ok = create_translation(lang) - return ({"created": ok}, 201 if ok else 400) - - -@translations_bp.route("/api/translations/", methods=["GET"]) -def api_get_translation(lang: str) -> tuple[dict[str, object], int]: - if lang not in load_metadata().get("messages", {}): - return {"error": "translation not found"}, 404 - return {"lang": lang, "content": load_translation(lang)}, 200 - - -@translations_bp.route("/api/translations/", methods=["PUT"]) -def api_update_translation(lang: str) -> tuple[dict[str, str], int]: - payload = request.get_json(force=True) - updated = update_translation(lang, payload) - if not updated: - return {"error": "unable to update"}, 400 - return {"status": "saved"}, 200 - - -@translations_bp.route("/api/translations/", methods=["DELETE"]) -def api_delete_translation(lang: str) -> tuple[dict[str, str], int]: - deleted = delete_translation(lang) - if not deleted: - return {"error": "cannot delete"}, 400 - return {"deleted": True}, 200 diff --git a/backend/autometabuilder/data/server.py b/backend/autometabuilder/data/server.py deleted file mode 100644 index d4c7fc2..0000000 --- a/backend/autometabuilder/data/server.py +++ /dev/null @@ -1,25 +0,0 @@ -"""Flask-based API surface that replaces the legacy FastAPI frontend.""" -from __future__ import annotations - -from flask import Flask - -from .routes.context import context_bp -from .routes.navigation import navigation_bp -from .routes.prompt import prompt_bp -from .routes.run import run_bp -from .routes.settings import settings_bp -from .routes.translations import translations_bp - -app = Flask(__name__) -app.config["JSON_SORT_KEYS"] = False - -app.register_blueprint(context_bp) -app.register_blueprint(run_bp) -app.register_blueprint(prompt_bp) -app.register_blueprint(settings_bp) -app.register_blueprint(translations_bp) -app.register_blueprint(navigation_bp) - - -def start_web_ui(host: str = "0.0.0.0", port: int = 8000) -> None: - app.run(host=host, port=port) diff --git a/backend/autometabuilder/workflow/plugin_map.json b/backend/autometabuilder/workflow/plugin_map.json index 2359209..558092b 100644 --- a/backend/autometabuilder/workflow/plugin_map.json +++ b/backend/autometabuilder/workflow/plugin_map.json @@ -108,6 +108,12 @@ "web.persist_env_vars": "autometabuilder.workflow.plugins.web.web_persist_env_vars.web_persist_env_vars.run", "web.read_json": "autometabuilder.workflow.plugins.web.web_read_json.web_read_json.run", "web.register_blueprint": "autometabuilder.workflow.plugins.web.web_register_blueprint.web_register_blueprint.run", + "web.route_context": "autometabuilder.workflow.plugins.web.web_route_context.web_route_context.run", + "web.route_navigation": "autometabuilder.workflow.plugins.web.web_route_navigation.web_route_navigation.run", + "web.route_prompt": "autometabuilder.workflow.plugins.web.web_route_prompt.web_route_prompt.run", + "web.route_run": "autometabuilder.workflow.plugins.web.web_route_run.web_route_run.run", + "web.route_settings": "autometabuilder.workflow.plugins.web.web_route_settings.web_route_settings.run", + "web.route_translations": "autometabuilder.workflow.plugins.web.web_route_translations.web_route_translations.run", "web.start_server": "autometabuilder.workflow.plugins.web.web_start_server.web_start_server.run", "web.summarize_workflow_packages": "autometabuilder.workflow.plugins.web.web_summarize_workflow_packages.web_summarize_workflow_packages.run", "web.update_translation": "autometabuilder.workflow.plugins.web.web_update_translation.web_update_translation.run", diff --git a/backend/autometabuilder/workflow/plugins/web/web_register_blueprint/web_register_blueprint.py b/backend/autometabuilder/workflow/plugins/web/web_register_blueprint/web_register_blueprint.py index 50c56f9..189e8a2 100644 --- a/backend/autometabuilder/workflow/plugins/web/web_register_blueprint/web_register_blueprint.py +++ b/backend/autometabuilder/workflow/plugins/web/web_register_blueprint/web_register_blueprint.py @@ -6,24 +6,33 @@ def run(runtime, inputs): Register a Flask blueprint with the Flask app. Inputs: - blueprint_path: Dotted path to the blueprint (e.g., "autometabuilder.web.routes.context.context_bp") + blueprint_path: Dotted path to the blueprint (e.g., "autometabuilder.data.routes.context.context_bp") + blueprint: Direct blueprint object (alternative to blueprint_path) Returns: dict: Success indicator """ - from ....loaders.callable_loader import load_callable - app = runtime.context.get("flask_app") if not app: return {"error": "Flask app not found in context. Run web.create_flask_app first."} - blueprint_path = inputs.get("blueprint_path") - if not blueprint_path: - return {"error": "blueprint_path is required"} + # Try direct blueprint first + blueprint = inputs.get("blueprint") + + # Otherwise load from path + if not blueprint: + blueprint_path = inputs.get("blueprint_path") + if not blueprint_path: + return {"error": "blueprint or blueprint_path is required"} + + from ....loaders.callable_loader import load_callable + try: + blueprint = load_callable(blueprint_path) + except Exception as e: + return {"error": f"Failed to load blueprint: {str(e)}"} try: - blueprint = load_callable(blueprint_path) app.register_blueprint(blueprint) - return {"result": f"Blueprint {blueprint_path} registered"} + return {"result": f"Blueprint {blueprint.name} registered"} except Exception as e: return {"error": f"Failed to register blueprint: {str(e)}"} diff --git a/backend/autometabuilder/workflow/plugins/web/web_route_context/package.json b/backend/autometabuilder/workflow/plugins/web/web_route_context/package.json new file mode 100644 index 0000000..2537f08 --- /dev/null +++ b/backend/autometabuilder/workflow/plugins/web/web_route_context/package.json @@ -0,0 +1,13 @@ +{ + "name": "@autometabuilder/web_route_context", + "version": "1.0.0", + "description": "Flask blueprint for context API routes", + "author": "AutoMetabuilder", + "license": "MIT", + "keywords": ["web", "workflow", "plugin", "flask", "routes"], + "main": "web_route_context.py", + "metadata": { + "plugin_type": "web.route_context", + "category": "web" + } +} diff --git a/backend/autometabuilder/workflow/plugins/web/web_route_context/web_route_context.py b/backend/autometabuilder/workflow/plugins/web/web_route_context/web_route_context.py new file mode 100644 index 0000000..2c9d843 --- /dev/null +++ b/backend/autometabuilder/workflow/plugins/web/web_route_context/web_route_context.py @@ -0,0 +1,65 @@ +"""Workflow plugin: context API routes blueprint.""" +import os +from flask import Blueprint, jsonify +from autometabuilder.loaders.metadata_loader import load_metadata +from autometabuilder.data.run_state import bot_process, current_run_config, mock_running +from autometabuilder.roadmap_utils import is_mvp_reached + + +def run(runtime, _inputs): + """Create and return the context routes blueprint.""" + context_bp = Blueprint("context", __name__) + + def build_context(): + """Build complete context for API.""" + from autometabuilder.data import ( + get_env_vars, + get_navigation_items, + get_prompt_content, + get_recent_logs, + get_ui_messages, + get_workflow_content, + list_translations, + load_workflow_packages, + summarize_workflow_packages, + ) + + lang = os.environ.get("APP_LANG", "en") + metadata = load_metadata() + packages = load_workflow_packages() + + return { + "logs": get_recent_logs(), + "env_vars": get_env_vars(), + "translations": list_translations(), + "metadata": metadata, + "navigation": get_navigation_items(), + "prompt_content": get_prompt_content(), + "workflow_content": get_workflow_content(), + "workflow_packages": summarize_workflow_packages(packages), + "workflow_packages_raw": packages, + "messages": get_ui_messages(lang), + "lang": lang, + "status": { + "is_running": bot_process is not None or mock_running, + "mvp_reached": is_mvp_reached(), + "config": current_run_config, + }, + } + + @context_bp.route("/api/context") + def api_context(): + return jsonify(build_context()), 200 + + @context_bp.route("/api/status") + def api_status(): + return jsonify(build_context()["status"]), 200 + + @context_bp.route("/api/logs") + def api_logs(): + from autometabuilder.data import get_recent_logs + return jsonify({"logs": get_recent_logs()}), 200 + + # Store in runtime context and return + runtime.context["context_bp"] = context_bp + return {"result": context_bp, "blueprint_path": "context_bp"} diff --git a/backend/autometabuilder/workflow/plugins/web/web_route_navigation/package.json b/backend/autometabuilder/workflow/plugins/web/web_route_navigation/package.json new file mode 100644 index 0000000..64c3605 --- /dev/null +++ b/backend/autometabuilder/workflow/plugins/web/web_route_navigation/package.json @@ -0,0 +1,13 @@ +{ + "name": "@autometabuilder/web_route_navigation", + "version": "1.0.0", + "description": "Flask blueprint for navigation API routes", + "author": "AutoMetabuilder", + "license": "MIT", + "keywords": ["web", "workflow", "plugin", "flask", "routes"], + "main": "web_route_navigation.py", + "metadata": { + "plugin_type": "web.route_navigation", + "category": "web" + } +} diff --git a/backend/autometabuilder/workflow/plugins/web/web_route_navigation/web_route_navigation.py b/backend/autometabuilder/workflow/plugins/web/web_route_navigation/web_route_navigation.py new file mode 100644 index 0000000..2e47bac --- /dev/null +++ b/backend/autometabuilder/workflow/plugins/web/web_route_navigation/web_route_navigation.py @@ -0,0 +1,35 @@ +"""Workflow plugin: navigation API routes blueprint.""" +from flask import Blueprint, jsonify +from autometabuilder.loaders.metadata_loader import load_metadata +from autometabuilder.data.workflow_graph import build_workflow_graph + + +def run(runtime, _inputs): + """Create and return the navigation routes blueprint.""" + navigation_bp = Blueprint("navigation", __name__) + + @navigation_bp.route("/api/navigation") + def api_navigation(): + from autometabuilder.data import get_navigation_items + return jsonify({"navigation": get_navigation_items()}), 200 + + @navigation_bp.route("/api/workflow/packages") + def api_workflow_packages(): + from autometabuilder.data import load_workflow_packages, summarize_workflow_packages + packages = load_workflow_packages() + return jsonify({"packages": summarize_workflow_packages(packages)}), 200 + + @navigation_bp.route("/api/workflow/plugins") + def api_workflow_plugins(): + metadata = load_metadata() + plugins = metadata.get("workflow_plugins", {}) + return jsonify({"plugins": plugins}), 200 + + @navigation_bp.route("/api/workflow/graph") + def api_workflow_graph(): + graph = build_workflow_graph() + return jsonify(graph), 200 + + # Store in runtime context and return + runtime.context["navigation_bp"] = navigation_bp + return {"result": navigation_bp, "blueprint_path": "navigation_bp"} diff --git a/backend/autometabuilder/workflow/plugins/web/web_route_prompt/package.json b/backend/autometabuilder/workflow/plugins/web/web_route_prompt/package.json new file mode 100644 index 0000000..531ad2c --- /dev/null +++ b/backend/autometabuilder/workflow/plugins/web/web_route_prompt/package.json @@ -0,0 +1,13 @@ +{ + "name": "@autometabuilder/web_route_prompt", + "version": "1.0.0", + "description": "Flask blueprint for prompt API routes", + "author": "AutoMetabuilder", + "license": "MIT", + "keywords": ["web", "workflow", "plugin", "flask", "routes"], + "main": "web_route_prompt.py", + "metadata": { + "plugin_type": "web.route_prompt", + "category": "web" + } +} diff --git a/backend/autometabuilder/workflow/plugins/web/web_route_prompt/web_route_prompt.py b/backend/autometabuilder/workflow/plugins/web/web_route_prompt/web_route_prompt.py new file mode 100644 index 0000000..b50a329 --- /dev/null +++ b/backend/autometabuilder/workflow/plugins/web/web_route_prompt/web_route_prompt.py @@ -0,0 +1,31 @@ +"""Workflow plugin: prompt API routes blueprint.""" +from flask import Blueprint, jsonify, request + + +def run(runtime, _inputs): + """Create and return the prompt routes blueprint.""" + prompt_bp = Blueprint("prompt", __name__) + + @prompt_bp.route("/api/prompt", methods=["POST"]) + def api_save_prompt(): + from autometabuilder.data import build_prompt_yaml, write_prompt + payload = request.get_json(force=True) + system_content = payload.get("system") + user_content = payload.get("user") + model = payload.get("model") + + content = build_prompt_yaml(system_content, user_content, model) + write_prompt(content) + return jsonify({"status": "saved"}), 200 + + @prompt_bp.route("/api/workflow", methods=["POST"]) + def api_save_workflow(): + from autometabuilder.data import write_workflow + payload = request.get_json(force=True) + content = payload.get("content", "") + write_workflow(content) + return jsonify({"status": "saved"}), 200 + + # Store in runtime context and return + runtime.context["prompt_bp"] = prompt_bp + return {"result": prompt_bp, "blueprint_path": "prompt_bp"} diff --git a/backend/autometabuilder/workflow/plugins/web/web_route_run/package.json b/backend/autometabuilder/workflow/plugins/web/web_route_run/package.json new file mode 100644 index 0000000..b4864e9 --- /dev/null +++ b/backend/autometabuilder/workflow/plugins/web/web_route_run/package.json @@ -0,0 +1,13 @@ +{ + "name": "@autometabuilder/web_route_run", + "version": "1.0.0", + "description": "Flask blueprint for run API routes", + "author": "AutoMetabuilder", + "license": "MIT", + "keywords": ["web", "workflow", "plugin", "flask", "routes"], + "main": "web_route_run.py", + "metadata": { + "plugin_type": "web.route_run", + "category": "web" + } +} diff --git a/backend/autometabuilder/workflow/plugins/web/web_route_run/web_route_run.py b/backend/autometabuilder/workflow/plugins/web/web_route_run/web_route_run.py new file mode 100644 index 0000000..48fcead --- /dev/null +++ b/backend/autometabuilder/workflow/plugins/web/web_route_run/web_route_run.py @@ -0,0 +1,26 @@ +"""Workflow plugin: run API routes blueprint.""" +from flask import Blueprint, jsonify, request +from autometabuilder.data.run_state import start_bot + + +def run(runtime, _inputs): + """Create and return the run routes blueprint.""" + run_bp = Blueprint("run", __name__) + + @run_bp.route("/api/run", methods=["POST"]) + def api_run_bot(): + payload = request.get_json(force=True) + mode = payload.get("mode", "once") + iterations = payload.get("iterations", 1) + yolo = payload.get("yolo", True) + stop_at_mvp = payload.get("stop_at_mvp", False) + + started = start_bot(mode, iterations, yolo, stop_at_mvp) + if not started: + return jsonify({"error": "Bot already running"}), 400 + + return jsonify({"status": "started"}), 200 + + # Store in runtime context and return + runtime.context["run_bp"] = run_bp + return {"result": run_bp, "blueprint_path": "run_bp"} diff --git a/backend/autometabuilder/workflow/plugins/web/web_route_settings/package.json b/backend/autometabuilder/workflow/plugins/web/web_route_settings/package.json new file mode 100644 index 0000000..49b80c8 --- /dev/null +++ b/backend/autometabuilder/workflow/plugins/web/web_route_settings/package.json @@ -0,0 +1,13 @@ +{ + "name": "@autometabuilder/web_route_settings", + "version": "1.0.0", + "description": "Flask blueprint for settings API routes", + "author": "AutoMetabuilder", + "license": "MIT", + "keywords": ["web", "workflow", "plugin", "flask", "routes"], + "main": "web_route_settings.py", + "metadata": { + "plugin_type": "web.route_settings", + "category": "web" + } +} diff --git a/backend/autometabuilder/workflow/plugins/web/web_route_settings/web_route_settings.py b/backend/autometabuilder/workflow/plugins/web/web_route_settings/web_route_settings.py new file mode 100644 index 0000000..f9183a9 --- /dev/null +++ b/backend/autometabuilder/workflow/plugins/web/web_route_settings/web_route_settings.py @@ -0,0 +1,19 @@ +"""Workflow plugin: settings API routes blueprint.""" +from flask import Blueprint, jsonify, request + + +def run(runtime, _inputs): + """Create and return the settings routes blueprint.""" + settings_bp = Blueprint("settings", __name__) + + @settings_bp.route("/api/settings", methods=["POST"]) + def api_update_settings(): + from autometabuilder.data import persist_env_vars + payload = request.get_json(force=True) + env_vars = payload.get("env_vars", {}) + persist_env_vars(env_vars) + return jsonify({"status": "saved"}), 200 + + # Store in runtime context and return + runtime.context["settings_bp"] = settings_bp + return {"result": settings_bp, "blueprint_path": "settings_bp"} diff --git a/backend/autometabuilder/workflow/plugins/web/web_route_translations/package.json b/backend/autometabuilder/workflow/plugins/web/web_route_translations/package.json new file mode 100644 index 0000000..ecac83f --- /dev/null +++ b/backend/autometabuilder/workflow/plugins/web/web_route_translations/package.json @@ -0,0 +1,13 @@ +{ + "name": "@autometabuilder/web_route_translations", + "version": "1.0.0", + "description": "Flask blueprint for translation API routes", + "author": "AutoMetabuilder", + "license": "MIT", + "keywords": ["web", "workflow", "plugin", "flask", "routes"], + "main": "web_route_translations.py", + "metadata": { + "plugin_type": "web.route_translations", + "category": "web" + } +} diff --git a/backend/autometabuilder/workflow/plugins/web/web_route_translations/web_route_translations.py b/backend/autometabuilder/workflow/plugins/web/web_route_translations/web_route_translations.py new file mode 100644 index 0000000..ce925b1 --- /dev/null +++ b/backend/autometabuilder/workflow/plugins/web/web_route_translations/web_route_translations.py @@ -0,0 +1,51 @@ +"""Workflow plugin: translation API routes blueprint.""" +from flask import Blueprint, jsonify, request +from autometabuilder.loaders.metadata_loader import load_metadata + + +def run(runtime, _inputs): + """Create and return the translations routes blueprint.""" + translations_bp = Blueprint("translations", __name__) + + @translations_bp.route("/api/translation-options") + def api_translation_options(): + from autometabuilder.data import list_translations + return jsonify({"translations": list_translations()}), 200 + + @translations_bp.route("/api/translations", methods=["POST"]) + def api_create_translation(): + from autometabuilder.data import create_translation + payload = request.get_json(force=True) + lang = payload.get("lang") + if not lang: + return jsonify({"error": "lang required"}), 400 + ok = create_translation(lang) + return jsonify({"created": ok}), (201 if ok else 400) + + @translations_bp.route("/api/translations/", methods=["GET"]) + def api_get_translation(lang): + from autometabuilder.data import load_translation + if lang not in load_metadata().get("messages", {}): + return jsonify({"error": "translation not found"}), 404 + return jsonify({"lang": lang, "content": load_translation(lang)}), 200 + + @translations_bp.route("/api/translations/", methods=["PUT"]) + def api_update_translation(lang): + from autometabuilder.data import update_translation + payload = request.get_json(force=True) + updated = update_translation(lang, payload) + if not updated: + return jsonify({"error": "unable to update"}), 400 + return jsonify({"status": "saved"}), 200 + + @translations_bp.route("/api/translations/", methods=["DELETE"]) + def api_delete_translation(lang): + from autometabuilder.data import delete_translation + deleted = delete_translation(lang) + if not deleted: + return jsonify({"error": "cannot delete"}), 400 + return jsonify({"deleted": True}), 200 + + # Store in runtime context and return + runtime.context["translations_bp"] = translations_bp + return {"result": translations_bp, "blueprint_path": "translations_bp"}