Skip to content

Commit

Permalink
add confirmation box on exit button click
Browse files Browse the repository at this point in the history
  • Loading branch information
sumn2u committed Jul 8, 2024
1 parent 0bb65ac commit 3d4a1c6
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 42 deletions.
43 changes: 43 additions & 0 deletions client/src/AlertDialog/AlertDialog.test.js
Original file line number Diff line number Diff line change
@@ -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(
<AlertDialog
open={true}
handleClose={handleClose}
handleExit={handleExit}
title={title}
description={description}
exitConfirm={exitConfirm}
exitCancel={exitCancel}
/>
);
});

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);
});
});
38 changes: 38 additions & 0 deletions client/src/AlertDialog/index.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<Dialog
open={open}
onClose={handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
data-testid="alert-dialog"
>
<DialogTitle id="alert-dialog-title" data-testid="alert-dialog-title">
{title}
</DialogTitle>
<DialogContent data-testid="alert-dialog-content">
<DialogContentText id="alert-dialog-description" data-testid="alert-dialog-description">
{description}
</DialogContentText>
</DialogContent>
<DialogActions data-testid="alert-dialog-actions">
<Button onClick={handleClose} data-testid="disagree-button">{exitCancel}</Button>
<Button onClick={handleExit} autoFocus data-testid="agree-button">
{exitConfirm}
</Button>
</DialogActions>
</Dialog>
);
}

export default AlertDialog;
92 changes: 68 additions & 24 deletions client/src/Annotation/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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([])
Expand All @@ -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) => {

Expand Down Expand Up @@ -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|| {};
Expand Down Expand Up @@ -221,29 +254,40 @@ export default () => {
<CircularProgress />
</Box>
) : (
<Annotator
taskDescription={settings.taskDescription || "Annotate each image according to this _markdown_ specification."}
images={settings.images || []}
enabledTools={getEnabledTools(settings.configuration.regionTypesAllowed) || []}
regionClsList={settings.configuration.labels.map(label => 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}
/>
<>
<AlertDialog
open={open}
handleClose={handleClose}
title={t("exit_alert_title")}
description={t("exit_alert_description")}
exitConfirm={t("exit_alert_confirm")}
exitCancel={t("exit_alert_cancel")}
handleExit= {handleExit}
/>
<Annotator
taskDescription={settings.taskDescription || "Annotate each image according to this _markdown_ specification."}
images={settings.images || []}
enabledTools={getEnabledTools(settings.configuration.regionTypesAllowed) || []}
regionClsList={settings.configuration.labels.map(label => 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}
/>
</>
)}
</>
)}
Expand Down
1 change: 1 addition & 0 deletions client/src/Annotator/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ export const Annotator = ({
hideSettings={hideSettings}
hideSave={hideSave}
allImages= {allImages}
onExit={onExit}
enabledRegionProps={enabledRegionProps}
onSelectJump={onSelectJump}
saveActiveImage = {saveCurrentData}
Expand Down
6 changes: 5 additions & 1 deletion client/src/Localization/translation-de-DE.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
4 changes: 4 additions & 0 deletions client/src/Localization/translation-en-EN.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
19 changes: 2 additions & 17 deletions client/src/MainLayout/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -45,6 +44,7 @@ export const MainLayout = ({
onRegionClassAdded,
hideHeader,
hideHeaderText,
onExit,
hideClone = true,
hideSettings = false,
hideSave = false,
Expand Down Expand Up @@ -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 = (
<ImageCanvas
Expand Down Expand Up @@ -197,7 +182,7 @@ export const MainLayout = ({

const onClickHeaderItem = useEventCallback((item) => {
if(item.name === "Exit"){
logout()
onExit()
} else {
dispatch({type: "HEADER_BUTTON_CLICKED", buttonName: item.name})
}
Expand Down

0 comments on commit 3d4a1c6

Please sign in to comment.