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 web/apps/labelstudio/src/components/Modal/Modal.scss
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
}

&__footer {
padding: 1rem 1.5rem;
padding: var(--spacing-base) var(--spacing-wider);
text-align: center;
font-size: 14px;
line-height: 22px;
Expand Down
182 changes: 145 additions & 37 deletions web/apps/labelstudio/src/pages/Settings/DangerZone.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { useMemo, useState } from "react";
import { useHistory } from "react-router";
import { Button } from "@humansignal/ui";
import { Button, Typography, useToast } from "@humansignal/ui";
import { useUpdatePageTitle, createTitleFromSegments } from "@humansignal/core";
import { Label } from "../../components/Form";
import { confirm } from "../../components/Modal/Modal";
import { modal } from "../../components/Modal/Modal";
import { useModalControls } from "../../components/Modal/ModalPopup";
import Input from "../../components/Form/Elements/Input/Input";
import { Space } from "../../components/Space/Space";
import { Spinner } from "../../components/Spinner/Spinner";
import { useAPI } from "../../providers/ApiProvider";
import { useProject } from "../../providers/ProjectProvider";
Expand All @@ -13,45 +16,143 @@ export const DangerZone = () => {
const { project } = useProject();
const api = useAPI();
const history = useHistory();
const toast = useToast();
const [processing, setProcessing] = useState(null);

useUpdatePageTitle(createTitleFromSegments([project?.title, "Danger Zone"]));

const showDangerConfirmation = ({ title, message, requiredWord, buttonText, onConfirm }) => {
const isDev = process.env.NODE_ENV === "development";

return modal({
title,
width: 600,
allowClose: false,
body: () => {
const ctrl = useModalControls();
const inputValue = ctrl?.state?.inputValue || "";

return (
<div>
<Typography variant="body" size="medium" className="mb-tight">
{message}
</Typography>
<Input
label={`To proceed, type "${requiredWord}" in the field below:`}
value={inputValue}
onChange={(e) => ctrl?.setState({ inputValue: e.target.value })}
autoFocus
data-testid="danger-zone-confirmation-input"
autoComplete="off"
/>
</div>
);
},
footer: () => {
const ctrl = useModalControls();
const inputValue = (ctrl?.state?.inputValue || "").trim().toLowerCase();
const isValid = isDev || inputValue === requiredWord.toLowerCase();

return (
<Space align="end">
<Button
variant="neutral"
look="outline"
onClick={() => ctrl?.hide()}
data-testid="danger-zone-cancel-button"
>
Cancel
</Button>
<Button
variant="negative"
disabled={!isValid}
onClick={async () => {
await onConfirm();
ctrl?.hide();
}}
data-testid="danger-zone-confirm-button"
>
{buttonText}
</Button>
</Space>
);
},
});
};

const handleOnClick = (type) => () => {
confirm({
title: "Action confirmation",
body: "You're about to delete all things. This action cannot be undone.",
okText: "Proceed",
buttonLook: "negative",
onOk: async () => {
const actionConfig = {
reset_cache: {
title: "Reset Cache",
message: (
<>
You are about to reset the cache for <strong>{project.title}</strong>. This action cannot be undone.
</>
),
requiredWord: "cache",
buttonText: "Reset Cache",
},
tabs: {
title: "Drop All Tabs",
message: (
<>
You are about to drop all tabs for <strong>{project.title}</strong>. This action cannot be undone.
</>
),
requiredWord: "tabs",
buttonText: "Drop All Tabs",
},
project: {
title: "Delete Project",
message: (
<>
You are about to delete the project <strong>{project.title}</strong>. This action cannot be undone.
</>
),
requiredWord: "delete",
buttonText: "Delete Project",
},
};

const config = actionConfig[type];

if (!config) {
return;
}

showDangerConfirmation({
...config,
onConfirm: async () => {
setProcessing(type);
if (type === "annotations") {
// console.log('delete annotations');
} else if (type === "tasks") {
// console.log('delete tasks');
} else if (type === "predictions") {
// console.log('delete predictions');
} else if (type === "reset_cache") {
await api.callApi("projectResetCache", {
params: {
pk: project.id,
},
});
} else if (type === "tabs") {
await api.callApi("deleteTabs", {
body: {
project: project.id,
},
});
} else if (type === "project") {
await api.callApi("deleteProject", {
params: {
pk: project.id,
},
});
history.replace("/projects");
try {
if (type === "reset_cache") {
await api.callApi("projectResetCache", {
params: {
pk: project.id,
},
});
toast.show({ message: "Cache reset successfully" });
} else if (type === "tabs") {
await api.callApi("deleteTabs", {
body: {
project: project.id,
},
});
toast.show({ message: "All tabs dropped successfully" });
} else if (type === "project") {
await api.callApi("deleteProject", {
params: {
pk: project.id,
},
});
toast.show({ message: "Project deleted successfully" });
history.replace("/projects");
}
} catch (error) {
toast.show({ message: `Error: ${error.message}`, type: "error" });
} finally {
setProcessing(null);
}
setProcessing(null);
},
});
};
Expand Down Expand Up @@ -97,8 +198,13 @@ export const DangerZone = () => {

return (
<div className={cn("simple-settings")}>
<h1>Danger Zone</h1>
<Label description="Perform these actions at your own risk. Actions you take on this page can't be reverted. Make sure your data is backed up." />
<Typography variant="headline" size="large" className="mb-tighter">
Danger Zone
</Typography>
<Typography variant="body" size="medium" className="text-neutral-content-subtler !mb-base">
Perform these actions at your own risk. Actions you take on this page can't be reverted. Make sure your data is
backed up.
</Typography>

{project.id ? (
<div style={{ marginTop: 16 }}>
Expand All @@ -109,7 +215,9 @@ export const DangerZone = () => {
return (
btn.disabled !== true && (
<div className={cn("settings-wrapper")} key={btn.type}>
<h3>{btn.label}</h3>
<Typography variant="title" size="large">
{btn.label}
</Typography>
{btn.help && <Label description={btn.help} style={{ width: 600, display: "block" }} />}
<Button
key={btn.type}
Expand Down
4 changes: 2 additions & 2 deletions web/libs/datamanager/src/components/Common/Modal/Modal.scss
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
min-height: 40px;
align-items: center;
justify-content: space-between;
padding: 16px 32px;
padding: var(--spacing-base) var(--spacing-wider);
box-sizing: content-box;

&_divided {
Expand All @@ -54,7 +54,7 @@
}

&__body {
padding: 0 40px 32px;
padding: 0 var(--spacing-wider) var(--spacing-wider);
color: var(--color-neutral-content);

&_bare {
Expand Down
Loading