parent
fc5519e744
commit
91ac3a5e36
91
web/src/app/operations/[operationId]/(styles)/page.scss
Normal file
91
web/src/app/operations/[operationId]/(styles)/page.scss
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
119
web/src/app/operations/[operationId]/page.tsx
Normal file
119
web/src/app/operations/[operationId]/page.tsx
Normal file
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user