Updated form dialog components to be using ModalBoxWrapper component (#66)

Updated all form dialog components in mcs to be using the new ModalBoxWrapper component, This doesn't affect delete dialogs since we are going to create an independent component for those.

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
Alex
2020-04-14 00:27:34 -05:00
committed by GitHub
parent 0211827c74
commit e1f177257a
16 changed files with 868 additions and 799 deletions

View File

@@ -16,23 +16,20 @@
import React from "react";
import Grid from "@material-ui/core/Grid";
import Title from "../../../../common/Title";
import Typography from "@material-ui/core/Typography";
import {
Button,
Dialog,
DialogContent,
DialogTitle,
LinearProgress,
TextField
} from "@material-ui/core";
import { Button, LinearProgress } from "@material-ui/core";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import api from "../../../../common/api";
import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper";
import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
const styles = (theme: Theme) =>
createStyles({
errorBlock: {
color: "red"
},
buttonContainer: {
textAlign: "right"
}
});
@@ -88,10 +85,11 @@ class AddBucket extends React.Component<IAddBucketProps, IAddBucketState> {
render() {
const { classes, open } = this.props;
const { addLoading, addError } = this.state;
const { addLoading, addError, bucketName } = this.state;
return (
<Dialog
open={open}
<ModalWrapper
title="Create Bucket"
modalOpen={open}
onClose={() => {
this.setState({ addError: "" }, () => {
this.props.closeModalAndRefresh();
@@ -100,63 +98,58 @@ class AddBucket extends React.Component<IAddBucketProps, IAddBucketState> {
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">
<Title>Create Bucket</Title>
</DialogTitle>
<DialogContent>
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
this.addRecord(e);
}}
>
<Grid container>
{addError !== "" && (
<Grid item xs={12}>
<Typography
component="p"
variant="body1"
className={classes.errorBlock}
>
{addError}
</Typography>
</Grid>
)}
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
this.addRecord(e);
}}
>
<Grid container>
{addError !== "" && (
<Grid item xs={12}>
<TextField
id="standard-basic"
fullWidth
label="Bucket Name"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ bucketName: e.target.value });
}}
/>
</Grid>
<Grid item xs={12}>
<br />
<br />
</Grid>
<Grid item xs={12}>
<Button
type="submit"
variant="contained"
color="primary"
fullWidth
disabled={addLoading}
<Typography
component="p"
variant="body1"
className={classes.errorBlock}
>
Save
</Button>
{addError}
</Typography>
</Grid>
{addLoading && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
)}
<Grid item xs={12}>
<InputBoxWrapper
id="bucket-name"
name="bucket-name"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ bucketName: e.target.value });
}}
label="Bucket Name"
value={bucketName}
/>
</Grid>
</form>
</DialogContent>
</Dialog>
<Grid item xs={12}>
<br />
<br />
</Grid>
<Grid item xs={12} className={classes.buttonContainer}>
<Button
type="submit"
variant="contained"
color="primary"
disabled={addLoading}
>
Save
</Button>
</Grid>
{addLoading && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
</Grid>
</form>
</ModalWrapper>
);
}
}

View File

@@ -210,12 +210,23 @@ class ListBuckets extends React.Component<
return (
<React.Fragment>
<AddBucket
open={addScreenOpen}
closeModalAndRefresh={() => {
this.closeAddModalAndRefresh();
}}
/>
{addScreenOpen && (
<AddBucket
open={addScreenOpen}
closeModalAndRefresh={() => {
this.closeAddModalAndRefresh();
}}
/>
)}
{deleteOpen && (
<DeleteBucket
deleteOpen={deleteOpen}
selectedBucket={selectedBucket}
closeDeleteModalAndRefresh={(refresh: boolean) => {
this.closeDeleteModalAndRefresh(refresh);
}}
/>
)}
<Grid container>
<Grid item xs={12}>
<Typography variant="h6">Buckets</Typography>
@@ -334,14 +345,6 @@ class ListBuckets extends React.Component<
</Paper>
</Grid>
</Grid>
<DeleteBucket
deleteOpen={deleteOpen}
selectedBucket={selectedBucket}
closeDeleteModalAndRefresh={(refresh: boolean) => {
this.closeDeleteModalAndRefresh(refresh);
}}
/>
</React.Fragment>
);
}

View File

@@ -16,20 +16,8 @@
import React, { ChangeEvent } from "react";
import Grid from "@material-ui/core/Grid";
import Title from "../../../../common/Title";
import Typography from "@material-ui/core/Typography";
import {
Button,
Dialog,
DialogContent,
DialogTitle,
FormControl,
InputLabel,
LinearProgress,
MenuItem,
Select,
TextField
} from "@material-ui/core";
import { Button, LinearProgress } from "@material-ui/core";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import api from "../../../../common/api";
import TableHead from "@material-ui/core/TableHead";
@@ -39,6 +27,9 @@ import TableBody from "@material-ui/core/TableBody";
import Checkbox from "@material-ui/core/Checkbox";
import Table from "@material-ui/core/Table";
import { ArnList } from "../types";
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({
@@ -52,6 +43,9 @@ const styles = (theme: Theme) =>
fontWeight: "bold"
}
}
},
buttonContainer: {
textAlign: "right"
}
});
@@ -148,7 +142,15 @@ class AddEvent extends React.Component<IAddEventProps, IAddEventState> {
render() {
const { classes, open } = this.props;
const { addLoading, addError, arn, selectedEvents, arnList } = this.state;
const {
addLoading,
addError,
arn,
selectedEvents,
arnList,
prefix,
suffix
} = this.state;
const events = [
{ label: "PUT - Object Uploaded", value: "put" },
@@ -179,134 +181,131 @@ class AddEvent extends React.Component<IAddEventProps, IAddEventState> {
this.setState({ selectedEvents: newSelected });
};
const arnValues = arnList.map(arnConstant => ({
label: arnConstant,
value: arnConstant
}));
return (
<Dialog
open={open}
<ModalWrapper
modalOpen={open}
onClose={() => {
this.setState({ addError: "" }, () => {
this.props.closeModalAndRefresh();
});
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
title="Subscribe To Event"
>
<DialogTitle id="alert-dialog-title">
<Title>Subscribe To Event</Title>
</DialogTitle>
<DialogContent>
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
this.addRecord(e);
}}
>
<Grid container>
{addError !== "" && (
<Grid item xs={12}>
<Typography
component="p"
variant="body1"
className={classes.errorBlock}
>
{addError}
</Typography>
</Grid>
)}
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
this.addRecord(e);
}}
>
<Grid container>
{addError !== "" && (
<Grid item xs={12}>
<FormControl className={classes.formControl} fullWidth>
<InputLabel id="select-access-policy">ARN</InputLabel>
<Select
labelId="select-access-policy"
id="select-access-policy"
value={arn}
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
this.setState({ arn: e.target.value as string });
}}
>
{arnList.map(arn => (
<MenuItem value={arn}>{arn}</MenuItem>
))}
</Select>
</FormControl>
</Grid>
<Grid item xs={12}>
<Table size="medium">
<TableHead className={classes.minTableHeader}>
<TableRow>
<TableCell>Select</TableCell>
<TableCell>Event</TableCell>
</TableRow>
</TableHead>
<TableBody>
{events.map(row => (
<TableRow
key={`group-${row.value}`}
onClick={event => handleClick(event, row.value)}
>
<TableCell padding="checkbox">
<Checkbox
value={row.value}
color="primary"
inputProps={{
"aria-label": "secondary checkbox"
}}
onChange={event => handleClick(event, row.value)}
checked={selectedEvents.includes(row.value)}
/>
</TableCell>
<TableCell className={classes.wrapCell}>
{row.label}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</Grid>
<Grid item xs={12}>
<TextField
id="standard-basic"
fullWidth
label="Prefix"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ prefix: e.target.value });
}}
/>
</Grid>
<Grid item xs={12}>
<TextField
id="standard-basic"
fullWidth
label="Suffix"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ suffix: e.target.value });
}}
/>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12}>
<Button
type="submit"
variant="contained"
color="primary"
fullWidth
disabled={addLoading}
<Typography
component="p"
variant="body1"
className={classes.errorBlock}
>
Save
</Button>
{addError}
</Typography>
</Grid>
{addLoading && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
)}
<Grid item xs={12}>
<SelectWrapper
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
this.setState({ arn: e.target.value as string });
}}
id="select-access-policy"
name="select-access-policy"
label={"ARN"}
value={arn}
options={arnValues}
/>
</Grid>
</form>
</DialogContent>
</Dialog>
<Grid item xs={12}>
<Table size="medium">
<TableHead className={classes.minTableHeader}>
<TableRow>
<TableCell>Select</TableCell>
<TableCell>Event</TableCell>
</TableRow>
</TableHead>
<TableBody>
{events.map(row => (
<TableRow
key={`group-${row.value}`}
onClick={event => handleClick(event, row.value)}
>
<TableCell padding="checkbox">
<Checkbox
value={row.value}
color="primary"
inputProps={{
"aria-label": "secondary checkbox"
}}
onChange={event => handleClick(event, row.value)}
checked={selectedEvents.includes(row.value)}
/>
</TableCell>
<TableCell className={classes.wrapCell}>
{row.label}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12}>
<InputBoxWrapper
id="prefix-input"
name="prefix-input"
label="Prefix"
value={prefix}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ prefix: e.target.value });
}}
/>
</Grid>
<Grid item xs={12}>
<InputBoxWrapper
id="suffix-input"
name="suffix-input"
label="Suffix"
value={suffix}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ suffix: e.target.value });
}}
/>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12} className={classes.buttonContainer}>
<Button
type="submit"
variant="contained"
color="primary"
disabled={addLoading}
>
Save
</Button>
</Grid>
{addLoading && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
</Grid>
</form>
</ModalWrapper>
);
}
}

View File

@@ -15,21 +15,12 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React from "react";
import Grid from "@material-ui/core/Grid";
import Title from "../../../../common/Title";
import Typography from "@material-ui/core/Typography";
import {
Button,
Dialog,
DialogContent,
DialogTitle,
FormControl,
InputLabel,
LinearProgress,
MenuItem,
Select
} from "@material-ui/core";
import { Button, LinearProgress } from "@material-ui/core";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import api from "../../../../common/api";
import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper";
import SelectWrapper from "../../Common/FormComponents/SelectWrapper/SelectWrapper";
const styles = (theme: Theme) =>
createStyles({
@@ -97,80 +88,71 @@ class SetAccessPolicy extends React.Component<
const { classes, open } = this.props;
const { addLoading, addError, accessPolicy } = this.state;
return (
<Dialog
open={open}
<ModalWrapper
title="Change Access Policy"
modalOpen={open}
onClose={() => {
this.setState({ addError: "" }, () => {
this.props.closeModalAndRefresh();
});
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">
<Title>Change Access Policy</Title>
</DialogTitle>
<DialogContent>
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
this.addRecord(e);
}}
>
<Grid container>
{addError !== "" && (
<Grid item xs={12}>
<Typography
component="p"
variant="body1"
className={classes.errorBlock}
>
{addError}
</Typography>
</Grid>
)}
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
this.addRecord(e);
}}
>
<Grid container>
{addError !== "" && (
<Grid item xs={12}>
<FormControl className={classes.formControl} fullWidth>
<InputLabel id="select-access-policy">
Access Policy
</InputLabel>
<Select
labelId="select-access-policy"
id="select-access-policy"
value={accessPolicy}
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
this.setState({ accessPolicy: e.target.value as string });
}}
>
<MenuItem value="PRIVATE">Private</MenuItem>
<MenuItem value="PUBLIC">Public</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12}>
<Button
type="submit"
variant="contained"
color="primary"
fullWidth
disabled={addLoading}
<Typography
component="p"
variant="body1"
className={classes.errorBlock}
>
Set
</Button>
{addError}
</Typography>
</Grid>
{addLoading && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
)}
<Grid item xs={12}>
<SelectWrapper
value={accessPolicy}
label="Access Policy"
id="select-access-policy"
name="select-access-policy"
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
this.setState({ accessPolicy: e.target.value as string });
}}
options={[
{ value: "PRIVATE", label: "Private" },
{ value: "PUBLIC", label: "Public" }
]}
/>
</Grid>
</form>
</DialogContent>
</Dialog>
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12}>
<Button
type="submit"
variant="contained"
color="primary"
fullWidth
disabled={addLoading}
>
Set
</Button>
</Grid>
{addLoading && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
</Grid>
</form>
</ModalWrapper>
);
}
}

View File

@@ -315,24 +315,28 @@ class ViewBucket extends React.Component<IViewBucketProps, IViewBucketState> {
</TableRow>
</TableHead>
<TableBody>
{records.slice(offset, offset + rowsPerPage).map(row => (
<TableRow key={row.id}>
<TableCell>{row.arn}</TableCell>
<TableCell>{row.events.join(", ")}</TableCell>
<TableCell>{row.prefix}</TableCell>
<TableCell>{row.suffix}</TableCell>
<TableCell align="right">
<IconButton
aria-label="delete"
onClick={() => {
confirmDeleteEvent(row);
}}
>
<DeleteIcon />
</IconButton>
</TableCell>
</TableRow>
))}
{records
.slice(offset, offset + rowsPerPage)
.map((row, index) => (
<TableRow
key={`bucket-evt-${row.id}-${index.toString()}`}
>
<TableCell>{row.arn}</TableCell>
<TableCell>{row.events.join(", ")}</TableCell>
<TableCell>{row.prefix}</TableCell>
<TableCell>{row.suffix}</TableCell>
<TableCell align="right">
<IconButton
aria-label="delete"
onClick={() => {
confirmDeleteEvent(row);
}}
>
<DeleteIcon />
</IconButton>
</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>

View File

@@ -27,7 +27,7 @@ import { fieldBasic } from "../common/styleLibrary";
interface InputBoxProps {
label: string;
classes: any;
onChangeFunc: (e: React.ChangeEvent<HTMLInputElement>) => void;
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
value: string;
id: string;
name: string;
@@ -71,7 +71,7 @@ function InputField(props: TextFieldProps) {
const InputBoxWrapper = ({
label,
onChangeFunc,
onChange,
value,
id,
name,
@@ -95,7 +95,7 @@ const InputBoxWrapper = ({
fullWidth
value={value}
disabled={disabled}
onChange={onChangeFunc}
onChange={onChange}
type={type}
autoComplete={autoComplete}
/>

View File

@@ -0,0 +1,112 @@
// 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 <http://www.gnu.org/licenses/>.
import React from "react";
import Grid from "@material-ui/core/Grid";
import {
FormControl,
InputLabel,
MenuItem,
Select,
InputBase
} from "@material-ui/core";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import { fieldBasic } from "../common/styleLibrary";
interface selectorTypes {
label: string;
value: string;
}
interface SelectProps {
options: selectorTypes[];
value: string;
label: string;
id: string;
name: string;
onChange: (
e: React.ChangeEvent<{ name?: string | undefined; value: unknown }>
) => void;
classes: any;
}
const styles = (theme: Theme) =>
createStyles({
...fieldBasic
});
const SelectStyled = withStyles((theme: Theme) =>
createStyles({
root: {
"label + &": {
marginTop: theme.spacing(3)
}
},
input: {
borderRadius: 0,
position: "relative",
color: "#393939",
fontSize: 14,
padding: "11px 20px",
border: "1px solid #c4c4c4",
"&:hover": {
borderColor: "#393939"
},
"&:focus": {
backgroundColor: "#fff"
}
}
})
)(InputBase);
const SelectWrapper = ({
classes,
id,
name,
onChange,
options,
label,
value
}: SelectProps) => {
return (
<React.Fragment>
<Grid item xs={12} className={classes.fieldContainer}>
<InputLabel htmlFor={id} className={classes.inputLabel}>
{label}
</InputLabel>
<FormControl variant="outlined" fullWidth>
<Select
id={id}
name={name}
value={value}
onChange={onChange}
input={<SelectStyled />}
>
{options.map(option => (
<MenuItem
value={option.value}
key={`select-${name}-${option.label}`}
>
{option.label}
</MenuItem>
))}
</Select>
</FormControl>
</Grid>
</React.Fragment>
);
};
export default withStyles(styles)(SelectWrapper);

View File

@@ -19,7 +19,7 @@ export const fieldBasic = {
inputLabel: {
fontWeight: 500,
marginRight: 16,
minWidth: 80,
minWidth: 90,
fontSize: 14,
color: "#393939"
},

View File

@@ -20,7 +20,7 @@ import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
interface IModalProps {
classes: any;
closeModalAndRefresh: () => void;
onClose: () => void;
modalOpen: boolean;
title: string;
children: any;
@@ -85,7 +85,7 @@ const styles = (theme: Theme) =>
});
const ModalWrapper = ({
closeModalAndRefresh,
onClose,
modalOpen,
title,
children,
@@ -94,7 +94,7 @@ const ModalWrapper = ({
return (
<Dialog
open={modalOpen}
onClose={closeModalAndRefresh}
onClose={onClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
maxWidth={"md"}
@@ -105,7 +105,7 @@ const ModalWrapper = ({
<IconButton
aria-label="close"
className={classes.closeButton}
onClick={closeModalAndRefresh}
onClick={onClose}
disableRipple
>
<span className={classes.closeIcon} />

View File

@@ -16,22 +16,14 @@
import React, { useEffect, useState } from "react";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import {
Button,
Dialog,
DialogContent,
DialogTitle,
LinearProgress,
TextField
} from "@material-ui/core";
import Radio from "@material-ui/core/Radio";
import RadioGroup from "@material-ui/core/RadioGroup";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import { Button, LinearProgress } from "@material-ui/core";
import Grid from "@material-ui/core/Grid";
import Typography from "@material-ui/core/Typography";
import api from "../../../common/api";
import UsersSelectors from "./UsersSelectors";
import Title from "../../../common/Title";
import ModalWrapper from "../Common/ModalWrapper/ModalWrapper";
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
import RadioGroupSelector from "../Common/FormComponents/RadioGroupSelector/RadioGroupSelector";
interface IGroupProps {
open: boolean;
@@ -56,6 +48,9 @@ const styles = (theme: Theme) =>
},
keyName: {
marginLeft: 5
},
buttonContainer: {
textAlign: "right"
}
});
@@ -157,102 +152,88 @@ const AddGroup = ({
};
return (
<Dialog
open={open}
<ModalWrapper
modalOpen={open}
onClose={closeModalAndRefresh}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
title={selectedGroup !== null ? `Group Edit - ${groupName}` : "Add Group"}
>
<DialogTitle id="alert-dialog-title">
{selectedGroup !== null ? `Group Edit - ${groupName}` : "Add Group"}
</DialogTitle>
<DialogContent>
<form noValidate autoComplete="off" onSubmit={setSaving}>
<Grid container>
{addError !== "" && (
<Grid item xs={12}>
<Typography
component="p"
variant="body1"
className={classes.errorBlock}
>
{addError}
</Typography>
</Grid>
)}
{selectedGroup !== null ? (
<React.Fragment>
<Grid item xs={12}>
<Title>Status</Title>
<RadioGroup
aria-label="status"
name="status"
value={groupEnabled}
onChange={e => {
setGroupEnabled(e.target.value);
}}
>
<FormControlLabel
value="enabled"
control={<Radio color={"primary"} />}
label="Enabled"
/>
<FormControlLabel
value="disabled"
control={<Radio color={"primary"} />}
label="Disabled"
/>
</RadioGroup>
</Grid>
</React.Fragment>
) : (
<React.Fragment>
<Grid item xs={12}>
<TextField
id="standard-basic"
fullWidth
label="Name"
value={groupName}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setGroupName(e.target.value);
}}
/>
</Grid>
</React.Fragment>
)}
<form noValidate autoComplete="off" onSubmit={setSaving}>
<Grid container>
{addError !== "" && (
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12}>
<UsersSelectors
selectedUsers={selectedUsers}
setSelectedUsers={setSelectedUsers}
/>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12}>
<Button
type="submit"
variant="contained"
color="primary"
fullWidth
disabled={saving}
<Typography
component="p"
variant="body1"
className={classes.errorBlock}
>
Save
</Button>
{addError}
</Typography>
</Grid>
{saving && (
)}
{selectedGroup !== null ? (
<React.Fragment>
<Grid item xs={12}>
<LinearProgress />
<RadioGroupSelector
currentSelection={groupEnabled}
id="group-status"
name="group-status"
label="Status"
onChange={e => {
setGroupEnabled(e.target.value);
}}
selectorOptions={[
{ label: "Enabled", value: "enabled" },
{ label: "Disabled", value: "disabled" }
]}
/>
</Grid>
)}
</React.Fragment>
) : (
<React.Fragment>
<Grid item xs={12}>
<InputBoxWrapper
id="group-name"
name="group-name"
label="Name"
value={groupName}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setGroupName(e.target.value);
}}
/>
</Grid>
</React.Fragment>
)}
<Grid item xs={12}>
<br />
</Grid>
</form>
</DialogContent>
</Dialog>
<Grid item xs={12}>
<UsersSelectors
selectedUsers={selectedUsers}
setSelectedUsers={setSelectedUsers}
/>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12} className={classes.buttonContainer}>
<Button
type="submit"
variant="contained"
color="primary"
disabled={saving}
>
Save
</Button>
</Grid>
{saving && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
</Grid>
</form>
</ModalWrapper>
);
};

View File

@@ -18,20 +18,14 @@ import React from "react";
import Grid from "@material-ui/core/Grid";
import { UnControlled as CodeMirror } from "react-codemirror2";
import Typography from "@material-ui/core/Typography";
import {
Button,
Dialog,
DialogContent,
DialogTitle,
LinearProgress,
TextField
} from "@material-ui/core";
import { Button, LinearProgress } from "@material-ui/core";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import Title from "../../../common/Title";
import api from "../../../common/api";
import "codemirror/lib/codemirror.css";
import "codemirror/theme/material.css";
import { Policy } from "./types";
import ModalWrapper from "../Common/ModalWrapper/ModalWrapper";
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
require("codemirror/mode/javascript/javascript");
@@ -46,6 +40,9 @@ const styles = (theme: Theme) =>
},
codeMirror: {
fontSize: 14
},
buttonContainer: {
textAlign: "right"
}
});
@@ -103,100 +100,103 @@ class AddPolicy extends React.Component<IAddPolicyProps, IAddPolicyState> {
});
}
componentDidMount() {
const { policyEdit } = this.props;
if (policyEdit) {
this.setState({
policyName: policyEdit.name
});
}
}
render() {
const { classes, open, policyEdit } = this.props;
const { addLoading, addError } = this.state;
const { addLoading, addError, policyName } = this.state;
return (
<Dialog
fullWidth
open={open}
<ModalWrapper
modalOpen={open}
onClose={() => {
this.setState({ addError: "" }, () => {
this.props.closeModalAndRefresh();
});
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
title={`${policyEdit ? "Info" : "Create"} Policy`}
>
<DialogTitle id="alert-dialog-title">
<Title>{policyEdit ? "Info" : "Create"} Policy</Title>
</DialogTitle>
<DialogContent>
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
this.addRecord(e);
}}
>
<Grid container>
{addError !== "" && (
<Grid item xs={12}>
<Typography
component="p"
variant="body1"
className={classes.errorBlock}
>
{addError}
</Typography>
</Grid>
)}
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
this.addRecord(e);
}}
>
<Grid container>
{addError !== "" && (
<Grid item xs={12}>
<TextField
defaultValue={policyEdit ? policyEdit.name : ""}
id="standard-basic"
fullWidth
label="Policy Name"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ policyName: e.target.value });
}}
/>
<Typography
component="p"
variant="body1"
className={classes.errorBlock}
>
{addError}
</Typography>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12}>
<CodeMirror
className={classes.codeMirror}
value={
policyEdit
? JSON.stringify(JSON.parse(policyEdit.policy), null, 4)
: ""
}
options={{
mode: "javascript",
lineNumbers: true
}}
onChange={(editor, data, value) => {
this.setState({ policyDefinition: value });
}}
/>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
{!policyEdit && (
<Grid item xs={12}>
<Button
type="submit"
variant="contained"
color="primary"
fullWidth
disabled={addLoading}
>
Save
</Button>
</Grid>
)}
{addLoading && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
)}
<Grid item xs={12}>
<InputBoxWrapper
id="policy-name"
name="policy-name"
label="Policy Name"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ policyName: e.target.value });
}}
value={policyName}
disabled={!!policyEdit}
/>
</Grid>
</form>
</DialogContent>
</Dialog>
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12}>
<CodeMirror
className={classes.codeMirror}
value={
policyEdit
? JSON.stringify(JSON.parse(policyEdit.policy), null, 4)
: ""
}
options={{
mode: "javascript",
lineNumbers: true
}}
onChange={(editor, data, value) => {
this.setState({ policyDefinition: value });
}}
/>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
{!policyEdit && (
<Grid item xs={12} className={classes.buttonContainer}>
<Button
type="submit"
variant="contained"
color="primary"
disabled={addLoading}
>
Save
</Button>
</Grid>
)}
{addLoading && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
</Grid>
</form>
</ModalWrapper>
);
}
}

View File

@@ -208,13 +208,24 @@ class Policies extends React.Component<IPoliciesProps, IPoliciesState> {
return (
<React.Fragment>
<AddPolicy
open={addScreenOpen}
closeModalAndRefresh={() => {
this.closeAddModalAndRefresh();
}}
policyEdit={policyEdit}
/>
{addScreenOpen && (
<AddPolicy
open={addScreenOpen}
closeModalAndRefresh={() => {
this.closeAddModalAndRefresh();
}}
policyEdit={policyEdit}
/>
)}
{deleteOpen && (
<DeletePolicy
deleteOpen={deleteOpen}
selectedPolicy={selectedPolicy}
closeDeleteModalAndRefresh={(refresh: boolean) => {
this.closeDeleteModalAndRefresh(refresh);
}}
/>
)}
<Grid container>
<Grid item xs={12}>
<Typography variant="h6">IAM Policies</Typography>
@@ -336,14 +347,6 @@ class Policies extends React.Component<IPoliciesProps, IPoliciesState> {
</Paper>
</Grid>
</Grid>
<DeletePolicy
deleteOpen={deleteOpen}
selectedPolicy={selectedPolicy}
closeDeleteModalAndRefresh={(refresh: boolean) => {
this.closeDeleteModalAndRefresh(refresh);
}}
/>
</React.Fragment>
);
}

View File

@@ -17,15 +17,7 @@
import React from "react";
import Grid from "@material-ui/core/Grid";
import Typography from "@material-ui/core/Typography";
import {
Button,
Dialog,
DialogContent,
DialogTitle,
FormControlLabel,
LinearProgress,
TextField
} from "@material-ui/core";
import { Button, FormControlLabel, LinearProgress } from "@material-ui/core";
import {
createStyles,
lighten,
@@ -54,6 +46,8 @@ import {
ServiceAccountDetails
} from "./types";
import Switch from "@material-ui/core/Switch";
import ModalWrapper from "../Common/ModalWrapper/ModalWrapper";
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
const useToolbarStyles = makeStyles((theme: Theme) =>
createStyles({
@@ -209,7 +203,7 @@ class AddServiceAccountContent extends React.Component<
saveRecord(event: React.FormEvent) {
event.preventDefault();
const { name, addLoading, selectedPermissions,enabled } = this.state;
const { name, addLoading, selectedPermissions, enabled } = this.state;
const { selectedServiceAccount } = this.props;
if (addLoading) {
return;
@@ -272,7 +266,12 @@ class AddServiceAccountContent extends React.Component<
}
render() {
const { classes, selectedServiceAccount } = this.props;
const {
classes,
selectedServiceAccount,
open,
closeModalAndRefresh
} = this.props;
const {
addLoading,
addError,
@@ -342,177 +341,175 @@ class AddServiceAccountContent extends React.Component<
const handleChange = (name: string) => (
event: React.ChangeEvent<HTMLInputElement>
) => {
this.setState({enabled:event.target.checked})
this.setState({ enabled: event.target.checked });
};
return (
<React.Fragment>
<DialogTitle id="alert-dialog-title">
{selectedServiceAccount !== null ? (
<span>Edit Service Account</span>
) : (
<span>Create Service Account</span>
)}
</DialogTitle>
<DialogContent>
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
this.saveRecord(e);
}}
>
<Grid container>
{loadingServiceAccount && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
{addError !== "" && (
<Grid item xs={12}>
<Typography
component="p"
variant="body1"
className={classes.errorBlock}
>
{addError}
</Typography>
</Grid>
)}
<ModalWrapper
modalOpen={open}
onClose={() => {
this.setState({ addError: "" }, () => {
closeModalAndRefresh(null);
});
}}
title={
selectedServiceAccount !== null
? "Edit Service Account"
: "Create Service Account"
}
>
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
this.saveRecord(e);
}}
>
<Grid container>
{loadingServiceAccount && (
<Grid item xs={12}>
<TextField
id="standard-basic"
fullWidth
label="Name"
value={name}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ name: e.target.value });
}}
/>
<LinearProgress />
</Grid>
)}
{addError !== "" && (
<Grid item xs={12}>
<div className={classes.root}>
<EnhancedTableToolbar
numSelected={selectedPermissions.length}
/>
<TableContainer>
<Table
className={classes.table}
aria-labelledby="tableTitle"
size={"small"}
aria-label="enhanced table"
>
<TableHead>
<TableRow>
<TableCell padding="checkbox">
<Checkbox
indeterminate={
selectedPermissions.length > 0 &&
selectedPermissions.length < permissions.length
}
checked={
selectedPermissions.length > 0 &&
selectedPermissions.length ===
permissions.length
}
onChange={handleSelectAllClick}
inputProps={{
"aria-label": "select all desserts"
}}
/>
</TableCell>
<TableCell>Permission</TableCell>
<TableCell>Description</TableCell>
</TableRow>
</TableHead>
<TableBody>
{permissions
.slice(
page * rowsPerPage,
page * rowsPerPage + rowsPerPage
)
.map((row, index) => {
const isItemSelected = isSelected(row);
const labelId = `enhanced-table-checkbox-${index}`;
return (
<TableRow
hover
onClick={event => handleClick(event, row)}
role="checkbox"
aria-checked={isItemSelected}
tabIndex={-1}
key={row.name}
selected={isItemSelected}
>
<TableCell padding="checkbox">
<Checkbox
checked={isItemSelected}
inputProps={{ "aria-labelledby": labelId }}
/>
</TableCell>
<TableCell id={labelId}>{row.name}</TableCell>
<TableCell>{row.description}</TableCell>
</TableRow>
);
})}
{emptyRows > 0 && (
<TableRow style={{ height: 33 * emptyRows }}>
<TableCell colSpan={6} />
</TableRow>
)}
</TableBody>
</Table>
</TableContainer>
<TablePagination
rowsPerPageOptions={[5, 10, 25]}
component="div"
count={permissions.length}
rowsPerPage={rowsPerPage}
page={page}
labelRowsPerPage={null}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
/>
</div>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12}>
<FormControlLabel
control={
<Switch
onChange={handleChange("enabled")}
value="checkedA"
/>
}
label="Enabled"
/>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12}>
<Button
type="submit"
variant="contained"
color="primary"
disabled={addLoading}
<Typography
component="p"
variant="body1"
className={classes.errorBlock}
>
Save
</Button>
{addError}
</Typography>
</Grid>
{addLoading && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
)}
<Grid item xs={12}>
<InputBoxWrapper
id="service-account-name"
name="service-account-name"
label="Name"
value={name}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ name: e.target.value });
}}
/>
</Grid>
</form>
</DialogContent>
</React.Fragment>
<Grid item xs={12}>
<div className={classes.root}>
<EnhancedTableToolbar
numSelected={selectedPermissions.length}
/>
<TableContainer>
<Table
className={classes.table}
aria-labelledby="tableTitle"
size={"small"}
aria-label="enhanced table"
>
<TableHead>
<TableRow>
<TableCell padding="checkbox">
<Checkbox
indeterminate={
selectedPermissions.length > 0 &&
selectedPermissions.length < permissions.length
}
checked={
selectedPermissions.length > 0 &&
selectedPermissions.length === permissions.length
}
onChange={handleSelectAllClick}
inputProps={{
"aria-label": "select all desserts"
}}
/>
</TableCell>
<TableCell>Permission</TableCell>
<TableCell>Description</TableCell>
</TableRow>
</TableHead>
<TableBody>
{permissions
.slice(
page * rowsPerPage,
page * rowsPerPage + rowsPerPage
)
.map((row, index) => {
const isItemSelected = isSelected(row);
const labelId = `enhanced-table-checkbox-${index}`;
return (
<TableRow
hover
onClick={event => handleClick(event, row)}
role="checkbox"
aria-checked={isItemSelected}
tabIndex={-1}
key={row.name}
selected={isItemSelected}
>
<TableCell padding="checkbox">
<Checkbox
checked={isItemSelected}
inputProps={{ "aria-labelledby": labelId }}
/>
</TableCell>
<TableCell id={labelId}>{row.name}</TableCell>
<TableCell>{row.description}</TableCell>
</TableRow>
);
})}
{emptyRows > 0 && (
<TableRow style={{ height: 33 * emptyRows }}>
<TableCell colSpan={6} />
</TableRow>
)}
</TableBody>
</Table>
</TableContainer>
<TablePagination
rowsPerPageOptions={[5, 10, 25]}
component="div"
count={permissions.length}
rowsPerPage={rowsPerPage}
page={page}
labelRowsPerPage={null}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
/>
</div>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12}>
<FormControlLabel
control={
<Switch onChange={handleChange("enabled")} value="checkedA" />
}
label="Enabled"
/>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12}>
<Button
type="submit"
variant="contained"
color="primary"
disabled={addLoading}
>
Save
</Button>
</Grid>
{addLoading && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
</Grid>
</form>
</ModalWrapper>
);
}
}
@@ -534,21 +531,7 @@ class AddServiceAccount extends React.Component<
state: IAddServiceAccountState = {};
render() {
const { open } = this.props;
return (
<Dialog
open={open}
onClose={() => {
this.setState({ addError: "" }, () => {
this.props.closeModalAndRefresh(null);
});
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<AddServiceAccountWrapper {...this.props} />
</Dialog>
);
return <AddServiceAccountWrapper {...this.props} />;
}
}

View File

@@ -19,13 +19,12 @@ import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import { NewServiceAccount } from "./types";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle
DialogContentText
} from "@material-ui/core";
import Typography from "@material-ui/core/Typography";
import ModalWrapper from "../Common/ModalWrapper/ModalWrapper";
const styles = (theme: Theme) =>
createStyles({
@@ -49,18 +48,21 @@ class CredentialsPrompt extends React.Component<
> {
state: ICredentialsPromptState = {};
download(filename:string, text:string) {
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
element.setAttribute('download', filename);
download(filename: string, text: string) {
var element = document.createElement("a");
element.setAttribute(
"href",
"data:text/plain;charset=utf-8," + encodeURIComponent(text)
);
element.setAttribute("download", filename);
element.style.display = 'none';
document.body.appendChild(element);
element.style.display = "none";
document.body.appendChild(element);
element.click();
element.click();
document.body.removeChild(element);
}
document.body.removeChild(element);
}
render() {
const { classes, open, newServiceAccount } = this.props;
@@ -70,60 +72,63 @@ class CredentialsPrompt extends React.Component<
}
return (
<Dialog
open={open}
<ModalWrapper
modalOpen={open}
onClose={() => {
this.props.closeModal();
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
title="New Service Account"
>
<DialogTitle id="alert-dialog-title">New Service Account</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
A new service account has been created with the following details:
<ul>
<li>
<b>Access Key:</b>{" "}
{newServiceAccount.service_account.access_key}
</li>
<li>
<b>Secret Key:</b> {newServiceAccount.secret_key}
</li>
</ul>
<Typography
component="p"
variant="body1"
className={classes.errorBlock}
<React.Fragment>
<DialogContent>
<DialogContentText id="alert-dialog-description">
A new service account has been created with the following details:
<ul>
<li>
<b>Access Key:</b>{" "}
{newServiceAccount.service_account.access_key}
</li>
<li>
<b>Secret Key:</b> {newServiceAccount.secret_key}
</li>
</ul>
<Typography
component="p"
variant="body1"
className={classes.errorBlock}
>
Write these down, as this is the only time the secret will be
displayed.
</Typography>
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
onClick={() => {
this.download(
"credentials.json",
JSON.stringify({
access_key: newServiceAccount.service_account.access_key,
secret_key: newServiceAccount.secret_key
})
);
}}
color="primary"
>
Write these down, as this is the only time the secret will be
displayed.
</Typography>
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
onClick={() => {
this.download("credentials.json",JSON.stringify({
access_key: newServiceAccount.service_account.access_key,
secret_key: newServiceAccount.secret_key,
}))
}}
color="primary"
>
Download
</Button>
<Button
onClick={() => {
this.props.closeModal();
}}
color="secondary"
autoFocus
>
Done
</Button>
</DialogActions>
</Dialog>
Download
</Button>
<Button
onClick={() => {
this.props.closeModal();
}}
color="secondary"
autoFocus
>
Done
</Button>
</DialogActions>
</React.Fragment>
</ModalWrapper>
);
}
}

View File

@@ -80,7 +80,7 @@ const styles = (theme: Theme) =>
color: "#393939",
"& tr": {
"& th": {
fontWeight:'bold'
fontWeight: "bold"
}
}
},
@@ -93,14 +93,14 @@ const styles = (theme: Theme) =>
actionsTray: {
textAlign: "right",
"& button": {
marginLeft: 10,
},
marginLeft: 10
}
},
searchField: {
background: "#FFFFFF",
padding: 12,
borderRadius: 5,
boxShadow: "0px 3px 6px #00000012",
boxShadow: "0px 3px 6px #00000012"
}
});
@@ -250,14 +250,33 @@ class ServiceAccounts extends React.Component<
return (
<React.Fragment>
<AddServiceAccount
open={addScreenOpen}
selectedServiceAccount={selectedServiceAccount}
closeModalAndRefresh={(res: NewServiceAccount | null) => {
this.closeAddModalAndRefresh(res);
}}
/>
{addScreenOpen && (
<AddServiceAccount
open={addScreenOpen}
selectedServiceAccount={selectedServiceAccount}
closeModalAndRefresh={(res: NewServiceAccount | null) => {
this.closeAddModalAndRefresh(res);
}}
/>
)}
{deleteOpen && (
<DeleteServiceAccount
deleteOpen={deleteOpen}
selectedServiceAccount={selectedServiceAccount}
closeDeleteModalAndRefresh={(refresh: boolean) => {
this.closeDeleteModalAndRefresh(refresh);
}}
/>
)}
{showNewCredentials && (
<CredentialsPrompt
newServiceAccount={newServiceAccount}
open={showNewCredentials}
closeModal={() => {
this.closeCredentialsModal();
}}
/>
)}
<Grid container>
<Grid item xs={12}>
<Typography variant="h6">Service Accounts</Typography>
@@ -277,7 +296,7 @@ class ServiceAccounts extends React.Component<
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
),
)
}}
/>
<Button
@@ -331,7 +350,7 @@ class ServiceAccounts extends React.Component<
<Checkbox
value="secondary"
color="primary"
inputProps={{ 'aria-label': 'secondary checkbox' }}
inputProps={{ "aria-label": "secondary checkbox" }}
/>
</TableCell>
<TableCell className={classes.wrapCell}>
@@ -387,21 +406,6 @@ class ServiceAccounts extends React.Component<
</Paper>
</Grid>
</Grid>
<DeleteServiceAccount
deleteOpen={deleteOpen}
selectedServiceAccount={selectedServiceAccount}
closeDeleteModalAndRefresh={(refresh: boolean) => {
this.closeDeleteModalAndRefresh(refresh);
}}
/>
<CredentialsPrompt
newServiceAccount={newServiceAccount}
open={showNewCredentials}
closeModal={() => {
this.closeCredentialsModal();
}}
/>
</React.Fragment>
);
}

View File

@@ -195,7 +195,7 @@ class AddUserContent extends React.Component<
return (
<ModalWrapper
closeModalAndRefresh={() => {
onClose={() => {
this.props.closeModalAndRefresh();
}}
modalOpen={this.props.open}
@@ -227,7 +227,7 @@ class AddUserContent extends React.Component<
name="accesskey-input"
label="Access Key"
value={accessKey}
onChangeFunc={(e: React.ChangeEvent<HTMLInputElement>) => {
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ accessKey: e.target.value });
}}
disabled={selectedUser !== null}
@@ -254,7 +254,7 @@ class AddUserContent extends React.Component<
label="Secret Key"
type="password"
value={secretKey}
onChangeFunc={(e: React.ChangeEvent<HTMLInputElement>) => {
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ secretKey: e.target.value });
}}
autoComplete="current-password"