FormLayout Component (#1922)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
This commit is contained in:
@@ -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;
|
||||
|
||||
51
portal-ui/src/screens/Console/Common/FormLayout.tsx
Normal file
51
portal-ui/src/screens/Console/Common/FormLayout.tsx
Normal 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;
|
||||
@@ -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,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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));
|
||||
@@ -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",
|
||||
},
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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));
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user