Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions app/(build-model)/plant/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
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';

Check warning on line 18 in app/(build-model)/plant/page.tsx

View workflow job for this annotation

GitHub Actions / Verify (lint, typecheck, test, build, audit)

'DialogActions' is defined but never used
import Link from 'next/link';
import AuthGuard from '@/components/auth/AuthGuard';
import { useAuth } from '@/components/auth/AuthProvider';
Expand Down Expand Up @@ -461,11 +461,23 @@
maxWidth="sm"
fullWidth
>
<DialogActions>
<Button onClick={() => setPlantseedDialogOpen(false)}>
Close
</Button>
</DialogActions>
<Box sx={{ p: 3 }}>
<Typography variant="h6" fontWeight={600} gutterBottom>
PlantSEED — Update In Progress
</Typography>
<Typography variant="body2" sx={{ color: 'text.secondary', mb: 2 }}>
PlantSEED v2.0 → PlantSEED v3.0
</Typography>
<Alert severity="info" sx={{ mb: 2 }}>
Annotation and reconstruction services are temporarily offline for updates
and will be restored shortly.
</Alert>
<Box sx={{ display: 'flex', justifyContent: 'flex-end' }}>
<Button onClick={() => setPlantseedDialogOpen(false)} variant="contained">
Close
</Button>
</Box>
</Box>
</Dialog>
</Box>
</AuthGuard >
Expand Down
32 changes: 5 additions & 27 deletions app/(reference-data)/biochem/reactions/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
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';

Check warning on line 20 in app/(reference-data)/biochem/reactions/page.tsx

View workflow job for this annotation

GitHub Actions / Verify (lint, typecheck, test, build, audit)

'ChatBubbleOutlineIcon' is defined but never used
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';
Expand Down Expand Up @@ -211,8 +211,8 @@
}, [handleFilterModelChange]);

// Modal state
const [commentModalOpen, setCommentModalOpen] = useState(false);

Check warning on line 214 in app/(reference-data)/biochem/reactions/page.tsx

View workflow job for this annotation

GitHub Actions / Verify (lint, typecheck, test, build, audit)

'commentModalOpen' is assigned a value but never used
const [commentReactionId, setCommentReactionId] = useState<string | null>(null);

Check warning on line 215 in app/(reference-data)/biochem/reactions/page.tsx

View workflow job for this annotation

GitHub Actions / Verify (lint, typecheck, test, build, audit)

'commentReactionId' is assigned a value but never used
const [exportModalOpen, setExportModalOpen] = useState(false);
const [pathwaysModalOpen, setPathwaysModalOpen] = useState(false);
const [pathwaysModalReactionId, setPathwaysModalReactionId] = useState<string | null>(null);
Expand Down Expand Up @@ -272,23 +272,7 @@
</Link>
),
},
{
field: 'actions',
headerName: '',
width: 50,
sortable: false,
disableColumnMenu: true,
renderCell: (params) => (
<IconButton
size="small"
title="Comment on this reaction"
onClick={() => handleOpenComment(params.row.id)}
sx={{ color: '#00acc1' }}
>
<ChatBubbleOutlineIcon fontSize="small" />
</IconButton>
)
},
/* comment button column disabled */
{
field: 'name',
headerName: 'Name',
Expand Down Expand Up @@ -348,13 +332,7 @@
);
},
},
{
field: 'notes',
headerName: 'Notes',
width: 100,
sortable: false,
renderCell: (params) => <GridHighlightText text={(params.row.notes ?? []).join(' | ')} />,
},
/* notes column disabled */
{
field: 'synonyms',
headerName: 'Synonyms',
Expand Down Expand Up @@ -397,7 +375,7 @@
return row.ontology;
},
},
], [handleOpenComment, handleOpenPathwaysModal]);

Check warning on line 378 in app/(reference-data)/biochem/reactions/page.tsx

View workflow job for this annotation

GitHub Actions / Verify (lint, typecheck, test, build, audit)

React Hook useMemo has an unnecessary dependency: 'handleOpenComment'. Either exclude it or remove the dependency array

const queryOpts = useMemo<SolrQueryOpts>(() => ({
limit: paginationModel.pageSize,
Expand Down Expand Up @@ -463,11 +441,11 @@
autoHeight
/>

<ReactionCommentModal
{/* <ReactionCommentModal
open={commentModalOpen}
onClose={() => setCommentModalOpen(false)}
reactionId={commentReactionId}
/>
/> */}

<ExportModal
open={exportModalOpen}
Expand Down
52 changes: 52 additions & 0 deletions app/api/maintenance/route.ts
Original file line number Diff line number Diff line change
@@ -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)
*/
Comment on lines +1 to +9
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<NextResponse> {
// 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: '' });
}
Comment on lines +34 to +52
2 changes: 2 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -35,6 +36,7 @@ export default function RootLayout({
<Providers>
<AuthProvider>
<CssBaseline />
<OutageBanner />
<HeaderLayoutRouter />
<Box
component="main"
Expand Down
42 changes: 42 additions & 0 deletions components/ui/OutageBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
'use client';

import { useEffect, useState } from 'react';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import Alert from '@mui/material/Alert';

interface MaintenanceStatus {
enabled: boolean;
message: string;
}

export default function OutageBanner() {
const [status, setStatus] = useState<MaintenanceStatus | null>(null);

useEffect(() => {
fetch('/api/maintenance')
.then((res) => res.json())
Comment on lines +17 to +18
.then((data: MaintenanceStatus) => setStatus(data))
.catch(() => setStatus({ enabled: false, message: '' }));
}, []);

if (!status || !status.enabled) return null;

return (
<Box sx={{ width: '100%' }}>
<Alert
severity="warning"
sx={{
borderRadius: 0,
textAlign: 'center',
justifyContent: 'center',
'& .MuiAlert-message': { flex: 'unset' },
}}
>
<Typography variant="body1" fontWeight={600}>
{status.message || 'Site is undergoing maintenance. Please check back shortly.'}
</Typography>
</Alert>
</Box>
);
}
Loading