diff --git a/backend/migrations.db b/backend/migrations.db index 3153f44..25d54ec 100644 Binary files a/backend/migrations.db and b/backend/migrations.db differ diff --git a/backend/src/api/routes/environments.py b/backend/src/api/routes/environments.py index 3f7ff36..dde6686 100644 --- a/backend/src/api/routes/environments.py +++ b/backend/src/api/routes/environments.py @@ -39,6 +39,9 @@ class DatabaseResponse(BaseModel): @router.get("", response_model=List[EnvironmentResponse]) async def get_environments(config_manager=Depends(get_config_manager)): envs = config_manager.get_environments() + # Ensure envs is a list + if not isinstance(envs, list): + envs = [] return [EnvironmentResponse(id=e.id, name=e.name, url=e.url) for e in envs] # [/DEF:get_environments] diff --git a/backend/src/api/routes/tasks.py b/backend/src/api/routes/tasks.py index 418615d..921a730 100755 --- a/backend/src/api/routes/tasks.py +++ b/backend/src/api/routes/tasks.py @@ -22,7 +22,7 @@ class ResolveTaskRequest(BaseModel): class ResumeTaskRequest(BaseModel): passwords: Dict[str, str] -@router.post("/", response_model=Task, status_code=status.HTTP_201_CREATED) +@router.post("", response_model=Task, status_code=status.HTTP_201_CREATED) async def create_task( request: CreateTaskRequest, task_manager: TaskManager = Depends(get_task_manager) @@ -39,7 +39,7 @@ async def create_task( except ValueError as e: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e)) -@router.get("/", response_model=List[Task]) +@router.get("", response_model=List[Task]) async def list_tasks( limit: int = 10, offset: int = 0, @@ -107,7 +107,7 @@ async def resume_task( except ValueError as e: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e)) -@router.delete("/", status_code=status.HTTP_204_NO_CONTENT) +@router.delete("", status_code=status.HTTP_204_NO_CONTENT) async def clear_tasks( status: Optional[TaskStatus] = None, task_manager: TaskManager = Depends(get_task_manager) diff --git a/backend/src/app.py b/backend/src/app.py index 82a964c..1a0933d 100755 --- a/backend/src/app.py +++ b/backend/src/app.py @@ -11,7 +11,7 @@ from pathlib import Path project_root = Path(__file__).resolve().parent.parent.parent sys.path.append(str(project_root)) -from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Depends +from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Depends, Request from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse @@ -45,6 +45,13 @@ app.add_middleware( ) +@app.middleware("http") +async def log_requests(request: Request, call_next): + logger.info(f"[DEBUG] Incoming request: {request.method} {request.url.path}") + response = await call_next(request) + logger.info(f"[DEBUG] Response status: {response.status_code} for {request.url.path}") + return response + # Include API routes app.include_router(plugins.router, prefix="/api/plugins", tags=["Plugins"]) app.include_router(tasks.router, prefix="/api/tasks", tags=["Tasks"]) diff --git a/backend/src/core/task_manager/manager.py b/backend/src/core/task_manager/manager.py index 5900502..b0a9c69 100644 --- a/backend/src/core/task_manager/manager.py +++ b/backend/src/core/task_manager/manager.py @@ -353,8 +353,8 @@ class TaskManager: if task.status == status: should_remove = True else: - # Clear all non-active tasks - if task.status not in [TaskStatus.RUNNING]: + # Clear all non-active tasks (keep RUNNING, AWAITING_INPUT, AWAITING_MAPPING) + if task.status not in [TaskStatus.RUNNING, TaskStatus.AWAITING_INPUT, TaskStatus.AWAITING_MAPPING]: should_remove = True if should_remove: diff --git a/backend/src/core/task_manager/persistence.py b/backend/src/core/task_manager/persistence.py index 8fa2696..38d3abe 100644 --- a/backend/src/core/task_manager/persistence.py +++ b/backend/src/core/task_manager/persistence.py @@ -42,6 +42,7 @@ class TaskPersistenceService: cursor.execute(""" CREATE TABLE IF NOT EXISTS persistent_tasks ( id TEXT PRIMARY KEY, + plugin_id TEXT NOT NULL, status TEXT NOT NULL, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, @@ -68,10 +69,11 @@ class TaskPersistenceService: if task.status == TaskStatus.AWAITING_INPUT: cursor.execute(""" INSERT OR REPLACE INTO persistent_tasks - (id, status, created_at, updated_at, input_request, context) - VALUES (?, ?, ?, ?, ?, ?) + (id, plugin_id, status, created_at, updated_at, input_request, context) + VALUES (?, ?, ?, ?, ?, ?, ?) """, ( task.id, + task.plugin_id, task.status.value, task.started_at.isoformat() if task.started_at else datetime.utcnow().isoformat(), datetime.utcnow().isoformat(), @@ -98,16 +100,30 @@ class TaskPersistenceService: conn = sqlite3.connect(str(self.db_path)) cursor = conn.cursor() - cursor.execute("SELECT id, status, created_at, input_request, context FROM persistent_tasks") + # Check if plugin_id column exists (migration for existing db) + cursor.execute("PRAGMA table_info(persistent_tasks)") + columns = [info[1] for info in cursor.fetchall()] + has_plugin_id = "plugin_id" in columns + + if has_plugin_id: + cursor.execute("SELECT id, plugin_id, status, created_at, input_request, context FROM persistent_tasks") + else: + cursor.execute("SELECT id, status, created_at, input_request, context FROM persistent_tasks") + rows = cursor.fetchall() loaded_tasks = [] for row in rows: - task_id, status, created_at, input_request_json, context_json = row + if has_plugin_id: + task_id, plugin_id, status, created_at, input_request_json, context_json = row + else: + task_id, status, created_at, input_request_json, context_json = row + plugin_id = "superset-migration" # Default fallback + try: task = Task( id=task_id, - plugin_id="migration", # Default, assumes migration context for now + plugin_id=plugin_id, status=TaskStatus(status), started_at=datetime.fromisoformat(created_at), input_required=True, diff --git a/frontend/vite.config.js b/frontend/vite.config.js index 46ce1c5..c6b3f57 100755 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -6,13 +6,16 @@ export default defineConfig({ server: { proxy: { '/api': { - target: 'http://localhost:8000', - changeOrigin: true + target: 'http://127.0.0.1:8000', + changeOrigin: true, + secure: false, + rewrite: (path) => path.replace(/^\/api/, '/api') }, '/ws': { - target: 'ws://localhost:8000', + target: 'ws://127.0.0.1:8000', ws: true, - changeOrigin: true + changeOrigin: true, + secure: false } } } diff --git a/tests/output.txt b/tests/output.txt new file mode 100644 index 0000000..e69de29 diff --git a/tests/output_safe.txt b/tests/output_safe.txt new file mode 100644 index 0000000..e69de29