FormLayout Component (#1922)

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
This commit is contained in:
Daniel Valdivia
2022-04-28 15:13:20 -07:00
committed by GitHub
parent 0e5147bb1d
commit f79a8e8177
12 changed files with 275 additions and 774 deletions

View File

@@ -48,7 +48,7 @@ const FeatureItem = ({
</Box>
);
};
const AddUserHelpBox = ({ hasMargin = true }: { hasMargin?: boolean }) => {
const AddServiceAccountHelpBox = () => {
return (
<Box
sx={{
@@ -58,11 +58,6 @@ const AddUserHelpBox = ({ hasMargin = true }: { hasMargin?: boolean }) => {
display: "flex",
flexFlow: "column",
padding: "20px",
marginLeft: {
xs: "0px",
sm: "0px",
md: hasMargin ? "30px" : "",
},
marginTop: {
xs: "0px",
},
@@ -144,4 +139,4 @@ const AddUserHelpBox = ({ hasMargin = true }: { hasMargin?: boolean }) => {
);
};
export default AddUserHelpBox;
export default AddServiceAccountHelpBox;

View File

@@ -0,0 +1,51 @@
// This file is part of MinIO Console Server
// Copyright (c) 2022 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 { Box } from "@mui/material";
import SectionTitle from "./SectionTitle";
type Props = {
title: string;
icon: React.ReactNode;
helpbox?: React.ReactNode;
};
const FormLayout: React.FC<Props> = ({ children, title, helpbox, icon }) => {
return (
<Box
sx={{
display: "grid",
padding: "25px",
gap: "25px",
gridTemplateColumns: {
md: "2fr 1.2fr",
xs: "1fr",
},
border: "1px solid #eaeaea",
}}
>
<Box>
<SectionTitle icon={icon}>{title}</SectionTitle>
{children}
</Box>
{helpbox}
</Box>
);
};
export default FormLayout;

View File

@@ -103,7 +103,7 @@ const ObjectManager = React.lazy(
const Buckets = React.lazy(() => import("./Buckets/Buckets"));
const Policies = React.lazy(() => import("./Policies/Policies"));
const AddPolicy = React.lazy(() => import("./Policies/AddPolicyScreen"));
const AddPolicyScreen = React.lazy(() => import("./Policies/AddPolicyScreen"));
const Dashboard = React.lazy(() => import("./Dashboard/Dashboard"));
const Account = React.lazy(() => import("./Account/Account"));
@@ -311,7 +311,7 @@ const Console = ({
path: IAM_PAGES.POLICIES_VIEW,
},
{
component: AddPolicy,
component: AddPolicyScreen,
path: IAM_PAGES.POLICY_ADD,
},
{

View File

@@ -1,266 +0,0 @@
// 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, { useEffect, useState } from "react";
import { connect } from "react-redux";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import { Button, LinearProgress } from "@mui/material";
import Grid from "@mui/material/Grid";
import {
formFieldStyles,
modalStyleUtils,
spacingUtils,
} from "../Common/FormComponents/common/styleLibrary";
import { setModalErrorSnackMessage } from "../../../actions";
import { ErrorResponseHandler } from "../../../common/types";
import api from "../../../common/api";
import UsersSelectors from "./UsersSelectors";
import ModalWrapper from "../Common/ModalWrapper/ModalWrapper";
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
import FormSwitchWrapper from "../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
import PredefinedList from "../Common/FormComponents/PredefinedList/PredefinedList";
import { CreateGroupIcon } from "../../../icons";
interface IGroupProps {
open: boolean;
selectedGroup: any;
closeModalAndRefresh: any;
classes: any;
setModalErrorSnackMessage: typeof setModalErrorSnackMessage;
}
interface MainGroupProps {
members: string[];
name: string;
status: string;
}
const styles = (theme: Theme) =>
createStyles({
buttonContainer: {
textAlign: "right",
},
userSelector: {
"& .MuiPaper-root": {
padding: 0,
marginBottom: 15,
},
},
...formFieldStyles,
...spacingUtils,
...modalStyleUtils,
});
const AddGroup = ({
open,
selectedGroup,
closeModalAndRefresh,
classes,
setModalErrorSnackMessage,
}: IGroupProps) => {
//Local States
const [groupName, setGroupName] = useState<string>("");
const [groupEnabled, setGroupEnabled] = useState<boolean>(false);
const [saving, isSaving] = useState<boolean>(false);
const [selectedUsers, setSelectedUsers] = useState<string[]>([]);
const [loadingGroup, isLoadingGroup] = useState<boolean>(false);
const [validGroup, setValidGroup] = useState<boolean>(false);
//Effects
useEffect(() => {
if (selectedGroup !== null) {
isLoadingGroup(true);
} else {
setGroupName("");
setSelectedUsers([]);
}
}, [selectedGroup]);
useEffect(() => {
setValidGroup(groupName.trim() !== "");
}, [groupName, selectedUsers]);
useEffect(() => {
if (saving) {
const saveRecord = () => {
if (selectedGroup !== null) {
api
.invoke("PUT", `/api/v1/group?name=${encodeURI(groupName)}`, {
group: groupName,
members: selectedUsers,
status: groupEnabled ? "enabled" : "disabled",
})
.then((res) => {
isSaving(false);
closeModalAndRefresh();
})
.catch((err: ErrorResponseHandler) => {
isSaving(false);
setModalErrorSnackMessage(err);
});
} else {
api
.invoke("POST", "/api/v1/groups", {
group: groupName,
members: selectedUsers,
})
.then((res) => {
isSaving(false);
closeModalAndRefresh();
})
.catch((err: ErrorResponseHandler) => {
isSaving(false);
setModalErrorSnackMessage(err);
});
}
};
saveRecord();
}
}, [
saving,
groupName,
selectedUsers,
groupEnabled,
selectedGroup,
closeModalAndRefresh,
setModalErrorSnackMessage,
]);
useEffect(() => {
if (selectedGroup && loadingGroup) {
const fetchGroupInfo = () => {
api
.invoke("GET", `/api/v1/group?name=${encodeURI(selectedGroup)}`)
.then((res: MainGroupProps) => {
setGroupEnabled(res.status === "enabled");
setGroupName(res.name);
setSelectedUsers(res.members);
})
.catch((err: ErrorResponseHandler) => {
setModalErrorSnackMessage(err);
isLoadingGroup(false);
});
};
fetchGroupInfo();
}
}, [loadingGroup, selectedGroup, setModalErrorSnackMessage]);
//Fetch Actions
const setSaving = (event: React.FormEvent) => {
event.preventDefault();
isSaving(true);
};
const resetForm = () => {
if (selectedGroup === null) {
setGroupName("");
}
setSelectedUsers([]);
};
return (
<ModalWrapper
modalOpen={open}
onClose={closeModalAndRefresh}
title={selectedGroup !== null ? `Edit Group` : "Create Group"}
titleIcon={<CreateGroupIcon />}
>
{selectedGroup !== null && (
<div className={classes.floatingEnabled}>
<FormSwitchWrapper
indicatorLabels={["Enabled", "Disabled"]}
checked={groupEnabled}
value={"group_enabled"}
id="group-status"
name="group-status"
onChange={(e) => {
setGroupEnabled(e.target.checked);
}}
switchOnly
/>
</div>
)}
<form noValidate autoComplete="off" onSubmit={setSaving}>
<Grid container>
<Grid item xs={12} className={classes.modalFormScrollable}>
{selectedGroup === null ? (
<Grid item xs={12} className={classes.formFieldRow}>
<InputBoxWrapper
id="group-name"
name="group-name"
label="Group Name"
autoFocus={true}
value={groupName}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setGroupName(e.target.value);
}}
/>
</Grid>
) : (
<Grid item xs={12} className={classes.formFieldRow}>
<PredefinedList label={"Group Name"} content={selectedGroup} />
</Grid>
)}
<Grid item xs={12} className={classes.userSelector}>
<UsersSelectors
selectedUsers={selectedUsers}
setSelectedUsers={setSelectedUsers}
editMode={selectedGroup !== null}
/>
</Grid>
</Grid>
<Grid item xs={12} className={classes.buttonContainer}>
<Button
type="button"
variant="outlined"
color="primary"
className={classes.spacerRight}
onClick={resetForm}
>
Clear
</Button>
<Button
type="submit"
variant="contained"
color="primary"
disabled={saving || !validGroup}
>
Save
</Button>
</Grid>
{saving && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
</Grid>
</form>
</ModalWrapper>
);
};
const mapDispatchToProps = {
setModalErrorSnackMessage,
};
const connector = connect(null, mapDispatchToProps);
export default withStyles(styles)(connector(AddGroup));

View File

@@ -43,7 +43,7 @@ const FeatureItem = ({
</Box>
);
};
const AddGroupHelpBox = ({ hasMargin = true }: { hasMargin?: boolean }) => {
const AddGroupHelpBox = () => {
return (
<Box
sx={{
@@ -53,11 +53,6 @@ const AddGroupHelpBox = ({ hasMargin = true }: { hasMargin?: boolean }) => {
display: "flex",
flexFlow: "column",
padding: "20px",
marginLeft: {
xs: "0px",
sm: "0px",
md: hasMargin ? "30px" : "",
},
marginTop: {
xs: "0px",
},

View File

@@ -23,7 +23,7 @@ import {
modalStyleUtils,
} from "../Common/FormComponents/common/styleLibrary";
import Grid from "@mui/material/Grid";
import { Box, Button, LinearProgress } from "@mui/material";
import { Button, LinearProgress } from "@mui/material";
import PageHeader from "../Common/PageHeader/PageHeader";
import PageLayout from "../Common/Layout/PageLayout";
import history from "../../../../src/history";
@@ -37,7 +37,7 @@ import { IAM_PAGES } from "../../../common/SecureComponent/permissions";
import { ErrorResponseHandler } from "../../../../src/common/types";
import api from "../../../../src/common/api";
import { setErrorSnackMessage } from "../../../../src/actions";
import SectionTitle from "../Common/SectionTitle";
import FormLayout from "../Common/FormLayout";
interface IAddGroupProps {
classes: any;
@@ -152,81 +152,60 @@ const AddGroupScreen = ({ classes, setErrorSnackMessage }: IAddGroupProps) => {
label={<BackLink to={IAM_PAGES.GROUPS} label={"Groups"} />}
/>
<PageLayout>
<Box
sx={{
display: "grid",
padding: "25px",
gap: "25px",
gridTemplateColumns: {
md: "2fr 1.2fr",
xs: "1fr",
},
border: "1px solid #eaeaea",
}}
<FormLayout
title={"Create Group"}
icon={<CreateGroupIcon />}
helpbox={<AddGroupHelpBox />}
>
<Box>
<form noValidate autoComplete="off" onSubmit={setSaving}>
<Grid container item spacing="20">
<Grid item xs={12}>
<SectionTitle icon={<CreateGroupIcon />}>
Create Group
</SectionTitle>
</Grid>
<Grid item xs={12}>
<Grid container>
<Grid item xs={12} className={classes.formFieldRow}>
<InputBoxWrapper
id="group-name"
name="group-name"
label="Group Name"
autoFocus={true}
value={groupName}
onChange={(
e: React.ChangeEvent<HTMLInputElement>
) => {
setGroupName(e.target.value);
}}
/>
</Grid>
<Grid item xs={12} className={classes.userSelector}>
<UsersSelectors
selectedUsers={selectedUsers}
setSelectedUsers={setSelectedUsers}
editMode={true}
/>
</Grid>
</Grid>
<Grid item xs={12} className={classes.modalButtonBar}>
<Button
type="button"
variant="outlined"
color="primary"
className={classes.spacerRight}
onClick={resetForm}
>
Clear
</Button>
<Button
type="submit"
variant="contained"
color="primary"
disabled={saving || !validGroup}
>
Save
</Button>
</Grid>
</Grid>
{saving && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
<form noValidate autoComplete="off" onSubmit={setSaving}>
<Grid container marginTop={"16px"}>
<Grid item xs={12} className={classes.formFieldRow}>
<InputBoxWrapper
id="group-name"
name="group-name"
label="Group Name"
autoFocus={true}
value={groupName}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setGroupName(e.target.value);
}}
/>
</Grid>
</form>
</Box>
<AddGroupHelpBox />
</Box>
<Grid item xs={12} className={classes.userSelector}>
<UsersSelectors
selectedUsers={selectedUsers}
setSelectedUsers={setSelectedUsers}
editMode={true}
/>
</Grid>
</Grid>
<Grid item xs={12} className={classes.modalButtonBar}>
<Button
type="button"
variant="outlined"
color="primary"
className={classes.spacerRight}
onClick={resetForm}
>
Clear
</Button>
<Button
type="submit"
variant="contained"
color="primary"
disabled={saving || !validGroup}
>
Save
</Button>
</Grid>
{saving && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
</form>
</FormLayout>
</PageLayout>
</Grid>
</Fragment>

View File

@@ -45,15 +45,14 @@ import {
IAM_SCOPES,
} from "../../../common/SecureComponent/permissions";
import {
SecureComponent,
hasPermission,
SecureComponent,
} from "../../../common/SecureComponent";
import withSuspense from "../Common/Components/withSuspense";
import RBIconButton from "../Buckets/BucketDetails/SummaryItems/RBIconButton";
const DeleteGroup = withSuspense(React.lazy(() => import("./DeleteGroup")));
const AddGroup = withSuspense(React.lazy(() => import("../Groups/AddGroup")));
const SetPolicy = withSuspense(
React.lazy(() => import("../Policies/SetPolicy"))
);
@@ -80,7 +79,6 @@ const styles = (theme: Theme) =>
});
const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => {
const [addGroupOpen, setGroupOpen] = useState<boolean>(false);
const [selectedGroup, setSelectedGroup] = useState<any>(null);
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
const [loading, isLoading] = useState<boolean>(false);
@@ -134,11 +132,6 @@ const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => {
}
}, [loading, setErrorSnackMessage, displayGroups]);
const closeAddModalAndRefresh = () => {
setGroupOpen(false);
isLoading(true);
};
const closeDeleteModalAndRefresh = (refresh: boolean) => {
setDeleteOpen(false);
@@ -175,13 +168,6 @@ const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => {
return (
<React.Fragment>
{addGroupOpen && (
<AddGroup
open={addGroupOpen}
selectedGroup={selectedGroup}
closeModalAndRefresh={closeAddModalAndRefresh}
/>
)}
{deleteOpen && (
<DeleteGroup
deleteOpen={deleteOpen}

View File

@@ -1,195 +0,0 @@
// 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, { useEffect, useState } from "react";
import { connect } from "react-redux";
import Grid from "@mui/material/Grid";
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 api from "../../../common/api";
import { Policy } from "./types";
import { setModalErrorSnackMessage } from "../../../actions";
import {
fieldBasic,
modalStyleUtils,
spacingUtils,
} from "../Common/FormComponents/common/styleLibrary";
import { ErrorResponseHandler } from "../../../common/types";
import ModalWrapper from "../Common/ModalWrapper/ModalWrapper";
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
import CodeMirrorWrapper from "../Common/FormComponents/CodeMirrorWrapper/CodeMirrorWrapper";
const styles = (theme: Theme) =>
createStyles({
buttonContainer: {
textAlign: "right",
},
codeMirrorContainer: {
marginBottom: 20,
marginTop: 20,
"& label": {
marginBottom: ".5rem",
},
"& label + div": {
display: "none",
},
},
...spacingUtils,
...modalStyleUtils,
...fieldBasic,
});
interface IAddPolicyProps {
classes: any;
open: boolean;
closeModalAndRefresh: (refresh: boolean) => void;
policyEdit: Policy;
setModalErrorSnackMessage: typeof setModalErrorSnackMessage;
}
const AddPolicy = ({
classes,
open,
closeModalAndRefresh,
policyEdit,
setModalErrorSnackMessage,
}: IAddPolicyProps) => {
const [addLoading, setAddLoading] = useState<boolean>(false);
const [policyName, setPolicyName] = useState<string>("");
const [policyDefinition, setPolicyDefinition] = useState<string>("");
const addRecord = (event: React.FormEvent) => {
event.preventDefault();
if (addLoading) {
return;
}
setAddLoading(true);
api
.invoke("POST", "/api/v1/policies", {
name: policyName,
policy: policyDefinition,
})
.then((res) => {
setAddLoading(false);
closeModalAndRefresh(true);
})
.catch((err: ErrorResponseHandler) => {
setAddLoading(false);
setModalErrorSnackMessage(err);
});
};
useEffect(() => {
if (policyEdit) {
setPolicyName(policyEdit.name);
setPolicyDefinition(
policyEdit ? JSON.stringify(JSON.parse(policyEdit.policy), null, 4) : ""
);
}
}, [policyEdit]);
const resetForm = () => {
setPolicyName("");
setPolicyDefinition("");
};
const validSave = policyName.trim() !== "";
return (
<ModalWrapper
modalOpen={open}
onClose={() => {
closeModalAndRefresh(false);
}}
title={`${policyEdit ? "Info" : "Create"} Policy`}
>
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
addRecord(e);
}}
>
<Grid container>
<Grid item xs={12} className={classes.modalFormScrollable}>
<Grid item xs={12} className={classes.formFieldRow}>
<InputBoxWrapper
id="policy-name"
name="policy-name"
label="Policy Name"
placeholder="Enter Policy Name"
autoFocus={true}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setPolicyName(e.target.value);
}}
value={policyName}
disabled={!!policyEdit}
/>
</Grid>
<Grid item xs={12} className={classes.codeMirrorContainer}>
<CodeMirrorWrapper
label={`${policyEdit ? "Edit" : "Write"} Policy`}
value={policyDefinition}
onBeforeChange={(editor, data, value) => {
setPolicyDefinition(value);
}}
editorHeight={"350px"}
/>
</Grid>
</Grid>
<Grid item xs={12} className={classes.modalButtonBar}>
{!policyEdit && (
<Button
type="button"
variant="outlined"
color="primary"
onClick={resetForm}
>
Clear
</Button>
)}
<Button
type="submit"
variant="contained"
color="primary"
disabled={addLoading || !validSave}
>
Save
</Button>
</Grid>
{addLoading && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
</Grid>
</form>
</ModalWrapper>
);
};
const mapDispatchToProps = {
setModalErrorSnackMessage,
};
const connector = connect(null, mapDispatchToProps);
export default withStyles(styles)(connector(AddPolicy));

View File

@@ -43,7 +43,8 @@ const FeatureItem = ({
</Box>
);
};
const AddPolicyHelpBox = ({ hasMargin = true }: { hasMargin?: boolean }) => {
const AddPolicyHelpBox = () => {
return (
<Box
sx={{
@@ -53,14 +54,6 @@ const AddPolicyHelpBox = ({ hasMargin = true }: { hasMargin?: boolean }) => {
display: "flex",
flexFlow: "column",
padding: "20px",
marginLeft: {
xs: "0px",
sm: "0px",
md: hasMargin ? "30px" : "",
},
marginTop: {
xs: "0px",
},
}}
>
<Box

View File

@@ -37,6 +37,7 @@ import { IAM_PAGES } from "../../../common/SecureComponent/permissions";
import { ErrorResponseHandler } from "../../../../src/common/types";
import api from "../../../../src/common/api";
import { setErrorSnackMessage } from "../../../../src/actions";
import FormLayout from "../Common/FormLayout";
interface IAddPolicyProps {
classes: any;
@@ -143,90 +144,73 @@ const AddPolicyScreen = ({
label={<BackLink to={IAM_PAGES.POLICIES} label={"Policies"} />}
/>
<PageLayout>
<Grid
item
xs={12}
container
className={classes.title}
align-items="stretch"
<FormLayout
title={"Create Policy"}
icon={<AddAccessRuleIcon />}
helpbox={<AddPolicyHelpBox />}
>
<Grid item className={classes.headIcon}>
<AddAccessRuleIcon />
</Grid>
<Grid item className={classes.headTitle}>
Create Policy
</Grid>
</Grid>
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
addRecord(e);
}}
>
<Grid container item spacing={1} marginTop={"8px"}>
<Grid item xs={12}>
<InputBoxWrapper
id="policy-name"
name="policy-name"
label="Policy Name"
autoFocus={true}
value={policyName}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setPolicyName(e.target.value);
}}
/>
</Grid>
<Grid item xs={12}>
<CodeMirrorWrapper
label={"Write Policy"}
value={policyDefinition}
onBeforeChange={(editor, data, value) => {
setPolicyDefinition(value);
}}
editorHeight={"350px"}
/>
</Grid>
<Grid item xs={12} textAlign={"right"}>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "flex-end",
marginTop: "20px",
gap: "15px",
}}
>
<Button
type="button"
variant="outlined"
color="primary"
onClick={resetForm}
>
Clear
</Button>
<Grid container align-items="center">
<Grid item xs={8}>
<Box>
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
addRecord(e);
}}
>
<Grid container item spacing="20">
<Grid item xs={12}>
<Grid container>
<Grid item xs={12} className={classes.formFieldRow}>
<InputBoxWrapper
id="policy-name"
name="policy-name"
label="Policy Name"
autoFocus={true}
value={policyName}
onChange={(
e: React.ChangeEvent<HTMLInputElement>
) => {
setPolicyName(e.target.value);
}}
/>
</Grid>
<Grid item xs={12} className={classes.userSelector}>
<CodeMirrorWrapper
label={"Write Policy"}
value={policyDefinition}
onBeforeChange={(editor, data, value) => {
setPolicyDefinition(value);
}}
editorHeight={"350px"}
/>
</Grid>
</Grid>
<Grid item xs={12} className={classes.modalButtonBar}>
<Button
type="button"
variant="outlined"
color="primary"
className={classes.spacerRight}
onClick={resetForm}
>
Clear
</Button>
<Button
type="submit"
variant="contained"
color="primary"
disabled={addLoading || !validSave}
>
Save
</Button>
</Grid>
</Grid>
</Grid>
</form>
</Box>
</Grid>
<Grid item xs={4}>
<Box>
<AddPolicyHelpBox />
</Box>
</Grid>
</Grid>
<Button
type="submit"
variant="contained"
color="primary"
disabled={addLoading || !validSave}
>
Save
</Button>
</Box>
</Grid>
</Grid>
</form>
</FormLayout>
</PageLayout>
</Grid>
</Fragment>

View File

@@ -48,7 +48,7 @@ const FeatureItem = ({
</Box>
);
};
const AddUserHelpBox = ({ hasMargin = true }: { hasMargin?: boolean }) => {
const AddUserHelpBox = () => {
return (
<Box
sx={{
@@ -58,11 +58,6 @@ const AddUserHelpBox = ({ hasMargin = true }: { hasMargin?: boolean }) => {
display: "flex",
flexFlow: "column",
padding: "20px",
marginLeft: {
xs: "0px",
sm: "0px",
md: hasMargin ? "30px" : "",
},
marginTop: {
xs: "0px",
},

View File

@@ -23,7 +23,7 @@ import {
modalStyleUtils,
} from "../Common/FormComponents/common/styleLibrary";
import Grid from "@mui/material/Grid";
import { Box, Button, LinearProgress } from "@mui/material";
import { Button, LinearProgress } from "@mui/material";
import { CreateUserIcon } from "../../../icons";
import PageHeader from "../Common/PageHeader/PageHeader";
@@ -44,8 +44,9 @@ import { ErrorResponseHandler } from "../../../../src/common/types";
import api from "../../../../src/common/api";
import { setErrorSnackMessage } from "../../../../src/actions";
import SectionTitle from "../Common/SectionTitle";
import AddUserHelpBox from "../Account/AddServiceAccountHelpBox";
import FormLayout from "../Common/FormLayout";
import AddUserHelpBox from "./AddUserHelpBox";
interface IAddUserProps {
classes: any;
@@ -159,120 +160,103 @@ const AddUser = ({ classes, setErrorSnackMessage }: IAddUserProps) => {
<Grid item xs={12}>
<PageHeader label={<BackLink to={IAM_PAGES.USERS} label={"Users"} />} />
<PageLayout>
<Box
sx={{
display: "grid",
padding: "25px",
gap: "25px",
gridTemplateColumns: {
md: "2fr 1.2fr",
xs: "1fr",
},
border: "1px solid #eaeaea",
}}
<FormLayout
title={"Create User"}
icon={<CreateUserIcon />}
helpbox={<AddUserHelpBox />}
>
<Box>
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
saveRecord(e);
}}
>
<Grid container spacing={1}>
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
saveRecord(e);
}}
>
<Grid item xs={12}>
<div className={classes.formFieldRow}>
<InputBoxWrapper
className={classes.spacerBottom}
classes={{
inputLabel: classes.sizedLabel,
}}
id="accesskey-input"
name="accesskey-input"
label="User Name"
value={accessKey}
autoFocus={true}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setAccessKey(e.target.value);
}}
/>
</div>
<div className={classes.formFieldRow}>
<InputBoxWrapper
className={classes.spacerBottom}
classes={{
inputLabel: classes.sizedLabel,
}}
id="standard-multiline-static"
name="standard-multiline-static"
label="Password"
type={showPassword ? "text" : "password"}
value={secretKey}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setSecretKey(e.target.value);
}}
autoComplete="current-password"
overlayIcon={
showPassword ? (
<VisibilityOffIcon />
) : (
<RemoveRedEyeIcon />
)
}
overlayAction={() => setShowPassword(!showPassword)}
/>
</div>
<Grid container item spacing="20">
<Grid item xs={12}>
<SectionTitle icon={<CreateUserIcon />}>
Create User
</SectionTitle>
<PolicySelectors
selectedPolicy={selectedPolicies}
setSelectedPolicy={setSelectedPolicies}
/>
</Grid>
<Grid item xs={12}>
<div className={classes.formFieldRow}>
<InputBoxWrapper
className={classes.spacerBottom}
classes={{
inputLabel: classes.sizedLabel,
}}
id="accesskey-input"
name="accesskey-input"
label="User Name"
value={accessKey}
autoFocus={true}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setAccessKey(e.target.value);
}}
/>
</div>
<div className={classes.formFieldRow}>
<InputBoxWrapper
className={classes.spacerBottom}
classes={{
inputLabel: classes.sizedLabel,
}}
id="standard-multiline-static"
name="standard-multiline-static"
label="Password"
type={showPassword ? "text" : "password"}
value={secretKey}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setSecretKey(e.target.value);
}}
autoComplete="current-password"
overlayIcon={
showPassword ? (
<VisibilityOffIcon />
) : (
<RemoveRedEyeIcon />
)
}
overlayAction={() => setShowPassword(!showPassword)}
/>
</div>
<Grid container item spacing="20">
<Grid item xs={12}>
<PolicySelectors
selectedPolicy={selectedPolicies}
setSelectedPolicy={setSelectedPolicies}
/>
</Grid>
<Grid item xs={12}>
<GroupsSelectors
selectedGroups={selectedGroups}
setSelectedGroups={(elements: string[]) => {
setSelectedGroups(elements);
}}
/>
</Grid>
</Grid>
{addLoading && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
</Grid>
<Grid item xs={12} className={classes.modalButtonBar}>
<Button
type="button"
variant="outlined"
color="primary"
onClick={resetForm}
>
Clear
</Button>
<Button
type="submit"
variant="contained"
color="primary"
disabled={addLoading || !sendEnabled}
>
Save
</Button>
<GroupsSelectors
selectedGroups={selectedGroups}
setSelectedGroups={(elements: string[]) => {
setSelectedGroups(elements);
}}
/>
</Grid>
</Grid>
</form>
</Box>
<AddUserHelpBox />
</Box>
{addLoading && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
</Grid>
<Grid item xs={12} className={classes.modalButtonBar}>
<Button
type="button"
variant="outlined"
color="primary"
onClick={resetForm}
>
Clear
</Button>
<Button
type="submit"
variant="contained"
color="primary"
disabled={addLoading || !sendEnabled}
>
Save
</Button>
</Grid>
</form>
</FormLayout>
</PageLayout>
</Grid>
</Fragment>