diff --git a/client/src/AlertDialog/AlertDialog.test.js b/client/src/AlertDialog/AlertDialog.test.js
new file mode 100644
index 0000000..356b52f
--- /dev/null
+++ b/client/src/AlertDialog/AlertDialog.test.js
@@ -0,0 +1,43 @@
+import React from 'react';
+import { render, fireEvent, screen } from '@testing-library/react';
+import '@testing-library/jest-dom';
+import AlertDialog from './index';
+
+describe('AlertDialog Component', () => {
+ const handleClose = jest.fn();
+ const handleExit = jest.fn();
+ const title = "Are you sure you want to exit?";
+ const description = "Do you really want to exit? This action will clear the storage and all data will be lost.";
+ const exitConfirm = "Agree";
+ const exitCancel = "Cancel";
+
+ beforeEach(() => {
+ render(
+
+ );
+ });
+
+ test('renders the alert dialog with correct title and description', () => {
+ expect(screen.getByTestId('alert-dialog')).toBeInTheDocument();
+ expect(screen.getByTestId('alert-dialog-title')).toHaveTextContent(title);
+ expect(screen.getByTestId('alert-dialog-description')).toHaveTextContent(description);
+ });
+
+ test('calls handleClose when cancel button is clicked', () => {
+ fireEvent.click(screen.getByTestId('disagree-button'));
+ expect(handleClose).toHaveBeenCalledTimes(1);
+ });
+
+ test('calls handleExit when agree button is clicked', () => {
+ fireEvent.click(screen.getByTestId('agree-button'));
+ expect(handleExit).toHaveBeenCalledTimes(1);
+ });
+});
diff --git a/client/src/AlertDialog/index.jsx b/client/src/AlertDialog/index.jsx
new file mode 100644
index 0000000..c7f783c
--- /dev/null
+++ b/client/src/AlertDialog/index.jsx
@@ -0,0 +1,38 @@
+import * as React from 'react';
+import Button from '@mui/material/Button';
+import Dialog from '@mui/material/Dialog';
+import DialogActions from '@mui/material/DialogActions';
+import DialogContent from '@mui/material/DialogContent';
+import DialogContentText from '@mui/material/DialogContentText';
+import DialogTitle from '@mui/material/DialogTitle';
+
+export const AlertDialog = (props) => {
+ const { open, handleClose, handleExit, title, description, exitConfirm, exitCancel } = props;
+
+ return (
+
+ );
+}
+
+export default AlertDialog;
\ No newline at end of file
diff --git a/client/src/Annotation/index.jsx b/client/src/Annotation/index.jsx
index 28f9f16..3690bc0 100644
--- a/client/src/Annotation/index.jsx
+++ b/client/src/Annotation/index.jsx
@@ -8,7 +8,10 @@ import { useSnackbar } from '../SnackbarContext'
import { getImagesAnnotation } from "../utils/send-data-to-server"
import CircularProgress from '@mui/material/CircularProgress';
import Box from '@mui/material/Box';
+import AlertDialog from "../AlertDialog";
+import { clear_db } from "../utils/get-data-from-server"
import colors from "../colors.js";
+import {useTranslation} from "react-i18next"
const extractRelevantProps = (region) => ({
cls: region.cls,
@@ -52,6 +55,8 @@ const userReducer = (state, action) => {
export default () => {
const [selectedImageIndex, changeSelectedImageIndex] = useState(0)
+ const [open, setOpen] = useState(false);
+ const {t} = useTranslation();
const [showLabel, setShowLabel] = useState(false)
const [isSettingsOpen, setIsSettingsOpen] = useState(false)
const [imageNames, setImageNames] = useState([])
@@ -71,7 +76,18 @@ export default () => {
}
})
-
+ const handleClickOpen = () => {
+ setOpen(true);
+ };
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+ const handleExit = () => {
+ logout()
+ handleClose()
+ }
+
const [loading, setLoading] = useState(true); // Add loading state
const onSelectJumpHandle = (selectedImageName) => {
@@ -181,6 +197,23 @@ export default () => {
const regions = [ {name: "Polygon", value: "create-polygon"}, {name: "Bounding Box", value: "create-box"}, {name: "Point", value: "create-point"}]
return regions.filter(region => region.name === toolName)[0]?.value || "create-polygon"
}
+
+ const reloadApp = () => {
+ settingsConfig.changeSetting('settings', null);
+ window.location.reload();
+ }
+
+ const logout = async () => {
+ try {
+ const response = await clear_db();
+ showSnackbar(response.message, 'success');
+ await new Promise(resolve => setTimeout(resolve, 500)); // Wait for 500 milliseconds
+ } catch (error) {
+ showSnackbar(error.message, 'error');
+ }
+ reloadApp()
+ };
+
const preloadConfiguration = () => {
// get last saved configuration
const savedConfiguration = settingsConfig.settings|| {};
@@ -221,29 +254,40 @@ export default () => {
) : (
- label.id) || []}
- selectedImage={selectedImageIndex}
- enabledRegionProps={["class", "comment"]}
- userReducer={userReducer}
- onExit={(output) => {
- console.log("Exiting!");
- }}
- settings={settings}
- onSelectJump={onSelectJumpHandle}
- showTags={true}
- selectedTool={getToolSelectionType(settings.configuration.regions)}
- openDocs={() => window.open(config.DOCS_URL, '_blank')}
- hideSettings={false}
- onShowSettings={() => {
- setIsSettingsOpen(!isSettingsOpen);
- setShowLabel(false);
- }}
- selectedImageIndex={selectedImageIndex}
- />
+ <>
+
+ label.id) || []}
+ selectedImage={selectedImageIndex}
+ enabledRegionProps={["class", "comment"]}
+ userReducer={userReducer}
+ onExit={(output) => {
+ handleClickOpen()
+ }}
+ settings={settings}
+ onSelectJump={onSelectJumpHandle}
+ showTags={true}
+ selectedTool={getToolSelectionType(settings.configuration.regions)}
+ openDocs={() => window.open(config.DOCS_URL, '_blank')}
+ hideSettings={false}
+ onShowSettings={() => {
+ setIsSettingsOpen(!isSettingsOpen);
+ setShowLabel(false);
+ }}
+ selectedImageIndex={selectedImageIndex}
+ />
+ >
)}
>
)}
diff --git a/client/src/Annotator/index.jsx b/client/src/Annotator/index.jsx
index dc5669b..936ece0 100644
--- a/client/src/Annotator/index.jsx
+++ b/client/src/Annotator/index.jsx
@@ -207,6 +207,7 @@ export const Annotator = ({
hideSettings={hideSettings}
hideSave={hideSave}
allImages= {allImages}
+ onExit={onExit}
enabledRegionProps={enabledRegionProps}
onSelectJump={onSelectJump}
saveActiveImage = {saveCurrentData}
diff --git a/client/src/Localization/translation-de-DE.js b/client/src/Localization/translation-de-DE.js
index 7ab1486..0193a4d 100644
--- a/client/src/Localization/translation-de-DE.js
+++ b/client/src/Localization/translation-de-DE.js
@@ -82,7 +82,11 @@ const translationDeDE = {
"expand_selection": "Auswahl erweitern",
"collapse_selection": "Auswahl verkleinern",
"error.image_not_found": "Bild nicht gefunden",
- "info": "Die Info"
+ "info": "Die Info",
+ "exit_alert_title": "Sind Sie sicher, dass Sie beenden möchten?",
+ "exit_alert_description": "Möchten Sie wirklich beenden? Diese Aktion wird den Speicher löschen und alle Daten werden verloren gehen.",
+ "exit_alert_cancel": "Abbrechen",
+ "exit_alert_confirm": "Zustimmen",
};
export default translationDeDE;
diff --git a/client/src/Localization/translation-en-EN.js b/client/src/Localization/translation-en-EN.js
index d2a8f60..158396c 100644
--- a/client/src/Localization/translation-en-EN.js
+++ b/client/src/Localization/translation-en-EN.js
@@ -84,6 +84,10 @@ const translationEnEN = {
"collapse_selection": "Collapse selection",
"error.image_not_found": "Image not found",
"info": "Info",
+ "exit_alert_title": "Are you sure you want to exit?",
+ "exit_alert_description": "Do you really want to exit? This action will clear the storage and all data will be lost.",
+ "exit_alert_cancel": "Cancel",
+ "exit_alert_confirm": "Exit",
};
export default translationEnEN;
diff --git a/client/src/MainLayout/index.jsx b/client/src/MainLayout/index.jsx
index ba2f014..16eb86f 100644
--- a/client/src/MainLayout/index.jsx
+++ b/client/src/MainLayout/index.jsx
@@ -25,7 +25,6 @@ import {withHotKeys} from "react-hotkeys"
import {Save, ExitToApp} from "@mui/icons-material"
import capitalize from "lodash/capitalize"
import { useTranslation } from "react-i18next"
-import { clear_db } from "../utils/get-data-from-server"
import { useSnackbar} from "../SnackbarContext"
import ClassDistributionSidebarBox from "../ClassDistributionSidebarBox"
@@ -45,6 +44,7 @@ export const MainLayout = ({
onRegionClassAdded,
hideHeader,
hideHeaderText,
+ onExit,
hideClone = true,
hideSettings = false,
hideSave = false,
@@ -97,21 +97,6 @@ export const MainLayout = ({
}
}, [])
- const reloadApp = () => {
- settings.changeSetting('settings', null);
- window.location.reload();
- }
-
- const logout = async () => {
- try {
- const response = await clear_db();
- showSnackbar(response.message, 'success');
- await new Promise(resolve => setTimeout(resolve, 500)); // Wait for 500 milliseconds
- } catch (error) {
- showSnackbar(error.message, 'error');
- }
- reloadApp()
- };
const canvas = (
{
if(item.name === "Exit"){
- logout()
+ onExit()
} else {
dispatch({type: "HEADER_BUTTON_CLICKED", buttonName: item.name})
}