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 { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles"; import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles"; 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 { NewServiceAccount } from "../Common/CredentialsPrompt/types";
import { setModalErrorSnackMessage } from "../../../actions"; import { setModalErrorSnackMessage } from "../../../actions";
import { ErrorResponseHandler } from "../../../common/types"; import { ErrorResponseHandler } from "../../../common/types";
@@ -33,26 +36,7 @@ import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWr
const styles = (theme: Theme) => const styles = (theme: Theme) =>
createStyles({ createStyles({
jsonPolicyEditor: { ...serviceAccountStyles,
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,
},
...modalBasic, ...modalBasic,
}); });
@@ -157,72 +141,82 @@ const AddServiceAccount = ({
</div> </div>
</Grid> </Grid>
<Grid item xs={12}> <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}> <Grid item xs={12}>
<InputBoxWrapper <FormSwitchWrapper
value={accessKey} value="locking"
label={"Access Key"} classes={classes}
id={"accessKey"} id="locking"
name={"accessKey"} name="locking"
placeholder={"Enter Access Key"} checked={addCredentials}
onChange={(e) => { onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
setAccessKey(e.target.value); setAddCredentials(event.target.checked);
}}
/>
<InputBoxWrapper
value={secretKey}
label={"Secret Key"}
id={"secretKey"}
name={"secretKey"}
placeholder={"Enter Secret Key"}
onChange={(e) => {
setSecretKey(e.target.value);
}} }}
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>
)} <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>
<Grid container> <Grid container>
<Grid item xs={12} className={classes.buttonContainer}> <Grid item xs={12} className={classes.buttonContainer}>
<button <Button
type="button" type="button"
color="primary" color="primary"
className={classes.clearButton} variant="outlined"
className={classes.buttonSpacer}
onClick={resetForm} onClick={resetForm}
> >
Clear Clear
</button> </Button>
<Button <Button
type="submit" type="submit"
variant="contained" 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 withStyles from "@mui/styles/withStyles";
import { NewServiceAccount } from "./types"; import { NewServiceAccount } from "./types";
import { Button } from "@mui/material"; import { Button } from "@mui/material";
import Typography from "@mui/material/Typography";
import ModalWrapper from "../ModalWrapper/ModalWrapper"; import ModalWrapper from "../ModalWrapper/ModalWrapper";
import Grid from "@mui/material/Grid"; 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) => const styles = (theme: Theme) =>
createStyles({ createStyles({
warningBlock: { warningBlock: {
color: "red", 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: { buttonContainer: {
textAlign: "right", textAlign: "right",
marginTop: "1rem",
}, },
credentialsPanel: { credentialsPanel: {
overflowY: "auto", overflowY: "auto",
maxHeight: 350, maxHeight: 350,
}, },
promptTitle: {
display: "flex",
alignItems: "center",
},
buttonSpacer: {
marginRight: ".9rem",
},
promptIcon: {
marginRight: ".1rem",
display: "flex",
alignItems: "center",
height: "2rem",
width: "2rem",
},
}); });
interface ICredentialsPromptProps { interface ICredentialsPromptProps {
@@ -83,115 +113,125 @@ const CredentialsPrompt = ({
onClose={() => { onClose={() => {
closeModal(); 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 container> <Grid item xs={12} className={classes.formScrollable}>
<Grid item xs={12} className={classes.formScrollable}> A new {entity} has been created with the following details:
A new {entity} has been created with the following details: {!idp && consoleCreds && (
{!idp && consoleCreds && ( <React.Fragment>
<React.Fragment> <Grid item xs={12} className={classes.credentialsPanel}>
<Grid item xs={12} className={classes.credentialsPanel}> <div className={classes.credentialTitle}>
<strong>Console Credentials</strong> Console Credentials
{Array.isArray(consoleCreds) && </div>
consoleCreds.map((credentialsPair, index) => { {Array.isArray(consoleCreds) &&
return ( consoleCreds.map((credentialsPair, index) => {
<ul key={`creds-item-${index.toString()}`}> return (
<li> <>
<b>Access Key:</b> {credentialsPair.accessKey} <CredentialItem
</li> label="Access Key"
<li> value={credentialsPair.accessKey}
<b>Secret Key:</b> {credentialsPair.secretKey} />
</li> <CredentialItem
</ul> label="Secret Key"
); value={credentialsPair.secretKey}
})} />
{!Array.isArray(consoleCreds) && ( </>
<ul> );
<li> })}
<b>Access Key:</b> {consoleCreds.accessKey} {!Array.isArray(consoleCreds) && (
</li> <>
<li> <CredentialItem
<b>Secret Key:</b> {consoleCreds.secretKey} label="Access Key"
</li> value={consoleCreds.accessKey}
</ul> />
)} <CredentialItem
</Grid> label="Secret Key"
</React.Fragment> value={consoleCreds.secretKey}
)} />
{idp ? ( </>
<Typography )}
component="p" </Grid>
variant="body1" </React.Fragment>
className={classes.warningBlock} )}
> {idp ? (
Please Login via the configured external identity provider. <div className={classes.warningBlock}>
</Typography> Please Login via the configured external identity provider.
) : ( </div>
<Typography ) : (
component="p" <div className={classes.warningBlock}>
variant="body1" <WarnIcon />
className={classes.warningBlock} <span>
>
Write these down, as this is the only time the secret will be Write these down, as this is the only time the secret will be
displayed. displayed.
</Typography> </span>
)} </div>
</Grid> )}
<Grid item xs={12} className={classes.buttonContainer}> </Grid>
{!idp && ( <Grid item xs={12} className={classes.buttonContainer}>
<Button <Button
onClick={() => { variant="outlined"
let consoleExtras = {}; className={classes.buttonSpacer}
onClick={() => {
closeModal();
}}
color="primary"
>
Done
</Button>
if (consoleCreds) { {!idp && (
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>
)}
<Button <Button
onClick={() => { 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" endIcon={<DownloadIcon />}
autoFocus variant="contained"
color="primary"
> >
Done Download
</Button> </Button>
</Grid> )}
</Grid> </Grid>
</React.Fragment> </Grid>
</ModalWrapper> </ModalWrapper>
); );
}; };

View File

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

View File

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

View File

@@ -21,7 +21,10 @@ import { Button, LinearProgress } from "@mui/material";
import { Theme } from "@mui/material/styles"; import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles"; import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles"; 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 { NewServiceAccount } from "../Common/CredentialsPrompt/types";
import { setModalErrorSnackMessage } from "../../../actions"; import { setModalErrorSnackMessage } from "../../../actions";
import { ErrorResponseHandler } from "../../../common/types"; import { ErrorResponseHandler } from "../../../common/types";
@@ -33,23 +36,7 @@ import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWr
const styles = (theme: Theme) => const styles = (theme: Theme) =>
createStyles({ createStyles({
jsonPolicyEditor: { ...serviceAccountStyles,
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,
},
...modalBasic, ...modalBasic,
}); });
@@ -157,72 +144,84 @@ const AddUserServiceAccount = ({
</div> </div>
</Grid> </Grid>
<Grid item xs={12}> <Grid item xs={12}>
<FormSwitchWrapper <Grid item xs={12}>
value="locking" <FormSwitchWrapper
id="locking" classes={classes}
name="locking" value="locking"
checked={isRestrictedByPolicy} id="locking"
onChange={(event: React.ChangeEvent<HTMLInputElement>) => { name="locking"
setIsRestrictedByPolicy(event.target.checked); checked={addCredentials}
}} onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
label={"Restrict with policy"} setAddCredentials(event.target.checked);
/> }}
<FormSwitchWrapper label={"Customize Credentials"}
value="locking" />
id="locking"
name="locking" {addCredentials && (
checked={addCredentials} <Grid item xs={12}>
onChange={(event: React.ChangeEvent<HTMLInputElement>) => { <div className={classes.stackedInputs}>
setAddCredentials(event.target.checked); <InputBoxWrapper
}} value={accessKey}
label={"Customize Credentials"} 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>
{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>
<Grid container> <Grid container>
<Grid item xs={12} className={classes.buttonContainer}> <Grid item xs={12} className={classes.buttonContainer}>
<button <Button
type="button" type="button"
color="primary" color="primary"
className={classes.clearButton} variant="outlined"
className={classes.buttonSpacer}
onClick={resetForm} onClick={resetForm}
> >
Clear Clear
</button> </Button>
<Button <Button
type="submit" type="submit"
variant="contained" variant="contained"