From 78eeda2886816776fa5f056f7fc9463ca4d9632e Mon Sep 17 00:00:00 2001 From: VibhavSetlur Date: Tue, 19 May 2026 13:35:03 -0500 Subject: [PATCH 1/6] feat(ui): add maintenance mode banner toggleable via file or env var - GET /api/maintenance checks /tmp/maintenance.json first (runtime toggle, no restart needed), then falls back to MAINTENANCE_MODE env var - OutageBanner component renders a yellow warning banner at the top of every page when maintenance mode is enabled - Sam can toggle by: echo '{enabled:true,message:...}' > /tmp/maintenance.json --- app/api/maintenance/route.ts | 52 ++++++++++++++++++++++++++++++++++ app/layout.tsx | 2 ++ components/ui/OutageBanner.tsx | 42 +++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 app/api/maintenance/route.ts create mode 100644 components/ui/OutageBanner.tsx diff --git a/app/api/maintenance/route.ts b/app/api/maintenance/route.ts new file mode 100644 index 00000000..cff8ed56 --- /dev/null +++ b/app/api/maintenance/route.ts @@ -0,0 +1,52 @@ +/** + * Maintenance mode status endpoint. + * + * Returns whether the site is in maintenance mode and an optional message. + * Sam can toggle this by: + * 1. Setting MAINTENANCE_MODE env var (requires container restart) + * 2. Creating /tmp/maintenance.json with {"enabled":true,"message":"..."} + * (file is checked at runtime, no restart needed) + */ +import { NextResponse } from 'next/server'; +import fs from 'fs'; + +interface MaintenanceStatus { + enabled: boolean; + message: string; +} + +function readFileStatus(): MaintenanceStatus | null { + try { + const raw = fs.readFileSync('/tmp/maintenance.json', 'utf-8'); + const data = JSON.parse(raw); + if (data && typeof data.enabled === 'boolean') { + return { + enabled: data.enabled, + message: typeof data.message === 'string' ? data.message : '', + }; + } + } catch { + // File doesn't exist or invalid — ignore + } + return null; +} + +export async function GET(): Promise { + // 1. Check file-based toggle first (runtime toggle, no restart needed) + const fileStatus = readFileStatus(); + if (fileStatus) { + return NextResponse.json(fileStatus); + } + + // 2. Fall back to env var (requires container restart) + const envEnabled = process.env.MAINTENANCE_MODE === 'true' || process.env.MAINTENANCE_MODE === '1'; + if (envEnabled) { + return NextResponse.json({ + enabled: true, + message: process.env.MAINTENANCE_MESSAGE || 'Site is undergoing maintenance. Please check back shortly.', + }); + } + + // 3. Default: not in maintenance + return NextResponse.json({ enabled: false, message: '' }); +} diff --git a/app/layout.tsx b/app/layout.tsx index 9a472634..25487af4 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -4,6 +4,7 @@ import CssBaseline from '@mui/material/CssBaseline'; import theme from '@/lib/theme'; import Box from '@mui/material/Box'; import HeaderLayoutRouter from '@/app/HeaderLayoutRouter'; +import OutageBanner from '@/components/ui/OutageBanner'; import Providers from '@/components/Providers'; import { AuthProvider } from '@/components/auth/AuthProvider'; import type { Metadata } from "next"; @@ -35,6 +36,7 @@ export default function RootLayout({ + (null); + + useEffect(() => { + fetch('/api/maintenance') + .then((res) => res.json()) + .then((data: MaintenanceStatus) => setStatus(data)) + .catch(() => setStatus({ enabled: false, message: '' })); + }, []); + + if (!status || !status.enabled) return null; + + return ( + + + + {status.message || 'Site is undergoing maintenance. Please check back shortly.'} + + + + ); +} From 21e47825dff5a98f1e00a3b8d4c4a386f1bacef1 Mon Sep 17 00:00:00 2001 From: VibhavSetlur Date: Tue, 19 May 2026 13:37:25 -0500 Subject: [PATCH 2/6] fix(ui): add proper maintenance message to PlantSEED dialog The PlantSEED tab dialog was rendering empty (just a Close button). Added title, version info, and explanation that annotation/reconstruction services are temporarily offline for updates. --- app/(build-model)/plant/page.tsx | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/app/(build-model)/plant/page.tsx b/app/(build-model)/plant/page.tsx index a91b7848..33823ccd 100644 --- a/app/(build-model)/plant/page.tsx +++ b/app/(build-model)/plant/page.tsx @@ -461,11 +461,23 @@ export default function BuildModelPlantPage() { maxWidth="sm" fullWidth > - - - + + + PlantSEED — Update In Progress + + + PlantSEED v2.0 → PlantSEED v3.0 + + + Annotation and reconstruction services are temporarily offline for updates + and will be restored shortly. + + + + + From b949c2a61ca34722c995cb166bfbfee7874abf6e Mon Sep 17 00:00:00 2001 From: VibhavSetlur Date: Tue, 19 May 2026 14:04:53 -0500 Subject: [PATCH 3/6] fix(ui): disable comments column on biochem reactions table Comment button column, Notes column, and ReactionCommentModal are commented out with a /* disabled */ comment. The code stays in the file for easy re-enabling. --- .../biochem/reactions/page.tsx | 32 +++---------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/app/(reference-data)/biochem/reactions/page.tsx b/app/(reference-data)/biochem/reactions/page.tsx index 5c41e597..870cb3b9 100644 --- a/app/(reference-data)/biochem/reactions/page.tsx +++ b/app/(reference-data)/biochem/reactions/page.tsx @@ -18,7 +18,7 @@ import { getReactions, type Reaction, type SolrQueryOpts, EXTERNAL_DBS } from '@ import ChemicalEquation from '@/components/ui/ChemicalEquation'; import IconButton from '@mui/material/IconButton'; import ChatBubbleOutlineIcon from '@mui/icons-material/ChatBubbleOutline'; -import ReactionCommentModal from '@/components/ui/ReactionCommentModal'; +/* import ReactionCommentModal from '@/components/ui/ReactionCommentModal'; */ import { GridHighlightText } from '@/components/GridHighlightText'; import DataControlHeader from '@/components/layout/DataControlHeader'; import ExportModal from '@/components/ui/ExportModal'; @@ -272,23 +272,7 @@ export default function ReactionsPage() { ), }, - { - field: 'actions', - headerName: '', - width: 50, - sortable: false, - disableColumnMenu: true, - renderCell: (params) => ( - handleOpenComment(params.row.id)} - sx={{ color: '#00acc1' }} - > - - - ) - }, + /* comment button column disabled */ { field: 'name', headerName: 'Name', @@ -348,13 +332,7 @@ export default function ReactionsPage() { ); }, }, - { - field: 'notes', - headerName: 'Notes', - width: 100, - sortable: false, - renderCell: (params) => , - }, + /* notes column disabled */ { field: 'synonyms', headerName: 'Synonyms', @@ -463,11 +441,11 @@ export default function ReactionsPage() { autoHeight /> - setCommentModalOpen(false)} reactionId={commentReactionId} - /> + /> */} Date: Wed, 20 May 2026 10:33:06 -0500 Subject: [PATCH 4/6] =?UTF-8?q?fix:=20address=20PR=20review=20issues=20?= =?UTF-8?q?=E2=80=94=20unused=20imports,=20cache=20headers,=20fetch=20erro?= =?UTF-8?q?r=20handling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Restored IconButton import (used by Pathways dialog) - Commented out ChatBubbleOutlineIcon import - Removed unused DialogActions import from plant page - Added Cache-Control: no-store to all maintenance endpoint responses - Added cache: 'no-store' and error handling to OutageBanner fetch - Genericized maintenance route comment --- .../3b3b2185-902f-401d-b929-f422f0fd1d5b.json | 1 + app/(build-model)/plant/page.tsx | 1 - app/(reference-data)/biochem/reactions/page.tsx | 2 +- app/api/maintenance/route.ts | 17 +++++++++++------ components/ui/OutageBanner.tsx | 7 +++++-- 5 files changed, 18 insertions(+), 10 deletions(-) create mode 120000 .antigravitycli/3b3b2185-902f-401d-b929-f422f0fd1d5b.json diff --git a/.antigravitycli/3b3b2185-902f-401d-b929-f422f0fd1d5b.json b/.antigravitycli/3b3b2185-902f-401d-b929-f422f0fd1d5b.json new file mode 120000 index 00000000..de58dee9 --- /dev/null +++ b/.antigravitycli/3b3b2185-902f-401d-b929-f422f0fd1d5b.json @@ -0,0 +1 @@ +/home/vibhav/.gemini/config/projects/3b3b2185-902f-401d-b929-f422f0fd1d5b.json \ No newline at end of file diff --git a/app/(build-model)/plant/page.tsx b/app/(build-model)/plant/page.tsx index 33823ccd..cbdb8d4c 100644 --- a/app/(build-model)/plant/page.tsx +++ b/app/(build-model)/plant/page.tsx @@ -15,7 +15,6 @@ import Stack from '@mui/material/Stack'; import CircularProgress from '@mui/material/CircularProgress'; import WarningAmberIcon from '@mui/icons-material/WarningAmber'; import Dialog from '@mui/material/Dialog'; -import DialogActions from '@mui/material/DialogActions'; import Link from 'next/link'; import AuthGuard from '@/components/auth/AuthGuard'; import { useAuth } from '@/components/auth/AuthProvider'; diff --git a/app/(reference-data)/biochem/reactions/page.tsx b/app/(reference-data)/biochem/reactions/page.tsx index 870cb3b9..f93a997e 100644 --- a/app/(reference-data)/biochem/reactions/page.tsx +++ b/app/(reference-data)/biochem/reactions/page.tsx @@ -17,7 +17,7 @@ import Link from 'next/link'; import { getReactions, type Reaction, type SolrQueryOpts, EXTERNAL_DBS } from '@/lib/api/biochem'; import ChemicalEquation from '@/components/ui/ChemicalEquation'; import IconButton from '@mui/material/IconButton'; -import ChatBubbleOutlineIcon from '@mui/icons-material/ChatBubbleOutline'; +/* import ChatBubbleOutlineIcon from '@mui/icons-material/ChatBubbleOutline'; */ /* import ReactionCommentModal from '@/components/ui/ReactionCommentModal'; */ import { GridHighlightText } from '@/components/GridHighlightText'; import DataControlHeader from '@/components/layout/DataControlHeader'; diff --git a/app/api/maintenance/route.ts b/app/api/maintenance/route.ts index cff8ed56..ee153a71 100644 --- a/app/api/maintenance/route.ts +++ b/app/api/maintenance/route.ts @@ -2,14 +2,16 @@ * Maintenance mode status endpoint. * * Returns whether the site is in maintenance mode and an optional message. - * Sam can toggle this by: - * 1. Setting MAINTENANCE_MODE env var (requires container restart) - * 2. Creating /tmp/maintenance.json with {"enabled":true,"message":"..."} + * Operators can toggle this by: + * 1. Creating /tmp/maintenance.json with {"enabled":true,"message":"..."} * (file is checked at runtime, no restart needed) + * 2. Setting MAINTENANCE_MODE env var (requires container restart) */ import { NextResponse } from 'next/server'; import fs from 'fs'; +const NO_CACHE_HEADERS = { 'Cache-Control': 'no-store, max-age=0' }; + interface MaintenanceStatus { enabled: boolean; message: string; @@ -35,7 +37,7 @@ export async function GET(): Promise { // 1. Check file-based toggle first (runtime toggle, no restart needed) const fileStatus = readFileStatus(); if (fileStatus) { - return NextResponse.json(fileStatus); + return NextResponse.json(fileStatus, { headers: NO_CACHE_HEADERS }); } // 2. Fall back to env var (requires container restart) @@ -44,9 +46,12 @@ export async function GET(): Promise { return NextResponse.json({ enabled: true, message: process.env.MAINTENANCE_MESSAGE || 'Site is undergoing maintenance. Please check back shortly.', - }); + }, { headers: NO_CACHE_HEADERS }); } // 3. Default: not in maintenance - return NextResponse.json({ enabled: false, message: '' }); + return NextResponse.json( + { enabled: false, message: '' }, + { headers: NO_CACHE_HEADERS }, + ); } diff --git a/components/ui/OutageBanner.tsx b/components/ui/OutageBanner.tsx index 7e7bad69..113c65ff 100644 --- a/components/ui/OutageBanner.tsx +++ b/components/ui/OutageBanner.tsx @@ -14,8 +14,11 @@ export default function OutageBanner() { const [status, setStatus] = useState(null); useEffect(() => { - fetch('/api/maintenance') - .then((res) => res.json()) + fetch('/api/maintenance', { cache: 'no-store' }) + .then((res) => { + if (!res.ok) throw new Error(`HTTP ${res.status}`); + return res.json(); + }) .then((data: MaintenanceStatus) => setStatus(data)) .catch(() => setStatus({ enabled: false, message: '' })); }, []); From 19a8854be22a5be838d6cd99236e2efa625699b0 Mon Sep 17 00:00:00 2001 From: VibhavSetlur Date: Wed, 20 May 2026 10:33:21 -0500 Subject: [PATCH 5/6] chore: remove accidentally committed antigravitycli config --- .antigravitycli/3b3b2185-902f-401d-b929-f422f0fd1d5b.json | 1 - 1 file changed, 1 deletion(-) delete mode 120000 .antigravitycli/3b3b2185-902f-401d-b929-f422f0fd1d5b.json diff --git a/.antigravitycli/3b3b2185-902f-401d-b929-f422f0fd1d5b.json b/.antigravitycli/3b3b2185-902f-401d-b929-f422f0fd1d5b.json deleted file mode 120000 index de58dee9..00000000 --- a/.antigravitycli/3b3b2185-902f-401d-b929-f422f0fd1d5b.json +++ /dev/null @@ -1 +0,0 @@ -/home/vibhav/.gemini/config/projects/3b3b2185-902f-401d-b929-f422f0fd1d5b.json \ No newline at end of file From bcc9ddd6b28783f6c585bcaeb3c5e0c51e64e860 Mon Sep 17 00:00:00 2001 From: VibhavSetlur Date: Wed, 20 May 2026 10:33:34 -0500 Subject: [PATCH 6/6] chore: add .antigravitycli/ to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3835bdc4..82189a45 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,7 @@ playwright-report/ # AI assistant/tooling metadata (keep local, do not track) .agent/ +.antigravitycli/ .cursor/ .gemini/ .cursorrules