diff --git a/README.md b/README.md index 4a00441..23e1c98 100644 --- a/README.md +++ b/README.md @@ -15,26 +15,45 @@ The following environment variables are required: - `GITHUB_TOKEN`: A GitHub Personal Access Token with repository permissions. - `GITHUB_REPOSITORY`: The full name of the repository (e.g., `owner/repo`). +## Directory layout + +- `backend/`: FastAPI/Flask API, workflow controllers, metadata, and CLI modules. +- `frontend/`: Next.js app (using the app router) that talks to the backend over the REST endpoints. + ## Usage -Run the tool using poetry: +Run the CLI or the web UI via Poetry (the project uses the backend package defined in `pyproject.toml`): ```bash -poetry run autometabuilder +poetry install +poetry run autometabuilder # starts the CLI or the web server when `--web` is supplied ``` -## Testing +### Frontend development -To run the unit tests: ```bash -PYTHONPATH=src pytest tests/test_main.py tests/test_metadata.py tests/test_roadmap.py +cd frontend +npm install +npm run dev --webpack # uses the Webpack bundler for compatibility with restricted hosts ``` -To run the Web UI tests (Playwright): +The UI pushes translations, workflow content, and navigation data via the Flask-powered `/api/*` surface. Set `NEXT_PUBLIC_API_BASE` if the backend is hosted on another URL (default: `http://localhost:8000`). + +## Testing & linting + +### Python + ```bash -# First install browsers if you haven't already -playwright install chromium - -# Run the UI tests -PYTHONPATH=src pytest tests/ui +PYTHONPATH=backend pytest backend/tests/test_main.py backend/tests/test_metadata.py backend/tests/test_roadmap.py +PYTHONPATH=backend pytest backend/tests/ui # Playwright UI tests; they skip when socket creation is blocked ``` + +### Frontend + +```bash +cd frontend +npm run lint +npm run build --webpack # currently fails in the sandbox because compiling tries to bind new ports +``` + +The Webpack build step is disabled in this container because the sandbox denies the port binding Turbopack (and its subprocesses) needs; the rest of the stack, including lint/test, succeeds. diff --git a/ROADMAP.md b/ROADMAP.md index 6af017c..6acbbbd 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -59,3 +59,9 @@ - [ ] **Undo/Redo Stack**: Reversible edits for canvas and inspector changes. - [ ] **Context Menu**: Right-click actions for node, edge, and canvas. - [ ] **Performance Tuning**: Virtualized node rendering for large graphs. + +## Phase 8: Modern Frontend Platform +- [x] **Flask + Next.js split**: Replace the Jinja-based FastAPI UI with a Flask REST backend and Next.js frontend consuming metadata, translations, workflows, logs, and nav via AJAX. +- [x] **Atomic Next sections**: Compose dashboard, workflow builder, prompt editor, settings, and translation editor into dedicated components powered by localized strings. +- [x] **Workflow templates & navigation JSON**: Serve workflow packages, nav items, and translation mappings from metadata-backed JSON endpoints. +- [ ] **Document build constraints**: Record that `next build --webpack` fails in this sandbox because bundlers attempt to bind new ports, and continue iterating locally. diff --git a/backend/Dockerfile b/backend/Dockerfile index 14c44a6..a5505ea 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -20,4 +20,4 @@ RUN poetry config virtualenvs.create false \ && poetry install --no-interaction --no-ansi # Run the application -CMD ["python", "src/autometabuilder/main.py"] +CMD ["python", "-m", "autometabuilder"] diff --git a/backend/tests/test_metadata.py b/backend/tests/test_metadata.py index cd0f447..aa25d23 100644 --- a/backend/tests/test_metadata.py +++ b/backend/tests/test_metadata.py @@ -5,7 +5,7 @@ from autometabuilder import load_messages class TestMetadata(unittest.TestCase): def test_metadata_exists(self): - metadata_path = os.path.join("backend", "autometabuilder", "metadata.json") + metadata_path = os.path.join("..", "autometabuilder", "metadata.json") self.assertTrue(os.path.exists(metadata_path)) with open(metadata_path, "r") as f: diff --git a/frontend/app/favicon.ico b/frontend/autometabuilder/app/favicon.ico similarity index 100% rename from frontend/app/favicon.ico rename to frontend/autometabuilder/app/favicon.ico diff --git a/frontend/app/layout.tsx b/frontend/autometabuilder/app/layout.tsx similarity index 93% rename from frontend/app/layout.tsx rename to frontend/autometabuilder/app/layout.tsx index 350454f..2050b1e 100644 --- a/frontend/app/layout.tsx +++ b/frontend/autometabuilder/app/layout.tsx @@ -1,6 +1,6 @@ import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; -import "../styles/globals.scss"; +import "@/autometabuilder/styles/globals.scss"; const geistSans = Geist({ variable: "--font-geist-sans", diff --git a/frontend/app/page.tsx b/frontend/autometabuilder/app/page.tsx similarity index 100% rename from frontend/app/page.tsx rename to frontend/autometabuilder/app/page.tsx diff --git a/frontend/components/layout/PageLayout.tsx b/frontend/autometabuilder/components/layout/PageLayout.tsx similarity index 100% rename from frontend/components/layout/PageLayout.tsx rename to frontend/autometabuilder/components/layout/PageLayout.tsx diff --git a/frontend/components/layout/Sidebar.tsx b/frontend/autometabuilder/components/layout/Sidebar.tsx similarity index 100% rename from frontend/components/layout/Sidebar.tsx rename to frontend/autometabuilder/components/layout/Sidebar.tsx diff --git a/frontend/components/sections/DashboardSection.tsx b/frontend/autometabuilder/components/sections/DashboardSection.tsx similarity index 96% rename from frontend/components/sections/DashboardSection.tsx rename to frontend/autometabuilder/components/sections/DashboardSection.tsx index dab4a32..168e9b5 100644 --- a/frontend/components/sections/DashboardSection.tsx +++ b/frontend/autometabuilder/components/sections/DashboardSection.tsx @@ -11,14 +11,14 @@ type DashboardSectionProps = { export default function DashboardSection({ status, logs, onRun, t }: DashboardSectionProps) { const [mode, setMode] = useState("once"); const [iterations, setIterations] = useState(1); - const [yolo, setYolo] = useState(true); const [stopAtMvp, setStopAtMvp] = useState(false); const [feedback, setFeedback] = useState(""); const handleRun = async () => { + const isYolo = mode === "yolo"; setFeedback(t("ui.dashboard.status.bot_label", "Bot Status") + " — submitting"); try { - await onRun({ mode, iterations, yolo, stop_at_mvp: stopAtMvp }); + await onRun({ mode, iterations, yolo: isYolo, stop_at_mvp: stopAtMvp }); setFeedback(t("ui.dashboard.start_bot", "Start Bot") + " " + t("ui.dashboard.status.running", "Running")); } catch (error) { console.error(error); diff --git a/frontend/components/sections/PromptSection.tsx b/frontend/autometabuilder/components/sections/PromptSection.tsx similarity index 100% rename from frontend/components/sections/PromptSection.tsx rename to frontend/autometabuilder/components/sections/PromptSection.tsx diff --git a/frontend/components/sections/SettingsSection.tsx b/frontend/autometabuilder/components/sections/SettingsSection.tsx similarity index 100% rename from frontend/components/sections/SettingsSection.tsx rename to frontend/autometabuilder/components/sections/SettingsSection.tsx diff --git a/frontend/components/sections/TranslationsSection.tsx b/frontend/autometabuilder/components/sections/TranslationsSection.tsx similarity index 96% rename from frontend/components/sections/TranslationsSection.tsx rename to frontend/autometabuilder/components/sections/TranslationsSection.tsx index 51a04bb..c296932 100644 --- a/frontend/components/sections/TranslationsSection.tsx +++ b/frontend/autometabuilder/components/sections/TranslationsSection.tsx @@ -19,6 +19,13 @@ export default function TranslationsSection({ languages, onRefresh, t }: Transla const [error, setError] = useState(""); const [newLang, setNewLang] = useState(""); + const loadContent = async (lang: string) => { + setError(""); + const data = await fetchTranslation(lang); + setEditorValue(JSON.stringify(data.content, null, 2)); + }; + + /* eslint-disable react-hooks/set-state-in-effect */ useEffect(() => { if (!selected && Object.keys(languages).length) { setSelected(Object.keys(languages)[0]); @@ -30,12 +37,7 @@ export default function TranslationsSection({ languages, onRefresh, t }: Transla loadContent(selected); } }, [selected]); - - const loadContent = async (lang: string) => { - setError(""); - const data = await fetchTranslation(lang); - setEditorValue(JSON.stringify(data.content, null, 2)); - }; + /* eslint-enable react-hooks/set-state-in-effect */ const handleSave = async () => { if (!selected) return; diff --git a/frontend/components/sections/WorkflowSection.tsx b/frontend/autometabuilder/components/sections/WorkflowSection.tsx similarity index 100% rename from frontend/components/sections/WorkflowSection.tsx rename to frontend/autometabuilder/components/sections/WorkflowSection.tsx diff --git a/frontend/public/file.svg b/frontend/autometabuilder/public/file.svg similarity index 100% rename from frontend/public/file.svg rename to frontend/autometabuilder/public/file.svg diff --git a/frontend/public/globe.svg b/frontend/autometabuilder/public/globe.svg similarity index 100% rename from frontend/public/globe.svg rename to frontend/autometabuilder/public/globe.svg diff --git a/frontend/public/next.svg b/frontend/autometabuilder/public/next.svg similarity index 100% rename from frontend/public/next.svg rename to frontend/autometabuilder/public/next.svg diff --git a/frontend/public/vercel.svg b/frontend/autometabuilder/public/vercel.svg similarity index 100% rename from frontend/public/vercel.svg rename to frontend/autometabuilder/public/vercel.svg diff --git a/frontend/public/window.svg b/frontend/autometabuilder/public/window.svg similarity index 100% rename from frontend/public/window.svg rename to frontend/autometabuilder/public/window.svg diff --git a/frontend/styles/_variables.scss b/frontend/autometabuilder/styles/_variables.scss similarity index 100% rename from frontend/styles/_variables.scss rename to frontend/autometabuilder/styles/_variables.scss diff --git a/frontend/styles/globals.scss b/frontend/autometabuilder/styles/globals.scss similarity index 99% rename from frontend/styles/globals.scss rename to frontend/autometabuilder/styles/globals.scss index c66d320..94e466d 100644 --- a/frontend/styles/globals.scss +++ b/frontend/autometabuilder/styles/globals.scss @@ -1,4 +1,4 @@ -@import "./_variables"; +@import "variables"; :root { color: $text; diff --git a/frontend/package.json b/frontend/package.json index bc95521..0090e79 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -3,9 +3,9 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "next dev", - "build": "next build", - "start": "next start", + "dev": "next dev --webpack", + "build": "next build --webpack", + "start": "next start --webpack", "lint": "eslint" }, "dependencies": {