Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/src/core/code/code_dto.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
class CodeBaseDTO(BaseModel):
name: str = Field(description="Name of the Code")
color: str = Field(description="Color of the Code")
description: str = Field(description="Description of the Code")
description: str = Field(description="Description of the Code", default="")
parent_id: int | None = Field(description="Parent of the Code", default=None)
enabled: bool = Field(
default=True,
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/api/openapi/models/CodeCreate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export type CodeCreate = {
/**
* Description of the Code
*/
description: string;
description?: string;
/**
* Parent of the Code
*/
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/api/openapi/models/CodeRead.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export type CodeRead = {
/**
* Description of the Code
*/
description: string;
description?: string;
/**
* Parent of the Code
*/
Expand Down
1 change: 0 additions & 1 deletion frontend/src/components/Code/CodeCreateDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,6 @@ function CodeCreateDialog() {
<FormTextMultiline
name="description"
control={control}
rules={{ required: "Description is required" }}
textFieldProps={{
label: "Description",
error: Boolean(errors.description),
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Code/CodeEditDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ function CodeEditDialog() {
if (code && !code.is_system) {
ConfirmationAPI.openConfirmationDialog({
text: `Do you really want to delete the code "${code.name}"? This action cannot be undone!`,
type: "DELETE",
onAccept: () => {
deleteCodeMutation(
{ codeId: code.id },
Expand Down Expand Up @@ -213,7 +214,6 @@ function CodeEditDialog() {
<FormTextMultiline
name="description"
control={control}
rules={{ required: "Description is required" }}
textFieldProps={{
label: "Description",
error: Boolean(errors.description),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import eventBus from "../../EventBus.ts";

export interface ConfirmationEvent {
text: string;
type?: "DELETE" | "CONFIRM";
onAccept: () => void;
onReject?: () => void;
}
Expand Down
16 changes: 13 additions & 3 deletions frontend/src/components/ConfirmationDialog/ConfirmationDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import DeleteIcon from "@mui/icons-material/Delete";
import { Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle } from "@mui/material";
import { memo, useCallback, useEffect, useState } from "react";
import eventBus from "../../EventBus.ts";
Expand Down Expand Up @@ -41,6 +42,9 @@ function ConfirmationDialog() {
if (confirmationEventData?.onAccept) confirmationEventData.onAccept();
}, [confirmationEventData, handleClose]);

const cancelText = "Cancel";
const confirmText = confirmationEventData?.type == "DELETE" ? "Delete" : "Confirm";

return (
<Dialog open={dialog.isOpen} onClose={handleClose} maxWidth="sm" fullWidth>
{confirmationEventData && (
Expand All @@ -50,9 +54,15 @@ function ConfirmationDialog() {
<DialogContentText id="alert-dialog-description">{confirmationEventData.text}</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleReject}>Cancel</Button>
<Button onClick={handleAccept} autoFocus>
Confirm
<Button onClick={handleReject}>{cancelText}</Button>
<Button
onClick={handleAccept}
autoFocus
variant="contained"
startIcon={confirmationEventData.type == "DELETE" ? <DeleteIcon /> : null}
color={confirmationEventData.type == "DELETE" ? "error" : "primary"}
>
{confirmText}
</Button>
</DialogActions>
</>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/Folder/FolderEditDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ function FolderEditDialog() {
if (folder) {
ConfirmationAPI.openConfirmationDialog({
text: `Do you really want to delete the folder "${folder.name}"? This will delete ALL contained documents, their annotations, memos, etc. This action cannot be undone!`,
type: "DELETE",
onAccept: () => {
deleteFolderMutation(
{ folderId: folder.id },
Expand Down
47 changes: 8 additions & 39 deletions frontend/src/components/ProjectSettings/ProjectSettingsDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import DeleteIcon from "@mui/icons-material/Delete";
import { LoadingButton, TabContext } from "@mui/lab";
import { TabContext } from "@mui/lab";
import TabPanel from "@mui/lab/TabPanel";
import { AppBar, Box, Dialog, DialogActions, DialogContent, Divider, Tabs } from "@mui/material";
import { AppBar, Dialog, DialogContent, Tabs } from "@mui/material";
import Tab from "@mui/material/Tab";
import React, { memo, useCallback, useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { useParams } from "react-router-dom";
import ProjectHooks from "../../api/ProjectHooks.ts";
import { useDialogMaximize } from "../../hooks/useDialogMaximize.ts";
import { useAppDispatch, useAppSelector } from "../../plugins/ReduxHooks.ts";
import ConfirmationAPI from "../ConfirmationDialog/ConfirmationAPI.ts";
import { CRUDDialogActions } from "../dialogSlice.ts";
import DATSDialogHeader from "../MUI/DATSDialogHeader.tsx";
import ProjectCodes from "./tabs/ProjectCodes.tsx";
import ProjectDangerZone from "./tabs/ProjectDangerZone.tsx";
import ProjectDetails from "./tabs/ProjectDetails.tsx";
import ProjectImport from "./tabs/ProjectImport.tsx";
import ProjectTags from "./tabs/ProjectTags.tsx";
Expand All @@ -37,24 +36,6 @@ function ProjectSettingsDialog() {
setTab(newValue);
}, []);

const navigate = useNavigate();
const { mutate: deleteProject, isPending } = ProjectHooks.useDeleteProject();
const handleClickRemoveProject = useCallback(() => {
if (project.data) {
ConfirmationAPI.openConfirmationDialog({
text: `Do you really want to delete the project "${project.data.title}"? This action cannot be undone and will remove project and all of it's content including documents!`,
onAccept: () => {
deleteProject(
{ projId: project.data.id },
{
onSuccess: () => navigate(`/projects`),
},
);
},
});
}
}, [project.data, deleteProject, navigate]);

// maximize
const { isMaximized, toggleMaximize } = useDialogMaximize();

Expand Down Expand Up @@ -86,6 +67,7 @@ function ProjectSettingsDialog() {
<Tab label="Codes" value="3" />
<Tab label="Tags" value="4" />
<Tab label="Import" value="5" />
<Tab label="Danger Zone" value="6" />
</Tabs>
</AppBar>
{project.isLoading && <DialogContent>Loading project...</DialogContent>}
Expand All @@ -107,24 +89,11 @@ function ProjectSettingsDialog() {
<TabPanel value="5" sx={{ p: 0 }} className="myFlexFillAllContainer">
<ProjectImport project={project.data} />
</TabPanel>
<TabPanel value="6" sx={{ p: 0 }} className="myFlexFillAllContainer">
<ProjectDangerZone project={project.data} />
</TabPanel>
</React.Fragment>
)}
<Divider />
<DialogActions>
<LoadingButton
variant="contained"
color="error"
startIcon={<DeleteIcon />}
sx={{ mr: 1 }}
onClick={handleClickRemoveProject}
disabled={!project.isSuccess}
loading={isPending}
loadingPosition="start"
>
Delete Project
</LoadingButton>
<Box sx={{ flexGrow: 1 }} />
</DialogActions>
</TabContext>
</Dialog>
);
Expand Down
75 changes: 75 additions & 0 deletions frontend/src/components/ProjectSettings/tabs/ProjectDangerZone.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import DeleteIcon from "@mui/icons-material/Delete";
import { LoadingButton } from "@mui/lab";
import { Box, Stack, TextField, Typography } from "@mui/material";
import { useCallback, useState } from "react";
import { useNavigate } from "react-router-dom";
import { ProjectRead } from "../../../api/openapi/models/ProjectRead.ts";
import ProjectHooks from "../../../api/ProjectHooks.ts";
import ConfirmationAPI from "../../ConfirmationDialog/ConfirmationAPI.ts";

interface ProjectDangerZoneProps {
project: ProjectRead;
}

function ProjectDangerZone({ project }: ProjectDangerZoneProps) {
const { mutate: deleteProject, isPending } = ProjectHooks.useDeleteProject();
const navigate = useNavigate();

const [name, setName] = useState("");
const handleClickRemoveProject = useCallback(() => {
if (project) {
ConfirmationAPI.openConfirmationDialog({
text: `Do you really want to delete the project "${project.title}"? This action cannot be undone and will remove project and all of it's content including documents!`,
type: "DELETE",
onAccept: () => {
navigate(`/projects`);
deleteProject(
{ projId: project.id },
{
onSuccess: () => navigate(`/projects`),
},
);
},
});
}
}, [project, deleteProject, navigate]);

return (
<Box margin={2}>
<Stack direction="column" spacing={2} sx={{ width: "100%", alignItems: "left" }}>
<Typography variant="h6" component="div" flexShrink={0}>
Delete this entire project including all documents, annotations for you and every other person working on this
project. This cannot be undone!
</Typography>
<Stack direction="row" spacing={2} sx={{ width: "100%", alignItems: "left" }}>
<TextField
value={name}
fullWidth
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
setName(event.target.value);
}}
helperText="Enter the name of the project if you really want to delete the project"
error={name != project.title}
onPaste={(e) => {
e.preventDefault();
}}
/>
<LoadingButton
variant="contained"
color="error"
startIcon={<DeleteIcon />}
type="submit"
onClick={handleClickRemoveProject}
disabled={name != project.title}
loading={isPending}
loadingPosition="start"
>
Delete Project
</LoadingButton>
</Stack>
</Stack>
</Box>
);
}

export default ProjectDangerZone;
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ function DeleteSdocsButton({ sdocIds, navigateTo, ...props }: DeleteSdocsButtonP
text: `Do you really want to delete document(s) ${sdocIds.join(
", ",
)}? This action cannot be undone and will remove all annotations as well as memos associated with this document!`,
type: "DELETE",
onAccept: () => {
deleteDocuments(
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ function DeleteSdocsMenuItem({ sdocId, navigateTo, onClick, ...props }: DeleteSd
if (!sdocId) return;
ConfirmationAPI.openConfirmationDialog({
text: `Do you really want to delete document(s) ${sdocId}? This action cannot be undone and will remove all annotations as well as memos associated with this document!`,
type: "DELETE",
onAccept: () => {
deleteDocuments(
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ function MetadataEditMenu({ projectMetadata }: MetadataEditMenuProps) {
const handleDeleteMetadata = useCallback(() => {
ConfirmationAPI.openConfirmationDialog({
text: `Do you really want to delete the ProjectMetadata ${projectMetadata.id}? This will remove metadata from all corresponding documents. This action cannot be undone!`,
type: "DELETE",
onAccept: () => {
const mutation = deleteMutation.mutate;
mutation({
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/Tag/TagEditDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ function TagEditDialog() {
if (tag) {
ConfirmationAPI.openConfirmationDialog({
text: `Do you really want to delete the tag "${tag.name}"? This action cannot be undone!`,
type: "DELETE",
onAccept: () => {
deleteTagMutation(
{ tagId: tag.id },
Expand Down
Loading