@@ -195,17 +152,11 @@ const DeleteImagesAlert = () => {
{isSpinnerActive && (
-
-
-
-
-
+
)}
{title}
diff --git a/src/features/images/DeleteImagesProgressBar.jsx b/src/features/images/DeleteImagesProgressBar.jsx
new file mode 100644
index 00000000..fb7ea937
--- /dev/null
+++ b/src/features/images/DeleteImagesProgressBar.jsx
@@ -0,0 +1,75 @@
+import React, { useState, useEffect } from 'react';
+import * as Progress from '@radix-ui/react-progress';
+import { green } from '@radix-ui/colors';
+import { styled } from '../../theme/stitches.config.js';
+
+const ProgressBar = styled('div', {
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ position: 'absolute',
+ bottom: 0,
+ width: '100%',
+});
+
+const ProgressRoot = styled(Progress.Root, {
+ overflow: 'hidden',
+ background: '$backgroundDark',
+ // borderRadius: '99999px',
+ width: '100%',
+ height: '8px',
+
+ /* Fix overflow clipping in Safari */
+ /* https://gist.github.com/domske/b66047671c780a238b51c51ffde8d3a0 */
+ transform: 'translateZ(0)',
+});
+
+const ProgressIndicator = styled(Progress.Indicator, {
+ backgroundColor: green.green9, //sky.sky4, //'$blue600',
+ width: '100%',
+ height: '100%',
+ transition: 'transform 660ms cubic-bezier(0.65, 0, 0.35, 1)',
+});
+
+// show progress bar if deleting more than 3000 images (approx wait time will be > 10 seconds)
+const PROGRESS_BAR_IMAGE_COUNT_BREAKPOINT = 3000;
+
+export const DeleteImagesProgressBar = ({ imageCount }) => {
+ const [estimatedTotalTime, setEstimatedTotalTime] = useState(
+ imageCount > PROGRESS_BAR_IMAGE_COUNT_BREAKPOINT
+ ? imageCount * 0.0055 // estimated deletion time per image in seconds
+ : null,
+ ); // in seconds
+ const [elapsedTime, setElapsedTime] = useState(
+ imageCount > PROGRESS_BAR_IMAGE_COUNT_BREAKPOINT ? 0 : null,
+ );
+
+ useEffect(() => {
+ if (estimatedTotalTime) {
+ const interval = setInterval(() => {
+ setElapsedTime((prevElapsedTime) => {
+ if (prevElapsedTime >= estimatedTotalTime) {
+ clearInterval(interval);
+ setEstimatedTotalTime(null);
+ setElapsedTime(null);
+ return estimatedTotalTime;
+ }
+ return prevElapsedTime + 1;
+ });
+ }, 1000);
+ return () => clearInterval(interval);
+ }
+ }, [estimatedTotalTime, elapsedTime]);
+
+ return (
+
+
+
+
+
+ );
+};
diff --git a/src/features/images/imagesSlice.js b/src/features/images/imagesSlice.js
index ea10446c..316fe88f 100644
--- a/src/features/images/imagesSlice.js
+++ b/src/features/images/imagesSlice.js
@@ -189,8 +189,7 @@ export const imagesSlice = createSlice({
if (openStatus) {
state.deleteImagesAlertState.deleteImagesAlertOpen = openStatus;
state.deleteImagesAlertState.deleteImagesAlertByFilter = deleteImagesByFilter;
- }
- else {
+ } else {
state.deleteImagesAlertState.deleteImagesAlertOpen = openStatus;
state.deleteImagesAlertState.deleteImagesAlertByFilter = null;
}
@@ -350,10 +349,10 @@ export const deleteImages = (imageIds) => async (dispatch, getState) => {
);
dispatch(setSelectedImageIndices([]));
dispatch(deleteImagesSuccess(imageIds));
- dispatch(setDeleteImagesAlertStatus({ openStatus: false }));
} catch (err) {
console.log(`error attempting to delete image: `, err);
dispatch(deleteImagesError(err));
+ } finally {
dispatch(setDeleteImagesAlertStatus({ openStatus: false }));
}
};
diff --git a/src/features/tasks/tasksSlice.js b/src/features/tasks/tasksSlice.js
index 9762d7a7..fa1060d8 100644
--- a/src/features/tasks/tasksSlice.js
+++ b/src/features/tasks/tasksSlice.js
@@ -10,7 +10,15 @@ import {
} from '../projects/projectsSlice';
import { toggleOpenLoupe } from '../loupe/loupeSlice';
import { setFocus, setSelectedImageIndices } from '../review/reviewSlice.js';
-import { fetchImages, fetchImagesCount, setDeleteImagesAlertStatus } from '../images/imagesSlice.js';
+import {
+ fetchImages,
+ fetchImagesCount,
+ setDeleteImagesAlertStatus,
+} from '../images/imagesSlice.js';
+import {
+ setDeleteCameraAlertStatus,
+ clearCameraImageCount,
+} from '../cameras/wirelessCamerasSlice.js';
const initialState = {
loadingStates: {
@@ -44,10 +52,15 @@ const initialState = {
isLoading: false,
errors: null,
},
+ deleteCamera: {
+ taskId: null,
+ isLoading: false,
+ errors: null,
+ },
deleteImages: {
taskId: null,
isLoading: false,
- errors: null
+ errors: null,
},
},
imagesStats: null,
@@ -262,6 +275,42 @@ export const tasksSlice = createSlice({
state.loadingStates.cameraSerialNumber.errors.splice(index, 1);
},
+ // delete camera
+
+ updateDeleteCameraStart: (state) => {
+ let ls = state.loadingStates.deleteCamera;
+ ls.taskId = null;
+ ls.isLoading = true;
+ ls.errors = null;
+ },
+
+ updateDeleteCameraUpdate: (state, { payload }) => {
+ state.loadingStates.deleteCamera.taskId = payload.taskId;
+ },
+
+ updateDeleteCameraSuccess: (state) => {
+ let ls = state.loadingStates.deleteCamera;
+ ls.taskId = null;
+ ls.isLoading = false;
+ ls.errors = null;
+ },
+
+ updateDeleteCameraFailure: (state, { payload }) => {
+ let ls = state.loadingStates.deleteCamera;
+ ls.isLoading = false;
+ ls.errors = [payload.task.output.error];
+ },
+
+ clearDeleteCameraTask: (state) => {
+ state.loadingStates.deleteCamera = initialState.loadingStates.deleteCamera;
+ },
+
+ dismissDeleteCameraError: (state, { payload }) => {
+ const index = payload;
+ state.loadingStates.deleteCamera.taskId = null;
+ state.loadingStates.deleteCamera.errors.splice(index, 1);
+ },
+
// delete images
deleteImagesStart: (state) => {
@@ -297,7 +346,6 @@ export const tasksSlice = createSlice({
state.loadingStates.deleteImages.taskId = null;
state.loadingStates.deleteImages.errors.splice(index, 1);
},
-
},
});
@@ -339,6 +387,13 @@ export const {
clearCameraSerialNumberTask,
dismissCameraSerialNumberError,
+ updateDeleteCameraStart,
+ updateDeleteCameraUpdate,
+ updateDeleteCameraSuccess,
+ updateDeleteCameraFailure,
+ clearDeleteCameraTask,
+ dismissDeleteCameraError,
+
deleteImagesStart,
deleteImagesUpdate,
deleteImagesSuccess,
@@ -410,6 +465,19 @@ export const fetchTask = (taskId) => {
},
FAIL: (res) => dispatch(updateCameraSerialNumberFailure(res)),
},
+ DeleteCamera: {
+ COMPLETE: () => {
+ dispatch(updateDeleteCameraSuccess());
+ dispatch(toggleOpenLoupe(false));
+ dispatch(setModalOpen(false));
+ dispatch(setModalContent(null));
+ dispatch(setSelectedCamera(null));
+ dispatch(setDeleteCameraAlertStatus({ isOpen: false }));
+ dispatch(clearCameraImageCount());
+ dispatch(fetchProjects({ _ids: [selectedProj._id] }));
+ },
+ FAIL: (res) => dispatch(updateDeleteCameraFailure(res)),
+ },
DeleteImages: {
COMPLETE: (res) => {
const filters = getState().filters.activeFilters;
@@ -425,7 +493,7 @@ export const fetchTask = (taskId) => {
dispatch(fetchImages(filters));
dispatch(fetchImagesCount(filters));
},
- FAIL: (res) => dispatch(deleteImagesFailure(res))
+ FAIL: (res) => dispatch(deleteImagesFailure(res)),
},
DeleteImagesByFilter: {
COMPLETE: (res) => {
@@ -442,8 +510,8 @@ export const fetchTask = (taskId) => {
dispatch(fetchImagesCount(res.task.output.filters));
},
- FAIL: (res) => dispatch(deleteImagesFailure(res))
- }
+ FAIL: (res) => dispatch(deleteImagesFailure(res)),
+ },
};
if (res.task.type.includes('Deployment')) {
@@ -590,6 +658,29 @@ export const updateCameraSerialNumber = (payload) => {
};
};
+export const deleteCamera = (payload) => {
+ return async (dispatch, getState) => {
+ try {
+ dispatch(updateDeleteCameraStart());
+ const currentUser = await Auth.currentAuthenticatedUser();
+ const token = currentUser.getSignInUserSession().getIdToken().getJwtToken();
+ const projects = getState().projects.projects;
+ const selectedProj = projects.find((proj) => proj.selected);
+ if (token && selectedProj) {
+ const res = await call({
+ projId: selectedProj._id,
+ request: 'deleteCameraConfig',
+ input: payload,
+ });
+ console.log('deleteCamera - res: ', res);
+ dispatch(updateDeleteCameraUpdate({ taskId: res.deleteCameraConfig._id }));
+ }
+ } catch (err) {
+ dispatch(updateDeleteCameraFailure(err));
+ }
+ };
+};
+
// delete images thunk
export const deleteImagesTask = ({ imageIds = [], filters = null }) => {
/**
@@ -621,14 +712,12 @@ export const deleteImagesTask = ({ imageIds = [], filters = null }) => {
dispatch(deleteImagesUpdate({ taskId: res.deleteImagesTask._id }));
}
}
- }
- catch (err) {
+ } catch (err) {
dispatch(deleteImagesFailure(err));
}
};
};
-
export const selectImagesStats = (state) => state.tasks.imagesStats;
export const selectStatsLoading = (state) => state.tasks.loadingStates.stats;
export const selectStatsErrors = (state) => state.tasks.loadingStates.stats.errors;
@@ -646,6 +735,8 @@ export const selectCameraSerialNumberLoading = (state) =>
state.tasks.loadingStates.cameraSerialNumber;
export const selectCameraSerialNumberErrors = (state) =>
state.tasks.loadingStates.cameraSerialNumber.errors;
+export const selectDeleteCameraLoading = (state) => state.tasks.loadingStates.deleteCamera;
+export const selectDeleteCameraErrors = (state) => state.tasks.loadingStates.deleteCamera.errors;
export const selectDeleteImagesLoading = (state) => state.tasks.loadingStates.deleteImages;
export const selectDeleteImagesErrors = (state) => state.tasks.loadingStates.deleteImages.errors;