diff --git a/portal-ui/src/screens/Console/Account/DeleteServiceAccount.tsx b/portal-ui/src/screens/Console/Account/DeleteServiceAccount.tsx index 0177c0c64..e6c23251e 100644 --- a/portal-ui/src/screens/Console/Account/DeleteServiceAccount.tsx +++ b/portal-ui/src/screens/Console/Account/DeleteServiceAccount.tsx @@ -14,30 +14,19 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -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 ( - { - closeDeleteModalAndRefresh(false); - }} - aria-labelledby="alert-dialog-title" - aria-describedby="alert-dialog-description" - > - - Delete ServiceAccount - - { - closeDeleteModalAndRefresh(true); - }} - disableRipple - size="small" - > - - - - - - {deleteLoading && } - + Are you sure you want to delete service account{" "} {selectedServiceAccount}? - - - { - closeDeleteModalAndRefresh(false); - }} - color="primary" - disabled={deleteLoading} - > - Cancel - - - - Delete - - - + } + /> ); }; diff --git a/portal-ui/src/screens/Console/Buckets/BucketDetails/DeleteAccessRule.tsx b/portal-ui/src/screens/Console/Buckets/BucketDetails/DeleteAccessRule.tsx index a21d6fbb9..eeaf8b739 100644 --- a/portal-ui/src/screens/Console/Buckets/BucketDetails/DeleteAccessRule.tsx +++ b/portal-ui/src/screens/Console/Buckets/BucketDetails/DeleteAccessRule.tsx @@ -15,23 +15,17 @@ // along with this program. If not, see . 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 ( - - Delete Access Rule - - + confirmationContent={ + Are you sure you want to delete this access rule? - - - - Cancel - - { - deleteProcess(); - onClose(); - }} - color="secondary" - autoFocus - > - Delete - - - + } + /> ); }; diff --git a/portal-ui/src/screens/Console/Buckets/BucketDetails/DeleteBucketTagModal.tsx b/portal-ui/src/screens/Console/Buckets/BucketDetails/DeleteBucketTagModal.tsx index 6a9912365..abde79f58 100644 --- a/portal-ui/src/screens/Console/Buckets/BucketDetails/DeleteBucketTagModal.tsx +++ b/portal-ui/src/screens/Console/Buckets/BucketDetails/DeleteBucketTagModal.tsx @@ -14,18 +14,10 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -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(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 ( - { - onCloseAndUpdate(false); - }} - aria-labelledby="alert-dialog-title" - aria-describedby="alert-dialog-description" - > - Delete Tag - - {deleteLoading && } - + Are you sure you want to delete the tag{" "} {tagKey} : {tagLabel} - + {" "} + ? - - - { - onCloseAndUpdate(false); - }} - color="primary" - disabled={deleteLoading} - > - Cancel - - - Delete - - - + } + /> ); }; diff --git a/portal-ui/src/screens/Console/Buckets/BucketDetails/DeleteEvent.tsx b/portal-ui/src/screens/Console/Buckets/BucketDetails/DeleteEvent.tsx index 3225fe85b..7735e2ed9 100644 --- a/portal-ui/src/screens/Console/Buckets/BucketDetails/DeleteEvent.tsx +++ b/portal-ui/src/screens/Console/Buckets/BucketDetails/DeleteEvent.tsx @@ -14,22 +14,15 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -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(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 ( - { - closeDeleteModalAndRefresh(false); - }} - aria-labelledby="alert-dialog-title" - aria-describedby="alert-dialog-description" - > - Delete Event - - {deleteLoading && } - + Are you sure you want to delete this event? - - - { - closeDeleteModalAndRefresh(false); - }} - color="primary" - disabled={deleteLoading} - > - Cancel - - { - removeRecord(); - }} - color="secondary" - autoFocus - > - Delete - - - + } + /> ); }; diff --git a/portal-ui/src/screens/Console/Buckets/BucketDetails/DeleteReplicationRule.tsx b/portal-ui/src/screens/Console/Buckets/BucketDetails/DeleteReplicationRule.tsx index 656ca6131..a0d94b953 100644 --- a/portal-ui/src/screens/Console/Buckets/BucketDetails/DeleteReplicationRule.tsx +++ b/portal-ui/src/screens/Console/Buckets/BucketDetails/DeleteReplicationRule.tsx @@ -14,20 +14,13 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -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(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 ( - { - closeDeleteModalAndRefresh(false); - }} - aria-labelledby="alert-dialog-title" - aria-describedby="alert-dialog-description" - > - Delete Replication Rule - - {deleteLoading && } - + Are you sure you want to delete replication rule {ruleToDelete} ? Remember, at lease one rule must be present once replication has been enabled - - - { - closeDeleteModalAndRefresh(false); - }} - color="primary" - disabled={deleteLoading} - > - Cancel - - { - removeRecord(); - }} - color="secondary" - autoFocus - > - Delete - - - + } + /> ); }; diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/DeleteBucket.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/DeleteBucket.tsx index 633991ef2..5896c2d6b 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/DeleteBucket.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/DeleteBucket.tsx @@ -14,21 +14,13 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -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(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 ( - { - closeDeleteModalAndRefresh(false); - }} - aria-labelledby="alert-dialog-title" - aria-describedby="alert-dialog-description" - > - Delete Bucket - - {deleteLoading && } - + Are you sure you want to delete bucket {selectedBucket}? A bucket can only be deleted if it's empty. - - - { - closeDeleteModalAndRefresh(false); - }} - color="primary" - disabled={deleteLoading} - > - Cancel - - { - removeRecord(); - }} - color="secondary" - autoFocus - > - Delete - - - + } + /> ); }; diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteMultipleObjects.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteMultipleObjects.tsx index f5e3f6f63..8b462b0bc 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteMultipleObjects.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteMultipleObjects.tsx @@ -14,20 +14,13 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -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(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 ( - { - closeDeleteModalAndRefresh(false); - }} - aria-labelledby="alert-dialog-title" - aria-describedby="alert-dialog-description" - > - Delete - - {deleteLoading && } - - Are you sure you want to delete the selected objects?{" "} + + Are you sure you want to delete the selected {selectedObjects.length}{" "} + objects?{" "} - - - { - closeDeleteModalAndRefresh(false); - }} - color="primary" - disabled={deleteLoading} - > - Cancel - - { - removeRecord(); - }} - color="secondary" - disabled={deleteLoading} - > - Delete - - - + } + /> ); }; diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteObject.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteObject.tsx index 01c22bd75..7d1ea122b 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteObject.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteObject.tsx @@ -14,21 +14,14 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -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(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 ( - { - closeDeleteModalAndRefresh(false); - }} - aria-labelledby="alert-dialog-title" - aria-describedby="alert-dialog-description" - > - Delete - - {deleteLoading && } - + Are you sure you want to delete:{" "} {decodeFileName(selectedObject)}?{" "} - - - { - closeDeleteModalAndRefresh(false); - }} - color="primary" - disabled={deleteLoading} - > - Cancel - - { - removeRecord(); - }} - color="secondary" - disabled={deleteLoading} - > - Delete - - - + } + /> ); }; diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/DeleteTagModal.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/DeleteTagModal.tsx index 34f7df1a4..975b8ddf5 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/DeleteTagModal.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/DeleteTagModal.tsx @@ -14,27 +14,19 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -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(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 ( - { - onCloseAndUpdate(false); - }} - aria-labelledby="alert-dialog-title" - aria-describedby="alert-dialog-description" - > - Delete Tag - - {deleteLoading && } - + Are you sure you want to delete the tag{" "} {tagKey} : {tagLabel} {" "} from {selectedObject}? - - - { - onCloseAndUpdate(false); - }} - color="primary" - disabled={deleteLoading} - > - Cancel - - - Delete - - - + } + /> ); }; diff --git a/portal-ui/src/screens/Console/Common/Hooks/useApi.tsx b/portal-ui/src/screens/Console/Common/Hooks/useApi.tsx new file mode 100644 index 000000000..1f7155c47 --- /dev/null +++ b/portal-ui/src/screens/Console/Common/Hooks/useApi.tsx @@ -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(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; diff --git a/portal-ui/src/screens/Console/Common/ModalWrapper/ConfirmDialog.tsx b/portal-ui/src/screens/Console/Common/ModalWrapper/ConfirmDialog.tsx new file mode 100644 index 000000000..4f9905795 --- /dev/null +++ b/portal-ui/src/screens/Console/Common/ModalWrapper/ConfirmDialog.tsx @@ -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; + cancelButtonProps?: Partial; +}; + +const ConfirmDialog = ({ + isOpen = false, + onClose, + onCancel, + onConfirm, + classes = {}, + title = "", + isLoading, + confirmationContent, + cancelText = "Cancel", + confirmText = "Confirm", + confirmButtonProps = {}, + cancelButtonProps = {}, +}: ConfirmDialogProps) => { + return ( + { + if (reason !== "backdropClick") { + onClose(); // close on Esc but not on click outside + } + }} + className={classes.root} + onBackdropClick={() => { + return false; + }} + > + + {title} + + + + + + + + + {confirmationContent} + + + + {cancelText} + + + + {confirmText} + + + + ); +}; + +export default withStyles(styles)(ConfirmDialog); diff --git a/portal-ui/src/screens/Console/Groups/DeleteGroup.tsx b/portal-ui/src/screens/Console/Groups/DeleteGroup.tsx index f2edda8b0..d0192b45a 100644 --- a/portal-ui/src/screens/Console/Groups/DeleteGroup.tsx +++ b/portal-ui/src/screens/Console/Groups/DeleteGroup.tsx @@ -14,38 +14,19 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -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(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 ( - - - Delete Group - - - - - - - - {isDeleting && } - - Are you sure you want to delete group + + Are you sure you want to delete group + {selectedGroup}? - - - - Cancel - - { - setDeleteLoading(true); - }} - color="secondary" - autoFocus - > - Delete - - - + } + /> ); }; @@ -150,4 +73,4 @@ const mapDispatchToProps = { const connector = connect(null, mapDispatchToProps); -export default withStyles(styles)(connector(DeleteGroup)); +export default connector(DeleteGroup); diff --git a/portal-ui/src/screens/Console/Policies/DeletePolicy.tsx b/portal-ui/src/screens/Console/Policies/DeletePolicy.tsx index 267bbe73f..795645137 100644 --- a/portal-ui/src/screens/Console/Policies/DeletePolicy.tsx +++ b/portal-ui/src/screens/Console/Policies/DeletePolicy.tsx @@ -14,123 +14,56 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -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(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 ( - { - closeDeleteModalAndRefresh(false); - }} - aria-labelledby="alert-dialog-title" - aria-describedby="alert-dialog-description" - > - - Delete Policy - - { - closeDeleteModalAndRefresh(false); - }} - disableRipple - size="small" - > - - - - - - {deleteLoading && } - + Are you sure you want to delete policy {selectedPolicy}? - - - { - closeDeleteModalAndRefresh(false); - }} - color="primary" - disabled={deleteLoading} - > - Cancel - - { - removeRecord(); - }} - color="secondary" - autoFocus - > - Delete - - - + } + /> ); }; @@ -139,4 +72,4 @@ const mapDispatchToProps = { }; const connector = connect(null, mapDispatchToProps); -export default withStyles(styles)(connector(DeletePolicy)); +export default connector(DeletePolicy); diff --git a/portal-ui/src/screens/Console/Tenants/ListTenants/DeleteTenant.tsx b/portal-ui/src/screens/Console/Tenants/ListTenants/DeleteTenant.tsx index 04f2dcf7c..c13419b12 100644 --- a/portal-ui/src/screens/Console/Tenants/ListTenants/DeleteTenant.tsx +++ b/portal-ui/src/screens/Console/Tenants/ListTenants/DeleteTenant.tsx @@ -14,23 +14,16 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -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 ( - { - closeDeleteModalAndRefresh(false); + - Delete Tenant - - {deleteLoading && } - + confirmationContent={ + To continue please type {selectedTenant.name} in the box. - - - { - closeDeleteModalAndRefresh(false); - }} - color="primary" - disabled={deleteLoading} - > - Cancel - - - Delete - - - + } + /> ); }; diff --git a/portal-ui/src/screens/Console/Tenants/TenantDetails/ConfirmationDialog.tsx b/portal-ui/src/screens/Console/Tenants/TenantDetails/ConfirmationDialog.tsx deleted file mode 100644 index 73ad53ea4..000000000 --- a/portal-ui/src/screens/Console/Tenants/TenantDetails/ConfirmationDialog.tsx +++ /dev/null @@ -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(false); - const onClick = () => { - setIsSending(true); - if (okOnClick !== null) { - okOnClick(); - } - setIsSending(false); - }; - if (!open) return null; - return ( - - {title} - - {isSending && } - - {description} - - - - - {cancelLabel || "Cancel"} - - - {okLabel || "Ok"} - - - - ); -}; - -export default withStyles(styles)(ConfirmationDialog); diff --git a/portal-ui/src/screens/Console/Tenants/TenantDetails/DeletePod.tsx b/portal-ui/src/screens/Console/Tenants/TenantDetails/DeletePod.tsx index 78960445c..e328290ce 100644 --- a/portal-ui/src/screens/Console/Tenants/TenantDetails/DeletePod.tsx +++ b/portal-ui/src/screens/Console/Tenants/TenantDetails/DeletePod.tsx @@ -14,23 +14,16 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -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 ( - { - closeDeleteModalAndRefresh(false); + - Delete Pod - - {deleteLoading && } - + confirmationContent={ + To continue please type {selectedPod.name} in the box. - - - { - closeDeleteModalAndRefresh(false); - }} - color="primary" - disabled={deleteLoading} - > - Cancel - - - Delete - - - + } + /> ); }; diff --git a/portal-ui/src/screens/Console/Tenants/TenantDetails/TenantSecurity.tsx b/portal-ui/src/screens/Console/Tenants/TenantDetails/TenantSecurity.tsx index ae2f36c11..f05cff77f 100644 --- a/portal-ui/src/screens/Console/Tenants/TenantDetails/TenantSecurity.tsx +++ b/portal-ui/src/screens/Console/Tenants/TenantDetails/TenantSecurity.tsx @@ -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 ( - setDialogOpen(false)} - cancelOnClick={() => setDialogOpen(false)} - okOnClick={updateTenantSecurity} - cancelLabel="Cancel" - okLabel={"Restart"} + isOpen={dialogOpen} + onConfirm={updateTenantSecurity} + confirmationContent={ + + Are you sure you want to save the changes and restart the service? + + } /> {loadingTenant ? ( diff --git a/portal-ui/src/screens/Console/Users/DeleteUser.tsx b/portal-ui/src/screens/Console/Users/DeleteUser.tsx index 795df8f16..ff0a11f8b 100644 --- a/portal-ui/src/screens/Console/Users/DeleteUser.tsx +++ b/portal-ui/src/screens/Console/Users/DeleteUser.tsx @@ -14,141 +14,63 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -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(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 ; + if (!selectedUser) { + return null; } - return ( - { - closeDeleteModalAndRefresh(false); - }} - classes={classes} - className={classes.root} - aria-labelledby="alert-dialog-title" - aria-describedby="alert-dialog-description" - > - - Delete User - - { - closeDeleteModalAndRefresh(true); - }} - disableRipple - size="small" - > - - - - + const onConfirmDelete = () => { + invokeDeleteApi( + "DELETE", + `/api/v1/user?name=${encodeURI(selectedUser.accessKey)}`, + { + id: selectedUser.id, + } + ); + }; - - {deleteLoading && } - + return ( + Are you sure you want to delete user {selectedUser.accessKey}? - - - { - closeDeleteModalAndRefresh(false); - }} - color="primary" - disabled={deleteLoading} - > - Cancel - - - { - removeRecord(); - }} - type="button" - variant="outlined" - color="secondary" - autoFocus - > - Delete - - - + } + /> ); }; @@ -158,4 +80,4 @@ const mapDispatchToProps = { const connector = connect(null, mapDispatchToProps); -export default withStyles(styles)(connector(DeleteUser)); +export default connector(DeleteUser); diff --git a/portal-ui/src/screens/Console/Users/DeleteUserString.tsx b/portal-ui/src/screens/Console/Users/DeleteUserString.tsx index 41fbde6b2..6a7a7fa9a 100644 --- a/portal-ui/src/screens/Console/Users/DeleteUserString.tsx +++ b/portal-ui/src/screens/Console/Users/DeleteUserString.tsx @@ -14,22 +14,14 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -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(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 ; + const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError); + + if (!userName) { + return null; } + const onConfirmDelete = () => { + invokeDeleteApi("DELETE", `/api/v1/user?name=${encodeURI(userName)}`, { + id: userName, + }); + }; + return ( - { - closeDeleteModalAndRefresh(false); - }} - aria-labelledby="alert-dialog-title" - aria-describedby="alert-dialog-description" - > - Delete User - - {deleteLoading && } - - Are you sure you want to delete user {userName}? + + Are you sure you want to delete user + {userName}? - - - { - closeDeleteModalAndRefresh(false); - }} - color="primary" - disabled={deleteLoading} - > - Cancel - - { - removeRecord(); - closeDeleteModalAndRefresh(true); - history.push(`/users/`); - }} - color="secondary" - autoFocus - > - Delete - - - + } + /> ); };