Service account ux (#1229)

Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
This commit is contained in:
Prakash Senthil Vel
2021-11-16 02:22:55 +05:30
committed by GitHub
parent 373bfbfe3f
commit 70a4d76283
9 changed files with 560 additions and 265 deletions

View File

@@ -0,0 +1,81 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 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 <http://www.gnu.org/licenses/>.
import React from "react";
import { SvgIcon } from "@mui/material";
const NewAccountIcon = () => {
return (
<SvgIcon>
<svg
id="Account_Icon"
data-name="Account Icon"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16.409 13.096"
>
<path
id="Trazado_391"
data-name="Trazado 391"
d="M-4332.855-1143.481a3.023,3.023,0,0,0,2.958-3.078,3.023,3.023,0,0,0-2.958-3.078,3.023,3.023,0,0,0-2.958,3.078A3.023,3.023,0,0,0-4332.855-1143.481Zm0-5.194a2.078,2.078,0,0,1,2.03,2.116,2.077,2.077,0,0,1-2.03,2.116,2.075,2.075,0,0,1-2.028-2.116A2.076,2.076,0,0,1-4332.855-1148.675Z"
transform="translate(4339.12 1149.637)"
fill="#07193e"
/>
<path
id="Trazado_392"
data-name="Trazado 392"
d="M-4337.952-1130.053a1.374,1.374,0,0,0,1.252.775h4.993a1.354,1.354,0,0,0,1.25-.786,1.675,1.675,0,0,0-.164-1.686,4.521,4.521,0,0,0-1.7-1.405,4.361,4.361,0,0,0-2.125-.438,4.483,4.483,0,0,0-3.318,1.808c-.026.035-.051.071-.075.106A1.641,1.641,0,0,0-4337.952-1130.053Zm6.663-.437a.426.426,0,0,1-.417.25h-4.993a.453.453,0,0,1-.427-.254.64.64,0,0,1,.053-.632h0c.017-.027.037-.054.057-.08a3.539,3.539,0,0,1,2.622-1.424c.056,0,.113,0,.168,0a3.606,3.606,0,0,1,2.864,1.466A.686.686,0,0,1-4331.29-1130.49Z"
transform="translate(4340.467 1140.236)"
fill="#07193e"
/>
<path
id="Trazado_393"
data-name="Trazado 393"
d="M-4329.387-1146.951h-3.506a.476.476,0,0,0-.477.476.477.477,0,0,0,.477.476h3.506a1.047,1.047,0,0,1,1.046,1.045v7.99a1.047,1.047,0,0,1-1.046,1.045H-4341.8a1.047,1.047,0,0,1-1.046-1.045v-7.99A1.048,1.048,0,0,1-4341.8-1146a.476.476,0,0,0,.476-.476.476.476,0,0,0-.476-.476,2,2,0,0,0-2,2v7.99a2,2,0,0,0,2,2h12.412a2,2,0,0,0,2-2v-7.99A2,2,0,0,0-4329.387-1146.951Z"
transform="translate(4343.797 1148.063)"
fill="#07193e"
/>
<rect
id="Rectángulo_809"
data-name="Rectángulo 809"
width="3.266"
height="2.781"
rx="1.024"
transform="translate(11.002 3.376)"
fill="#07193e"
/>
<rect
id="Rectángulo_810"
data-name="Rectángulo 810"
width="3.266"
height="1.336"
rx="0.668"
transform="translate(11.002 7.328)"
fill="#07193e"
/>
<rect
id="Rectángulo_811"
data-name="Rectángulo 811"
width="3.266"
height="1.336"
rx="0.668"
transform="translate(11.002 9.621)"
fill="#07193e"
/>
</svg>
</SvgIcon>
);
};
export default NewAccountIcon;

View File

@@ -0,0 +1,35 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 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 <http://www.gnu.org/licenses/>.
import * as React from "react";
const WarnIcon = () => {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
<circle
cx="8"
cy="8"
r="7"
fill="none"
stroke="#e04006"
stroke-width="2"
/>
<path fill="none" stroke="#e04006" stroke-width="2" d="M8 4v6m0 1v2" />
</svg>
);
};
export default WarnIcon;

View File

@@ -21,7 +21,10 @@ import { Button, LinearProgress } 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 {
modalBasic,
serviceAccountStyles,
} from "../Common/FormComponents/common/styleLibrary";
import { NewServiceAccount } from "../Common/CredentialsPrompt/types";
import { setModalErrorSnackMessage } from "../../../actions";
import { ErrorResponseHandler } from "../../../common/types";
@@ -33,26 +36,7 @@ import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWr
const styles = (theme: Theme) =>
createStyles({
jsonPolicyEditor: {
minHeight: 400,
width: "100%",
},
buttonContainer: {
textAlign: "right",
},
infoDetails: {
color: "#393939",
fontSize: 12,
fontStyle: "italic",
marginBottom: "8px",
},
containerScrollable: {
maxHeight: "calc(100vh - 300px)" as const,
overflowY: "auto" as const,
},
codeMirrorContainer: {
marginBottom: 20,
},
...serviceAccountStyles,
...modalBasic,
});
@@ -157,72 +141,82 @@ const AddServiceAccount = ({
</div>
</Grid>
<Grid item xs={12}>
<FormSwitchWrapper
value="locking"
id="locking"
name="locking"
checked={isRestrictedByPolicy}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
setIsRestrictedByPolicy(event.target.checked);
}}
label={"Restrict with policy"}
/>
<FormSwitchWrapper
value="locking"
id="locking"
name="locking"
checked={addCredentials}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
setAddCredentials(event.target.checked);
}}
label={"Customize Credentials"}
/>
</Grid>
{isRestrictedByPolicy && (
<Grid item xs={12} className={classes.codeMirrorContainer}>
<CodeMirrorWrapper
value={policyDefinition}
onBeforeChange={(editor, data, value) => {
setPolicyDefinition(value);
}}
/>
</Grid>
)}
{addCredentials && (
<Grid item xs={12}>
<InputBoxWrapper
value={accessKey}
label={"Access Key"}
id={"accessKey"}
name={"accessKey"}
placeholder={"Enter Access Key"}
onChange={(e) => {
setAccessKey(e.target.value);
}}
/>
<InputBoxWrapper
value={secretKey}
label={"Secret Key"}
id={"secretKey"}
name={"secretKey"}
placeholder={"Enter Secret Key"}
onChange={(e) => {
setSecretKey(e.target.value);
<FormSwitchWrapper
value="locking"
classes={classes}
id="locking"
name="locking"
checked={addCredentials}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
setAddCredentials(event.target.checked);
}}
label={"Customize Credentials"}
/>
{addCredentials && (
<Grid item xs={12}>
<div className={classes.stackedInputs}>
<InputBoxWrapper
value={accessKey}
label={"Access Key"}
id={"accessKey"}
name={"accessKey"}
placeholder={"Enter Access Key"}
onChange={(e) => {
setAccessKey(e.target.value);
}}
/>
<InputBoxWrapper
value={secretKey}
label={"Secret Key"}
id={"secretKey"}
name={"secretKey"}
placeholder={"Enter Secret Key"}
onChange={(e) => {
setSecretKey(e.target.value);
}}
/>
</div>
</Grid>
)}
</Grid>
)}
<Grid item xs={12}>
<FormSwitchWrapper
value="locking"
id="locking"
name="locking"
classes={classes}
checked={isRestrictedByPolicy}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
setIsRestrictedByPolicy(event.target.checked);
}}
label={"Restrict with policy"}
/>
{isRestrictedByPolicy && (
<Grid item xs={12} className={classes.codeMirrorContainer}>
<CodeMirrorWrapper
label={"Policy "}
value={policyDefinition}
onBeforeChange={(editor, data, value) => {
setPolicyDefinition(value);
}}
/>
</Grid>
)}
</Grid>
</Grid>
</Grid>
<Grid container>
<Grid item xs={12} className={classes.buttonContainer}>
<button
<Button
type="button"
color="primary"
className={classes.clearButton}
variant="outlined"
className={classes.buttonSpacer}
onClick={resetForm}
>
Clear
</button>
</Button>
<Button
type="submit"
variant="contained"

View File

@@ -0,0 +1,94 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 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 <http://www.gnu.org/licenses/>.
import React from "react";
import { InputAdornment, OutlinedInput } from "@mui/material";
import BoxIconButton from "../BoxIconButton/BoxIconButton";
import withStyles from "@mui/styles/withStyles";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import CopyToClipboard from "react-copy-to-clipboard";
import { CopyIcon } from "../../../../icons";
const styles = (theme: Theme) =>
createStyles({
container: {
display: "flex",
flexFlow: "column",
padding: "20px 0 8px 0",
},
inputWithCopy: {
"& .MuiInputBase-root ": {
width: "100%",
background: "#FBFAFA",
"& .MuiInputBase-input": {
height: ".8rem",
},
"& .MuiInputAdornment-positionEnd": {
marginRight: ".5rem",
"& .MuiButtonBase-root": {
height: "2rem",
},
},
},
"& .MuiButtonBase-root .MuiSvgIcon-root": {
fontSize: ".8rem",
},
},
inputLabel: {
fontSize: ".8rem",
fontWeight: 600,
},
});
const CredentialItem = ({
label = "",
value = "",
classes = {},
}: {
label: string;
value: string;
classes: any;
}) => {
return (
<div className={classes.container}>
<div className={classes.inputLabel}>{label}:</div>
<div className={classes.inputWithCopy}>
<OutlinedInput
value={value}
readOnly
endAdornment={
<InputAdornment position="end">
<CopyToClipboard text={value}>
<BoxIconButton
aria-label="copy"
tooltip={"Copy"}
onClick={() => {}}
onMouseDown={() => {}}
edge="end"
>
<CopyIcon />
</BoxIconButton>
</CopyToClipboard>
</InputAdornment>
}
/>
</div>
</div>
);
};
export default withStyles(styles)(CredentialItem);

View File

@@ -21,22 +21,52 @@ import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import { NewServiceAccount } from "./types";
import { Button } from "@mui/material";
import Typography from "@mui/material/Typography";
import ModalWrapper from "../ModalWrapper/ModalWrapper";
import Grid from "@mui/material/Grid";
import CredentialItem from "./CredentialItem";
import NewAccountIcon from "../../../../icons/NewAccountIcon";
import WarnIcon from "../../../../icons/WarnIcon";
import { DownloadIcon } from "../../../../icons";
const styles = (theme: Theme) =>
createStyles({
warningBlock: {
color: "red",
fontSize: ".85rem",
margin: ".5rem 0 .5rem 0",
display: "flex",
alignItems: "center",
"& svg ": {
marginRight: ".3rem",
},
},
credentialTitle: {
padding: ".8rem 0 0 0",
fontWeight: 600,
fontSize: ".9rem",
},
buttonContainer: {
textAlign: "right",
marginTop: "1rem",
},
credentialsPanel: {
overflowY: "auto",
maxHeight: 350,
},
promptTitle: {
display: "flex",
alignItems: "center",
},
buttonSpacer: {
marginRight: ".9rem",
},
promptIcon: {
marginRight: ".1rem",
display: "flex",
alignItems: "center",
height: "2rem",
width: "2rem",
},
});
interface ICredentialsPromptProps {
@@ -83,115 +113,125 @@ const CredentialsPrompt = ({
onClose={() => {
closeModal();
}}
title={`New ${entity} Created`}
title={
<div className={classes.promptTitle}>
<div className={classes.promptIcon}>
<NewAccountIcon />
</div>{" "}
<div>New {entity} Created</div>
</div>
}
>
<React.Fragment>
<Grid container>
<Grid item xs={12} className={classes.formScrollable}>
A new {entity} has been created with the following details:
{!idp && consoleCreds && (
<React.Fragment>
<Grid item xs={12} className={classes.credentialsPanel}>
<strong>Console Credentials</strong>
{Array.isArray(consoleCreds) &&
consoleCreds.map((credentialsPair, index) => {
return (
<ul key={`creds-item-${index.toString()}`}>
<li>
<b>Access Key:</b> {credentialsPair.accessKey}
</li>
<li>
<b>Secret Key:</b> {credentialsPair.secretKey}
</li>
</ul>
);
})}
{!Array.isArray(consoleCreds) && (
<ul>
<li>
<b>Access Key:</b> {consoleCreds.accessKey}
</li>
<li>
<b>Secret Key:</b> {consoleCreds.secretKey}
</li>
</ul>
)}
</Grid>
</React.Fragment>
)}
{idp ? (
<Typography
component="p"
variant="body1"
className={classes.warningBlock}
>
Please Login via the configured external identity provider.
</Typography>
) : (
<Typography
component="p"
variant="body1"
className={classes.warningBlock}
>
<Grid container>
<Grid item xs={12} className={classes.formScrollable}>
A new {entity} has been created with the following details:
{!idp && consoleCreds && (
<React.Fragment>
<Grid item xs={12} className={classes.credentialsPanel}>
<div className={classes.credentialTitle}>
Console Credentials
</div>
{Array.isArray(consoleCreds) &&
consoleCreds.map((credentialsPair, index) => {
return (
<>
<CredentialItem
label="Access Key"
value={credentialsPair.accessKey}
/>
<CredentialItem
label="Secret Key"
value={credentialsPair.secretKey}
/>
</>
);
})}
{!Array.isArray(consoleCreds) && (
<>
<CredentialItem
label="Access Key"
value={consoleCreds.accessKey}
/>
<CredentialItem
label="Secret Key"
value={consoleCreds.secretKey}
/>
</>
)}
</Grid>
</React.Fragment>
)}
{idp ? (
<div className={classes.warningBlock}>
Please Login via the configured external identity provider.
</div>
) : (
<div className={classes.warningBlock}>
<WarnIcon />
<span>
Write these down, as this is the only time the secret will be
displayed.
</Typography>
)}
</Grid>
<Grid item xs={12} className={classes.buttonContainer}>
{!idp && (
<Button
onClick={() => {
let consoleExtras = {};
</span>
</div>
)}
</Grid>
<Grid item xs={12} className={classes.buttonContainer}>
<Button
variant="outlined"
className={classes.buttonSpacer}
onClick={() => {
closeModal();
}}
color="primary"
>
Done
</Button>
if (consoleCreds) {
if (!Array.isArray(consoleCreds)) {
consoleExtras = {
console: [
{
access_key: consoleCreds.accessKey,
secret_key: consoleCreds.secretKey,
},
],
};
} else {
const cCreds = consoleCreds.map((itemMap) => {
return {
access_key: itemMap.accessKey,
secret_key: itemMap.secretKey,
};
});
consoleExtras = {
console: [...cCreds],
};
}
}
download(
"credentials.json",
JSON.stringify({
...consoleExtras,
})
);
}}
color="primary"
>
Download
</Button>
)}
{!idp && (
<Button
onClick={() => {
closeModal();
let consoleExtras = {};
if (consoleCreds) {
if (!Array.isArray(consoleCreds)) {
consoleExtras = {
console: [
{
access_key: consoleCreds.accessKey,
secret_key: consoleCreds.secretKey,
},
],
};
} else {
const cCreds = consoleCreds.map((itemMap) => {
return {
access_key: itemMap.accessKey,
secret_key: itemMap.secretKey,
};
});
consoleExtras = {
console: [...cCreds],
};
}
}
download(
"credentials.json",
JSON.stringify({
...consoleExtras,
})
);
}}
color="secondary"
autoFocus
endIcon={<DownloadIcon />}
variant="contained"
color="primary"
>
Done
Download
</Button>
</Grid>
)}
</Grid>
</React.Fragment>
</Grid>
</ModalWrapper>
);
};

View File

@@ -253,7 +253,13 @@ const FormSwitchWrapper = ({
</Grid>
</Grid>
<Grid item xs={12} sm={2} textAlign={"right"}>
<Grid
item
xs={12}
sm={2}
textAlign={"right"}
className={classes.switchContainer}
>
{switchComponent}
</Grid>
</Grid>

View File

@@ -1011,3 +1011,51 @@ export const linkStyles = (color: string) => ({
cursor: "pointer",
},
});
export const serviceAccountStyles: any = {
jsonPolicyEditor: {
minHeight: 400,
width: "100%",
},
buttonContainer: {
textAlign: "right",
},
infoDetails: {
color: "#393939",
fontSize: 12,
fontStyle: "italic",
marginBottom: "8px",
},
containerScrollable: {
maxHeight: "calc(100vh - 200px)" as const,
overflowY: "auto" as const,
},
codeMirrorContainer: {
marginBottom: 20,
paddingLeft: 15,
"&:nth-child(2) .MuiGrid-root:nth-child(3)": {
border: "1px solid #EAEAEA",
},
"& label": {
marginBottom: ".5rem",
},
"& label + div": {
display: "none",
},
},
stackedInputs: {
display: "flex",
gap: 15,
paddingBottom: "1rem",
paddingLeft: "1rem",
flexFlow: "column",
},
buttonSpacer: {
marginRight: "1rem",
},
switchContainer: {
display: "flex",
alignItems: "center",
justifyContent: "flex-end",
},
};

View File

@@ -31,7 +31,7 @@ interface IModalProps {
classes: any;
onClose: () => void;
modalOpen: boolean;
title: string;
title: string | React.ReactNode;
children: any;
wideLimit?: boolean;
modalSnackMessage?: snackBarMessage;
@@ -56,8 +56,8 @@ const styles = (theme: Theme) =>
textAlign: "right",
},
closeButton: {
width: 45,
height: 45,
height: 16,
width: 16,
padding: 0,
backgroundColor: "initial",
"&:hover": {
@@ -79,30 +79,28 @@ const styles = (theme: Theme) =>
"&::before": {
...baseCloseLine,
transform: "rotate(45deg)",
height: 12,
},
"&::after": {
...baseCloseLine,
transform: "rotate(-45deg)",
height: 12,
},
"&:hover::before, &:hover::after": {
borderColor: "#9C9C9C",
},
width: 24,
height: 24,
display: "block",
position: "relative",
height: 12,
width: 12,
},
titleClass: {
padding: "0px 50px 12px",
"& h2": {
fontWeight: 600,
color: "#000",
fontSize: 22,
width: "100%",
overflow: "hidden",
whiteSpace: "nowrap",
textOverflow: "ellipsis",
},
fontSize: "1.2rem",
fontWeight: 600,
overflow: "hidden",
whiteSpace: "nowrap",
textOverflow: "ellipsis",
},
modalContent: {
padding: "0 50px",

View File

@@ -21,7 +21,10 @@ import { Button, LinearProgress } 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 {
modalBasic,
serviceAccountStyles,
} from "../Common/FormComponents/common/styleLibrary";
import { NewServiceAccount } from "../Common/CredentialsPrompt/types";
import { setModalErrorSnackMessage } from "../../../actions";
import { ErrorResponseHandler } from "../../../common/types";
@@ -33,23 +36,7 @@ import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWr
const styles = (theme: Theme) =>
createStyles({
jsonPolicyEditor: {
minHeight: 400,
width: "100%",
},
buttonContainer: {
textAlign: "right",
},
infoDetails: {
color: "#393939",
fontSize: 12,
fontStyle: "italic",
marginBottom: "8px",
},
containerScrollable: {
maxHeight: "calc(100vh - 300px)" as const,
overflowY: "auto" as const,
},
...serviceAccountStyles,
...modalBasic,
});
@@ -157,72 +144,84 @@ const AddUserServiceAccount = ({
</div>
</Grid>
<Grid item xs={12}>
<FormSwitchWrapper
value="locking"
id="locking"
name="locking"
checked={isRestrictedByPolicy}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
setIsRestrictedByPolicy(event.target.checked);
}}
label={"Restrict with policy"}
/>
<FormSwitchWrapper
value="locking"
id="locking"
name="locking"
checked={addCredentials}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
setAddCredentials(event.target.checked);
}}
label={"Customize Credentials"}
/>
<Grid item xs={12}>
<FormSwitchWrapper
classes={classes}
value="locking"
id="locking"
name="locking"
checked={addCredentials}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
setAddCredentials(event.target.checked);
}}
label={"Customize Credentials"}
/>
{addCredentials && (
<Grid item xs={12}>
<div className={classes.stackedInputs}>
<InputBoxWrapper
value={accessKey}
label={"Access Key"}
id={"accessKey"}
name={"accessKey"}
placeholder={"Enter Access Key"}
onChange={(e) => {
setAccessKey(e.target.value);
}}
/>
<InputBoxWrapper
value={secretKey}
label={"Secret Key"}
id={"secretKey"}
name={"secretKey"}
placeholder={"Enter Secret Key"}
onChange={(e) => {
setSecretKey(e.target.value);
}}
/>
</div>
</Grid>
)}
</Grid>
<Grid item xs={12}>
<FormSwitchWrapper
value="locking"
id="locking"
name="locking"
classes={classes}
checked={isRestrictedByPolicy}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
setIsRestrictedByPolicy(event.target.checked);
}}
label={"Restrict with policy"}
/>
{isRestrictedByPolicy && (
<Grid item xs={12} className={classes.codeMirrorContainer}>
<CodeMirrorWrapper
label={"Policy "}
value={policyDefinition}
onBeforeChange={(editor, data, value) => {
setPolicyDefinition(value);
}}
/>
</Grid>
)}
</Grid>
</Grid>
{isRestrictedByPolicy && (
<Grid item xs={12}>
<CodeMirrorWrapper
value={policyDefinition}
onBeforeChange={(editor, data, value) => {
setPolicyDefinition(value);
}}
/>
</Grid>
)}
{addCredentials && (
<Grid item xs={12}>
<InputBoxWrapper
value={accessKey}
label={"Access Key"}
id={"accessKey"}
name={"accessKey"}
placeholder={"Enter Access Key"}
onChange={(e) => {
setAccessKey(e.target.value);
}}
/>
<InputBoxWrapper
value={secretKey}
label={"Secret Key"}
id={"secretKey"}
name={"secretKey"}
placeholder={"Enter Secret Key"}
onChange={(e) => {
setSecretKey(e.target.value);
}}
/>
</Grid>
)}
</Grid>
<Grid container>
<Grid item xs={12} className={classes.buttonContainer}>
<button
<Button
type="button"
color="primary"
className={classes.clearButton}
variant="outlined"
className={classes.buttonSpacer}
onClick={resetForm}
>
Clear
</button>
</Button>
<Button
type="submit"
variant="contained"