From 3d139712139a289a2d5f718e6259754e80733946 Mon Sep 17 00:00:00 2001 From: raiden9420 Date: Thu, 30 Apr 2026 22:49:53 +0530 Subject: [PATCH 1/7] Removed Dummy UI and dead code --- .gitignore | 2 +- backend/main.py | 68 +---------- frontend/package-lock.json | 28 ++--- frontend/src/App.jsx | 56 ++------- frontend/src/components/ActionsCard.jsx | 9 +- frontend/src/components/AuthProvider.jsx | 61 ---------- frontend/src/components/GeneInfo.jsx | 9 +- frontend/src/components/LoginPage.jsx | 111 ----------------- frontend/src/components/Sidebar.jsx | 149 +---------------------- frontend/src/components/TopBar.jsx | 123 +------------------ frontend/src/lib/supabaseClient.js | 20 --- frontend/src/main.jsx | 5 +- 12 files changed, 30 insertions(+), 611 deletions(-) delete mode 100644 frontend/src/components/AuthProvider.jsx delete mode 100644 frontend/src/components/LoginPage.jsx delete mode 100644 frontend/src/lib/supabaseClient.js diff --git a/.gitignore b/.gitignore index 4c4563d..9b1ee87 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ node_modules .pnp.js myenv/ venv/ - +*.md # testing coverage diff --git a/backend/main.py b/backend/main.py index 066ad1d..30e1bb8 100644 --- a/backend/main.py +++ b/backend/main.py @@ -2,8 +2,11 @@ Protly Backend — FastAPI server for ESMFold protein structure prediction. Endpoints: - GET /api/health → health check - POST /api/predict → accepts { sequence: str }, returns PDB + pLDDT data + GET /api/health → health check + POST /api/predict → accepts { sequence: str }, returns PDB + pLDDT data + GET /api/uniprot/search → proxy UniProt search + GET /api/uniprot/entry/{id} → fetch full UniProt entry + POST /api/analyze → Biopython lab-readiness metrics """ import re @@ -22,7 +25,6 @@ from slowapi import Limiter, _rate_limit_exceeded_handler from slowapi.util import get_remote_address from slowapi.errors import RateLimitExceeded -from jose import jwt, JWTError from dotenv import load_dotenv load_dotenv() @@ -46,15 +48,6 @@ app.state.limiter = limiter app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler) -# --------------------------------------------------------------------------- -# Supabase Auth Config -# --------------------------------------------------------------------------- -SUPABASE_URL = os.getenv("SUPABASE_URL", "") -SUPABASE_JWT_SECRET = os.getenv("SUPABASE_JWT_SECRET", "") -SUPABASE_ANON_KEY = os.getenv("SUPABASE_ANON_KEY", "") - -if not SUPABASE_JWT_SECRET: - logger.warning("SUPABASE_JWT_SECRET is not set — JWT auth verification will be skipped!") # --------------------------------------------------------------------------- # CORS — allow the Vite dev server and common local origins @@ -68,7 +61,7 @@ allow_origins=ALLOWED_ORIGINS, allow_credentials=True, allow_methods=["GET", "POST", "OPTIONS"], - allow_headers=["Authorization", "Content-Type", "X-Requested-With"], + allow_headers=["Content-Type", "X-Requested-With"], ) @@ -88,55 +81,6 @@ async def add_security_headers(request: Request, call_next): return response -# --------------------------------------------------------------------------- -# JWT Authentication middleware -# --------------------------------------------------------------------------- -# Endpoints that do NOT require authentication -PUBLIC_PATHS = {"/api/health", "/docs", "/openapi.json", "/redoc"} - - -@app.middleware("http") -async def authenticate_requests(request: Request, call_next): - """Validate Supabase JWT on protected endpoints.""" - path = request.url.path - - # Skip auth for public endpoints and CORS preflight - if path in PUBLIC_PATHS or request.method == "OPTIONS": - return await call_next(request) - - # If no JWT secret configured, skip validation (dev mode) - if not SUPABASE_JWT_SECRET: - return await call_next(request) - - # Extract Bearer token - auth_header = request.headers.get("Authorization", "") - if not auth_header.startswith("Bearer "): - return JSONResponse( - status_code=401, - content={"detail": "Missing or invalid Authorization header. Please sign in."}, - ) - - token = auth_header.split(" ", 1)[1] - - try: - payload = jwt.decode( - token, - SUPABASE_JWT_SECRET, - algorithms=["HS256"], - audience="authenticated", - ) - # Attach user info to request state for downstream handlers - request.state.user_id = payload.get("sub") - request.state.user_email = payload.get("email", "") - except JWTError as exc: - logger.warning("JWT verification failed: %s", exc) - return JSONResponse( - status_code=401, - content={"detail": "Invalid or expired token. Please sign in again."}, - ) - - return await call_next(request) - # --------------------------------------------------------------------------- # Request logging middleware diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 4f8beac..75e577b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -134,7 +134,6 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -497,7 +496,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=20.19.0" }, @@ -546,7 +544,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=20.19.0" } @@ -1856,7 +1853,8 @@ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -2019,7 +2017,6 @@ "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -2030,7 +2027,6 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -2206,7 +2202,6 @@ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2247,6 +2242,7 @@ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -2355,7 +2351,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -2433,7 +2428,6 @@ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz", "integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==", "license": "MIT", - "peer": true, "dependencies": { "@kurkle/color": "^0.3.0" }, @@ -2715,7 +2709,8 @@ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/electron-to-chromium": { "version": "1.5.302", @@ -2825,7 +2820,6 @@ "integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -3526,6 +3520,7 @@ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -3752,7 +3747,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -3821,6 +3815,7 @@ "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -3836,6 +3831,7 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -3858,7 +3854,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -3878,7 +3873,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -3898,7 +3892,6 @@ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", "license": "MIT", - "peer": true, "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" @@ -3975,8 +3968,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/redux-thunk": { "version": "3.1.0", @@ -4411,7 +4403,6 @@ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -4718,7 +4709,6 @@ "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index aa8d081..beff4e6 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,6 +1,4 @@ import { useState, useCallback, useRef } from 'react'; -import { useAuth } from './components/AuthProvider'; -import LoginPage from './components/LoginPage'; import Sidebar from './components/Sidebar'; import TopBar from './components/TopBar'; import MolViewer from './components/MolViewer'; @@ -32,16 +30,6 @@ const DEFAULT_FILTERS = { let toastId = 0; export default function App() { - const { session, user, loading, signOut } = useAuth(); - - // ---- auth helpers ---- - const authHeaders = useCallback(() => { - const headers = { 'Content-Type': 'application/json' }; - if (session?.access_token) { - headers['Authorization'] = `Bearer ${session.access_token}`; - } - return headers; - }, [session]); // ---- view state ---- const [view, setView] = useState('dashboard'); // 'dashboard' | 'discovery' | 'analysis' @@ -97,7 +85,7 @@ export default function App() { try { const res = await fetch(`${API_BASE}/api/predict`, { method: 'POST', - headers: authHeaders(), + headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ sequence: seq.trim() }), }); @@ -118,7 +106,7 @@ export default function App() { addToast('error', err.message); } }, - [sequence, addToast, authHeaders] + [sequence, addToast] ); // ---- UniProt search ---- @@ -145,7 +133,7 @@ export default function App() { }); const res = await fetch(`${API_BASE}/api/uniprot/search?${params}`, { - headers: authHeaders(), + headers: { 'Content-Type': 'application/json' }, }); if (!res.ok) { const errBody = await res.json().catch(() => ({})); @@ -164,7 +152,7 @@ export default function App() { setSearchLoading(false); } }, - [filters, addToast, authHeaders] + [filters, addToast] ); const handleFiltersChange = useCallback((updater) => { @@ -197,7 +185,7 @@ export default function App() { try { const entryRes = await fetch(`${API_BASE}/api/uniprot/entry/${accession}`, { - headers: authHeaders(), + headers: { 'Content-Type': 'application/json' }, }); if (!entryRes.ok) { const errBody = await entryRes.json().catch(() => ({})); @@ -222,12 +210,12 @@ export default function App() { const [predictRes, analyzeRes] = await Promise.all([ fetch(`${API_BASE}/api/predict`, { method: 'POST', - headers: authHeaders(), + headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ sequence: protein.sequence }), }), fetch(`${API_BASE}/api/analyze`, { method: 'POST', - headers: authHeaders(), + headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ sequence: protein.sequence }), }), ]); @@ -257,7 +245,7 @@ export default function App() { addToast('error', err.message); } }, - [addToast, authHeaders] + [addToast] ); // ---- navigation ---- @@ -285,33 +273,9 @@ export default function App() { URL.revokeObjectURL(url); }, [pdbData, selectedProtein]); - // Show loading spinner during auth check - if (loading) { - return ( -
-
-
-
-
-
-
-

Loading Protly…

-
-
- ); - } - - // Redirect to login when not authenticated - if (!session) { - return ; - } - return (
- +
{/* ========== DASHBOARD VIEW ========== */} diff --git a/frontend/src/components/ActionsCard.jsx b/frontend/src/components/ActionsCard.jsx index 6a3fdc1..7ff442b 100644 --- a/frontend/src/components/ActionsCard.jsx +++ b/frontend/src/components/ActionsCard.jsx @@ -26,14 +26,7 @@ export default function ActionsCard({ pdbData, onDownload, status, sequence }) { Export & Actions
-
- - -
+
diff --git a/frontend/src/components/AuthProvider.jsx b/frontend/src/components/AuthProvider.jsx deleted file mode 100644 index 515e11d..0000000 --- a/frontend/src/components/AuthProvider.jsx +++ /dev/null @@ -1,61 +0,0 @@ -/* eslint-disable react-refresh/only-export-components */ -import { createContext, useContext, useEffect, useState } from 'react'; -import { supabase } from '../lib/supabaseClient'; - -const AuthContext = createContext({ - session: null, - user: null, - loading: true, - signInWithGoogle: async () => {}, - signOut: async () => {}, -}); - -export function useAuth() { - return useContext(AuthContext); -} - -export default function AuthProvider({ children }) { - const [session, setSession] = useState(null); - const [loading, setLoading] = useState(true); - - useEffect(() => { - // Get current session on mount - supabase.auth.getSession().then(({ data: { session: s } }) => { - setSession(s); - setLoading(false); - }); - - // Listen for auth state changes (login, logout, token refresh) - const { - data: { subscription }, - } = supabase.auth.onAuthStateChange((_event, s) => { - setSession(s); - setLoading(false); - }); - - return () => subscription.unsubscribe(); - }, []); - - const signInWithGoogle = async () => { - const { error } = await supabase.auth.signInWithOAuth({ - provider: 'google', - options: { - redirectTo: window.location.origin, - }, - }); - if (error) throw error; - }; - - const signOut = async () => { - const { error } = await supabase.auth.signOut(); - if (error) throw error; - }; - - const user = session?.user ?? null; - - return ( - - {children} - - ); -} diff --git a/frontend/src/components/GeneInfo.jsx b/frontend/src/components/GeneInfo.jsx index f05ec03..c2b2f5a 100644 --- a/frontend/src/components/GeneInfo.jsx +++ b/frontend/src/components/GeneInfo.jsx @@ -13,14 +13,7 @@ export default function GeneInfo({ status }) { Gene & Organism
-
- - -
+
diff --git a/frontend/src/components/LoginPage.jsx b/frontend/src/components/LoginPage.jsx deleted file mode 100644 index 0a1bf5b..0000000 --- a/frontend/src/components/LoginPage.jsx +++ /dev/null @@ -1,111 +0,0 @@ -import { useState } from 'react'; -import { useAuth } from './AuthProvider'; - -export default function LoginPage() { - const { signInWithGoogle } = useAuth(); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); - - const handleGoogleLogin = async () => { - setIsLoading(true); - setError(null); - try { - await signInWithGoogle(); - } catch (err) { - setError(err.message || 'Failed to sign in with Google'); - setIsLoading(false); - } - }; - - return ( -
- {/* Floating orbs background */} -
-
-
-
-
- -
- {/* Logo */} -
-
P
- - Protly. - -
- -

Welcome Back

-

- Sign in to access the Protein Folding Analysis Dashboard -

- - {error && ( -
- - {error} -
- )} - - - -
- Secure Authentication -
- -
-
- 🔒 -
- End-to-End Security -

OAuth 2.0 via Supabase with encrypted sessions

-
-
-
- 🧬 -
- Protein Analysis -

ESMFold structure prediction & visualization

-
-
-
- 🔍 -
- UniProt Discovery -

Search & analyze millions of protein entries

-
-
-
-
-
- ); -} diff --git a/frontend/src/components/Sidebar.jsx b/frontend/src/components/Sidebar.jsx index 6b0daa1..13e496c 100644 --- a/frontend/src/components/Sidebar.jsx +++ b/frontend/src/components/Sidebar.jsx @@ -1,19 +1,4 @@ -import { useState } from 'react'; - -export default function Sidebar({ activeView, onViewChange, user, onSignOut }) { - const [showMenu, setShowMenu] = useState(false); - - const initials = user?.user_metadata?.full_name - ? user.user_metadata.full_name - .split(' ') - .map((n) => n[0]) - .join('') - .slice(0, 2) - .toUpperCase() - : user?.email?.[0]?.toUpperCase() || 'U'; - - const avatarUrl = user?.user_metadata?.avatar_url; - +export default function Sidebar({ activeView, onViewChange }) { return ( ); } diff --git a/frontend/src/components/TopBar.jsx b/frontend/src/components/TopBar.jsx index 9d0dc80..04673a8 100644 --- a/frontend/src/components/TopBar.jsx +++ b/frontend/src/components/TopBar.jsx @@ -1,4 +1,4 @@ -import { useState, useRef, useEffect } from 'react'; +import { useState } from 'react'; export default function TopBar({ onSearch, @@ -6,12 +6,7 @@ export default function TopBar({ setSearchQuery, view, onBackToSearch, - user, - onSignOut, }) { - const [showUserMenu, setShowUserMenu] = useState(false); - const menuRef = useRef(null); - const handleKeyDown = (e) => { if (e.key === 'Enter' && searchQuery.trim()) { onSearch(searchQuery.trim()); @@ -24,26 +19,6 @@ export default function TopBar({ } }; - // Close menu on outside click - useEffect(() => { - const handleClick = (e) => { - if (menuRef.current && !menuRef.current.contains(e.target)) { - setShowUserMenu(false); - } - }; - if (showUserMenu) document.addEventListener('mousedown', handleClick); - return () => document.removeEventListener('mousedown', handleClick); - }, [showUserMenu]); - - const avatarUrl = user?.user_metadata?.avatar_url; - const displayName = user?.user_metadata?.full_name || user?.email || 'User'; - const initials = displayName - .split(' ') - .map((n) => n[0]) - .join('') - .slice(0, 2) - .toUpperCase(); - return (
@@ -65,15 +40,6 @@ export default function TopBar({ Discovery )} - - Schedule - - - History - - - Activity -
@@ -129,93 +95,6 @@ export default function TopBar({ )}
)} - - - - {/* User avatar with dropdown */} -
- - - {showUserMenu && ( -
-
- {avatarUrl && ( - - )} -
-
{displayName}
-
{user?.email}
-
-
-
- -
- )} -
); diff --git a/frontend/src/lib/supabaseClient.js b/frontend/src/lib/supabaseClient.js deleted file mode 100644 index 620f731..0000000 --- a/frontend/src/lib/supabaseClient.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Supabase Client — singleton used across the React app for auth & database. - * - * Reads config from Vite environment variables: - * VITE_SUPABASE_URL → Supabase project URL - * VITE_SUPABASE_ANON_KEY → Supabase anon / public key - */ - -import { createClient } from '@supabase/supabase-js'; - -const supabaseUrl = import.meta.env.VITE_SUPABASE_URL; -const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY; - -if (!supabaseUrl || !supabaseAnonKey) { - console.warn( - '[Supabase] Missing VITE_SUPABASE_URL or VITE_SUPABASE_ANON_KEY — auth features will not work.' - ); -} - -export const supabase = createClient(supabaseUrl || '', supabaseAnonKey || ''); diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx index e10d79b..d9cc93c 100644 --- a/frontend/src/main.jsx +++ b/frontend/src/main.jsx @@ -2,12 +2,9 @@ import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import './index.css'; import App from './App.jsx'; -import AuthProvider from './components/AuthProvider'; createRoot(document.getElementById('root')).render( - - - + ); From 4f90b14c2b714a2a63ce06e05a9d26745477f34f Mon Sep 17 00:00:00 2001 From: Rudraksh Mahajan <91263379+raiden9420@users.noreply.github.com> Date: Thu, 30 Apr 2026 22:55:43 +0530 Subject: [PATCH 2/7] Potential fix for pull request finding 'Unused variable, import, function or class' Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> --- frontend/src/components/TopBar.jsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/src/components/TopBar.jsx b/frontend/src/components/TopBar.jsx index 04673a8..c956d51 100644 --- a/frontend/src/components/TopBar.jsx +++ b/frontend/src/components/TopBar.jsx @@ -1,5 +1,3 @@ -import { useState } from 'react'; - export default function TopBar({ onSearch, searchQuery, From 6876ca56b6a941554c1b3edad09c46b665fa715a Mon Sep 17 00:00:00 2001 From: raiden9420 Date: Thu, 30 Apr 2026 23:00:29 +0530 Subject: [PATCH 3/7] removed usestate import --- frontend/src/components/TopBar.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/components/TopBar.jsx b/frontend/src/components/TopBar.jsx index 04673a8..f7c2803 100644 --- a/frontend/src/components/TopBar.jsx +++ b/frontend/src/components/TopBar.jsx @@ -1,4 +1,3 @@ -import { useState } from 'react'; export default function TopBar({ onSearch, From d9560e5058e3c0ce2f4605b896a333f12a2cf52c Mon Sep 17 00:00:00 2001 From: raiden9420 Date: Thu, 30 Apr 2026 23:06:03 +0530 Subject: [PATCH 4/7] Format backend/main.py with Black --- backend/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/main.py b/backend/main.py index 30e1bb8..0984410 100644 --- a/backend/main.py +++ b/backend/main.py @@ -81,7 +81,6 @@ async def add_security_headers(request: Request, call_next): return response - # --------------------------------------------------------------------------- # Request logging middleware # --------------------------------------------------------------------------- From 8bd6bb344fb10479c30d577a0849b9a695bb29c2 Mon Sep 17 00:00:00 2001 From: raiden9420 Date: Thu, 30 Apr 2026 23:08:03 +0530 Subject: [PATCH 5/7] fixed topbar.jsx --- frontend/src/components/TopBar.jsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/frontend/src/components/TopBar.jsx b/frontend/src/components/TopBar.jsx index 543b11b..c956d51 100644 --- a/frontend/src/components/TopBar.jsx +++ b/frontend/src/components/TopBar.jsx @@ -1,7 +1,3 @@ -<<<<<<< HEAD - -======= ->>>>>>> 4f90b14c2b714a2a63ce06e05a9d26745477f34f export default function TopBar({ onSearch, searchQuery, From ac7e1a200f55285b60e962e9a1d4e444d0417ee3 Mon Sep 17 00:00:00 2001 From: raiden9420 Date: Thu, 30 Apr 2026 23:09:30 +0530 Subject: [PATCH 6/7] remove line20 from backend/main.py --- backend/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/main.py b/backend/main.py index 0984410..78b2fd7 100644 --- a/backend/main.py +++ b/backend/main.py @@ -17,7 +17,6 @@ from fastapi import FastAPI, HTTPException, Request from fastapi.middleware.cors import CORSMiddleware -from fastapi.responses import JSONResponse from pydantic import BaseModel, Field, field_validator import requests import numpy as np From 940ababe374313a85d6fcec25b3de70c818fbd32 Mon Sep 17 00:00:00 2001 From: raiden9420 Date: Thu, 30 Apr 2026 23:18:02 +0530 Subject: [PATCH 7/7] removed all dead references --- PROJECT_DOCUMENTATION.md | 18 +--- backend/.env | 8 -- backend/.env.example | 6 -- backend/TESTING_GUIDE.md | 3 - backend/requirements.txt | 2 - backend/tests/test_api.py | 3 - backend/tests/test_subcellular.py | 3 - frontend/.env | 4 - frontend/.env.example | 5 - frontend/TESTING_GUIDE.md | 2 +- frontend/package-lock.json | 140 ++------------------------ frontend/package.json | 1 - frontend/src/tests/LoginPage.test.jsx | 45 --------- 13 files changed, 13 insertions(+), 227 deletions(-) delete mode 100644 frontend/src/tests/LoginPage.test.jsx diff --git a/PROJECT_DOCUMENTATION.md b/PROJECT_DOCUMENTATION.md index 9cb7d7e..e8a0532 100644 --- a/PROJECT_DOCUMENTATION.md +++ b/PROJECT_DOCUMENTATION.md @@ -27,23 +27,21 @@ The frontend is a Single Page Application (SPA) built with React and bundled usi - **Styling**: Vanilla CSS (`index.css`) emphasizing a dark-mode, premium UI with smooth transitions and glassmorphism elements. - **Routing/State**: Managed primarily via React local state (`useState`, `useCallback`) within a primary layout orchestrator (`App.jsx`). - **Key Libraries**: - - `@supabase/supabase-js`: Handles user authentication and session management. - `3dmol`: Used in `MolViewer.jsx` to render interactive 3D models of protein structures based on PDB data. - `chart.js` / `react-chartjs-2`: Powers the graphical rendering of pLDDT metrics (per-residue confidence lines/bars). - `recharts`: Alternate charting library for other analytical visualizations. - **Testing**: Setup with `vitest` and `@testing-library/react`. ### 2.2 Backend (FastAPI / Python) -The backend is a high-performance RESTful API that handles analytical computations, rate-limiting, authentication checks, and proxies external biological APIs. +The backend is a high-performance RESTful API that handles analytical computations, rate-limiting, and proxies external biological APIs. - **Core Framework**: FastAPI, served via Uvicorn. -- **Authentication**: Validates Supabase JWTs attached to requests to protect endpoints. - **Rate Limiting**: Implemented using `slowapi` to prevent abuse (e.g., 10 predictions/min, 30 UniProt searches/min). - **Key Python Libraries**: - `biotite`: Parses the PDB structures returned from ESMFold to reliably extract `b_factor` data, which maps to the pLDDT confidence scores. - `biopython`: Powers the `/api/analyze` endpoint. Uses `Bio.SeqUtils.ProtParam.ProteinAnalysis` to calculate biochemical metrics. - `requests` / `httpx`: Handles secure outbound HTTP calls to UniProt and ESMAtlas APIs. - `numpy`: Fast mathematical aggregation and distribution calculations of pLDDT scores. - - `python-jose`: Secured JWT decoding for Supabase authentication. + ### 2.3 Auxiliary Components - **ESMFold Streamlit App (`esmfold-master` directory)**: Contains an alternative, standalone `streamlit_app.py` for interacting with ESMFold structure predictions natively in Python, acting potentially as a prototype or a specialized tool alongside the main stack. @@ -52,13 +50,7 @@ The backend is a high-performance RESTful API that handles analytical computatio ## 3. Core Functionality & Implementation -### 3.1 Authentication Flow -- **Implementation**: The `AuthProvider.jsx` context wrapper initializes a Supabase client. Users must log in via `LoginPage.jsx`. -- Upon successful login, Supabase provides a JWT. -- The `App.jsx` constructs an `Authorization: Bearer ` header for all outward requests to the FastAPI backend. -- The backend's `authenticate_requests` middleware decodes this token using `SUPABASE_JWT_SECRET`. If invalid or missing, it blocks the request (`401 Unauthorized`). - -### 3.2 Feature: Protein Structure Prediction +### 3.1 Feature: Protein Structure Prediction - **Frontend Flow**: User enters an amino acid sequence in `SequenceInput.jsx`. `App.jsx` issues a POST to `/api/predict`. - **Backend Flow**: 1. Sequence is validated by Pydantic (`PredictRequest`) against valid 20 standard amino acid characters. Length is constrained (10 to 2000 AAs). @@ -73,12 +65,12 @@ The backend is a high-performance RESTful API that handles analytical computatio - **Very Low**: < 50 - **Visualization**: Data returns to the frontend. `MolViewer.jsx` uses `3dmol` to spin up an interactive 3D WebGL viewer of the PDB output. `ConfidenceBar.jsx` and `PldtMetrics.jsx` visualize the confidence metrics using Chart.js. -### 3.3 Feature: UniProt Discovery & Search +### 3.2 Feature: UniProt Discovery & Search - **Frontend Flow**: Switching the view to '*Discovery*' opens the `SearchPanel.jsx` and `DiscoveryTable.jsx`. - **Filters**: Users can toggle 'Reviewed' (Swiss-Prot), Organism specificity, and Max Sequence Length. - **Backend Flow (`/api/uniprot/search`)**: Proxy endpoint converts UI filters into a complex Solr query string (e.g., `(reviewed:true) AND (organism_id:9606) AND (length:[1 TO 1000])`). Fetches paginated JSON results from UniProt REST API, standardizing fields (Gene Name, Accession, Organism) for the frontend discovery table. -### 3.4 Feature: Lab Readiness Analysis +### 3.3 Feature: Lab Readiness Analysis - When a user selects a protein from the Discovery Table, the view shifts to '*Analysis*'. - **Frontend Flow**: Triggers concurrent requests to `/api/predict` (for structure) and `/api/analyze` (for properties). - **Backend Flow (`/api/analyze`)**: diff --git a/backend/.env b/backend/.env index bcb0917..4445a54 100644 --- a/backend/.env +++ b/backend/.env @@ -1,12 +1,4 @@ VALID_AMINO_ACIDS=A,C,D,E,F,G,H,I,K,L,M,N,P,Q,R,S,T,V,W,Y -# Supabase Auth Configuration -SUPABASE_URL=https://amimmaueterlwesbeatn.supabase.co -SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImFtaW1tYXVldGVybHdlc2JlYXRuIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzQxMjgxOTgsImV4cCI6MjA4OTcwNDE5OH0.j1rRXxN6Ikzt13WgjCDT9gUcI2LihmzkwhX4NnPVNxU - -# JWT Secret — IMPORTANT: Get this from Supabase Dashboard → Project Settings → API → JWT Secret -# Without this, the backend will skip JWT verification (dev mode) -SUPABASE_JWT_SECRET= - # CORS — comma-separated list of allowed origins CORS_ALLOWED_ORIGINS=http://localhost:5173,http://127.0.0.1:5173,http://localhost:3000 diff --git a/backend/.env.example b/backend/.env.example index a9aede8..8bd5564 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -6,11 +6,5 @@ # Amino acid whitelist (usually unchanged) VALID_AMINO_ACIDS=A,C,D,E,F,G,H,I,K,L,M,N,P,Q,R,S,T,V,W,Y -# Supabase Auth Configuration -# Get these from: https://supabase.com/dashboard → Project Settings → API -SUPABASE_URL=https://your-project-id.supabase.co -SUPABASE_ANON_KEY=your-supabase-anon-public-key -SUPABASE_JWT_SECRET=your-supabase-jwt-secret - # CORS — comma-separated list of allowed frontend origins CORS_ALLOWED_ORIGINS=http://localhost:5173,http://127.0.0.1:5173,http://localhost:3000 diff --git a/backend/TESTING_GUIDE.md b/backend/TESTING_GUIDE.md index 70649c6..d5e8f25 100644 --- a/backend/TESTING_GUIDE.md +++ b/backend/TESTING_GUIDE.md @@ -63,9 +63,6 @@ from fastapi.testclient import TestClient from unittest.mock import patch import main -# If testing public functionality and avoiding middleware token checks: -main.SUPABASE_JWT_SECRET = "" - client = TestClient(main.app) @patch("main.requests.post") diff --git a/backend/requirements.txt b/backend/requirements.txt index 9ad2bf1..55d03e4 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -5,9 +5,7 @@ biotite numpy slowapi biopython -python-jose[cryptography] python-dotenv -supabase pytest pytest-asyncio httpx diff --git a/backend/tests/test_api.py b/backend/tests/test_api.py index b007505..76b9f24 100644 --- a/backend/tests/test_api.py +++ b/backend/tests/test_api.py @@ -2,9 +2,6 @@ from unittest.mock import patch import main -# Force bypass of JWT auth for testing by removing the secret -main.SUPABASE_JWT_SECRET = "" - client = TestClient(main.app) diff --git a/backend/tests/test_subcellular.py b/backend/tests/test_subcellular.py index 851cb3a..d50c2ee 100644 --- a/backend/tests/test_subcellular.py +++ b/backend/tests/test_subcellular.py @@ -9,9 +9,6 @@ from fastapi.testclient import TestClient import main -# Bypass JWT auth for testing -main.SUPABASE_JWT_SECRET = "" - client = TestClient(main.app) diff --git a/frontend/.env b/frontend/.env index 4ff3a42..9570e19 100644 --- a/frontend/.env +++ b/frontend/.env @@ -1,8 +1,4 @@ VITE_VALID_AMINO_ACIDS=A,C,D,E,F,G,H,I,K,L,M,N,P,Q,R,S,T,V,W,Y -# Supabase Auth Configuration -VITE_SUPABASE_URL=https://amimmaueterlwesbeatn.supabase.co -VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImFtaW1tYXVldGVybHdlc2JlYXRuIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzQxMjgxOTgsImV4cCI6MjA4OTcwNDE5OH0.j1rRXxN6Ikzt13WgjCDT9gUcI2LihmzkwhX4NnPVNxU - # Backend API base URL VITE_API_BASE=http://localhost:8000 diff --git a/frontend/.env.example b/frontend/.env.example index 50b817c..3a8f8f5 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -6,10 +6,5 @@ # Amino acid whitelist (usually unchanged) VITE_VALID_AMINO_ACIDS=A,C,D,E,F,G,H,I,K,L,M,N,P,Q,R,S,T,V,W,Y -# Supabase Auth Configuration -# Get these from: https://supabase.com/dashboard → Project Settings → API -VITE_SUPABASE_URL=https://your-project-id.supabase.co -VITE_SUPABASE_ANON_KEY=your-supabase-anon-public-key - # Backend API base URL VITE_API_BASE=http://localhost:8000 diff --git a/frontend/TESTING_GUIDE.md b/frontend/TESTING_GUIDE.md index f555b6a..1276799 100644 --- a/frontend/TESTING_GUIDE.md +++ b/frontend/TESTING_GUIDE.md @@ -87,4 +87,4 @@ describe('SequenceInput Component', () => { ### Best Practices - **Query by Accessibility**: Prefer `getByRole`, `getByLabelText`, and `getByText`. Avoid querying by CSS classes, as tests should test functionality, not DOM structure. -- **Mock External Hooks**: If your component relies on global states (like `useAuth`), mock the hook using `vi.spyOn(AuthProvider, 'useAuth')` so you can test the component in isolation. +- **Mock External Hooks**: If your component relies on global state or context hooks, mock the hook using `vi.spyOn` so you can test the component in isolation. diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 75e577b..ca81545 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,7 +8,6 @@ "name": "frontend", "version": "0.0.0", "dependencies": { - "@supabase/supabase-js": "^2.99.3", "3dmol": "^2.5.4", "chart.js": "^4.5.1", "react": "^19.2.0", @@ -1678,86 +1677,6 @@ "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", "license": "MIT" }, - "node_modules/@supabase/auth-js": { - "version": "2.99.3", - "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.99.3.tgz", - "integrity": "sha512-vMEVLA1kGGYd/kdsJSwtjiFUZM1nGfrz2DWmgMBZtocV48qL+L2+4QpIkueXyBEumMQZFEyhz57i/5zGHjvdBw==", - "license": "MIT", - "dependencies": { - "tslib": "2.8.1" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@supabase/functions-js": { - "version": "2.99.3", - "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.99.3.tgz", - "integrity": "sha512-6tk2zrcBkzKaaBXPOG5nshn30uJNFGOH9LxOnE8i850eQmsX+jVm7vql9kTPyvUzEHwU4zdjSOkXS9M+9ukMVA==", - "license": "MIT", - "dependencies": { - "tslib": "2.8.1" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@supabase/postgrest-js": { - "version": "2.99.3", - "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.99.3.tgz", - "integrity": "sha512-8HxEf+zNycj7Z8+ONhhlu+7J7Ha+L6weyCtdEeK2mN5OWJbh6n4LPU4iuJ5UlCvvNnbSXMoutY7piITEEAgl2g==", - "license": "MIT", - "dependencies": { - "tslib": "2.8.1" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@supabase/realtime-js": { - "version": "2.99.3", - "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.99.3.tgz", - "integrity": "sha512-c1azgZ2nZPczbY5k5u5iFrk1InpxN81IvNE+UBAkjrBz3yc5ALLJNkeTQwbJZT4PZBuYXEzqYGLMuh9fdTtTMg==", - "license": "MIT", - "dependencies": { - "@types/phoenix": "^1.6.6", - "@types/ws": "^8.18.1", - "tslib": "2.8.1", - "ws": "^8.18.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@supabase/storage-js": { - "version": "2.99.3", - "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.99.3.tgz", - "integrity": "sha512-lOfIm4hInNcd8x0i1LWphnLKxec42wwbjs+vhaVAvR801Vda0UAMbTooUY6gfqgQb8v29GofqKuQMMTAsl6w/w==", - "license": "MIT", - "dependencies": { - "iceberg-js": "^0.8.1", - "tslib": "2.8.1" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@supabase/supabase-js": { - "version": "2.99.3", - "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.99.3.tgz", - "integrity": "sha512-GuPbzoEaI51AkLw9VGhLNvnzw4PHbS3p8j2/JlvLeZNQMKwZw4aEYQIDBRtFwL5Nv7/275n9m4DHtakY8nCvgg==", - "license": "MIT", - "dependencies": { - "@supabase/auth-js": "2.99.3", - "@supabase/functions-js": "2.99.3", - "@supabase/postgrest-js": "2.99.3", - "@supabase/realtime-js": "2.99.3", - "@supabase/storage-js": "2.99.3" - }, - "engines": { - "node": ">=20.0.0" - } - }, "node_modules/@testing-library/dom": { "version": "10.4.1", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", @@ -2000,17 +1919,14 @@ "version": "25.5.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", + "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "undici-types": "~7.18.0" } }, - "node_modules/@types/phoenix": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.7.tgz", - "integrity": "sha512-oN9ive//QSBkf19rfDv45M7eZPi0eEXylht2OLEXicu5b4KoQ1OzXIw+xDSGWxSxe1JmepRR/ZH283vsu518/Q==", - "license": "MIT" - }, "node_modules/@types/react": { "version": "19.2.14", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", @@ -2037,15 +1953,6 @@ "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", "license": "MIT" }, - "node_modules/@types/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@vitejs/plugin-react": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.4.tgz", @@ -3221,15 +3128,6 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/iceberg-js": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz", - "integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==", - "license": "MIT", - "engines": { - "node": ">=20.0.0" - } - }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -4275,12 +4173,6 @@ "node": ">=20" } }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -4308,7 +4200,10 @@ "version": "7.18.2", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", - "license": "MIT" + "dev": true, + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/update-browserslist-db": { "version": "1.2.3", @@ -4645,27 +4540,6 @@ "node": ">=0.10.0" } }, - "node_modules/ws": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", - "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/xml-name-validator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index a43f208..838a876 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,7 +14,6 @@ "preview": "vite preview" }, "dependencies": { - "@supabase/supabase-js": "^2.99.3", "3dmol": "^2.5.4", "chart.js": "^4.5.1", "react": "^19.2.0", diff --git a/frontend/src/tests/LoginPage.test.jsx b/frontend/src/tests/LoginPage.test.jsx deleted file mode 100644 index 5eb31f7..0000000 --- a/frontend/src/tests/LoginPage.test.jsx +++ /dev/null @@ -1,45 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import { describe, it, expect, vi } from 'vitest'; -import userEvent from '@testing-library/user-event'; -import LoginPage from '../components/LoginPage'; -import * as AuthProvider from '../components/AuthProvider'; - -describe('LoginPage Component', () => { - it('renders login elements correctly', () => { - vi.spyOn(AuthProvider, 'useAuth').mockReturnValue({ - signInWithGoogle: vi.fn(), - }); - - render(); - expect(screen.getByText('Welcome Back')).toBeInTheDocument(); - expect(screen.getByRole('button', { name: /Continue with Google/i })).toBeInTheDocument(); - }); - - it('calls signInWithGoogle on button click', async () => { - const mockSignIn = vi.fn().mockResolvedValue(); - vi.spyOn(AuthProvider, 'useAuth').mockReturnValue({ - signInWithGoogle: mockSignIn, - }); - const user = userEvent.setup(); - - render(); - const btn = screen.getByRole('button', { name: /Continue with Google/i }); - await user.click(btn); - - expect(mockSignIn).toHaveBeenCalled(); - }); - - it('displays the loading spinner when loading', async () => { - const mockSignIn = vi.fn().mockImplementation(() => new Promise(() => {})); // Never resolves - vi.spyOn(AuthProvider, 'useAuth').mockReturnValue({ - signInWithGoogle: mockSignIn, - }); - const user = userEvent.setup(); - - render(); - const btn = screen.getByRole('button', { name: /Continue with Google/i }); - await user.click(btn); - - expect(screen.getByText('Signing in…')).toBeInTheDocument(); - }); -});