Operation Page

This commit is contained in:
ic3w0lf 2025-04-02 22:20:13 -06:00 committed by Quaternions
parent fc5519e744
commit 91ac3a5e36
3 changed files with 212 additions and 2 deletions
web/src/app
operations/[operationId]
submit

@ -0,0 +1,91 @@
.operation-status {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #121212;
color: #e0e0e0;
.operation-card {
width: 400px;
padding: 20px;
background: #1e1e1e;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
border-radius: 8px;
h5 {
margin-bottom: 15px;
font-weight: bold;
color: #ffffff;
}
p {
margin: 5px 0;
color: #b0b0b0;
}
}
.status-indicator {
display: flex;
align-items: center;
gap: 8px;
font-weight: bold;
margin-top: 10px;
&.created {
color: #ffca28;
}
&.completed {
color: #66bb6a;
}
&.failed {
color: #ef5350;
}
.status-icon {
width: 12px;
height: 12px;
border-radius: 50%;
display: inline-block;
&.created {
background-color: #ffca28;
}
&.completed {
background-color: #66bb6a;
}
&.failed {
background-color: #ef5350;
}
}
}
.MuiCircularProgress-root {
color: #90caf9;
}
.submission-button {
margin-top: 20px;
display: flex;
justify-content: center;
width: 100%;
button {
width: 100%;
height: 60px;
background-color: #66bb6a;
color: white;
font-size: 20px;
font-weight: bold;
padding: 20px;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background 0.3s;
&:hover {
background-color: #57a05a;
}
}
}
}

@ -0,0 +1,119 @@
"use client";
import { useEffect, useState } from "react";
import { useParams, useRouter } from "next/navigation";
import { CircularProgress, Typography, Card, CardContent, Button } from "@mui/material";
import Webpage from "@/app/_components/webpage";
import "./(styles)/page.scss";
interface Operation {
OperationID: number;
Status: number;
StatusMessage: string;
Owner: string;
Date: number;
Path: string;
}
export default function OperationStatusPage() {
const { operationId } = useParams();
const router = useRouter();
const [operation, setOperation] = useState<Operation | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
if (!operationId) return;
const fetchOperation = async () => {
try {
const response = await fetch(`/api/operations/${operationId}`);
if (!response.ok) throw new Error("Failed to fetch operation");
const data = await response.json();
setOperation(data);
} catch (err: unknown) {
if (err instanceof Error) {
setError(err.message);
} else {
setError("An unknown error occurred");
}
} finally {
setLoading(false);
}
};
fetchOperation();
const interval = setInterval(fetchOperation, 5000);
return () => clearInterval(interval);
}, [operationId]);
const getStatusClass = (status: number) => {
switch (status) {
case 0:
return "created";
case 1:
return "completed";
case 2:
return "failed";
default:
return "";
}
};
const getStatusText = (status: number) => {
switch (status) {
case 0:
return "Created";
case 1:
return "Completed";
case 2:
return "Failed";
default:
return "Unknown";
}
};
return (
<Webpage>
<main className="operation-status">
{loading ? (
<CircularProgress />
) : error ? (
<Typography color="error">{error}</Typography>
) : operation ? (
<Card className="operation-card">
<CardContent>
<Typography variant="h5">Operation ID: {operation.OperationID}</Typography>
<div className={`status-indicator ${getStatusClass(operation.Status)}`}>
<span className={`status-icon ${getStatusClass(operation.Status)}`} />
{getStatusText(operation.Status)}
</div>
<Typography>Status Message: {operation.StatusMessage}</Typography>
<Typography>Owner: {operation.Owner}</Typography>
<Typography>Date: {new Date(operation.Date * 1000).toLocaleString()}</Typography>
<Typography>Path: {operation.Path}</Typography>
{operation.Status === 1 && (
<div className="submission-button">
<Button
variant="contained"
color="success"
onClick={() => router.push(`/submissions/${operation.OperationID}`)}
>
View Submission
</Button>
</div>
)}
</CardContent>
</Card>
) : (
<Typography>No operation found.</Typography>
)}
</main>
</Webpage>
);
}

@ -11,7 +11,7 @@ interface SubmissionPayload {
AssetID: number;
}
interface IdResponse {
ID: number;
OperationID: number;
}
export default function SubmissionInfoPage() {
@ -49,7 +49,7 @@ export default function SubmissionInfoPage() {
const id_response:IdResponse = await response.json();
// navigate to newly created submission
window.location.assign(`/submissions/${id_response.ID}`)
window.location.assign(`/operations/${id_response.OperationID}`)
} catch (error) {
console.error("Error submitting data:", error);