UX updates to Policy list Bucket and Object List (#1253)

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
This commit is contained in:
Prakash Senthil Vel
2021-11-26 03:40:23 +05:30
committed by GitHub
parent a69f597f43
commit 62fe583a21
10 changed files with 211 additions and 165 deletions

View File

@@ -249,7 +249,7 @@ const Account = ({
<PageLayout>
<Grid item xs={12} className={classes.actionsTray}>
<SearchBox
placeholder={"Search Groups"}
placeholder={"Search Service Accounts"}
onChange={setFilter}
classes={classes}
/>

View File

@@ -50,6 +50,7 @@ import PageHeader from "../../Common/PageHeader/PageHeader";
import BackLink from "../../../../common/BackLink";
import { BucketsIcon } from "../../../../icons";
import { setErrorSnackMessage } from "../../../../actions";
import PageLayout from "../../Common/Layout/PageLayout";
const styles = (theme: Theme) =>
createStyles({
@@ -279,10 +280,8 @@ const AddBucket = ({
return (
<Fragment>
<PageHeader label={"Create a Bucket"} />
<Grid container className={classes.container}>
<Grid item xs={12}>
<BackLink to="/buckets" label="Return to Buckets" />
</Grid>
<BackLink label={"Return to Buckets"} to={"/buckets"} />
<PageLayout>
<Grid item xs={12} className={classes.boxy}>
<form
noValidate
@@ -536,7 +535,7 @@ const AddBucket = ({
</Grid>
</form>
</Grid>
</Grid>
</PageLayout>
</Fragment>
);
};

View File

@@ -145,6 +145,26 @@ const styles = (theme: Theme) =>
width: 48,
},
},
bucketInfo: {
display: "flex",
"@media (max-width: 900px)": {
flexFlow: "column-reverse",
},
},
bucketStats: {
marginTop: 15,
borderTop: "1px solid rgb(234,234,234, .7)",
paddingTop: 14,
},
bucketActionButtons: {
display: "flex",
alignItems: "center",
justifyContent: "flex-end",
"@media (max-width: 900px)": {
marginTop: "-33px",
},
},
});
interface IBucketListItem {
@@ -183,10 +203,10 @@ const BucketListItem = ({
};
return (
<Grid container className={classes.root} spacing={1}>
<Grid container className={classes.root}>
<Grid item xs={12}>
<Grid container justifyContent={"space-between"}>
<Grid item xs={12} sm={8}>
<Grid item xs={12} sm={7}>
<Grid container>
<Grid item xs={12}>
{bulkSelect && (
@@ -209,22 +229,22 @@ const BucketListItem = ({
<h1 className={classes.bucketName}>{bucket.name}</h1>
</Grid>
<Grid item xs={12}>
<Grid container>
<Grid container className={classes.bucketInfo}>
<Grid item xs={12} sm>
<Typography variant="body2">
Created: <b>{bucket.creation_date}</b>
Created: {bucket.creation_date}
</Typography>
</Grid>
<Grid item xs={12} sm>
<Typography variant="body2">
Access: <b> {accessToStr(bucket)}</b>
Access: {accessToStr(bucket)}
</Typography>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} sm={4} textAlign={"right"}>
<Grid item xs={12} sm={5} className={classes.bucketActionButtons}>
<SecureComponent
scopes={IAM_PERMISSIONS[IAM_ROLES.admin]}
resource={bucket.name}
@@ -260,10 +280,8 @@ const BucketListItem = ({
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<hr />
</Grid>
<Grid item xs={12}>
<Grid item xs={12} className={classes.bucketStats}>
<Grid container justifyContent={"flex-start"} spacing={4}>
<Grid item className={classes.bucketIcon}>
<BucketsIcon />

View File

@@ -37,9 +37,6 @@ import BucketListItem from "./BucketListItem";
import BulkReplicationModal from "./BulkReplicationModal";
import HelpBox from "../../../../common/HelpBox";
import { ISessionResponse } from "../../types";
import TextField from "@mui/material/TextField";
import InputAdornment from "@mui/material/InputAdornment";
import SearchIcon from "../../../../icons/SearchIcon";
import BoxIconButton from "../../Common/BoxIconButton/BoxIconButton";
import RefreshIcon from "../../../../icons/RefreshIcon";
import AButton from "../../Common/AButton/AButton";
@@ -50,6 +47,8 @@ import {
CONSOLE_UI_RESOURCE,
IAM_SCOPES,
} from "../../../../common/SecureComponent/permissions";
import PageLayout from "../../Common/Layout/PageLayout";
import SearchBox from "../../Common/SearchBox";
const styles = (theme: Theme) =>
createStyles({
@@ -130,10 +129,18 @@ const styles = (theme: Theme) =>
marginRight: 10,
marginLeft: 10,
},
bucketList: {
marginTop: 25,
},
...containerForHeader(theme.spacing(4)),
...searchField,
constrainedContainer: {
maxWidth: 1180,
searchField: {
...searchField.searchField,
minWidth: 380,
"@media (max-width: 900px)": {
minWidth: 220,
},
},
});
@@ -251,89 +258,76 @@ const ListBuckets = ({
/>
)}
<PageHeader label={"Buckets"} />
<Grid container className={classes.container}>
<Grid item xs={12} className={classes.buttonTray}>
<Grid container>
<Grid item xs={12} sm>
<TextField
placeholder="Filter Buckets"
className={classes.searchField}
id="search-resource"
label=""
InputProps={{
disableUnderline: true,
startAdornment: (
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
),
}}
onChange={(e) => {
setFilterBuckets(e.target.value);
}}
variant="standard"
/>
</Grid>
<Grid item xs={12} sm={"auto"}>
<BoxIconButton
variant={bulkSelect ? "contained" : "outlined"}
tooltip={"Select Multiple"}
onClick={() => {
setBulkSelect(!bulkSelect);
}}
size={"small"}
className={classes.bulkSelect}
>
<SelectMultipleIcon />
</BoxIconButton>
<BoxIconButton
variant="outlined"
tooltip={"Set Replication"}
onClick={() => {
setReplicationModalOpen(true);
}}
disabled={selectedBuckets.length === 0}
size={"small"}
>
<MultipleBucketsIcon />
</BoxIconButton>
<BoxIconButton
<PageLayout>
<Grid item xs={12} className={classes.actionsTray} display="flex">
<SearchBox
onChange={setFilterBuckets}
classes={classes}
placeholder="Search Buckets"
/>
<Grid
item
xs={12}
display={"flex"}
alignItems={"center"}
justifyContent={"flex-end"}
>
<BoxIconButton
variant={bulkSelect ? "contained" : "outlined"}
tooltip={"Select Multiple"}
onClick={() => {
setBulkSelect(!bulkSelect);
}}
size={"small"}
className={classes.bulkSelect}
>
<SelectMultipleIcon />
</BoxIconButton>
<BoxIconButton
variant="outlined"
tooltip={"Set Replication"}
onClick={() => {
setReplicationModalOpen(true);
}}
disabled={selectedBuckets.length === 0}
size={"small"}
>
<MultipleBucketsIcon />
</BoxIconButton>
<BoxIconButton
color="primary"
aria-label="Refresh"
tooltip={"Refresh"}
onClick={() => {
setLoading(true);
}}
size="large"
>
<RefreshIcon />
</BoxIconButton>
<SecureComponent
scopes={[IAM_SCOPES.S3_CREATE_BUCKET]}
resource={CONSOLE_UI_RESOURCE}
>
<Button
variant="contained"
color="primary"
aria-label="Refresh"
tooltip={"Refresh"}
endIcon={<AddIcon />}
onClick={() => {
setLoading(true);
history.push("/add-bucket");
}}
size="large"
className={classes.addBucket}
>
<RefreshIcon />
</BoxIconButton>
<SecureComponent
scopes={[IAM_SCOPES.S3_CREATE_BUCKET]}
resource={CONSOLE_UI_RESOURCE}
>
<Button
variant="contained"
color="primary"
endIcon={<AddIcon />}
onClick={() => {
history.push("/add-bucket");
}}
className={classes.addBucket}
>
Create Bucket
</Button>
</SecureComponent>
</Grid>
Create Bucket
</Button>
</SecureComponent>
</Grid>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
{loading && <LinearProgress />}
{!loading && (
<Grid item xs={12}>
<Grid item xs={12} className={classes.bucketList}>
{filteredRecords.map((bucket, index) => {
return (
<BucketListItem
@@ -405,7 +399,7 @@ const ListBuckets = ({
)}
</Grid>
)}
</Grid>
</PageLayout>
</Fragment>
);
};

View File

@@ -22,8 +22,6 @@ import withStyles from "@mui/styles/withStyles";
import { withRouter } from "react-router-dom";
import Grid from "@mui/material/Grid";
import get from "lodash/get";
import TextField from "@mui/material/TextField";
import InputAdornment from "@mui/material/InputAdornment";
import {
BucketObject,
BucketObjectsList,
@@ -43,6 +41,7 @@ import {
containerForHeader,
objectBrowserCommon,
searchField,
tableStyles,
} from "../../../../Common/FormComponents/common/styleLibrary";
import { Badge, Button, Typography } from "@mui/material";
import * as reactMoment from "react-moment";
@@ -69,7 +68,6 @@ import ObjectBrowserIcon from "../../../../../../icons/ObjectBrowserIcon";
import ObjectBrowserFolderIcon from "../../../../../../icons/ObjectBrowserFolderIcon";
import FolderIcon from "../../../../../../icons/FolderIcon";
import RefreshIcon from "../../../../../../icons/RefreshIcon";
import SearchIcon from "../../../../../../icons/SearchIcon";
import UploadIcon from "../../../../../../icons/UploadIcon";
import { setBucketDetailsLoad, setBucketInfo } from "../../../actions";
import { AppState } from "../../../../../../store";
@@ -97,6 +95,7 @@ import { IAM_SCOPES } from "../../../../../../common/SecureComponent/permissions
import SecureComponent, {
hasPermission,
} from "../../../../../../common/SecureComponent/SecureComponent";
import SearchBox from "../../../../Common/SearchBox";
import withSuspense from "../../../../Common/Components/withSuspense";
@@ -200,8 +199,18 @@ const styles = (theme: Theme) =>
right: 10,
},
},
screenTitle: {
borderBottom: 0,
paddingTop: 0,
},
...tableStyles,
...actionsTray,
...searchField,
searchField: {
...searchField.searchField,
maxWidth: 380,
},
...objectBrowserCommon,
...containerForHeader(theme.spacing(4)),
});
@@ -1058,6 +1067,7 @@ const ListObjects = ({
<PageLayout>
<Grid item xs={12}>
<ScreenTitle
classes={classes}
icon={
<Fragment>
<FolderIcon width={40} />
@@ -1157,23 +1167,10 @@ const ListObjects = ({
scopes={[IAM_SCOPES.S3_LIST_BUCKET]}
resource={bucketName}
>
<TextField
<SearchBox
onChange={setFilterObjects}
classes={classes}
placeholder="Search Objects"
className={classes.searchField}
id="search-resource"
label=""
onChange={(val) => {
setFilterObjects(val.target.value);
}}
InputProps={{
disableUnderline: true,
startAdornment: (
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
),
}}
variant="standard"
/>
</SecureComponent>
<SecureComponent
@@ -1196,7 +1193,7 @@ const ListObjects = ({
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12}>
<Grid item xs={12} className={classes.tableBlock}>
<SecureComponent
scopes={[IAM_SCOPES.S3_LIST_BUCKET]}
resource={bucketName}

View File

@@ -52,9 +52,11 @@ const styles = (theme: Theme) =>
height: 16,
},
},
"& div[class|='InputBoxWrapper-textBoxContainer']": {
display: "flex",
},
},
textBoxContainer: {
flexGrow: 1,
position: "relative",
display: "flex",
},
overlayAction: {
top: 0,
@@ -69,13 +71,8 @@ const styles = (theme: Theme) =>
},
fieldContainer: {
"& .MuiInputLabel-root": {
flex: 1,
minWidth: 200,
},
"& div[class|='CommentBoxWrapper-textBoxContainer']": {
flexGrow: 1,
width: "100%",
},
},
tooltipContainer: {
...fieldBasic.tooltipContainer,

View File

@@ -27,6 +27,7 @@ import { setModalErrorSnackMessage } from "../../../actions";
import {
fieldBasic,
modalBasic,
spacingUtils,
} from "../Common/FormComponents/common/styleLibrary";
import { ErrorResponseHandler } from "../../../common/types";
import ModalWrapper from "../Common/ModalWrapper/ModalWrapper";
@@ -42,6 +43,20 @@ const styles = (theme: Theme) =>
buttonContainer: {
textAlign: "right",
},
codeMirrorContainer: {
marginBottom: 20,
marginTop: 20,
"&:nth-child(2) .MuiGrid-root:nth-child(3)": {
border: "1px solid #EAEAEA",
},
"& label": {
marginBottom: ".5rem",
},
"& label + div": {
display: "none",
},
},
...spacingUtils,
...modalBasic,
...fieldBasic,
});
@@ -120,7 +135,7 @@ const AddPolicy = ({
>
<Grid container>
<Grid item xs={12} className={classes.formScrollable}>
<Grid item xs={12}>
<Grid item xs={12} className={classes.formFieldRow}>
<InputBoxWrapper
id="policy-name"
name="policy-name"
@@ -133,29 +148,28 @@ const AddPolicy = ({
disabled={!!policyEdit}
/>
</Grid>
<Grid item xs={12}>
<br />
<Grid item xs={12} className={classes.codeMirrorContainer}>
<CodeMirrorWrapper
label={`${policyEdit ? "Edit" : "Write"} Policy`}
value={policyDefinition}
onBeforeChange={(editor, data, value) => {
setPolicyDefinition(value);
}}
/>
</Grid>
<CodeMirrorWrapper
label={`${policyEdit ? "Edit" : "Write"} Policy`}
value={policyDefinition}
onBeforeChange={(editor, data, value) => {
setPolicyDefinition(value);
}}
/>
</Grid>
<Grid item xs={12} className={classes.buttonContainer}>
{!policyEdit && (
<button
<Button
type="button"
variant="outlined"
color="primary"
className={classes.clearButton}
onClick={() => {
resetForm();
}}
className={classes.spacerRight}
onClick={resetForm}
>
Clear
</button>
</Button>
)}
<Button

View File

@@ -29,15 +29,28 @@ import api from "../../../common/api";
import { PolicyList } from "./types";
import { setErrorSnackMessage } from "../../../actions";
import { ErrorResponseHandler } from "../../../common/types";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import { deleteDialogStyles } from "../Common/FormComponents/common/styleLibrary";
import withStyles from "@mui/styles/withStyles";
import IconButton from "@mui/material/IconButton";
import CloseIcon from "@mui/icons-material/Close";
interface IDeletePolicyProps {
closeDeleteModalAndRefresh: (refresh: boolean) => void;
deleteOpen: boolean;
selectedPolicy: string;
setErrorSnackMessage: typeof setErrorSnackMessage;
classes: any;
}
const styles = (theme: Theme) =>
createStyles({
...deleteDialogStyles,
});
const DeletePolicy = ({
classes,
closeDeleteModalAndRefresh,
deleteOpen,
selectedPolicy,
@@ -63,6 +76,8 @@ const DeletePolicy = ({
};
return (
<Dialog
classes={classes}
className={classes.root}
open={deleteOpen}
onClose={() => {
closeDeleteModalAndRefresh(false);
@@ -70,15 +85,32 @@ const DeletePolicy = ({
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">Delete Policy</DialogTitle>
<DialogTitle id="alert-dialog-title" className={classes.title}>
<div className={classes.titleText}>Delete Policy</div>
<div className={classes.closeContainer}>
<IconButton
aria-label="close"
className={classes.closeButton}
onClick={() => {
closeDeleteModalAndRefresh(false);
}}
disableRipple
size="small"
>
<CloseIcon />
</IconButton>
</div>
</DialogTitle>
<DialogContent>
{deleteLoading && <LinearProgress />}
<DialogContentText id="alert-dialog-description">
Are you sure you want to delete policy <b>{selectedPolicy}</b>?
Are you sure you want to delete policy <br />
<b>{selectedPolicy}</b>?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
variant="outlined"
onClick={() => {
closeDeleteModalAndRefresh(false);
}}
@@ -88,6 +120,7 @@ const DeletePolicy = ({
Cancel
</Button>
<Button
variant="outlined"
onClick={() => {
removeRecord();
}}
@@ -106,5 +139,4 @@ const mapDispatchToProps = {
};
const connector = connect(null, mapDispatchToProps);
export default connector(DeletePolicy);
export default withStyles(styles)(connector(DeletePolicy));

View File

@@ -22,8 +22,6 @@ import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import { Button } from "@mui/material";
import Grid from "@mui/material/Grid";
import TextField from "@mui/material/TextField";
import InputAdornment from "@mui/material/InputAdornment";
import { Policy, PolicyList } from "./types";
import { AddIcon, IAMPoliciesIcon } from "../../../icons";
import { setErrorSnackMessage } from "../../../actions";
@@ -31,6 +29,7 @@ import {
actionsTray,
containerForHeader,
searchField,
tableStyles,
} from "../Common/FormComponents/common/styleLibrary";
import { ErrorResponseHandler } from "../../../common/types";
@@ -38,7 +37,6 @@ import TableWrapper from "../Common/TableWrapper/TableWrapper";
import PageHeader from "../Common/PageHeader/PageHeader";
import api from "../../../common/api";
import history from "../../../history";
import SearchIcon from "../../../icons/SearchIcon";
import HelpBox from "../../../common/HelpBox";
import PageLayout from "../Common/Layout/PageLayout";
import {
@@ -48,6 +46,7 @@ import {
import SecureComponent, {
hasPermission,
} from "../../../common/SecureComponent/SecureComponent";
import SearchBox from "../Common/SearchBox";
import withSuspense from "../Common/Components/withSuspense";
const AddPolicy = withSuspense(React.lazy(() => import("./AddPolicy")));
@@ -84,6 +83,14 @@ const styles = (theme: Theme) =>
},
...actionsTray,
...searchField,
searchField: {
...searchField.searchField,
maxWidth: 380,
},
tableBlock: {
...tableStyles.tableBlock,
marginTop: 15,
},
...containerForHeader(theme.spacing(4)),
});
@@ -216,24 +223,12 @@ const ListPolicies = ({ classes, setErrorSnackMessage }: IPoliciesProps) => {
<PageHeader label="IAM Policies" />
<PageLayout className={classes.pageContainer}>
<Grid item xs={12} className={classes.actionsTray}>
<TextField
<SearchBox
onChange={setFilterPolicies}
classes={classes}
placeholder="Search Policies"
className={classes.searchField}
id="search-resource"
label=""
onChange={(val) => {
setFilterPolicies(val.target.value);
}}
InputProps={{
disableUnderline: true,
startAdornment: (
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
),
}}
variant="standard"
/>
<SecureComponent
scopes={[IAM_SCOPES.ADMIN_CREATE_POLICY]}
resource={CONSOLE_UI_RESOURCE}
@@ -254,7 +249,7 @@ const ListPolicies = ({ classes, setErrorSnackMessage }: IPoliciesProps) => {
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12}>
<Grid item xs={12} className={classes.tableBlock}>
<SecureComponent
scopes={[IAM_SCOPES.ADMIN_LIST_USER_POLICIES]}
resource={CONSOLE_UI_RESOURCE}

View File

@@ -237,7 +237,7 @@ const ListUsers = ({ classes, setErrorSnackMessage, history }: IUsersProps) => {
<PageLayout>
<Grid item xs={12} className={classes.actionsTray}>
<SearchBox
placeholder={"Search Groups"}
placeholder={"Search Users"}
onChange={setFilter}
classes={classes}
/>