diff --git a/frontend/src/components/UploadToast.tsx b/frontend/src/components/UploadToast.tsx
index 1c200d29..673f0f5b 100644
--- a/frontend/src/components/UploadToast.tsx
+++ b/frontend/src/components/UploadToast.tsx
@@ -4,7 +4,7 @@ import { useDispatch, useSelector } from 'react-redux';
import { useTranslation } from 'react-i18next';
import {
selectUploadTasks,
- removeUploadTask,
+ dismissUploadTask,
clearCompletedTasks,
} from '../upload/uploadSlice';
import ChevronDown from '../assets/chevron-down.svg';
@@ -30,8 +30,6 @@ export default function UploadToast() {
const dispatch = useDispatch();
const uploadTasks = useSelector(selectUploadTasks);
- if (uploadTasks.length === 0) return null;
-
const getStatusHeading = (status: string) => {
switch (status) {
case 'preparing':
@@ -51,63 +49,64 @@ export default function UploadToast() {
return (
- {uploadTasks.map((task) => {
- const shouldShowProgress = [
- 'preparing',
- 'uploading',
- 'training',
- ].includes(task.status);
- const rawProgress = Math.min(Math.max(task.progress ?? 0, 0), 100);
- const formattedProgress = Math.round(rawProgress);
- const progressOffset = PROGRESS_CIRCUMFERENCE * (1 - rawProgress / 100);
- const isCollapsed = collapsedTasks[task.id] ?? false;
+ {uploadTasks
+ .filter((task) => !task.dismissed)
+ .map((task) => {
+ const shouldShowProgress = [
+ 'preparing',
+ 'uploading',
+ 'training',
+ ].includes(task.status);
+ const rawProgress = Math.min(Math.max(task.progress ?? 0, 0), 100);
+ const formattedProgress = Math.round(rawProgress);
+ const progressOffset =
+ PROGRESS_CIRCUMFERENCE * (1 - rawProgress / 100);
+ const isCollapsed = collapsedTasks[task.id] ?? false;
- return (
-
-
-
-
- {getStatusHeading(task.status)}
-
-
-
- {(task.status === 'completed' ||
- task.status === 'failed') && (
+ : task.status === 'failed'
+ ? 'bg-[#FBFBFB] dark:bg-[#26272E]'
+ : 'bg-[#FBFBFB] dark:bg-[#26272E]'
+ }`}
+ >
+
+
+
+ {getStatusHeading(task.status)}
+
+
+
- )}
-
-
-
-
-
-
-
- {task.fileName}
-
-
-
- {shouldShowProgress && (
-
- )}
-
- {task.status === 'completed' && (
-

- )}
-
- {task.status === 'failed' && (
-

- )}
-
+
- {task.status === 'failed' && task.errorMessage && (
-
- {task.errorMessage}
-
- )}
+
+
+
+
+ {task.fileName}
+
+
+
+ {shouldShowProgress && (
+
+ )}
+
+ {task.status === 'completed' && (
+

+ )}
+
+ {task.status === 'failed' && (
+

+ )}
+
+
+
+ {task.status === 'failed' && task.errorMessage && (
+
+ {task.errorMessage}
+
+ )}
+
-
- );
- })}
+ );
+ })}
{uploadTasks.some(
(task) => task.status === 'completed' || task.status === 'failed',
diff --git a/frontend/src/upload/uploadSlice.ts b/frontend/src/upload/uploadSlice.ts
index 5d18ebb2..eb9ef13c 100644
--- a/frontend/src/upload/uploadSlice.ts
+++ b/frontend/src/upload/uploadSlice.ts
@@ -24,6 +24,7 @@ export interface UploadTask {
status: UploadTaskStatus;
taskId?: string;
errorMessage?: string;
+ dismissed?: boolean;
}
interface UploadState {
@@ -83,10 +84,30 @@ export const uploadSlice = createSlice({
const index = state.tasks.findIndex(
(task) => task.id === action.payload.id,
);
+ if (index !== -1) {
+ const updates = action.payload.updates;
+
+ // When task completes or fails, set dismissed to false to notify user
+ if (updates.status === 'completed' || updates.status === 'failed') {
+ state.tasks[index] = {
+ ...state.tasks[index],
+ ...updates,
+ dismissed: false,
+ };
+ } else {
+ state.tasks[index] = {
+ ...state.tasks[index],
+ ...updates,
+ };
+ }
+ }
+ },
+ dismissUploadTask: (state, action: PayloadAction
) => {
+ const index = state.tasks.findIndex((task) => task.id === action.payload);
if (index !== -1) {
state.tasks[index] = {
...state.tasks[index],
- ...action.payload.updates,
+ dismissed: true,
};
}
},
@@ -111,6 +132,7 @@ export const {
clearAttachments,
addUploadTask,
updateUploadTask,
+ dismissUploadTask,
removeUploadTask,
clearCompletedTasks,
} = uploadSlice.actions;