diff --git a/portal-ui/src/screens/Console/Buckets/ViewBucket/AddReplicationModal.tsx b/portal-ui/src/screens/Console/Buckets/ViewBucket/AddReplicationModal.tsx index 98ffe358f..1d19642e9 100644 --- a/portal-ui/src/screens/Console/Buckets/ViewBucket/AddReplicationModal.tsx +++ b/portal-ui/src/screens/Console/Buckets/ViewBucket/AddReplicationModal.tsx @@ -25,11 +25,7 @@ import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBo import SelectWrapper from "../../Common/FormComponents/SelectWrapper/SelectWrapper"; import { Button, LinearProgress } from "@material-ui/core"; import api from "../../../../common/api"; -import { - IRemoteBucket, - IRemoteBucketsResponse, -} from "../../RemoteBuckets/types"; -import RemoteBucketsList from "../../RemoteBuckets/RemoteBuckets"; +import { IRemoteBucket } from "../types"; interface IReplicationModal { open: boolean; @@ -64,42 +60,61 @@ const AddReplicationModal = ({ bucketName, }: IReplicationModal) => { const [addError, setAddError] = useState(""); - const [loadingForm, setLoadingForm] = useState(true); const [addLoading, setAddLoading] = useState(false); - const [remoteURL, setRemoteURL] = useState(""); - const [source, setSource] = useState(""); - const [target, setTarget] = useState(""); - const [ARN, setARN] = useState(""); - const [arnValues, setARNValues] = useState([]); - - useEffect(() => { - if (addLoading) { - addRecord(); - } - }, [addLoading]); - - useEffect(() => { - if (loadingForm) { - getARNValues(); - } - }); + const [accessKey, setAccessKey] = useState(""); + const [secretKey, setSecretKey] = useState(""); + const [targetURL, setTargetURL] = useState(""); + const [targetBucket, setTargetBucket] = useState(""); + const [region, setRegion] = useState(""); const addRecord = () => { - const replicationInfo = { - destination_bucket: target, - arn: ARN, + const remoteBucketInfo = { + accessKey: accessKey, + secretKey: secretKey, + sourceBucket: bucketName, + targetURL: targetURL, + targetBucket: targetBucket, + region: region, }; api - .invoke( - "POST", - `/api/v1/buckets/${bucketName}/replication`, - replicationInfo - ) - .then((res) => { - setAddLoading(false); - setAddError(""); - closeModalAndRefresh(); + .invoke("POST", "/api/v1/remote-buckets", remoteBucketInfo) + .then(() => { + api + .invoke("GET", "/api/v1/remote-buckets") + .then((res: any) => { + const remoteBuckets = get(res, "buckets", []); + const remoteBucket = remoteBuckets.find( + (itemRemote: IRemoteBucket) => { + return itemRemote.sourceBucket === bucketName; + } + ); + if (remoteBucket && remoteBucket.remoteARN) { + const remoteARN = remoteBucket.remoteARN; + const replicationInfo = { + destination_bucket: targetBucket, + arn: remoteARN, + }; + api + .invoke( + "POST", + `/api/v1/buckets/${bucketName}/replication`, + replicationInfo + ) + .then(() => { + setAddLoading(false); + setAddError(""); + closeModalAndRefresh(); + }) + .catch((err) => { + setAddLoading(false); + setAddError(err); + }); + } + }) + .catch((err) => { + setAddError(err); + }); }) .catch((err) => { setAddLoading(false); @@ -107,23 +122,6 @@ const AddReplicationModal = ({ }); }; - const getARNValues = () => { - api - .invoke("GET", "/api/v1/remote-buckets") - .then((res: any) => { - const remoteBuckets = get(res, "buckets", []); - - const remoteARNS = remoteBuckets.map((itemRemote: IRemoteBucket) => { - return { label: itemRemote.remoteARN, value: itemRemote.remoteARN }; - }); - setLoadingForm(false); - setARNValues(remoteARNS); - }) - .catch((err) => { - setLoadingForm(false); - }); - }; - return ( ) => { e.preventDefault(); setAddLoading(true); + addRecord(); }} > - {loadingForm && ( - + + + {addError !== "" && ( + + + {addError} + + + )} + + + ) => { + setAccessKey(e.target.value); + }} + label="Access Key" + value={accessKey} + /> + + + ) => { + setSecretKey(e.target.value); + }} + label="Secret Key" + value={secretKey} + /> + + + ) => { + setTargetURL(e.target.value); + }} + placeholder="https://play.min.io:9000" + label="Target URL" + value={targetURL} + /> + + + ) => { + setTargetBucket(e.target.value); + }} + label="Target Bucket" + value={targetBucket} + /> + + + ) => { + setRegion(e.target.value); + }} + label="Region" + value={region} + /> + + + + + + {addLoading && ( - - )} - {!loadingForm && ( - - - {addError !== "" && ( - - - {addError} - - - )} - - - ) => { - setTarget(e.target.value); - }} - label="Destination Bucket" - value={target} - /> - - - ) => { - setARN(e.target.value as string); - }} - id="arn" - name="arn" - label={"ARN"} - value={ARN} - options={arnValues} - /> - - - - - - {addLoading && ( - - - - )} - - )} + )} + ); diff --git a/portal-ui/src/screens/Console/Buckets/ViewBucket/ViewBucket.tsx b/portal-ui/src/screens/Console/Buckets/ViewBucket/ViewBucket.tsx index ea565e435..483ac3605 100644 --- a/portal-ui/src/screens/Console/Buckets/ViewBucket/ViewBucket.tsx +++ b/portal-ui/src/screens/Console/Buckets/ViewBucket/ViewBucket.tsx @@ -515,51 +515,53 @@ class ViewBucket extends React.Component {
- - , newValue: number) => { - this.setState({ curTab: newValue }); - }} - indicatorColor="primary" - textColor="primary" - aria-label="cluster-tabs" - > - - - - - - {curTab === 0 && ( - - )} - {curTab === 1 && ( - - )} + + + + + + {curTab === 0 && ( + + )} + {curTab === 1 && ( + + )} + diff --git a/portal-ui/src/screens/Console/Buckets/types.tsx b/portal-ui/src/screens/Console/Buckets/types.tsx index ea1a2631f..1bb64fee1 100644 --- a/portal-ui/src/screens/Console/Buckets/types.tsx +++ b/portal-ui/src/screens/Console/Buckets/types.tsx @@ -79,3 +79,15 @@ export interface MakeBucketRequest { versioning: boolean; quota?: QuotaRequest; } + +export interface IRemoteBucket { + name: string; + accessKey: string; + secretKey: string; + sourceBucket: string; + targetURL: string; + targetBucket: string; + remoteARN: string; + status: string; + service: string; +} diff --git a/portal-ui/src/screens/Console/Console.tsx b/portal-ui/src/screens/Console/Console.tsx index 1a4812a6a..3f9135d1c 100644 --- a/portal-ui/src/screens/Console/Console.tsx +++ b/portal-ui/src/screens/Console/Console.tsx @@ -67,7 +67,6 @@ import { ISessionResponse } from "./types"; import { saveSessionResponse } from "./actions"; import TenantDetails from "./Tenants/TenantDetails/TenantDetails"; import { clearSession } from "../../common/utils"; -import RemoteBuckets from "./RemoteBuckets/RemoteBuckets"; import ObjectBrowser from "./ObjectBrowser/ObjectBrowser"; import ListObjects from "./Buckets/ListBuckets/Objects/ListObjects/ListObjects"; @@ -279,10 +278,6 @@ const Console = ({ component: Policies, path: "/policies", }, - { - component: RemoteBuckets, - path: "/remote-buckets", - }, { component: Trace, path: "/trace", diff --git a/portal-ui/src/screens/Console/Menu/Menu.tsx b/portal-ui/src/screens/Console/Menu/Menu.tsx index 2b4c20e20..bc8840860 100644 --- a/portal-ui/src/screens/Console/Menu/Menu.tsx +++ b/portal-ui/src/screens/Console/Menu/Menu.tsx @@ -21,7 +21,6 @@ import ListItem from "@material-ui/core/ListItem"; import ListItemIcon from "@material-ui/core/ListItemIcon"; import WebAssetIcon from "@material-ui/icons/WebAsset"; import HealingIcon from "@material-ui/icons/Healing"; -import CloudUploadIcon from "@material-ui/icons/CloudUpload"; import DescriptionIcon from "@material-ui/icons/Description"; import FileCopyIcon from "@material-ui/icons/FileCopy"; import Collapse from "@material-ui/core/Collapse"; @@ -247,14 +246,6 @@ const Menu = ({ userLoggedIn, classes, pages }: IMenuProps) => { name: "IAM Policies", icon: , }, - { - group: "Admin", - type: "item", - component: NavLink, - to: "/remote-buckets", - name: "Remote Buckets", - icon: , - }, { group: "Tools", type: "item", diff --git a/portal-ui/src/screens/Console/RemoteBuckets/AddRemoteBucket.tsx b/portal-ui/src/screens/Console/RemoteBuckets/AddRemoteBucket.tsx deleted file mode 100644 index 43301870d..000000000 --- a/portal-ui/src/screens/Console/RemoteBuckets/AddRemoteBucket.tsx +++ /dev/null @@ -1,209 +0,0 @@ -// This file is part of MinIO Console Server -// Copyright (c) 2020 MinIO, Inc. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -import React, { useState, useEffect } from "react"; -import Grid from "@material-ui/core/Grid"; -import Typography from "@material-ui/core/Typography"; -import { Button, LinearProgress } from "@material-ui/core"; -import { createStyles, Theme, withStyles } from "@material-ui/core/styles"; -import { modalBasic } from "../Common/FormComponents/common/styleLibrary"; -import api from "../../../common/api"; -import ModalWrapper from "../Common/ModalWrapper/ModalWrapper"; -import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper"; -import SelectWrapper from "../Common/FormComponents/SelectWrapper/SelectWrapper"; - -const styles = (theme: Theme) => - createStyles({ - errorBlock: { - color: "red", - }, - buttonContainer: { - textAlign: "right", - }, - ...modalBasic, - }); - -interface IAddBucketProps { - classes: any; - open: boolean; - closeModalAndRefresh: () => void; -} - -const AddRemoteBucket = ({ - classes, - open, - closeModalAndRefresh, -}: IAddBucketProps) => { - const [addLoading, setAddLoading] = useState(false); - const [addError, setAddError] = useState(""); - const [accessKey, setAccessKey] = useState(""); - const [secretKey, setSecretKey] = useState(""); - const [sourceBucket, setSourceBucket] = useState(""); - const [targetURL, setTargetURL] = useState(""); - const [targetBucket, setTargetBucket] = useState(""); - const [region, setRegion] = useState(""); - - useEffect(() => { - if (addLoading) { - addRecord(); - } - }, [addLoading]); - - const addRecord = () => { - const remoteBucketInfo = { - accessKey: accessKey, - secretKey: secretKey, - sourceBucket: sourceBucket, - targetURL: targetURL, - targetBucket: targetBucket, - region: region, - }; - - api - .invoke("POST", "/api/v1/remote-buckets", remoteBucketInfo) - .then((res) => { - setAddLoading(false); - setAddError(""); - closeModalAndRefresh(); - }) - .catch((err) => { - setAddLoading(false); - setAddError(err); - }); - }; - - return ( - { - setAddError(""); - closeModalAndRefresh(); - }} - aria-labelledby="alert-dialog-title" - aria-describedby="alert-dialog-description" - > -
) => { - e.preventDefault(); - addRecord(); - }} - > - - - {addError !== "" && ( - - - {addError} - - - )} - - ) => { - setAccessKey(e.target.value); - }} - label="Access Key" - value={accessKey} - /> - - - ) => { - setSecretKey(e.target.value); - }} - label="Secret Key" - value={secretKey} - /> - - - ) => { - setSourceBucket(e.target.value); - }} - label="Source Bucket" - value={sourceBucket} - /> - - - ) => { - setTargetURL(e.target.value); - }} - placeholder="https://play.min.io:9000" - label="Target URL" - value={targetURL} - /> - - - ) => { - setTargetBucket(e.target.value); - }} - label="Target Bucket" - value={targetBucket} - /> - - - ) => { - setRegion(e.target.value); - }} - label="Region" - value={region} - /> - - - - - - {addLoading && ( - - - - )} - -
-
- ); -}; - -export default withStyles(styles)(AddRemoteBucket); diff --git a/portal-ui/src/screens/Console/RemoteBuckets/DeleteRemoteBucket.tsx b/portal-ui/src/screens/Console/RemoteBuckets/DeleteRemoteBucket.tsx deleted file mode 100644 index 1e97a50d0..000000000 --- a/portal-ui/src/screens/Console/RemoteBuckets/DeleteRemoteBucket.tsx +++ /dev/null @@ -1,137 +0,0 @@ -// This file is part of MinIO Console Server -// Copyright (c) 2020 MinIO, Inc. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -import React, { useState, useEffect } from "react"; -import { createStyles, Theme, withStyles } from "@material-ui/core/styles"; -import get from "lodash/get"; -import { - Button, - Dialog, - DialogActions, - DialogContent, - DialogContentText, - DialogTitle, - LinearProgress, -} from "@material-ui/core"; -import api from "../../../common/api"; -import Typography from "@material-ui/core/Typography"; - -const styles = (theme: Theme) => - createStyles({ - errorBlock: { - color: "red", - }, - }); - -interface IDeleteEventProps { - classes: any; - closeDeleteModalAndRefresh: (refresh: boolean) => void; - deleteOpen: boolean; - bucketName: any; - sourceBucket: string; -} - -interface IDeleteEventState { - deleteLoading: boolean; - deleteError: string; -} - -const DeleteRemoteBucket = ({ - deleteOpen, - closeDeleteModalAndRefresh, - classes, - bucketName, - sourceBucket, -}: IDeleteEventProps) => { - const [deleteError, setDeleteError] = useState(""); - const [deleteLoading, setDeleteLoading] = useState(false); - - useEffect(() => { - if (deleteLoading) { - removeRecord(); - } - }, [deleteLoading]); - - const removeRecord = () => { - api - .invoke("DELETE", `/api/v1/remote-buckets/${sourceBucket}/${bucketName}`) - .then(() => { - setDeleteLoading(false); - setDeleteError(""); - closeDeleteModalAndRefresh(true); - }) - .catch((err) => { - setDeleteLoading(false); - setDeleteError(err); - }); - }; - - return ( - { - setDeleteError(""); - closeDeleteModalAndRefresh(false); - }} - aria-labelledby="alert-dialog-title" - aria-describedby="alert-dialog-description" - > - Delete Remote Bucket - - {deleteLoading && } - - Are you sure you want to delete '{bucketName}' Remote - Bucket? - {deleteError !== "" && ( - -
- - {deleteError} - -
- )} -
-
- - - - -
- ); -}; - -export default withStyles(styles)(DeleteRemoteBucket); diff --git a/portal-ui/src/screens/Console/RemoteBuckets/RemoteBuckets.tsx b/portal-ui/src/screens/Console/RemoteBuckets/RemoteBuckets.tsx deleted file mode 100644 index f187844c9..000000000 --- a/portal-ui/src/screens/Console/RemoteBuckets/RemoteBuckets.tsx +++ /dev/null @@ -1,273 +0,0 @@ -// This file is part of MinIO Console Server -// Copyright (c) 2020 MinIO, Inc. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -import React, { useState, useEffect } from "react"; -import { createStyles, Theme, withStyles } from "@material-ui/core/styles"; -import Grid from "@material-ui/core/Grid"; -import { Button } from "@material-ui/core"; -import Typography from "@material-ui/core/Typography"; -import TextField from "@material-ui/core/TextField"; -import InputAdornment from "@material-ui/core/InputAdornment"; -import SearchIcon from "@material-ui/icons/Search"; -import Moment from "react-moment"; -import api from "../../../common/api"; -import { Bucket } from "../Buckets/types"; -import TableWrapper from "../Common/TableWrapper/TableWrapper"; -import AddRemoteBucket from "./AddRemoteBucket"; -import { MinTablePaginationActions } from "../../../common/MinTablePaginationActions"; -import { CreateIcon } from "../../../icons"; -import { IRemoteBucket, IRemoteBucketsResponse } from "./types"; -import DeleteRemoteBucket from "./DeleteRemoteBucket"; -import { - actionsTray, - containerForHeader, - searchField, -} from "../Common/FormComponents/common/styleLibrary"; -import PageHeader from "../Common/PageHeader/PageHeader"; - -const styles = (theme: Theme) => - createStyles({ - seeMore: { - marginTop: theme.spacing(3), - }, - paper: { - display: "flex", - overflow: "auto", - flexDirection: "column", - }, - - addSideBar: { - width: "320px", - padding: "20px", - }, - errorBlock: { - color: "red", - }, - tableToolbar: { - paddingLeft: theme.spacing(2), - paddingRight: theme.spacing(0), - }, - minTableHeader: { - color: "#393939", - "& tr": { - "& th": { - fontWeight: "bold", - }, - }, - }, - ...actionsTray, - ...searchField, - ...containerForHeader(theme.spacing(4)), - }); - -interface IRemoteListBucketsProps { - classes: any; -} - -const RemoteBucketsList = ({ classes }: IRemoteListBucketsProps) => { - const [records, setRecords] = useState([]); - const [totalRecords, setTotalRecords] = useState(0); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(""); - const [addScreenOpen, setAddScreenOpen] = useState(false); - const [deleteScreenOpen, setDeleteOpen] = useState(false); - const [page, setPage] = useState(0); - const [rowsPerPage, setRowsPerPage] = useState(10); - const [selectedBucket, setSelectedBucket] = useState({ - remoteARN: "", - accessKey: "", - name: "", - secretKey: "", - service: "", - sourceBucket: "", - status: "", - targetBucket: "", - targetURL: "", - }); - const [filterBuckets, setFilterBuckets] = useState(""); - - useEffect(() => { - if (loading) { - fetchRecords(); - } - }, [loading]); - - const closeAddModalAndRefresh = () => { - setAddScreenOpen(false); - setLoading(true); - }; - - const closeDeleteModalAndRefresh = (reload: boolean) => { - setDeleteOpen(false); - - if (reload) { - setLoading(true); - } - }; - - const fetchRecords = () => { - const offset = page * rowsPerPage; - api - .invoke("GET", `/api/v1/remote-buckets`) - .then((res: IRemoteBucketsResponse) => { - setLoading(false); - setRecords(res.buckets || []); - setTotalRecords(!res.buckets ? 0 : res.total); - setError(""); - // if we get 0 results, and page > 0 , go down 1 page - if ( - (res.buckets === undefined || - res.buckets == null || - res.buckets.length === 0) && - page > 0 - ) { - const newPage = page - 1; - setPage(newPage); - setLoading(true); - } - }) - .catch((err: any) => { - setLoading(false); - setError(err); - }); - }; - - const offset = page * rowsPerPage; - - const handleChangePage = (event: unknown, newPage: number) => { - setPage(newPage); - }; - - const handleChangeRowsPerPage = ( - event: React.ChangeEvent - ) => { - const rPP = parseInt(event.target.value, 10); - setPage(0); - setRowsPerPage(rPP); - }; - - const confirmDeleteRemoteBucket = (arnRemoteBucket: IRemoteBucket) => { - setSelectedBucket(arnRemoteBucket); - setDeleteOpen(true); - }; - - const tableActions = [{ type: "delete", onClick: confirmDeleteRemoteBucket }]; - - const filteredRecords = records - .slice(offset, offset + rowsPerPage) - .filter((b: IRemoteBucket) => { - if (filterBuckets === "") { - return true; - } else { - if (b.name.indexOf(filterBuckets) >= 0) { - return true; - } else { - return false; - } - } - }); - - return ( - - {addScreenOpen && ( - { - closeAddModalAndRefresh(); - }} - /> - )} - {deleteScreenOpen && ( - { - closeDeleteModalAndRefresh(reload); - }} - deleteOpen={deleteScreenOpen} - /> - )} - - - - - { - setFilterBuckets(val.target.value); - }} - InputProps={{ - disableUnderline: true, - startAdornment: ( - - - - ), - }} - /> - - - -
-
- - - -
-
-
- ); -}; - -export default withStyles(styles)(RemoteBucketsList); diff --git a/portal-ui/src/screens/Console/RemoteBuckets/types.ts b/portal-ui/src/screens/Console/RemoteBuckets/types.ts deleted file mode 100644 index 35ac9fadc..000000000 --- a/portal-ui/src/screens/Console/RemoteBuckets/types.ts +++ /dev/null @@ -1,32 +0,0 @@ -// This file is part of MinIO Console Server -// Copyright (c) 2020 MinIO, Inc. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -export interface IRemoteBucketsResponse { - buckets: IRemoteBucket[]; - total: number; -} - -export interface IRemoteBucket { - name: string; - accessKey: string; - secretKey: string; - sourceBucket: string; - targetURL: string; - targetBucket: string; - remoteARN: string; - status: string; - service: string; -}