From a4cdfef620a2009d05bd7995cfe3d362736693ab Mon Sep 17 00:00:00 2001
From: Prakhar Trivedi
Date: Thu, 14 Aug 2025 16:27:15 +0800
Subject: [PATCH 1/9] updated sidebar to have upload link
---
src/components/Sidebar.jsx | 14 ++++++++------
src/pages/DataImport.jsx | 2 +-
2 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/src/components/Sidebar.jsx b/src/components/Sidebar.jsx
index fc42c5f..a041d3a 100644
--- a/src/components/Sidebar.jsx
+++ b/src/components/Sidebar.jsx
@@ -1,14 +1,14 @@
import { Badge, Box, Button, CloseButton, Drawer, Image, Portal, Span, Text, VStack } from '@chakra-ui/react'
-import React, { useState } from 'react'
+import { useState } from 'react'
import { useSelector } from 'react-redux'
import logoVisual from '../assets/logoVisual.svg';
import { useLocation, useNavigate } from 'react-router-dom';
-import { CiGrid32 } from 'react-icons/ci';
import { GrCatalogOption } from 'react-icons/gr';
-import { MdAdminPanelSettings, MdOutlinePublic } from 'react-icons/md';
+import { MdAdminPanelSettings } from 'react-icons/md';
import { FaPeopleGroup } from 'react-icons/fa6';
import { CgProfile } from 'react-icons/cg';
import { TbLogin2 } from 'react-icons/tb';
+import { FiUploadCloud } from 'react-icons/fi';
function Sidebar({ isOpen, onOpenChange }) {
const navigate = useNavigate();
@@ -45,13 +45,15 @@ function Sidebar({ isOpen, onOpenChange }) {
- >}
- {username && (
+
+
- )}
+ >}
{superuser === true && (
+
return (
diff --git a/src/components/DataImport/ImportMenuDialog.jsx b/src/components/DataImport/ImportMenuDialog.jsx
index 65be9a4..7419018 100644
--- a/src/components/DataImport/ImportMenuDialog.jsx
+++ b/src/components/DataImport/ImportMenuDialog.jsx
@@ -28,8 +28,7 @@ function ImportMenuDialog({ pendingBatches, fetchBatches }) {
unmountOnExit
>
-
- Upload Artefacts
+ Upload Artefacts
@@ -43,7 +42,6 @@ function ImportMenuDialog({ pendingBatches, fetchBatches }) {
b.id === targetBatchID) || null}
setBatchID={(id) => setTargetBatchID(id)}
- onClose={handleClose}
fetchBatches={fetchBatches}
onBackToPending={() => setView("pendingList")} />}
@@ -57,18 +55,14 @@ function ImportMenuDialog({ pendingBatches, fetchBatches }) {
- Pending Batches
+ {pendingBatches.length === 0 ? "No pending batches": "Pending Batches"}
- {pendingBatches.length === 0 ? (
-
- No pending batches.
-
- ) : (
+ {pendingBatches.length > 0 && (
{pendingBatches.map((batch) => (
a.stage === "processed").length;
const unprocessed = artefacts.filter(a => a.stage === "unprocessed").length;
+ const confirmed = artefacts.filter(a => a.stage === "confirmed").length;
+ const integrated = artefacts.filter(a => a.stage === "integrated").length;
const total = processed + unprocessed
return {
id,
...batch,
- artefactSummary: { processed, total },
+ artefactSummary: { processed, total, confirmed, integrated },
};
});
@@ -133,7 +135,6 @@ function DataImport() {
setBatches(sorted);
setBatchNumberMap(batchNumberMap);
setPendingBatches(pendingBatches);
-
} else {
throw new Error("Unexpected response format");
}
@@ -272,18 +273,7 @@ function DataImport() {
filtered.map((batch, idx) => (
console.log("Clicked batch", batch.id)}
+ batchData={batch}
/>
))
From 399bfb7f3b5d28bda257c323dc239da4ce6a7424 Mon Sep 17 00:00:00 2001
From: Prakhar Trivedi
Date: Thu, 14 Aug 2025 17:19:28 +0800
Subject: [PATCH 3/9] simplified stages
---
src/pages/DataImport.jsx | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/src/pages/DataImport.jsx b/src/pages/DataImport.jsx
index 0f8377b..736b01e 100644
--- a/src/pages/DataImport.jsx
+++ b/src/pages/DataImport.jsx
@@ -12,8 +12,7 @@ import CentredSpinner from "../components/CentredSpinner.jsx";
const stageCollection = createListCollection({
items: [
{ label: "Pending", value: "upload_pending" },
- { label: "Unprocessed", value: "unprocessed" },
- { label: "Processed", value: "processed" },
+ { label: "Processing", value: "unprocessed" },
{ label: "Vetting", value: "vetting" },
{ label: "Integration", value: "integration" },
{ label: "Completed", value: "completed" },
@@ -65,12 +64,11 @@ function DataImport() {
const { loaded } = useSelector(state => state.auth);
- const stages = ["upload_pending", "unprocessed", "processed", "vetting", "integration", "completed"];
+ const stages = ["upload_pending", "unprocessed", "vetting", "integration", "completed"];
const stageLabels = {
upload_pending: "Pending",
- unprocessed: "Unprocessed",
- processed: "Processed",
+ unprocessed: "Processing",
vetting: "Vetting",
integration: "Integration",
completed: "Completed",
From 54a9a81fcdae2a37170fb528332628d2132f393b Mon Sep 17 00:00:00 2001
From: Prakhar Trivedi
Date: Thu, 14 Aug 2025 18:22:50 +0800
Subject: [PATCH 4/9] reworked batch card rendering, added confirmBatch request
---
src/components/DataImport/BatchCard.jsx | 202 ++++++++++++++++++------
src/pages/DataImport.jsx | 6 +-
2 files changed, 156 insertions(+), 52 deletions(-)
diff --git a/src/components/DataImport/BatchCard.jsx b/src/components/DataImport/BatchCard.jsx
index 71d8451..e8cec4d 100644
--- a/src/components/DataImport/BatchCard.jsx
+++ b/src/components/DataImport/BatchCard.jsx
@@ -1,11 +1,28 @@
import { HStack, VStack, Text, Image, Button, Card, Progress, useBreakpointValue, Flex, Box } from "@chakra-ui/react";
+import { useEffect, useState } from "react";
+import server, { JSONResponse } from '../../networking';
+import ToastWizard from "../toastWizard";
-function BatchCard({ batchData }) {
- // const status = isCancelled
- // ? { label: "Cancelled", color: "red.500" }
- // : isProcessing
- // ? { label: "Processing", color: "blue.500" }
- // : { label: "Done", color: "green.500" };
+function BatchCard({ batchData, formatTimestamp, fetchBatches }) {
+ const statusColours = {
+ "upload_pending": "yellow.500",
+ "processing": "blue.500",
+ "vetting": "orange.500",
+ "integration": "purple.500",
+ "completed": "green.500",
+ "cancelled": "red.500"
+ }
+
+ const [content, setContent] = useState({
+ "displayMessage": null,
+ "timestamp": formatTimestamp(batchData.created),
+ "progress": null,
+ "name": batchData.name || "No name",
+ "statusColour": null,
+ "statusText": null,
+ "buttonText": null,
+ "buttonLoadingText": ''
+ });
const isMobile = useBreakpointValue({ base: true, md: false });
const imageWidth = useBreakpointValue({ base: "80px", md: "120px" });
@@ -14,10 +31,100 @@ function BatchCard({ batchData }) {
const buttonMinWidth = useBreakpointValue({ base: "80px", md: "100px" });
const infoMaxWidth = useBreakpointValue({ base: "180px", md: "400px" });
const fontSize = useBreakpointValue({ base: "sm", md: "md" });
+ const [requestInProgress, setRequestInProgress] = useState(false);
+
+ const handleButtonClick = async () => {
+ if (content.buttonText === "Confirm Batch") {
+ setRequestInProgress(true);
+
+ try {
+ const response = await server.post('/dataImport/confirm', {
+ batchID: batchData.id
+ })
+
+ if (response.data instanceof JSONResponse) {
+ if (response.data.isErrorStatus()) {
+ const errObject = {
+ response: {
+ data: response.data
+ }
+ };
+ throw new Error(errObject);
+ }
+
+ // Success case
+ if (fetchBatches) {
+ fetchBatches();
+ }
+ ToastWizard.standard("success", `Processing for '${batchData.name || 'Unknown'}' started`, "Batch was confirmed successfully. No more artefacts can be added.");
+ } else {
+ throw new Error("Unexpected response format");
+ }
+ } catch (err) {
+ if (err.response && err.response.data instanceof JSONResponse) {
+ console.log("Error response in batch confirmation request:", err.response.data.fullMessage());
+ if (err.response.data.userErrorType()) {
+ ToastWizard.standard("error", "Batch confirmation failed.", err.response.data.message);
+ } else {
+ ToastWizard.standard("error", "Something went wrong", "Couldn't confirm batch. Please try again.")
+ }
+ } else {
+ console.log("Unexpected error in batch confirmation request:", err);
+ ToastWizard.standard("error", "Something went wrong", "Couldn't confirm batch. Please try again.")
+ }
+ } finally {
+ setRequestInProgress(false);
+ }
+ return;
+ }
+ }
- console.log(batchData)
+ useEffect(() => {
+ if (batchData) {
+ var newContent = { ...content };
+ if (batchData.stage === "upload_pending") {
+ newContent.displayMessage = `${batchData.artefactSummary.total || 0} Uploaded (Upload more if you wish)`
+ // newContent.progress = Math.round((batchData.artefactSummary.unprocessed || 0) / (batchData.artefactSummary.total || 1) * 100);
+ newContent.progress = null;
+ newContent.statusColour = statusColours.upload_pending;
+ newContent.statusText = "Pending";
+ newContent.buttonText = "Confirm Batch";
+ newContent.buttonLoadingText = "Confirming...";
+ } else if (batchData.stage === "unprocessed") {
+ newContent.displayMessage = `${batchData.artefactSummary.processed || 0}/${batchData.artefactSummary.total || 0} Processed`
+ newContent.progress = Math.round((batchData.artefactSummary.processed || 0) / (batchData.artefactSummary.total || 1) * 100);
+ newContent.statusColour = statusColours.processing;
+ newContent.statusText = "Processing";
+ newContent.buttonText = null;
+ newContent.buttonLoadingText = '';
+ } else if (batchData.stage === "vetting") {
+ newContent.displayMessage = `${batchData.artefactSummary.confirmed || 0}/${batchData.artefactSummary.total || 0} Confirmed`
+ newContent.progress = Math.round((batchData.artefactSummary.confirmed || 0) / (batchData.artefactSummary.total || 1) * 100);
+ newContent.statusColour = statusColours.vetting;
+ newContent.statusText = "Vetting";
+ newContent.buttonText = batchData.artefactSummary.confirmed == batchData.artefactSummary.total ? 'Start Integration' : 'Continue Vetting';
+ newContent.buttonLoadingText = 'Continue Vetting';
+ } else if (batchData.stage === "integration") {
+ newContent.displayMessage = `${batchData.artefactSummary.integrated || 0}/${batchData.artefactSummary.total || 0} Integrated`
+ newContent.progress = Math.round((batchData.artefactSummary.integrated || 0) / (batchData.artefactSummary.total || 1) * 100);
+ newContent.statusColour = statusColours.integration;
+ newContent.statusText = "Integrating";
+ newContent.buttonText = null;
+ newContent.buttonLoadingText = '';
+ } else if (batchData.stage === "completed") {
+ newContent.displayMessage = `${batchData.artefactSummary.integrated || 0}/${batchData.artefactSummary.total || 0} Completed`
+ newContent.progress = Math.round((batchData.artefactSummary.integrated || 0) / (batchData.artefactSummary.total || 1) * 100);
+ newContent.statusColour = statusColours.completed;
+ newContent.statusText = "Completed";
+ newContent.buttonText = null;
+ newContent.buttonLoadingText = '';
+ }
- return WIP
+ setContent(newContent);
+ }
+ }, [batchData]);
+
+ console.log(content);
return (
@@ -26,56 +133,52 @@ function BatchCard({ batchData }) {
- {batchName}
+ {content.name}
- {displayMessage}
+ {content.displayMessage}
- {timestamp}
+ {content.timestamp}
-
- {status.label}
+
+ {content.statusText}
-
-
+
+
- {progress}%
+ {content.progress}%
-
- {isCancelled ? "Details" : isCompleted ? "Continue" : "Details"}
-
+ {content.buttonText &&
+
+ {content.buttonText}
+
+ }
) : (
{/* 1. Thumbnail */}
- {batchName}
+ {content.name}
- {displayMessage} | {timestamp}
+ {content.displayMessage || "No message"} | {content.timestamp || "Unknown Timestamp"}
{/* 3. Progress */}
-
-
+
+
- {progress}%
+ {content.progress}%
@@ -122,23 +219,28 @@ function BatchCard({ batchData }) {
{/* 4. Status */}
- {status.label}
+ {content.statusText || "Unknown"}
{/* 5. Button */}
-
- {isCancelled ? "Details" : isCompleted ? "Continue" : "Details"}
-
+ {content.buttonText &&
+
+ {content.buttonText}
+
+ }
)}
diff --git a/src/pages/DataImport.jsx b/src/pages/DataImport.jsx
index 736b01e..dff2c0e 100644
--- a/src/pages/DataImport.jsx
+++ b/src/pages/DataImport.jsx
@@ -107,12 +107,12 @@ function DataImport() {
const unprocessed = artefacts.filter(a => a.stage === "unprocessed").length;
const confirmed = artefacts.filter(a => a.stage === "confirmed").length;
const integrated = artefacts.filter(a => a.stage === "integrated").length;
- const total = processed + unprocessed
+ const total = artefacts.length;
return {
id,
...batch,
- artefactSummary: { processed, total, confirmed, integrated },
+ artefactSummary: { processed, total, confirmed, integrated, unprocessed },
};
});
@@ -272,6 +272,8 @@ function DataImport() {
))
From 3b4d00cc0e1d360f777b7f90b18ed9af51d2d03d Mon Sep 17 00:00:00 2001
From: Prakhar Trivedi
Date: Thu, 14 Aug 2025 18:31:24 +0800
Subject: [PATCH 5/9] added action for continue vetting
---
src/components/DataImport/BatchCard.jsx | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/src/components/DataImport/BatchCard.jsx b/src/components/DataImport/BatchCard.jsx
index e8cec4d..d90a81b 100644
--- a/src/components/DataImport/BatchCard.jsx
+++ b/src/components/DataImport/BatchCard.jsx
@@ -2,8 +2,11 @@ import { HStack, VStack, Text, Image, Button, Card, Progress, useBreakpointValue
import { useEffect, useState } from "react";
import server, { JSONResponse } from '../../networking';
import ToastWizard from "../toastWizard";
+import { useNavigate } from "react-router-dom";
function BatchCard({ batchData, formatTimestamp, fetchBatches }) {
+ const navigate = useNavigate();
+
const statusColours = {
"upload_pending": "yellow.500",
"processing": "blue.500",
@@ -76,9 +79,21 @@ function BatchCard({ batchData, formatTimestamp, fetchBatches }) {
setRequestInProgress(false);
}
return;
+ } else if (content.buttonText === "Continue Vetting") {
+ for (const artefactID in batchData.artefacts) {
+ if (batchData.artefacts[artefactID].stage !== "confirmed") {
+ navigate(`/studio/${batchData.id}/${artefactID}`);
+ return;
+ }
+ }
+
+ ToastWizard.standard("info", "Refresh page", "All artefacts in this batch have already been confirmed.");
+ return;
}
}
+ console.log(batchData)
+
useEffect(() => {
if (batchData) {
var newContent = { ...content };
From 146e51369f18c44974fb765a29aa99c4d2b9fe52 Mon Sep 17 00:00:00 2001
From: Prakhar Trivedi
Date: Thu, 14 Aug 2025 18:38:32 +0800
Subject: [PATCH 6/9] added start integration click handling
---
src/components/DataImport/BatchCard.jsx | 45 +++++++++++++++++++++++--
1 file changed, 43 insertions(+), 2 deletions(-)
diff --git a/src/components/DataImport/BatchCard.jsx b/src/components/DataImport/BatchCard.jsx
index d90a81b..55a31ee 100644
--- a/src/components/DataImport/BatchCard.jsx
+++ b/src/components/DataImport/BatchCard.jsx
@@ -89,6 +89,47 @@ function BatchCard({ batchData, formatTimestamp, fetchBatches }) {
ToastWizard.standard("info", "Refresh page", "All artefacts in this batch have already been confirmed.");
return;
+ } else if (content.buttonText === "Start Integration") {
+ setRequestInProgress(true);
+
+ try {
+ const response = await server.post('/dataImport/integration/start', {
+ batchID: batchData.id
+ })
+
+ if (response.data instanceof JSONResponse) {
+ if (response.data.isErrorStatus()) {
+ const errObject = {
+ response: {
+ data: response.data
+ }
+ };
+ throw new Error(errObject);
+ }
+
+ // Success case
+ if (fetchBatches) {
+ fetchBatches();
+ }
+ ToastWizard.standard("success", `Integration for '${batchData.name || 'Unknown'}' started`, "Batch is now being integrated. This may take some time.");
+ } else {
+ throw new Error("Unexpected response format");
+ }
+ } catch (err) {
+ if (err.response && err.response.data instanceof JSONResponse) {
+ console.log("Error response in batch start integration request:", err.response.data.fullMessage());
+ if (err.response.data.userErrorType()) {
+ ToastWizard.standard("error", "Integration request failed.", err.response.data.message);
+ } else {
+ ToastWizard.standard("error", "Something went wrong", "Couldn't start integration. Please try again.")
+ }
+ } else {
+ console.log("Unexpected error in batch start integration request:", err);
+ ToastWizard.standard("error", "Something went wrong", "Couldn't start integration. Please try again.");
+ }
+ } finally {
+ setRequestInProgress(false);
+ }
}
}
@@ -148,7 +189,7 @@ function BatchCard({ batchData, formatTimestamp, fetchBatches }) {
Date: Thu, 14 Aug 2025 18:44:40 +0800
Subject: [PATCH 7/9] added handling for view details
---
src/components/DataImport/BatchCard.jsx | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/components/DataImport/BatchCard.jsx b/src/components/DataImport/BatchCard.jsx
index 55a31ee..d459017 100644
--- a/src/components/DataImport/BatchCard.jsx
+++ b/src/components/DataImport/BatchCard.jsx
@@ -130,6 +130,10 @@ function BatchCard({ batchData, formatTimestamp, fetchBatches }) {
} finally {
setRequestInProgress(false);
}
+ } else if (content.buttonText === "View Details") {
+ navigate(`/studio/${batchData.id}`);
+ } else {
+ ToastWizard.standard("info", "No action available", "This batch is in a state that does not require any further action at this time.");
}
}
@@ -172,7 +176,7 @@ function BatchCard({ batchData, formatTimestamp, fetchBatches }) {
newContent.progress = Math.round((batchData.artefactSummary.integrated || 0) / (batchData.artefactSummary.total || 1) * 100);
newContent.statusColour = statusColours.completed;
newContent.statusText = "Completed";
- newContent.buttonText = null;
+ newContent.buttonText = "View Details";
newContent.buttonLoadingText = '';
}
From 853db4612d666146d7aff9ddd5356c7a5e0fb734 Mon Sep 17 00:00:00 2001
From: Prakhar Trivedi
Date: Thu, 14 Aug 2025 18:45:54 +0800
Subject: [PATCH 8/9] removed raw query param from batch preview link
---
src/components/DataImport/BatchCard.jsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/components/DataImport/BatchCard.jsx b/src/components/DataImport/BatchCard.jsx
index d459017..720b246 100644
--- a/src/components/DataImport/BatchCard.jsx
+++ b/src/components/DataImport/BatchCard.jsx
@@ -193,7 +193,7 @@ function BatchCard({ batchData, formatTimestamp, fetchBatches }) {
Date: Fri, 15 Aug 2025 11:18:50 +0800
Subject: [PATCH 9/9] fixed loading text at the point where starting
integration is available
---
src/components/DataImport/BatchCard.jsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/DataImport/BatchCard.jsx b/src/components/DataImport/BatchCard.jsx
index 720b246..e9121a9 100644
--- a/src/components/DataImport/BatchCard.jsx
+++ b/src/components/DataImport/BatchCard.jsx
@@ -163,7 +163,7 @@ function BatchCard({ batchData, formatTimestamp, fetchBatches }) {
newContent.statusColour = statusColours.vetting;
newContent.statusText = "Vetting";
newContent.buttonText = batchData.artefactSummary.confirmed == batchData.artefactSummary.total ? 'Start Integration' : 'Continue Vetting';
- newContent.buttonLoadingText = 'Continue Vetting';
+ newContent.buttonLoadingText = 'Starting...';
} else if (batchData.stage === "integration") {
newContent.displayMessage = `${batchData.artefactSummary.integrated || 0}/${batchData.artefactSummary.total || 0} Integrated`
newContent.progress = Math.round((batchData.artefactSummary.integrated || 0) / (batchData.artefactSummary.total || 1) * 100);