Add Bucket as a page (#1220)
* Add Bucket as a page Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com> * goimports Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com> * Redirect to bucket browse Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com> * Address comment Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com> Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
This commit is contained in:
@@ -39,6 +39,7 @@ var (
|
||||
dashboard = "/dashboard"
|
||||
metrics = "/metrics"
|
||||
profiling = "/profiling"
|
||||
addBucket = "/add-bucket"
|
||||
buckets = "/buckets"
|
||||
bucketsGeneral = "/buckets/*"
|
||||
bucketsAdmin = "/buckets/:bucketName/admin/*"
|
||||
@@ -335,6 +336,7 @@ var endpointRules = map[string]ConfigurationActionSet{
|
||||
dashboard: dashboardActionSet,
|
||||
metrics: dashboardActionSet,
|
||||
profiling: profilingActionSet,
|
||||
addBucket: bucketsActionSet,
|
||||
buckets: bucketsActionSet,
|
||||
bucketsGeneral: bucketsActionSet,
|
||||
bucketsAdmin: bucketsActionSet,
|
||||
|
||||
@@ -79,7 +79,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
|
||||
"s3:*",
|
||||
},
|
||||
},
|
||||
want: 9,
|
||||
want: 10,
|
||||
},
|
||||
{
|
||||
name: "all admin and s3 endpoints",
|
||||
@@ -89,7 +89,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
|
||||
"s3:*",
|
||||
},
|
||||
},
|
||||
want: 36,
|
||||
want: 37,
|
||||
},
|
||||
{
|
||||
name: "Console User - default endpoints",
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import React from "react";
|
||||
import history from "../../../history";
|
||||
import { Route, Router, Switch, withRouter, Redirect } from "react-router-dom";
|
||||
import { Redirect, Route, Router, Switch, withRouter } from "react-router-dom";
|
||||
import { connect } from "react-redux";
|
||||
import { AppState } from "../../../store";
|
||||
import { setMenuOpen } from "../../../actions";
|
||||
@@ -24,6 +24,7 @@ import NotFoundPage from "../../NotFoundPage";
|
||||
import ListBuckets from "./ListBuckets/ListBuckets";
|
||||
import BucketDetails from "./BucketDetails/BucketDetails";
|
||||
import BrowserHandler from "./BucketDetails/BrowserHandler";
|
||||
import AddBucket from "./ListBuckets/AddBucket";
|
||||
|
||||
const mapState = (state: AppState) => ({
|
||||
open: state.system.sidebarOpen,
|
||||
@@ -35,6 +36,7 @@ const Buckets = () => {
|
||||
return (
|
||||
<Router history={history}>
|
||||
<Switch>
|
||||
<Route path="/add-bucket" component={AddBucket} />
|
||||
<Route path="/buckets/:bucketName/admin/*" component={BucketDetails} />
|
||||
<Route path="/buckets/:bucketName/admin" component={BucketDetails} />
|
||||
<Route
|
||||
|
||||
@@ -16,23 +16,18 @@
|
||||
|
||||
import React, { Fragment, useEffect, useState } from "react";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import {
|
||||
Button,
|
||||
LinearProgress,
|
||||
SelectChangeEvent,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { Button, LinearProgress, SelectChangeEvent } 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 { containerForHeader } 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";
|
||||
import RadioGroupSelector from "../../Common/FormComponents/RadioGroupSelector/RadioGroupSelector";
|
||||
import { factorForDropdown, getBytes } from "../../../../common/utils";
|
||||
import { AppState } from "../../../../store";
|
||||
import history from "../../../../history";
|
||||
import { connect } from "react-redux";
|
||||
import {
|
||||
addBucketEnableObjectLocking,
|
||||
@@ -50,13 +45,20 @@ import {
|
||||
import { useDebounce } from "use-debounce";
|
||||
import { MakeBucketRequest } from "../types";
|
||||
import FormSwitchWrapper from "../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
|
||||
import { setModalErrorSnackMessage } from "../../../../actions";
|
||||
import { ErrorResponseHandler } from "../../../../common/types";
|
||||
import PageHeader from "../../Common/PageHeader/PageHeader";
|
||||
import BackLink from "../../../../common/BackLink";
|
||||
import { BucketsIcon } from "../../../../icons";
|
||||
import { setErrorSnackMessage } from "../../../../actions";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
buttonContainer: {
|
||||
marginTop: 24,
|
||||
textAlign: "right",
|
||||
"& .MuiButton-root": {
|
||||
marginLeft: 8,
|
||||
},
|
||||
},
|
||||
multiContainer: {
|
||||
display: "flex",
|
||||
@@ -78,13 +80,26 @@ const styles = (theme: Theme) =>
|
||||
padding: 8,
|
||||
borderRadius: 3,
|
||||
},
|
||||
...modalBasic,
|
||||
title: {
|
||||
marginBottom: 8,
|
||||
},
|
||||
headTitle: {
|
||||
fontWeight: "bold",
|
||||
fontSize: 16,
|
||||
paddingLeft: 8,
|
||||
},
|
||||
h6title: {
|
||||
fontWeight: "bold",
|
||||
color: "#000000",
|
||||
fontSize: 20,
|
||||
paddingBottom: 8,
|
||||
},
|
||||
...containerForHeader(theme.spacing(4)),
|
||||
});
|
||||
|
||||
interface IAddBucketProps {
|
||||
classes: any;
|
||||
open: boolean;
|
||||
closeModalAndRefresh: (refresh: boolean) => void;
|
||||
addBucketName: typeof addBucketName;
|
||||
addBucketVersioned: typeof addBucketVersioning;
|
||||
enableObjectLocking: typeof addBucketEnableObjectLocking;
|
||||
@@ -96,7 +111,7 @@ interface IAddBucketProps {
|
||||
addBucketRetentionMode: typeof addBucketRetentionMode;
|
||||
addBucketRetentionUnit: typeof addBucketRetentionUnit;
|
||||
addBucketRetentionValidity: typeof addBucketRetentionValidity;
|
||||
setModalError: typeof setModalErrorSnackMessage;
|
||||
setErrorSnackMessage: typeof setErrorSnackMessage;
|
||||
bucketName: string;
|
||||
versioningEnabled: boolean;
|
||||
lockingEnabled: boolean;
|
||||
@@ -113,8 +128,6 @@ interface IAddBucketProps {
|
||||
|
||||
const AddBucket = ({
|
||||
classes,
|
||||
open,
|
||||
closeModalAndRefresh,
|
||||
addBucketName,
|
||||
addBucketVersioned,
|
||||
enableObjectLocking,
|
||||
@@ -126,7 +139,7 @@ const AddBucket = ({
|
||||
addBucketRetentionMode,
|
||||
addBucketRetentionUnit,
|
||||
addBucketRetentionValidity,
|
||||
setModalError,
|
||||
setErrorSnackMessage,
|
||||
bucketName,
|
||||
versioningEnabled,
|
||||
lockingEnabled,
|
||||
@@ -181,14 +194,14 @@ const AddBucket = ({
|
||||
.invoke("POST", "/api/v1/buckets", request)
|
||||
.then((res) => {
|
||||
setAddLoading(false);
|
||||
closeModalAndRefresh(true);
|
||||
const newBucketName = `${bucketName}`;
|
||||
resetForm();
|
||||
history.push(`/buckets/${newBucketName}/browse`);
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
setAddLoading(false);
|
||||
setModalError(err);
|
||||
setErrorSnackMessage(err);
|
||||
});
|
||||
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const [value] = useDebounce(bucketName, 1000);
|
||||
@@ -265,251 +278,267 @@ const AddBucket = ({
|
||||
]);
|
||||
|
||||
return (
|
||||
<ModalWrapper
|
||||
title="Create Bucket"
|
||||
modalOpen={open}
|
||||
onClose={() => {
|
||||
closeModalAndRefresh(false);
|
||||
}}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<form
|
||||
noValidate
|
||||
autoComplete="off"
|
||||
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
|
||||
addRecord(e);
|
||||
}}
|
||||
>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.formScrollable}>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="bucket-name"
|
||||
name="bucket-name"
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
addBucketName(event.target.value);
|
||||
}}
|
||||
label="Bucket Name"
|
||||
value={bucketName}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Typography component="h6" variant="h6">
|
||||
Features
|
||||
</Typography>
|
||||
<br />
|
||||
{!distributedSetup && (
|
||||
<Fragment>
|
||||
<div className={classes.error}>
|
||||
These features are unavailable in a single-disk setup.
|
||||
<br />
|
||||
Please deploy a server in{" "}
|
||||
<a
|
||||
href="https://docs.min.io/minio/baremetal/installation/deploy-minio-distributed.html?ref=con"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Distributed Mode
|
||||
</a>{" "}
|
||||
to use these features.
|
||||
</div>
|
||||
<br />
|
||||
<br />
|
||||
</Fragment>
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<FormSwitchWrapper
|
||||
value="versioned"
|
||||
id="versioned"
|
||||
name="versioned"
|
||||
checked={versioningEnabled}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
addBucketVersioned(event.target.checked);
|
||||
}}
|
||||
description={
|
||||
"Allows to keep multiple versions of the same object under the same key."
|
||||
}
|
||||
label={"Versioning"}
|
||||
disabled={!distributedSetup}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<FormSwitchWrapper
|
||||
value="locking"
|
||||
id="locking"
|
||||
name="locking"
|
||||
disabled={lockingFieldDisabled || !distributedSetup}
|
||||
checked={lockingEnabled}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
enableObjectLocking(event.target.checked);
|
||||
}}
|
||||
label={"Object Locking"}
|
||||
description={
|
||||
"Required to support retention and legal hold. Can only be enabled at bucket creation."
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<FormSwitchWrapper
|
||||
value="bucket_quota"
|
||||
id="bucket_quota"
|
||||
name="bucket_quota"
|
||||
checked={quotaEnabled}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
addBucketQuota(event.target.checked);
|
||||
}}
|
||||
label={"Quota"}
|
||||
description={"Limit the amount of data in the bucket."}
|
||||
disabled={!distributedSetup}
|
||||
/>
|
||||
</Grid>
|
||||
{quotaEnabled && distributedSetup && (
|
||||
<React.Fragment>
|
||||
<Fragment>
|
||||
<PageHeader label={"Create a Bucket"} />
|
||||
<Grid container className={classes.container}>
|
||||
<Grid item xs={12}>
|
||||
<BackLink to="/buckets" label="Return to Buckets" />
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.boxy}>
|
||||
<form
|
||||
noValidate
|
||||
autoComplete="off"
|
||||
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
|
||||
addRecord(e);
|
||||
}}
|
||||
>
|
||||
<Grid container>
|
||||
<Grid item xs={12} container className={classes.title}>
|
||||
<Grid item xs={"auto"}>
|
||||
<BucketsIcon />
|
||||
</Grid>
|
||||
<Grid item xs className={classes.headTitle}>
|
||||
Create Bucket
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12} container>
|
||||
<Grid item xs={12}>
|
||||
<RadioGroupSelector
|
||||
currentSelection={quotaType}
|
||||
id="quota_type"
|
||||
name="quota_type"
|
||||
label="Quota Type"
|
||||
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
|
||||
addBucketQuotaType(e.target.value as string);
|
||||
<InputBoxWrapper
|
||||
id="bucket-name"
|
||||
name="bucket-name"
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
addBucketName(event.target.value);
|
||||
}}
|
||||
selectorOptions={[
|
||||
{ value: "hard", label: "Hard" },
|
||||
{ value: "fifo", label: "FIFO" },
|
||||
]}
|
||||
label="Bucket Name"
|
||||
value={bucketName}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid container>
|
||||
<Grid item xs={10}>
|
||||
<div className={classes.h6title}>Features</div>
|
||||
<br />
|
||||
{!distributedSetup && (
|
||||
<Fragment>
|
||||
<div className={classes.error}>
|
||||
These features are unavailable in a single-disk setup.
|
||||
<br />
|
||||
Please deploy a server in{" "}
|
||||
<a
|
||||
href="https://docs.min.io/minio/baremetal/installation/deploy-minio-distributed.html?ref=con"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Distributed Mode
|
||||
</a>{" "}
|
||||
to use these features.
|
||||
</div>
|
||||
<br />
|
||||
<br />
|
||||
</Fragment>
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<FormSwitchWrapper
|
||||
value="versioned"
|
||||
id="versioned"
|
||||
name="versioned"
|
||||
checked={versioningEnabled}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
addBucketVersioned(event.target.checked);
|
||||
}}
|
||||
description={
|
||||
"Allows to keep multiple versions of the same object under the same key."
|
||||
}
|
||||
label={"Versioning"}
|
||||
disabled={!distributedSetup}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<FormSwitchWrapper
|
||||
value="locking"
|
||||
id="locking"
|
||||
name="locking"
|
||||
disabled={lockingFieldDisabled || !distributedSetup}
|
||||
checked={lockingEnabled}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
enableObjectLocking(event.target.checked);
|
||||
}}
|
||||
label={"Object Locking"}
|
||||
description={
|
||||
"Required to support retention and legal hold. Can only be enabled at bucket creation."
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<FormSwitchWrapper
|
||||
value="bucket_quota"
|
||||
id="bucket_quota"
|
||||
name="bucket_quota"
|
||||
checked={quotaEnabled}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
addBucketQuota(event.target.checked);
|
||||
}}
|
||||
label={"Quota"}
|
||||
description={"Limit the amount of data in the bucket."}
|
||||
disabled={!distributedSetup}
|
||||
/>
|
||||
</Grid>
|
||||
{quotaEnabled && distributedSetup && (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12}>
|
||||
<RadioGroupSelector
|
||||
currentSelection={quotaType}
|
||||
id="quota_type"
|
||||
name="quota_type"
|
||||
label="Quota Type"
|
||||
onChange={(
|
||||
e: React.ChangeEvent<{ value: unknown }>
|
||||
) => {
|
||||
addBucketQuotaType(e.target.value as string);
|
||||
}}
|
||||
selectorOptions={[
|
||||
{ value: "hard", label: "Hard" },
|
||||
{ value: "fifo", label: "FIFO" },
|
||||
]}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid container>
|
||||
<Grid item xs={10}>
|
||||
<InputBoxWrapper
|
||||
type="number"
|
||||
id="quota_size"
|
||||
name="quota_size"
|
||||
onChange={(
|
||||
e: React.ChangeEvent<HTMLInputElement>
|
||||
) => {
|
||||
addBucketQuotaSize(e.target.value);
|
||||
}}
|
||||
label="Quota"
|
||||
value={quotaSize}
|
||||
required
|
||||
min="1"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={2}>
|
||||
<div style={{ width: 100 }}>
|
||||
<SelectWrapper
|
||||
label=""
|
||||
id="quota_unit"
|
||||
name="quota_unit"
|
||||
value={quotaUnit}
|
||||
onChange={(e: SelectChangeEvent<string>) => {
|
||||
addBucketQuotaUnit(e.target.value as string);
|
||||
}}
|
||||
options={factorForDropdown()}
|
||||
/>
|
||||
</div>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
)}
|
||||
{versioningEnabled && distributedSetup && (
|
||||
<Grid item xs={12}>
|
||||
<FormSwitchWrapper
|
||||
value="bucket_retention"
|
||||
id="bucket_retention"
|
||||
name="bucket_retention"
|
||||
checked={retentionEnabled}
|
||||
onChange={(
|
||||
event: React.ChangeEvent<HTMLInputElement>
|
||||
) => {
|
||||
addBucketRetention(event.target.checked);
|
||||
}}
|
||||
label={"Retention"}
|
||||
description={
|
||||
"Impose rules to prevent object deletion for a period of time."
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
{retentionEnabled && distributedSetup && (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12}>
|
||||
<RadioGroupSelector
|
||||
currentSelection={retentionMode}
|
||||
id="retention_mode"
|
||||
name="retention_mode"
|
||||
label="Retention Mode"
|
||||
onChange={(
|
||||
e: React.ChangeEvent<{ value: unknown }>
|
||||
) => {
|
||||
addBucketRetentionMode(e.target.value as string);
|
||||
}}
|
||||
selectorOptions={[
|
||||
{ value: "compliance", label: "Compliance" },
|
||||
{ value: "governance", label: "Governance" },
|
||||
]}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<RadioGroupSelector
|
||||
currentSelection={retentionUnit}
|
||||
id="retention_unit"
|
||||
name="retention_unit"
|
||||
label="Retention Unit"
|
||||
onChange={(
|
||||
e: React.ChangeEvent<{ value: unknown }>
|
||||
) => {
|
||||
addBucketRetentionUnit(e.target.value as string);
|
||||
}}
|
||||
selectorOptions={[
|
||||
{ value: "days", label: "Days" },
|
||||
{ value: "years", label: "Years" },
|
||||
]}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
type="number"
|
||||
id="quota_size"
|
||||
name="quota_size"
|
||||
id="retention_validity"
|
||||
name="retention_validity"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
addBucketQuotaSize(e.target.value);
|
||||
addBucketRetentionValidity(e.target.valueAsNumber);
|
||||
}}
|
||||
label="Quota"
|
||||
value={quotaSize}
|
||||
label="Retention Validity"
|
||||
value={String(retentionValidity)}
|
||||
required
|
||||
min="1"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={2}>
|
||||
<div style={{ width: 100 }}>
|
||||
<SelectWrapper
|
||||
label=""
|
||||
id="quota_unit"
|
||||
name="quota_unit"
|
||||
value={quotaUnit}
|
||||
onChange={(e: SelectChangeEvent<string>) => {
|
||||
addBucketQuotaUnit(e.target.value as string);
|
||||
}}
|
||||
options={factorForDropdown()}
|
||||
/>
|
||||
</div>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
)}
|
||||
{versioningEnabled && distributedSetup && (
|
||||
<Grid item xs={12}>
|
||||
<FormSwitchWrapper
|
||||
value="bucket_retention"
|
||||
id="bucket_retention"
|
||||
name="bucket_retention"
|
||||
checked={retentionEnabled}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
addBucketRetention(event.target.checked);
|
||||
}}
|
||||
label={"Retention"}
|
||||
description={
|
||||
"Impose rules to prevent object deletion for a period of time."
|
||||
}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</Grid>
|
||||
)}
|
||||
{retentionEnabled && distributedSetup && (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12} className={classes.buttonContainer}>
|
||||
<Button
|
||||
type="button"
|
||||
variant={"outlined"}
|
||||
className={classes.clearButton}
|
||||
onClick={resetForm}
|
||||
>
|
||||
Clear
|
||||
</Button>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={addLoading || !sendEnabled}
|
||||
>
|
||||
Create Bucket
|
||||
</Button>
|
||||
</Grid>
|
||||
{addLoading && (
|
||||
<Grid item xs={12}>
|
||||
<RadioGroupSelector
|
||||
currentSelection={retentionMode}
|
||||
id="retention_mode"
|
||||
name="retention_mode"
|
||||
label="Retention Mode"
|
||||
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
|
||||
addBucketRetentionMode(e.target.value as string);
|
||||
}}
|
||||
selectorOptions={[
|
||||
{ value: "compliance", label: "Compliance" },
|
||||
{ value: "governance", label: "Governance" },
|
||||
]}
|
||||
/>
|
||||
<LinearProgress />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<RadioGroupSelector
|
||||
currentSelection={retentionUnit}
|
||||
id="retention_unit"
|
||||
name="retention_unit"
|
||||
label="Retention Unit"
|
||||
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
|
||||
addBucketRetentionUnit(e.target.value as string);
|
||||
}}
|
||||
selectorOptions={[
|
||||
{ value: "days", label: "Days" },
|
||||
{ value: "years", label: "Years" },
|
||||
]}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
type="number"
|
||||
id="retention_validity"
|
||||
name="retention_validity"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
addBucketRetentionValidity(e.target.valueAsNumber);
|
||||
}}
|
||||
label="Retention Validity"
|
||||
value={String(retentionValidity)}
|
||||
required
|
||||
min="1"
|
||||
/>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.buttonContainer}>
|
||||
<button
|
||||
type="button"
|
||||
color="primary"
|
||||
className={classes.clearButton}
|
||||
onClick={resetForm}
|
||||
>
|
||||
Clear
|
||||
</button>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={addLoading || !sendEnabled}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</Grid>
|
||||
{addLoading && (
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
)}
|
||||
</Grid>
|
||||
)}
|
||||
</form>
|
||||
</Grid>
|
||||
</form>
|
||||
</ModalWrapper>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -541,7 +570,7 @@ const connector = connect(mapState, {
|
||||
addBucketRetentionMode: addBucketRetentionMode,
|
||||
addBucketRetentionUnit: addBucketRetentionUnit,
|
||||
addBucketRetentionValidity: addBucketRetentionValidity,
|
||||
setModalError: setModalErrorSnackMessage,
|
||||
setErrorSnackMessage: setErrorSnackMessage,
|
||||
});
|
||||
|
||||
export default connector(withStyles(styles)(AddBucket));
|
||||
|
||||
@@ -25,7 +25,6 @@ import FileCopyIcon from "@mui/icons-material/FileCopy";
|
||||
import { Bucket, BucketList, HasPermissionResponse } from "../types";
|
||||
import { AddIcon, BucketsIcon, WatchIcon } from "../../../../icons";
|
||||
import { AppState } from "../../../../store";
|
||||
import { addBucketOpen, addBucketReset } from "../actions";
|
||||
import { setErrorSnackMessage } from "../../../../actions";
|
||||
import {
|
||||
containerForHeader,
|
||||
@@ -33,7 +32,6 @@ import {
|
||||
} from "../../Common/FormComponents/common/styleLibrary";
|
||||
import { ErrorResponseHandler } from "../../../../common/types";
|
||||
import api from "../../../../common/api";
|
||||
import AddBucket from "./AddBucket";
|
||||
import DeleteBucket from "./DeleteBucket";
|
||||
import PageHeader from "../../Common/PageHeader/PageHeader";
|
||||
import BucketListItem from "./BucketListItem";
|
||||
@@ -136,9 +134,6 @@ const styles = (theme: Theme) =>
|
||||
interface IListBucketsProps {
|
||||
classes: any;
|
||||
history: any;
|
||||
addBucketOpen: typeof addBucketOpen;
|
||||
addBucketModalOpen: boolean;
|
||||
addBucketReset: typeof addBucketReset;
|
||||
setErrorSnackMessage: typeof setErrorSnackMessage;
|
||||
session: ISessionResponse;
|
||||
}
|
||||
@@ -146,9 +141,6 @@ interface IListBucketsProps {
|
||||
const ListBuckets = ({
|
||||
classes,
|
||||
history,
|
||||
addBucketOpen,
|
||||
addBucketModalOpen,
|
||||
addBucketReset,
|
||||
setErrorSnackMessage,
|
||||
session,
|
||||
}: IListBucketsProps) => {
|
||||
@@ -219,16 +211,6 @@ const ListBuckets = ({
|
||||
}
|
||||
}, [loading, setErrorSnackMessage]);
|
||||
|
||||
const closeAddModalAndRefresh = (refresh: boolean) => {
|
||||
addBucketOpen(false);
|
||||
addBucketReset();
|
||||
|
||||
if (refresh) {
|
||||
setLoading(true);
|
||||
setSelectedBuckets([]);
|
||||
}
|
||||
};
|
||||
|
||||
const closeDeleteModalAndRefresh = (refresh: boolean) => {
|
||||
setDeleteOpen(false);
|
||||
if (refresh) {
|
||||
@@ -283,12 +265,6 @@ const ListBuckets = ({
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{addBucketModalOpen && (
|
||||
<AddBucket
|
||||
open={addBucketModalOpen}
|
||||
closeModalAndRefresh={closeAddModalAndRefresh}
|
||||
/>
|
||||
)}
|
||||
{deleteOpen && (
|
||||
<DeleteBucket
|
||||
deleteOpen={deleteOpen}
|
||||
@@ -369,7 +345,7 @@ const ListBuckets = ({
|
||||
color="primary"
|
||||
endIcon={<AddIcon />}
|
||||
onClick={() => {
|
||||
addBucketOpen(true);
|
||||
history.push("/add-bucket");
|
||||
}}
|
||||
className={classes.addBucket}
|
||||
>
|
||||
@@ -439,7 +415,7 @@ const ListBuckets = ({
|
||||
To get started,
|
||||
<AButton
|
||||
onClick={() => {
|
||||
addBucketOpen(true);
|
||||
history.push("/add-bucket");
|
||||
}}
|
||||
>
|
||||
Create a Bucket.
|
||||
@@ -459,13 +435,10 @@ const ListBuckets = ({
|
||||
};
|
||||
|
||||
const mapState = (state: AppState) => ({
|
||||
addBucketModalOpen: state.buckets.open,
|
||||
session: state.console.session,
|
||||
});
|
||||
|
||||
const connector = connect(mapState, {
|
||||
addBucketOpen,
|
||||
addBucketReset,
|
||||
setErrorSnackMessage,
|
||||
});
|
||||
|
||||
|
||||
@@ -104,7 +104,6 @@ const styles = (theme: Theme) =>
|
||||
},
|
||||
divContainer: {
|
||||
marginBottom: 20,
|
||||
maxWidth: 840,
|
||||
},
|
||||
indicatorLabelOn: {
|
||||
fontWeight: "bold",
|
||||
@@ -227,31 +226,36 @@ const FormSwitchWrapper = ({
|
||||
<div className={classes.divContainer}>
|
||||
<Grid container alignItems={"center"}>
|
||||
<Grid item xs>
|
||||
{label !== "" && (
|
||||
<InputLabel htmlFor={id} className={classes.inputLabel}>
|
||||
<span>{label}</span>
|
||||
{tooltip !== "" && (
|
||||
<div className={classes.tooltipContainer}>
|
||||
<Tooltip title={tooltip} placement="top-start">
|
||||
<div>
|
||||
<HelpIcon className={classes.tooltip} />
|
||||
<Grid container>
|
||||
<Grid item xs={12} sm={4} md={3}>
|
||||
{label !== "" && (
|
||||
<InputLabel htmlFor={id} className={classes.inputLabel}>
|
||||
<span>{label}</span>
|
||||
{tooltip !== "" && (
|
||||
<div className={classes.tooltipContainer}>
|
||||
<Tooltip title={tooltip} placement="top-start">
|
||||
<div>
|
||||
<HelpIcon className={classes.tooltip} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
</InputLabel>
|
||||
)}
|
||||
</InputLabel>
|
||||
)}
|
||||
</Grid>
|
||||
<Grid item xs={12} sm textAlign={"left"}>
|
||||
{description !== "" && (
|
||||
<Typography component="p" className={classes.fieldDescription}>
|
||||
{description}
|
||||
</Typography>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs textAlign={"right"}>
|
||||
|
||||
<Grid item xs={12} sm={2} textAlign={"right"}>
|
||||
{switchComponent}
|
||||
</Grid>
|
||||
{description !== "" && (
|
||||
<Grid item xs={12}>
|
||||
<Typography component="p" className={classes.fieldDescription}>
|
||||
{description}
|
||||
</Typography>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -146,11 +146,8 @@ const InputBoxWrapper = ({
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
className={`${classes.fieldContainer} ${
|
||||
error !== "" ? classes.errorInField : ""
|
||||
}`}
|
||||
container
|
||||
className={` ${error !== "" ? classes.errorInField : ""}`}
|
||||
>
|
||||
{label !== "" && (
|
||||
<InputLabel
|
||||
|
||||
@@ -184,6 +184,12 @@ export const containerForHeader = (bottomSpacing: any) => ({
|
||||
topSpacer: {
|
||||
height: "8px",
|
||||
},
|
||||
boxy: {
|
||||
border: "#E5E5E5 1px solid",
|
||||
borderRadius: 2,
|
||||
padding: 40,
|
||||
backgroundColor: "#fff",
|
||||
},
|
||||
});
|
||||
|
||||
export const actionsTray = {
|
||||
|
||||
@@ -239,6 +239,10 @@ const Console = ({
|
||||
component: Metrics,
|
||||
path: "/metrics",
|
||||
},
|
||||
{
|
||||
component: Buckets,
|
||||
path: "/add-bucket",
|
||||
},
|
||||
{
|
||||
component: Buckets,
|
||||
path: "/buckets",
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
//
|
||||
// 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, { Fragment, useState, useEffect } from "react";
|
||||
import React, { Fragment, useEffect, useState } from "react";
|
||||
import {
|
||||
ICloseEvent,
|
||||
IMessageEvent,
|
||||
@@ -68,12 +68,6 @@ const styles = (theme: Theme) =>
|
||||
justifyContent: "flex-start",
|
||||
gap: 20,
|
||||
},
|
||||
boxy: {
|
||||
border: "#E5E5E5 1px solid",
|
||||
borderRadius: 2,
|
||||
padding: 40,
|
||||
backgroundColor: "#fff",
|
||||
},
|
||||
localMessage: {
|
||||
fontSize: 24,
|
||||
color: "#07193E",
|
||||
|
||||
@@ -42,12 +42,6 @@ interface ISpeedtest {
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
boxy: {
|
||||
border: "#E5E5E5 1px solid",
|
||||
borderRadius: 2,
|
||||
padding: 40,
|
||||
backgroundColor: "#fff",
|
||||
},
|
||||
advancedConfiguration: {
|
||||
color: "#2781B0",
|
||||
fontSize: 10,
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/minio/minio-go/v7"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/minio/console/models"
|
||||
"github.com/minio/madmin-go"
|
||||
@@ -171,6 +173,11 @@ func prepareError(err ...error) *models.Error {
|
||||
errorCode = 403
|
||||
errorMessage = err[0].Error()
|
||||
}
|
||||
// bucket already exists
|
||||
if minio.ToErrorResponse(err[0]).Code == "BucketAlreadyOwnedByYou" {
|
||||
errorCode = 400
|
||||
errorMessage = "Bucket already exists"
|
||||
}
|
||||
}
|
||||
return &models.Error{Code: errorCode, Message: swag.String(errorMessage), DetailedMessage: swag.String(err[0].Error())}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user