UX make all delete modals consistent (#1289)

This commit is contained in:
Prakash Senthil Vel
2021-12-07 20:58:38 +00:00
committed by GitHub
parent a7ab26c81e
commit dfcd49bb5d
19 changed files with 604 additions and 1180 deletions

View File

@@ -14,30 +14,19 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useEffect, useState } from "react";
import React from "react";
import { connect } from "react-redux";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
LinearProgress,
} from "@mui/material";
import { DialogContentText } from "@mui/material";
import { setErrorSnackMessage } from "../../../actions";
import { ErrorResponseHandler } from "../../../common/types";
import api from "../../../common/api";
import { deleteDialogStyles } from "../Common/FormComponents/common/styleLibrary";
import IconButton from "@mui/material/IconButton";
import CloseIcon from "@mui/icons-material/Close";
import useApi from "../Common/Hooks/useApi";
import ConfirmDialog from "../Common/ModalWrapper/ConfirmDialog";
const styles = (theme: Theme) =>
createStyles({
...deleteDialogStyles,
wrapText: {
maxWidth: "200px",
whiteSpace: "normal",
@@ -60,95 +49,38 @@ const DeleteServiceAccount = ({
selectedServiceAccount,
setErrorSnackMessage,
}: IDeleteServiceAccountProps) => {
const [deleteLoading, setDeleteLoading] = useState(false);
const onDelSuccess = () => closeDeleteModalAndRefresh(true);
const onDelError = (err: ErrorResponseHandler) => setErrorSnackMessage(err);
const onClose = () => closeDeleteModalAndRefresh(false);
useEffect(() => {
if (deleteLoading) {
api
.invoke("DELETE", `/api/v1/service-accounts/${selectedServiceAccount}`)
.then(() => {
setDeleteLoading(false);
closeDeleteModalAndRefresh(true);
})
.catch((err: ErrorResponseHandler) => {
setDeleteLoading(false);
setErrorSnackMessage(err);
});
}
}, [
deleteLoading,
closeDeleteModalAndRefresh,
selectedServiceAccount,
setErrorSnackMessage,
]);
const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError);
const removeRecord = () => {
if (selectedServiceAccount === null) {
return;
}
if (!selectedServiceAccount) {
return null;
}
setDeleteLoading(true);
const onConfirmDelete = () => {
invokeDeleteApi(
"DELETE",
`/api/v1/service-accounts/${selectedServiceAccount}`
);
};
return (
<Dialog
open={deleteOpen}
classes={classes}
className={classes.root}
onClose={() => {
closeDeleteModalAndRefresh(false);
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title" className={classes.title}>
<div className={classes.titleText}>Delete ServiceAccount</div>
<div className={classes.closeContainer}>
<IconButton
aria-label="close"
className={classes.closeButton}
onClick={() => {
closeDeleteModalAndRefresh(true);
}}
disableRipple
size="small"
>
<CloseIcon />
</IconButton>
</div>
</DialogTitle>
<DialogContent>
{deleteLoading && <LinearProgress />}
<DialogContentText id="alert-dialog-description">
<ConfirmDialog
title={`Delete Service Account`}
confirmText={"Delete"}
isOpen={deleteOpen}
isLoading={deleteLoading}
onConfirm={onConfirmDelete}
onClose={onClose}
confirmationContent={
<DialogContentText>
Are you sure you want to delete service account{" "}
<b className={classes.wrapText}>{selectedServiceAccount}</b>?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
type="button"
variant="outlined"
onClick={() => {
closeDeleteModalAndRefresh(false);
}}
color="primary"
disabled={deleteLoading}
>
Cancel
</Button>
<Button
type="button"
variant="outlined"
onClick={removeRecord}
color="secondary"
autoFocus
disabled={deleteLoading}
>
Delete
</Button>
</DialogActions>
</Dialog>
}
/>
);
};

View File

@@ -15,23 +15,17 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React from "react";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
} from "@mui/material";
import { DialogContentText } from "@mui/material";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import { modalBasic } from "../../Common/FormComponents/common/styleLibrary";
import { connect } from "react-redux";
import api from "../../../../common/api";
import { ErrorResponseHandler } from "../../../../common/types";
import { setErrorSnackMessage } from "../../../../actions";
import { AppState } from "../../../../store";
import useApi from "../../Common/Hooks/useApi";
import ConfirmDialog from "../../Common/ModalWrapper/ConfirmDialog";
const mapState = (state: AppState) => ({
session: state.console.session,
@@ -64,46 +58,31 @@ const DeleteAccessRule = ({
bucket,
toDelete,
}: IDeleteAccessRule) => {
const deleteProcess = () => {
api
.invoke("DELETE", `/api/v1/bucket/${bucket}/access-rules`, {
prefix: toDelete,
})
.then((res: any) => {})
.catch((err: ErrorResponseHandler) => {
setErrorSnackMessage(err);
});
const onDelSuccess = () => onClose();
const onDelError = (err: ErrorResponseHandler) => setErrorSnackMessage(err);
const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError);
const onConfirmDelete = () => {
invokeDeleteApi("DELETE", `/api/v1/bucket/${bucket}/access-rules`, {
prefix: toDelete,
});
};
return (
<Dialog
open={modalOpen}
<ConfirmDialog
title={`Delete Access Rule`}
confirmText={"Delete"}
isOpen={modalOpen}
isLoading={deleteLoading}
onConfirm={onConfirmDelete}
onClose={onClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">Delete Access Rule</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
confirmationContent={
<DialogContentText>
Are you sure you want to delete this access rule?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={onClose} color="primary">
Cancel
</Button>
<Button
onClick={() => {
deleteProcess();
onClose();
}}
color="secondary"
autoFocus
>
Delete
</Button>
</DialogActions>
</Dialog>
}
/>
);
};

View File

@@ -14,18 +14,10 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useState } from "react";
import React from "react";
import get from "lodash/get";
import { connect } from "react-redux";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
LinearProgress,
} from "@mui/material";
import { DialogContentText } from "@mui/material";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
@@ -33,7 +25,8 @@ import { modalBasic } from "../../Common/FormComponents/common/styleLibrary";
import { setErrorSnackMessage } from "../../../../actions";
import { AppState } from "../../../../store";
import { ErrorResponseHandler } from "../../../../common/types";
import api from "../../../../common/api";
import useApi from "../../Common/Hooks/useApi";
import ConfirmDialog from "../../Common/ModalWrapper/ConfirmDialog";
interface IDeleteBucketTagModal {
deleteOpen: boolean;
@@ -66,62 +59,45 @@ const DeleteBucketTagModal = ({
setErrorSnackMessage,
classes,
}: IDeleteBucketTagModal) => {
const [deleteLoading, setDeleteSending] = useState<boolean>(false);
const [tagKey, tagLabel] = selectedTag;
const removeTagProcess = () => {
setDeleteSending(true);
const onDelSuccess = () => onCloseAndUpdate(true);
const onDelError = (err: ErrorResponseHandler) => setErrorSnackMessage(err);
const onClose = () => onCloseAndUpdate(false);
const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError);
if (!selectedTag) {
return null;
}
const onConfirmDelete = () => {
const cleanObject = { ...currentTags };
delete cleanObject[tagKey];
api
.invoke("PUT", `/api/v1/buckets/${bucketName}/tags`, {
tags: cleanObject,
})
.then((res: any) => {
setDeleteSending(false);
onCloseAndUpdate(true);
})
.catch((error: ErrorResponseHandler) => {
setErrorSnackMessage(error);
setDeleteSending(false);
});
invokeDeleteApi("PUT", `/api/v1/buckets/${bucketName}/tags`, {
tags: cleanObject,
});
};
return (
<Dialog
open={deleteOpen}
onClose={() => {
onCloseAndUpdate(false);
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">Delete Tag</DialogTitle>
<DialogContent>
{deleteLoading && <LinearProgress />}
<DialogContentText id="alert-dialog-description">
<ConfirmDialog
title={`Delete Tag`}
confirmText={"Delete"}
isOpen={deleteOpen}
isLoading={deleteLoading}
onConfirm={onConfirmDelete}
onClose={onClose}
confirmationContent={
<DialogContentText>
Are you sure you want to delete the tag{" "}
<b className={classes.wrapText}>
{tagKey} : {tagLabel}
</b>
</b>{" "}
?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
onClick={() => {
onCloseAndUpdate(false);
}}
color="primary"
disabled={deleteLoading}
>
Cancel
</Button>
<Button onClick={removeTagProcess} color="secondary" autoFocus>
Delete
</Button>
</DialogActions>
</Dialog>
}
/>
);
};

View File

@@ -14,22 +14,15 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useState } from "react";
import React from "react";
import get from "lodash/get";
import { connect } from "react-redux";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
LinearProgress,
} from "@mui/material";
import api from "../../../../common/api";
import { BucketEvent, BucketList } from "../types";
import { DialogContentText } from "@mui/material";
import { BucketEvent } from "../types";
import { setErrorSnackMessage } from "../../../../actions";
import { ErrorResponseHandler } from "../../../../common/types";
import useApi from "../../Common/Hooks/useApi";
import ConfirmDialog from "../../Common/ModalWrapper/ConfirmDialog";
interface IDeleteEventProps {
closeDeleteModalAndRefresh: (refresh: boolean) => void;
@@ -46,78 +39,50 @@ const DeleteEvent = ({
bucketEvent,
setErrorSnackMessage,
}: IDeleteEventProps) => {
const [deleteLoading, setDeleteLoading] = useState<boolean>(false);
const onDelSuccess = () => closeDeleteModalAndRefresh(true);
const onDelError = (err: ErrorResponseHandler) => setErrorSnackMessage(err);
const onClose = () => closeDeleteModalAndRefresh(false);
const removeRecord = () => {
if (deleteLoading) {
return;
}
const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError);
if (!selectedBucket) {
return null;
}
const onConfirmDelete = () => {
if (bucketEvent === null) {
return;
}
setDeleteLoading(true);
const events = get(bucketEvent, "events", []);
const prefix = get(bucketEvent, "prefix", "");
const suffix = get(bucketEvent, "suffix", "");
api
.invoke(
"DELETE",
`/api/v1/buckets/${selectedBucket}/events/${bucketEvent.arn}`,
{
events,
prefix,
suffix,
}
)
.then((res: BucketList) => {
setDeleteLoading(false);
closeDeleteModalAndRefresh(true);
})
.catch((err: ErrorResponseHandler) => {
setDeleteLoading(false);
setErrorSnackMessage(err);
});
invokeDeleteApi(
"DELETE",
`/api/v1/buckets/${selectedBucket}/events/${bucketEvent.arn}`,
{
events,
prefix,
suffix,
}
);
};
return (
<Dialog
open={deleteOpen}
onClose={() => {
closeDeleteModalAndRefresh(false);
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">Delete Event</DialogTitle>
<DialogContent>
{deleteLoading && <LinearProgress />}
<DialogContentText id="alert-dialog-description">
<ConfirmDialog
title={`Delete Event`}
confirmText={"Delete"}
isOpen={deleteOpen}
isLoading={deleteLoading}
onConfirm={onConfirmDelete}
onClose={onClose}
confirmationContent={
<DialogContentText>
Are you sure you want to delete this event?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
onClick={() => {
closeDeleteModalAndRefresh(false);
}}
color="primary"
disabled={deleteLoading}
>
Cancel
</Button>
<Button
onClick={() => {
removeRecord();
}}
color="secondary"
autoFocus
>
Delete
</Button>
</DialogActions>
</Dialog>
}
/>
);
};

View File

@@ -14,20 +14,13 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useState } from "react";
import React from "react";
import { connect } from "react-redux";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
LinearProgress,
} from "@mui/material";
import { DialogContentText } from "@mui/material";
import { setErrorSnackMessage } from "../../../../actions";
import { ErrorResponseHandler } from "../../../../common/types";
import api from "../../../../common/api";
import useApi from "../../Common/Hooks/useApi";
import ConfirmDialog from "../../Common/ModalWrapper/ConfirmDialog";
interface IDeleteReplicationProps {
closeDeleteModalAndRefresh: (refresh: boolean) => void;
@@ -44,68 +37,40 @@ const DeleteReplicationRule = ({
ruleToDelete,
setErrorSnackMessage,
}: IDeleteReplicationProps) => {
const [deleteLoading, setDeleteLoading] = useState<boolean>(false);
const onDelSuccess = () => closeDeleteModalAndRefresh(true);
const onDelError = (err: ErrorResponseHandler) => setErrorSnackMessage(err);
const onClose = () => closeDeleteModalAndRefresh(false);
const removeRecord = () => {
if (!deleteLoading) {
setDeleteLoading(true);
const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError);
api
.invoke(
"DELETE",
`/api/v1/buckets/${selectedBucket}/replication/${ruleToDelete}`
)
.then(() => {
setDeleteLoading(false);
closeDeleteModalAndRefresh(true);
})
.catch((err: ErrorResponseHandler) => {
setDeleteLoading(false);
setErrorSnackMessage(err);
});
}
if (!selectedBucket) {
return null;
}
const onConfirmDelete = () => {
invokeDeleteApi(
"DELETE",
`/api/v1/buckets/${selectedBucket}/replication/${ruleToDelete}`
);
};
return (
<Dialog
open={deleteOpen}
onClose={() => {
closeDeleteModalAndRefresh(false);
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">Delete Replication Rule</DialogTitle>
<DialogContent>
{deleteLoading && <LinearProgress />}
<DialogContentText id="alert-dialog-description">
<ConfirmDialog
title={`Delete Replication Rule`}
confirmText={"Delete"}
isOpen={deleteOpen}
isLoading={deleteLoading}
onConfirm={onConfirmDelete}
onClose={onClose}
confirmationContent={
<DialogContentText>
Are you sure you want to delete replication rule <b>{ruleToDelete}</b>
? <br />
Remember, at lease one rule must be present once replication has been
enabled
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
onClick={() => {
closeDeleteModalAndRefresh(false);
}}
color="primary"
disabled={deleteLoading}
>
Cancel
</Button>
<Button
onClick={() => {
removeRecord();
}}
color="secondary"
autoFocus
>
Delete
</Button>
</DialogActions>
</Dialog>
}
/>
);
};

View File

@@ -14,21 +14,13 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useState } from "react";
import React from "react";
import { connect } from "react-redux";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
LinearProgress,
} from "@mui/material";
import { BucketList } from "../types";
import { DialogContentText } from "@mui/material";
import { setErrorSnackMessage } from "../../../../actions";
import { ErrorResponseHandler } from "../../../../common/types";
import api from "../../../../common/api";
import useApi from "../../Common/Hooks/useApi";
import ConfirmDialog from "../../Common/ModalWrapper/ConfirmDialog";
interface IDeleteBucketProps {
closeDeleteModalAndRefresh: (refresh: boolean) => void;
@@ -43,65 +35,37 @@ const DeleteBucket = ({
selectedBucket,
setErrorSnackMessage,
}: IDeleteBucketProps) => {
const [deleteLoading, setDeleteLoading] = useState<boolean>(false);
const onDelSuccess = () => closeDeleteModalAndRefresh(true);
const onDelError = (err: ErrorResponseHandler) => setErrorSnackMessage(err);
const onClose = () => closeDeleteModalAndRefresh(false);
const removeRecord = () => {
if (!deleteLoading) {
setDeleteLoading(true);
const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError);
api
.invoke("DELETE", `/api/v1/buckets/${selectedBucket}`, {
name: selectedBucket,
})
.then((res: BucketList) => {
setDeleteLoading(false);
closeDeleteModalAndRefresh(true);
})
.catch((err: ErrorResponseHandler) => {
setDeleteLoading(false);
setErrorSnackMessage(err);
});
}
if (!selectedBucket) {
return null;
}
const onConfirmDelete = () => {
invokeDeleteApi("DELETE", `/api/v1/buckets/${selectedBucket}`, {
name: selectedBucket,
});
};
return (
<Dialog
open={deleteOpen}
onClose={() => {
closeDeleteModalAndRefresh(false);
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">Delete Bucket</DialogTitle>
<DialogContent>
{deleteLoading && <LinearProgress />}
<DialogContentText id="alert-dialog-description">
<ConfirmDialog
title={`Delete Bucket`}
confirmText={"Delete"}
isOpen={deleteOpen}
isLoading={deleteLoading}
onConfirm={onConfirmDelete}
onClose={onClose}
confirmationContent={
<DialogContentText>
Are you sure you want to delete bucket <b>{selectedBucket}</b>? <br />
A bucket can only be deleted if it's empty.
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
onClick={() => {
closeDeleteModalAndRefresh(false);
}}
color="primary"
disabled={deleteLoading}
>
Cancel
</Button>
<Button
onClick={() => {
removeRecord();
}}
color="secondary"
autoFocus
>
Delete
</Button>
</DialogActions>
</Dialog>
}
/>
);
};

View File

@@ -14,20 +14,13 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useState } from "react";
import React from "react";
import { connect } from "react-redux";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
LinearProgress,
} from "@mui/material";
import { DialogContentText } from "@mui/material";
import { setErrorSnackMessage } from "../../../../../../actions";
import { ErrorResponseHandler } from "../../../../../../common/types";
import api from "../../../../../../common/api";
import useApi from "../../../../Common/Hooks/useApi";
import ConfirmDialog from "../../../../Common/ModalWrapper/ConfirmDialog";
interface IDeleteObjectProps {
closeDeleteModalAndRefresh: (refresh: boolean) => void;
@@ -44,12 +37,16 @@ const DeleteObject = ({
selectedObjects,
setErrorSnackMessage,
}: IDeleteObjectProps) => {
const [deleteLoading, setDeleteLoading] = useState<boolean>(false);
const onDelSuccess = () => closeDeleteModalAndRefresh(true);
const onDelError = (err: ErrorResponseHandler) => setErrorSnackMessage(err);
const onClose = () => closeDeleteModalAndRefresh(false);
const removeRecord = () => {
if (deleteLoading) {
return;
}
const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError);
if (!selectedObjects) {
return null;
}
const onConfirmDelete = () => {
let toSend = [];
for (let i = 0; i < selectedObjects.length; i++) {
if (selectedObjects[i].endsWith("/")) {
@@ -66,60 +63,31 @@ const DeleteObject = ({
});
}
}
setDeleteLoading(true);
api
.invoke(
if (toSend) {
invokeDeleteApi(
"POST",
`/api/v1/buckets/${selectedBucket}/delete-objects`,
toSend
)
.then(() => {
setDeleteLoading(false);
closeDeleteModalAndRefresh(true);
})
.catch((err: ErrorResponseHandler) => {
setDeleteLoading(false);
setErrorSnackMessage(err);
});
);
}
};
return (
<Dialog
open={deleteOpen}
onClose={() => {
closeDeleteModalAndRefresh(false);
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">Delete</DialogTitle>
<DialogContent>
{deleteLoading && <LinearProgress />}
<DialogContentText id="alert-dialog-description">
Are you sure you want to delete the selected objects?{" "}
<ConfirmDialog
title={`Delete Objects`}
confirmText={"Delete"}
isOpen={deleteOpen}
isLoading={deleteLoading}
onConfirm={onConfirmDelete}
onClose={onClose}
confirmationContent={
<DialogContentText>
Are you sure you want to delete the selected {selectedObjects.length}{" "}
objects?{" "}
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
onClick={() => {
closeDeleteModalAndRefresh(false);
}}
color="primary"
disabled={deleteLoading}
>
Cancel
</Button>
<Button
onClick={() => {
removeRecord();
}}
color="secondary"
disabled={deleteLoading}
>
Delete
</Button>
</DialogActions>
</Dialog>
}
/>
);
};

View File

@@ -14,21 +14,14 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useState } from "react";
import React from "react";
import { connect } from "react-redux";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
LinearProgress,
} from "@mui/material";
import { DialogContentText } from "@mui/material";
import { setErrorSnackMessage } from "../../../../../../actions";
import { ErrorResponseHandler } from "../../../../../../common/types";
import api from "../../../../../../common/api";
import { decodeFileName } from "../../../../../../common/utils";
import ConfirmDialog from "../../../../Common/ModalWrapper/ConfirmDialog";
import useApi from "../../../../Common/Hooks/useApi";
interface IDeleteObjectProps {
closeDeleteModalAndRefresh: (refresh: boolean) => void;
@@ -45,67 +38,39 @@ const DeleteObject = ({
selectedObject,
setErrorSnackMessage,
}: IDeleteObjectProps) => {
const [deleteLoading, setDeleteLoading] = useState<boolean>(false);
const onDelSuccess = () => closeDeleteModalAndRefresh(true);
const onDelError = (err: ErrorResponseHandler) => setErrorSnackMessage(err);
const onClose = () => closeDeleteModalAndRefresh(false);
const removeRecord = () => {
if (deleteLoading) {
return;
}
const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError);
if (!selectedObject) {
return null;
}
const onConfirmDelete = () => {
const decodedSelectedObject = decodeFileName(selectedObject);
const recursive = decodedSelectedObject.endsWith("/");
api
.invoke(
"DELETE",
`/api/v1/buckets/${selectedBucket}/objects?path=${selectedObject}&recursive=${recursive}`
)
.then(() => {
setDeleteLoading(false);
closeDeleteModalAndRefresh(true);
})
.catch((err: ErrorResponseHandler) => {
setDeleteLoading(false);
setErrorSnackMessage(err);
});
invokeDeleteApi(
"DELETE",
`/api/v1/buckets/${selectedBucket}/objects?path=${selectedObject}&recursive=${recursive}`
);
};
return (
<Dialog
open={deleteOpen}
onClose={() => {
closeDeleteModalAndRefresh(false);
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">Delete</DialogTitle>
<DialogContent>
{deleteLoading && <LinearProgress />}
<DialogContentText id="alert-dialog-description">
<ConfirmDialog
title={`Delete Object`}
confirmText={"Delete"}
isOpen={deleteOpen}
isLoading={deleteLoading}
onConfirm={onConfirmDelete}
onClose={onClose}
confirmationContent={
<DialogContentText>
Are you sure you want to delete:{" "}
<b>{decodeFileName(selectedObject)}</b>?{" "}
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
onClick={() => {
closeDeleteModalAndRefresh(false);
}}
color="primary"
disabled={deleteLoading}
>
Cancel
</Button>
<Button
onClick={() => {
removeRecord();
}}
color="secondary"
disabled={deleteLoading}
>
Delete
</Button>
</DialogActions>
</Dialog>
}
/>
);
};

View File

@@ -14,27 +14,19 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useState } from "react";
import React from "react";
import get from "lodash/get";
import { connect } from "react-redux";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
LinearProgress,
} from "@mui/material";
import { DialogContentText } from "@mui/material";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import { modalBasic } from "../../../../Common/FormComponents/common/styleLibrary";
import { setErrorSnackMessage } from "../../../../../../actions";
import { AppState } from "../../../../../../store";
import { ErrorResponseHandler } from "../../../../../../common/types";
import api from "../../../../../../common/api";
import { encodeFileName } from "../../../../../../common/utils";
import useApi from "../../../../Common/Hooks/useApi";
import ConfirmDialog from "../../../../Common/ModalWrapper/ConfirmDialog";
interface IDeleteTagModal {
deleteOpen: boolean;
@@ -58,7 +50,6 @@ const styles = (theme: Theme) =>
marginTop: 0,
marginBottom: 32,
},
...modalBasic,
});
const DeleteTagModal = ({
@@ -73,69 +64,51 @@ const DeleteTagModal = ({
setErrorSnackMessage,
classes,
}: IDeleteTagModal) => {
const [deleteLoading, setDeleteSending] = useState<boolean>(false);
const [tagKey, tagLabel] = selectedTag;
const removeTagProcess = () => {
setDeleteSending(true);
const onDelSuccess = () => onCloseAndUpdate(true);
const onDelError = (err: ErrorResponseHandler) => setErrorSnackMessage(err);
const onClose = () => onCloseAndUpdate(false);
const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError);
if (!selectedTag) {
return null;
}
const onConfirmDelete = () => {
const cleanObject = { ...currentTags };
delete cleanObject[tagKey];
const verID = distributedSetup ? versionId : "null";
api
.invoke(
"PUT",
`/api/v1/buckets/${bucketName}/objects/tags?prefix=${encodeFileName(
selectedObject
)}&version_id=${verID}`,
{ tags: cleanObject }
)
.then((res: any) => {
setDeleteSending(false);
onCloseAndUpdate(true);
})
.catch((error: ErrorResponseHandler) => {
setErrorSnackMessage(error);
setDeleteSending(false);
});
invokeDeleteApi(
"PUT",
`/api/v1/buckets/${bucketName}/objects/tags?prefix=${encodeFileName(
selectedObject
)}&version_id=${verID}`,
{ tags: cleanObject }
);
};
return (
<Dialog
open={deleteOpen}
onClose={() => {
onCloseAndUpdate(false);
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">Delete Tag</DialogTitle>
<DialogContent>
{deleteLoading && <LinearProgress />}
<DialogContentText id="alert-dialog-description">
<ConfirmDialog
title={`Delete Tag`}
confirmText={"Delete"}
isOpen={deleteOpen}
isLoading={deleteLoading}
onConfirm={onConfirmDelete}
onClose={onClose}
confirmationContent={
<DialogContentText>
Are you sure you want to delete the tag{" "}
<b className={classes.wrapText}>
{tagKey} : {tagLabel}
</b>{" "}
from {selectedObject}?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
onClick={() => {
onCloseAndUpdate(false);
}}
color="primary"
disabled={deleteLoading}
>
Cancel
</Button>
<Button onClick={removeTagProcess} color="secondary" autoFocus>
Delete
</Button>
</DialogActions>
</Dialog>
}
/>
);
};

View File

@@ -0,0 +1,32 @@
import { useState } from "react";
import api from "../../../../common/api";
import { ErrorResponseHandler } from "../../../../common/types";
type NoReturnFunction = (param?: any) => void;
type ApiMethodToInvoke = (method: string, url: string, data?: any) => void;
type IsApiInProgress = boolean;
const useApi = (
onSuccess: NoReturnFunction,
onError: NoReturnFunction
): [IsApiInProgress, ApiMethodToInvoke] => {
const [isLoading, setIsLoading] = useState<boolean>(false);
const callApi = (method: string, url: string, data?: any) => {
setIsLoading(true);
api
.invoke(method, url, data)
.then((res: any) => {
setIsLoading(false);
onSuccess(res);
})
.catch((err: ErrorResponseHandler) => {
setIsLoading(false);
onError(err);
});
};
return [isLoading, callApi];
};
export default useApi;

View File

@@ -0,0 +1,117 @@
import React from "react";
import {
Button,
ButtonProps,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
} from "@mui/material";
import { LoadingButton } from "@mui/lab";
import IconButton from "@mui/material/IconButton";
import CloseIcon from "@mui/icons-material/Close";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import { deleteDialogStyles } from "../FormComponents/common/styleLibrary";
const styles = (theme: Theme) =>
createStyles({
...deleteDialogStyles,
});
type ConfirmDialogProps = {
isOpen?: boolean;
onClose: () => void;
onCancel?: () => void;
onConfirm: () => void;
classes?: any;
title: string;
isLoading?: boolean;
confirmationContent: React.ReactNode | React.ReactNode[];
cancelText?: string;
confirmText?: string;
confirmButtonProps?: Partial<ButtonProps>;
cancelButtonProps?: Partial<ButtonProps>;
};
const ConfirmDialog = ({
isOpen = false,
onClose,
onCancel,
onConfirm,
classes = {},
title = "",
isLoading,
confirmationContent,
cancelText = "Cancel",
confirmText = "Confirm",
confirmButtonProps = {},
cancelButtonProps = {},
}: ConfirmDialogProps) => {
return (
<Dialog
open={isOpen}
classes={classes}
onClose={(event, reason) => {
if (reason !== "backdropClick") {
onClose(); // close on Esc but not on click outside
}
}}
className={classes.root}
onBackdropClick={() => {
return false;
}}
>
<DialogTitle className={classes.title}>
<div className={classes.titleText}>{title}</div>
<div className={classes.closeContainer}>
<IconButton
aria-label="close"
className={classes.closeButton}
onClick={onClose}
disableRipple
size="small"
>
<CloseIcon />
</IconButton>
</div>
</DialogTitle>
<DialogContent className={classes.content}>
{confirmationContent}
</DialogContent>
<DialogActions className={classes.actions}>
<Button
className={classes.cancelButton}
onClick={onCancel || onClose}
disabled={isLoading}
type="button"
{...cancelButtonProps}
variant="outlined"
color="primary"
>
{cancelText}
</Button>
<LoadingButton
className={classes.confirmButton}
type="button"
onClick={onConfirm}
loading={isLoading}
disabled={isLoading}
{...confirmButtonProps}
variant="outlined"
color="secondary"
loadingPosition="start"
startIcon={null}
autoFocus
>
{confirmText}
</LoadingButton>
</DialogActions>
</Dialog>
);
};
export default withStyles(styles)(ConfirmDialog);

View File

@@ -14,38 +14,19 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useEffect, useState } from "react";
import React from "react";
import { connect } from "react-redux";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
LinearProgress,
} from "@mui/material";
import api from "../../../common/api";
import { DialogContentText } from "@mui/material";
import { setErrorSnackMessage } from "../../../actions";
import { ErrorResponseHandler } from "../../../common/types";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import IconButton from "@mui/material/IconButton";
import CloseIcon from "@mui/icons-material/Close";
import { deleteDialogStyles } from "../Common/FormComponents/common/styleLibrary";
const styles = (theme: Theme) =>
createStyles({
...deleteDialogStyles,
});
import ConfirmDialog from "../Common/ModalWrapper/ConfirmDialog";
import useApi from "../Common/Hooks/useApi";
interface IDeleteGroup {
selectedGroup: string;
deleteOpen: boolean;
closeDeleteModalAndRefresh: any;
setErrorSnackMessage: typeof setErrorSnackMessage;
classes: any;
}
const DeleteGroup = ({
@@ -53,94 +34,36 @@ const DeleteGroup = ({
deleteOpen,
closeDeleteModalAndRefresh,
setErrorSnackMessage,
classes,
}: IDeleteGroup) => {
const [isDeleting, setDeleteLoading] = useState<boolean>(false);
const onDelSuccess = () => closeDeleteModalAndRefresh(true);
const onDelError = (err: ErrorResponseHandler) => setErrorSnackMessage(err);
const onClose = () => closeDeleteModalAndRefresh(false);
useEffect(() => {
if (isDeleting) {
const removeRecord = () => {
if (!selectedGroup) {
return;
}
const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError);
api
.invoke("DELETE", `/api/v1/group?name=${encodeURI(selectedGroup)}`)
.then(() => {
setDeleteLoading(false);
closeDeleteModalAndRefresh(true);
})
.catch((err: ErrorResponseHandler) => {
setDeleteLoading(false);
setErrorSnackMessage(err);
});
};
removeRecord();
}
}, [
isDeleting,
selectedGroup,
closeDeleteModalAndRefresh,
setErrorSnackMessage,
]);
const closeNoAction = () => {
closeDeleteModalAndRefresh(false);
if (!selectedGroup) {
return null;
}
const onDeleteGroup = () => {
invokeDeleteApi("DELETE", `/api/v1/group?name=${encodeURI(selectedGroup)}`);
};
return (
<Dialog
open={deleteOpen}
onClose={closeNoAction}
classes={classes}
className={classes.root}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title" className={classes.title}>
<div className={classes.titleText}>Delete Group</div>
<div className={classes.closeContainer}>
<IconButton
aria-label="close"
className={classes.closeButton}
onClick={closeNoAction}
disableRipple
size="small"
>
<CloseIcon />
</IconButton>
</div>
</DialogTitle>
<DialogContent>
{isDeleting && <LinearProgress />}
<DialogContentText id="alert-dialog-description">
Are you sure you want to delete group <br />
<ConfirmDialog
title={`Delete Group`}
confirmText={"Delete"}
isOpen={deleteOpen}
isLoading={deleteLoading}
onConfirm={onDeleteGroup}
onClose={onClose}
confirmationContent={
<DialogContentText>
Are you sure you want to delete group
<br />
<b>{selectedGroup}</b>?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
type="button"
variant="outlined"
onClick={closeNoAction}
color="primary"
disabled={isDeleting}
>
Cancel
</Button>
<Button
type="button"
variant="outlined"
onClick={() => {
setDeleteLoading(true);
}}
color="secondary"
autoFocus
>
Delete
</Button>
</DialogActions>
</Dialog>
}
/>
);
};
@@ -150,4 +73,4 @@ const mapDispatchToProps = {
const connector = connect(null, mapDispatchToProps);
export default withStyles(styles)(connector(DeleteGroup));
export default connector(DeleteGroup);

View File

@@ -14,123 +14,56 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useState } from "react";
import React from "react";
import { connect } from "react-redux";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
LinearProgress,
} from "@mui/material";
import api from "../../../common/api";
import { PolicyList } from "./types";
import { DialogContentText } from "@mui/material";
import { setErrorSnackMessage } from "../../../actions";
import { ErrorResponseHandler } from "../../../common/types";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import { deleteDialogStyles } from "../Common/FormComponents/common/styleLibrary";
import withStyles from "@mui/styles/withStyles";
import IconButton from "@mui/material/IconButton";
import CloseIcon from "@mui/icons-material/Close";
import useApi from "../Common/Hooks/useApi";
import ConfirmDialog from "../Common/ModalWrapper/ConfirmDialog";
interface IDeletePolicyProps {
closeDeleteModalAndRefresh: (refresh: boolean) => void;
deleteOpen: boolean;
selectedPolicy: string;
setErrorSnackMessage: typeof setErrorSnackMessage;
classes: any;
}
const styles = (theme: Theme) =>
createStyles({
...deleteDialogStyles,
});
const DeletePolicy = ({
classes,
closeDeleteModalAndRefresh,
deleteOpen,
selectedPolicy,
setErrorSnackMessage,
}: IDeletePolicyProps) => {
const [deleteLoading, setDeleteLoading] = useState<boolean>(false);
const removeRecord = () => {
if (deleteLoading) {
return;
}
setDeleteLoading(true);
api
.invoke("DELETE", `/api/v1/policy?name=${selectedPolicy}`)
.then((res: PolicyList) => {
setDeleteLoading(false);
const onDelSuccess = () => closeDeleteModalAndRefresh(true);
const onDelError = (err: ErrorResponseHandler) => setErrorSnackMessage(err);
const onClose = () => closeDeleteModalAndRefresh(false);
closeDeleteModalAndRefresh(true);
})
.catch((err: ErrorResponseHandler) => {
setDeleteLoading(false);
setErrorSnackMessage(err);
});
const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError);
if (!selectedPolicy) {
return null;
}
const onConfirmDelete = () => {
invokeDeleteApi("DELETE", `/api/v1/policy?name=${selectedPolicy}`);
};
return (
<Dialog
classes={classes}
className={classes.root}
open={deleteOpen}
onClose={() => {
closeDeleteModalAndRefresh(false);
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title" className={classes.title}>
<div className={classes.titleText}>Delete Policy</div>
<div className={classes.closeContainer}>
<IconButton
aria-label="close"
className={classes.closeButton}
onClick={() => {
closeDeleteModalAndRefresh(false);
}}
disableRipple
size="small"
>
<CloseIcon />
</IconButton>
</div>
</DialogTitle>
<DialogContent>
{deleteLoading && <LinearProgress />}
<DialogContentText id="alert-dialog-description">
<ConfirmDialog
title={`Delete Policy`}
confirmText={"Delete"}
isOpen={deleteOpen}
isLoading={deleteLoading}
onConfirm={onConfirmDelete}
onClose={onClose}
confirmationContent={
<DialogContentText>
Are you sure you want to delete policy <br />
<b>{selectedPolicy}</b>?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
variant="outlined"
onClick={() => {
closeDeleteModalAndRefresh(false);
}}
color="primary"
disabled={deleteLoading}
>
Cancel
</Button>
<Button
variant="outlined"
onClick={() => {
removeRecord();
}}
color="secondary"
autoFocus
>
Delete
</Button>
</DialogActions>
</Dialog>
}
/>
);
};
@@ -139,4 +72,4 @@ const mapDispatchToProps = {
};
const connector = connect(null, mapDispatchToProps);
export default withStyles(styles)(connector(DeletePolicy));
export default connector(DeletePolicy);

View File

@@ -14,23 +14,16 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useEffect, useState } from "react";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
LinearProgress,
} from "@mui/material";
import api from "../../../../common/api";
import React, { useState } from "react";
import { DialogContentText } from "@mui/material";
import { ITenant } from "./types";
import { connect } from "react-redux";
import { setErrorSnackMessage } from "../../../../actions";
import { ErrorResponseHandler } from "../../../../common/types";
import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
import Grid from "@mui/material/Grid";
import useApi from "../../Common/Hooks/useApi";
import ConfirmDialog from "../../Common/ModalWrapper/ConfirmDialog";
interface IDeleteTenant {
deleteOpen: boolean;
@@ -45,29 +38,15 @@ const DeleteTenant = ({
closeDeleteModalAndRefresh,
setErrorSnackMessage,
}: IDeleteTenant) => {
const [deleteLoading, setDeleteLoading] = useState(false);
const [retypeTenant, setRetypeTenant] = useState("");
useEffect(() => {
if (deleteLoading) {
api
.invoke(
"DELETE",
`/api/v1/namespaces/${selectedTenant.namespace}/tenants/${selectedTenant.name}`
)
.then(() => {
setDeleteLoading(false);
closeDeleteModalAndRefresh(true);
})
.catch((err: ErrorResponseHandler) => {
setDeleteLoading(false);
setErrorSnackMessage(err);
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [deleteLoading]);
const onDelSuccess = () => closeDeleteModalAndRefresh(true);
const onDelError = (err: ErrorResponseHandler) => setErrorSnackMessage(err);
const onClose = () => closeDeleteModalAndRefresh(false);
const removeRecord = () => {
const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError);
const onConfirmDelete = () => {
if (retypeTenant !== selectedTenant.name) {
setErrorSnackMessage({
errorMessage: "Tenant name is incorrect",
@@ -75,22 +54,25 @@ const DeleteTenant = ({
});
return;
}
setDeleteLoading(true);
invokeDeleteApi(
"DELETE",
`/api/v1/namespaces/${selectedTenant.namespace}/tenants/${selectedTenant.name}`
);
};
return (
<Dialog
open={deleteOpen}
onClose={() => {
closeDeleteModalAndRefresh(false);
<ConfirmDialog
title={`Delete Tenant`}
confirmText={"Delete"}
isOpen={deleteOpen}
isLoading={deleteLoading}
onConfirm={onConfirmDelete}
onClose={onClose}
confirmButtonProps={{
disabled: retypeTenant !== selectedTenant.name || deleteLoading,
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">Delete Tenant</DialogTitle>
<DialogContent>
{deleteLoading && <LinearProgress />}
<DialogContentText id="alert-dialog-description">
confirmationContent={
<DialogContentText>
To continue please type <b>{selectedTenant.name}</b> in the box.
<Grid item xs={12}>
<InputBoxWrapper
@@ -104,27 +86,8 @@ const DeleteTenant = ({
/>
</Grid>
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
onClick={() => {
closeDeleteModalAndRefresh(false);
}}
color="primary"
disabled={deleteLoading}
>
Cancel
</Button>
<Button
onClick={removeRecord}
color="secondary"
autoFocus
disabled={retypeTenant !== selectedTenant.name}
>
Delete
</Button>
</DialogActions>
</Dialog>
}
/>
);
};

View File

@@ -1,83 +0,0 @@
import React, { useState } from "react";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import {
containerForHeader,
tenantDetailsStyles,
} from "../../Common/FormComponents/common/styleLibrary";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
LinearProgress,
} from "@mui/material";
interface IConfirmationDialog {
classes: any;
open: boolean;
cancelLabel: string;
okLabel: string;
onClose: any;
cancelOnClick: any;
okOnClick: any;
title: string;
description: string;
}
const styles = (theme: Theme) =>
createStyles({
...tenantDetailsStyles,
...containerForHeader(theme.spacing(4)),
});
const ConfirmationDialog = ({
classes,
open,
cancelLabel,
okLabel,
onClose,
cancelOnClick,
okOnClick,
title,
description,
}: IConfirmationDialog) => {
const [isSending, setIsSending] = useState<boolean>(false);
const onClick = () => {
setIsSending(true);
if (okOnClick !== null) {
okOnClick();
}
setIsSending(false);
};
if (!open) return null;
return (
<Dialog
open={open}
onClose={onClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">{title}</DialogTitle>
<DialogContent>
{isSending && <LinearProgress />}
<DialogContentText id="alert-dialog-description">
{description}
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={cancelOnClick} color="primary" disabled={isSending}>
{cancelLabel || "Cancel"}
</Button>
<Button onClick={onClick} color="secondary" autoFocus>
{okLabel || "Ok"}
</Button>
</DialogActions>
</Dialog>
);
};
export default withStyles(styles)(ConfirmationDialog);

View File

@@ -14,23 +14,16 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useEffect, useState } from "react";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
LinearProgress,
} from "@mui/material";
import api from "../../../../common/api";
import React, { useState } from "react";
import { DialogContentText } from "@mui/material";
import { IPodListElement } from "../ListTenants/types";
import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
import Grid from "@mui/material/Grid";
import { connect } from "react-redux";
import { setErrorSnackMessage } from "../../../../actions";
import { ErrorResponseHandler } from "../../../../common/types";
import useApi from "../../Common/Hooks/useApi";
import ConfirmDialog from "../../Common/ModalWrapper/ConfirmDialog";
interface IDeletePod {
deleteOpen: boolean;
@@ -45,29 +38,15 @@ const DeletePod = ({
closeDeleteModalAndRefresh,
setErrorSnackMessage,
}: IDeletePod) => {
const [deleteLoading, setDeleteLoading] = useState(false);
const [retypePod, setRetypePod] = useState("");
useEffect(() => {
if (deleteLoading) {
api
.invoke(
"DELETE",
`/api/v1/namespaces/${selectedPod.namespace}/tenants/${selectedPod.tenant}/pods/${selectedPod.name}`
)
.then(() => {
setDeleteLoading(false);
closeDeleteModalAndRefresh(true);
})
.catch((err: ErrorResponseHandler) => {
setDeleteLoading(false);
setErrorSnackMessage(err);
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [deleteLoading]);
const onDelSuccess = () => closeDeleteModalAndRefresh(true);
const onDelError = (err: ErrorResponseHandler) => setErrorSnackMessage(err);
const onClose = () => closeDeleteModalAndRefresh(false);
const removeRecord = () => {
const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError);
const onConfirmDelete = () => {
if (retypePod !== selectedPod.name) {
setErrorSnackMessage({
errorMessage: "Tenant name is incorrect",
@@ -75,22 +54,25 @@ const DeletePod = ({
});
return;
}
setDeleteLoading(true);
invokeDeleteApi(
"DELETE",
`/api/v1/namespaces/${selectedPod.namespace}/tenants/${selectedPod.tenant}/pods/${selectedPod.name}`
);
};
return (
<Dialog
open={deleteOpen}
onClose={() => {
closeDeleteModalAndRefresh(false);
<ConfirmDialog
title={`Delete Pod`}
confirmText={"Delete"}
isOpen={deleteOpen}
isLoading={deleteLoading}
onConfirm={onConfirmDelete}
onClose={onClose}
confirmButtonProps={{
disabled: retypePod !== selectedPod.name || deleteLoading,
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">Delete Pod</DialogTitle>
<DialogContent>
{deleteLoading && <LinearProgress />}
<DialogContentText id="alert-dialog-description">
confirmationContent={
<DialogContentText>
To continue please type <b>{selectedPod.name}</b> in the box.
<Grid item xs={12}>
<InputBoxWrapper
@@ -104,27 +86,8 @@ const DeletePod = ({
/>
</Grid>
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
onClick={() => {
closeDeleteModalAndRefresh(false);
}}
color="primary"
disabled={deleteLoading}
>
Cancel
</Button>
<Button
onClick={removeRecord}
color="secondary"
autoFocus
disabled={retypePod !== selectedPod.name}
>
Delete
</Button>
</DialogActions>
</Dialog>
}
/>
);
};

View File

@@ -29,7 +29,12 @@ import Chip from "@mui/material/Chip";
import React, { Fragment, useCallback, useEffect, useState } from "react";
import Moment from "react-moment";
import FormSwitchWrapper from "../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
import { Button, CircularProgress, Typography } from "@mui/material";
import {
Button,
CircularProgress,
DialogContentText,
Typography,
} from "@mui/material";
import { KeyPair } from "../ListTenants/utils";
import FileSelector from "../../Common/FormComponents/FileSelector/FileSelector";
import api from "../../../../common/api";
@@ -38,7 +43,7 @@ import { connect } from "react-redux";
import { AppState } from "../../../../store";
import { ErrorResponseHandler } from "../../../../common/types";
import { setTenantDetailsLoad } from "../actions";
import ConfirmationDialog from "./ConfirmationDialog";
import ConfirmDialog from "../../Common/ModalWrapper/ConfirmDialog";
interface ITenantSecurity {
classes: any;
@@ -311,15 +316,19 @@ const TenantSecurity = ({
};
return (
<React.Fragment>
<ConfirmationDialog
open={dialogOpen}
title="Save and Restart"
description="Are you sure you want to save the changes and restart the service?"
<ConfirmDialog
title={"Save and Restart"}
confirmText={"Restart"}
cancelText="Cancel"
isLoading={isSending}
onClose={() => setDialogOpen(false)}
cancelOnClick={() => setDialogOpen(false)}
okOnClick={updateTenantSecurity}
cancelLabel="Cancel"
okLabel={"Restart"}
isOpen={dialogOpen}
onConfirm={updateTenantSecurity}
confirmationContent={
<DialogContentText>
Are you sure you want to save the changes and restart the service?
</DialogContentText>
}
/>
{loadingTenant ? (
<Paper className={classes.paperContainer}>

View File

@@ -14,141 +14,63 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useState } from "react";
import React from "react";
import { connect } from "react-redux";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
LinearProgress,
} from "@mui/material";
import api from "../../../common/api";
import { User, UsersList } from "./types";
import { DialogContentText } from "@mui/material";
import { User } from "./types";
import { setErrorSnackMessage } from "../../../actions";
import useApi from "../Common/Hooks/useApi";
import ConfirmDialog from "../Common/ModalWrapper/ConfirmDialog";
import { ErrorResponseHandler } from "../../../common/types";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import { deleteDialogStyles } from "../Common/FormComponents/common/styleLibrary";
import IconButton from "@mui/material/IconButton";
import CloseIcon from "@mui/icons-material/Close";
import withStyles from "@mui/styles/withStyles";
const styles = (theme: Theme) =>
createStyles({
...deleteDialogStyles,
});
interface IDeleteUserProps {
closeDeleteModalAndRefresh: (refresh: boolean) => void;
deleteOpen: boolean;
selectedUser: User | null;
setErrorSnackMessage: typeof setErrorSnackMessage;
classes: any;
}
const DeleteUser = ({
classes,
closeDeleteModalAndRefresh,
deleteOpen,
selectedUser,
setErrorSnackMessage,
}: IDeleteUserProps) => {
const [deleteLoading, setDeleteLoading] = useState<boolean>(false);
const onDelSuccess = () => closeDeleteModalAndRefresh(true);
const onDelError = (err: ErrorResponseHandler) => setErrorSnackMessage(err);
const onClose = () => closeDeleteModalAndRefresh(false);
const removeRecord = () => {
if (deleteLoading) {
return;
}
if (selectedUser === null) {
return;
}
setDeleteLoading(true);
api
.invoke(
"DELETE",
`/api/v1/user?name=${encodeURI(selectedUser.accessKey)}`,
{
id: selectedUser.id,
}
)
.then((res: UsersList) => {
setDeleteLoading(false);
closeDeleteModalAndRefresh(true);
})
.catch((err: ErrorResponseHandler) => {
setDeleteLoading(false);
setErrorSnackMessage(err);
});
};
const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError);
if (selectedUser === null) {
return <div />;
if (!selectedUser) {
return null;
}
return (
<Dialog
open={deleteOpen}
onClose={() => {
closeDeleteModalAndRefresh(false);
}}
classes={classes}
className={classes.root}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title" className={classes.title}>
<div className={classes.titleText}>Delete User</div>
<div className={classes.closeContainer}>
<IconButton
aria-label="close"
className={classes.closeButton}
onClick={() => {
closeDeleteModalAndRefresh(true);
}}
disableRipple
size="small"
>
<CloseIcon />
</IconButton>
</div>
</DialogTitle>
const onConfirmDelete = () => {
invokeDeleteApi(
"DELETE",
`/api/v1/user?name=${encodeURI(selectedUser.accessKey)}`,
{
id: selectedUser.id,
}
);
};
<DialogContent>
{deleteLoading && <LinearProgress />}
<DialogContentText id="alert-dialog-description">
return (
<ConfirmDialog
title={`Delete User`}
confirmText={"Delete"}
isOpen={deleteOpen}
isLoading={deleteLoading}
onConfirm={onConfirmDelete}
onClose={onClose}
confirmationContent={
<DialogContentText>
Are you sure you want to delete user <br />
<b>{selectedUser.accessKey}</b>?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
type="button"
variant="outlined"
onClick={() => {
closeDeleteModalAndRefresh(false);
}}
color="primary"
disabled={deleteLoading}
>
Cancel
</Button>
<Button
onClick={() => {
removeRecord();
}}
type="button"
variant="outlined"
color="secondary"
autoFocus
>
Delete
</Button>
</DialogActions>
</Dialog>
}
/>
);
};
@@ -158,4 +80,4 @@ const mapDispatchToProps = {
const connector = connect(null, mapDispatchToProps);
export default withStyles(styles)(connector(DeleteUser));
export default connector(DeleteUser);

View File

@@ -14,22 +14,14 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useState } from "react";
import React from "react";
import { connect } from "react-redux";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
LinearProgress,
} from "@mui/material";
import { DialogContentText } from "@mui/material";
import { setErrorSnackMessage } from "../../../actions";
import { UsersList } from "./types";
import { ErrorResponseHandler } from "../../../common/types";
import history from "../../../history";
import api from "../../../common/api";
import useApi from "../Common/Hooks/useApi";
import ConfirmDialog from "../Common/ModalWrapper/ConfirmDialog";
interface IDeleteUserProps {
closeDeleteModalAndRefresh: (refresh: boolean) => void;
@@ -44,73 +36,39 @@ const DeleteUserString = ({
userName,
setErrorSnackMessage,
}: IDeleteUserProps) => {
const [deleteLoading, setDeleteLoading] = useState<boolean>(false);
const removeRecord = () => {
if (deleteLoading) {
return;
}
if (userName === null) {
return;
}
setDeleteLoading(true);
api
.invoke("DELETE", `/api/v1/user?name=${encodeURI(userName)}`, {
id: userName,
})
.then((res: UsersList) => {
setDeleteLoading(false);
closeDeleteModalAndRefresh(true);
})
.catch((err: ErrorResponseHandler) => {
setDeleteLoading(false);
setErrorSnackMessage(err);
});
const onDelSuccess = () => {
history.push(`/users/`);
};
const onDelError = (err: ErrorResponseHandler) => setErrorSnackMessage(err);
const onClose = () => closeDeleteModalAndRefresh(false);
if (userName === null) {
return <div />;
const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError);
if (!userName) {
return null;
}
const onConfirmDelete = () => {
invokeDeleteApi("DELETE", `/api/v1/user?name=${encodeURI(userName)}`, {
id: userName,
});
};
return (
<Dialog
open={deleteOpen}
onClose={() => {
closeDeleteModalAndRefresh(false);
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">Delete User</DialogTitle>
<DialogContent>
{deleteLoading && <LinearProgress />}
<DialogContentText id="alert-dialog-description">
Are you sure you want to delete user <b>{userName}</b>?
<ConfirmDialog
title={`Delete User`}
confirmText={"Delete"}
isOpen={deleteOpen}
isLoading={deleteLoading}
onConfirm={onConfirmDelete}
onClose={onClose}
confirmationContent={
<DialogContentText>
Are you sure you want to delete user <br />
<b>{userName}</b>?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
onClick={() => {
closeDeleteModalAndRefresh(false);
}}
color="primary"
disabled={deleteLoading}
>
Cancel
</Button>
<Button
onClick={() => {
removeRecord();
closeDeleteModalAndRefresh(true);
history.push(`/users/`);
}}
color="secondary"
autoFocus
>
Delete
</Button>
</DialogActions>
</Dialog>
}
/>
);
};