diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f4df80..7f7988a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -87,15 +87,57 @@ jobs: frontend-build: name: Frontend Build runs-on: ubuntu-latest - - defaults: - run: - working-directory: web steps: - name: Checkout code uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + cache: 'pip' + cache-dependency-path: backend/requirements.txt + + - name: Install backend dependencies + working-directory: backend + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Start backend server + working-directory: backend + run: | + python app.py & + echo $! > backend.pid + env: + PORT: 8000 + LINKEDIN_CLIENT_ID: test_client_id + LINKEDIN_CLIENT_SECRET: test_client_secret + GROQ_API_KEY: test_groq_key + OPENAI_API_KEY: test_openai_key + ANTHROPIC_API_KEY: test_anthropic_key + DATABASE_URL: sqlite+aiosqlite:///./test.db + REDIS_URL: redis://localhost:6379/0 + ENCRYPTION_KEY: Ag45Scx9q_Q6w3xF8Lz5j2p7n9v0k1m3b5v7c9x1z3m= + CLERK_ISSUER: https://test-clerk.accounts.dev + STRIPE_SECRET_KEY: sk_test_placeholder + STRIPE_WEBHOOK_SECRET: whsec_test_placeholder + + - name: Wait for backend to be ready + run: | + echo "Waiting for backend to be healthy..." + for i in {1..30}; do + if curl -f http://localhost:8000/health > /dev/null 2>&1; then + echo "Backend is healthy!" + exit 0 + fi + echo "Attempt $i/30: Backend not ready yet..." + sleep 2 + done + echo "Backend failed to start in time" + exit 1 + - name: Set up Node.js uses: actions/setup-node@v4 with: @@ -103,16 +145,32 @@ jobs: cache: 'npm' cache-dependency-path: web/package-lock.json - - name: Install dependencies + - name: Install frontend dependencies + working-directory: web run: npm ci + - name: Generate TypeScript types from OpenAPI + run: npm run generate:types + env: + API_URL: http://localhost:8000 + - name: Build application + working-directory: web run: npm run build env: # Required for build but not for functionality NEXT_PUBLIC_API_URL: https://api.example.com NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: pk_test_placeholder + - name: Stop backend server + if: always() + working-directory: backend + run: | + if [ -f backend.pid ]; then + kill $(cat backend.pid) || true + rm backend.pid + fi + # ============================================ # Python Linting # ============================================ diff --git a/web/src/pages/settings.tsx b/web/src/pages/settings.tsx index 351cc2a..72836f6 100644 --- a/web/src/pages/settings.tsx +++ b/web/src/pages/settings.tsx @@ -8,7 +8,7 @@ * - Environment variables (GROQ_API_KEY, LINKEDIN_CLIENT_SECRET, etc.) * - Encrypted token_store.db (OAuth tokens) */ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useCallback } from 'react'; import { useRouter } from 'next/router'; import axios from 'axios'; import { useUser, UserButton, useAuth } from '@clerk/nextjs'; @@ -90,7 +90,7 @@ export default function Settings() { }, []); // Load connection status function - const loadConnectionStatus = async () => { + const loadConnectionStatus = useCallback(async () => { if (!userId) return; setLoading(true); try { @@ -114,14 +114,14 @@ export default function Settings() { } finally { setLoading(false); } - }; + }, [userId, getToken]); // Load connection status on mount and when shouldRefresh changes useEffect(() => { if (!isLoaded || !userId) return; setMounted(true); loadConnectionStatus(); - }, [isLoaded, userId, shouldRefresh]); + }, [isLoaded, userId, shouldRefresh, loadConnectionStatus]); // LinkedIn OAuth const handleConnectLinkedIn = async () => { diff --git a/web/src/types/dashboard.ts b/web/src/types/dashboard.ts index c017b9e..be14151 100644 --- a/web/src/types/dashboard.ts +++ b/web/src/types/dashboard.ts @@ -34,7 +34,7 @@ export type FullPublishRequest = components['schemas']['PublishFullRequest']; export type ScanRequest = components['schemas']['ScanRequest']; /** Request body for scheduling a post */ -export type SchedulePostRequest = components['schemas']['ScheduleRequest']; +export type SchedulePostRequest = components['schemas']['routes__posts__ScheduleRequest']; /** User settings request */ export type UserSettingsRequest = components['schemas']['SettingsRequest'];