Created Add Policy screen (#1896)
This commit is contained in:
@@ -127,6 +127,7 @@ export const IAM_PAGES = {
|
||||
ACCOUNT_ADD: "/identity/new-account",
|
||||
/* Access */
|
||||
POLICIES: "/access/policies",
|
||||
POLICY_ADD: "/access/add-policy",
|
||||
POLICIES_VIEW: "/access/policies/*",
|
||||
/* Monitoring */
|
||||
TOOLS_LOGS: "/tools/logs",
|
||||
@@ -329,6 +330,9 @@ export const IAM_PAGES_PERMISSIONS = {
|
||||
IAM_SCOPES.ADMIN_LIST_USER_POLICIES, // displays policies
|
||||
IAM_SCOPES.ADMIN_CREATE_POLICY, // displays create policy button
|
||||
],
|
||||
[IAM_PAGES.POLICY_ADD]: [
|
||||
IAM_SCOPES.ADMIN_CREATE_POLICY, // displays create policy button
|
||||
],
|
||||
[IAM_PAGES.SETTINGS]: [
|
||||
IAM_SCOPES.ADMIN_CONFIG_UPDATE, // displays configuration list
|
||||
],
|
||||
|
||||
@@ -102,6 +102,8 @@ 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 Dashboard = React.lazy(() => import("./Dashboard/Dashboard"));
|
||||
|
||||
const Account = React.lazy(() => import("./Account/Account"));
|
||||
@@ -304,6 +306,10 @@ const Console = ({
|
||||
component: Policies,
|
||||
path: IAM_PAGES.POLICIES_VIEW,
|
||||
},
|
||||
{
|
||||
component: AddPolicy,
|
||||
path: IAM_PAGES.POLICY_ADD,
|
||||
},
|
||||
{
|
||||
component: Policies,
|
||||
path: IAM_PAGES.POLICIES,
|
||||
|
||||
105
portal-ui/src/screens/Console/Policies/AddPolicyHelpBox.tsx
Normal file
105
portal-ui/src/screens/Console/Policies/AddPolicyHelpBox.tsx
Normal file
@@ -0,0 +1,105 @@
|
||||
// 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 {
|
||||
HelpIconFilled,
|
||||
IAMPoliciesIcon,
|
||||
} from "../../../icons";
|
||||
|
||||
const FeatureItem = ({
|
||||
icon,
|
||||
description,
|
||||
}: {
|
||||
icon: any;
|
||||
description: string;
|
||||
}) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
"& .min-icon": {
|
||||
marginRight: "10px",
|
||||
height: "23px",
|
||||
width: "23px",
|
||||
marginBottom: "10px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{icon}{" "}
|
||||
<div style={{ fontSize: "14px", fontStyle: "italic", color: "#5E5E5E" }}>
|
||||
{description}
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
const AddPolicyHelpBox = ({ hasMargin = true }: { hasMargin?: boolean }) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
flex: 1,
|
||||
border: "1px solid #eaeaea",
|
||||
borderRadius: "2px",
|
||||
display: "flex",
|
||||
flexFlow: "column",
|
||||
padding: "20px",
|
||||
marginLeft: {
|
||||
xs: "0px",
|
||||
sm: "0px",
|
||||
md: hasMargin ? "30px" : "",
|
||||
},
|
||||
marginTop: {
|
||||
xs: "0px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
fontSize: "16px",
|
||||
fontWeight: 600,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
marginBottom: "16px",
|
||||
paddingBottom: "20px",
|
||||
|
||||
"& .min-icon": {
|
||||
height: "21px",
|
||||
width: "21px",
|
||||
marginRight: "15px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<HelpIconFilled />
|
||||
<div>Learn more about Policies</div>
|
||||
</Box>
|
||||
<Box sx={{ fontSize: "14px", marginBottom: "15px" }}>
|
||||
<Box sx={{paddingBottom: "20px"}}>
|
||||
<FeatureItem icon={<IAMPoliciesIcon />} description={`Create Policies`} />
|
||||
<Box sx={{ paddingTop: "20px"}}>
|
||||
MinIO uses Policy-Based Access Control (PBAC) to define the authorized actions and resources to which an authenticated user has access. Each policy describes one or more actions and conditions that outline the permissions of a user or group of users. </Box>
|
||||
</Box>
|
||||
<Box sx={{paddingBottom: "20px"}}>
|
||||
MinIO PBAC is built for compatibility with AWS IAM policy syntax, structure, and behavior.
|
||||
</Box>
|
||||
<Box sx={{paddingBottom: "20px"}}>
|
||||
Each user can access only those resources and operations which are explicitly granted by the built-in role. MinIO denies access to any other resource or action by default.
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddPolicyHelpBox;
|
||||
242
portal-ui/src/screens/Console/Policies/AddPolicyScreen.tsx
Normal file
242
portal-ui/src/screens/Console/Policies/AddPolicyScreen.tsx
Normal file
@@ -0,0 +1,242 @@
|
||||
// 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, { Fragment, useState } from "react";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import {
|
||||
formFieldStyles,
|
||||
modalStyleUtils,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { Button, Box} from "@mui/material";
|
||||
import PageHeader from "../Common/PageHeader/PageHeader";
|
||||
import history from "../../../../src/history";
|
||||
import PageLayout from "../Common/Layout/PageLayout";
|
||||
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import AddPolicyHelpBox from "./AddPolicyHelpBox";
|
||||
import CodeMirrorWrapper from "../Common/FormComponents/CodeMirrorWrapper/CodeMirrorWrapper";
|
||||
import BackLink from "../../../common/BackLink";
|
||||
import { connect } from "react-redux";
|
||||
import { AddAccessRuleIcon } from "../../../icons";
|
||||
import { IAM_PAGES } from "../../../common/SecureComponent/permissions";
|
||||
import { ErrorResponseHandler } from "../../../../src/common/types";
|
||||
import api from "../../../../src/common/api";
|
||||
import { setErrorSnackMessage } from "../../../../src/actions";
|
||||
|
||||
interface IAddPolicyProps {
|
||||
classes: any;
|
||||
setErrorSnackMessage: typeof setErrorSnackMessage;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
buttonContainer: {
|
||||
textAlign: "right",
|
||||
},
|
||||
bottomContainer: {
|
||||
display: "flex",
|
||||
flexGrow: 1,
|
||||
alignItems: "center",
|
||||
margin: "auto",
|
||||
justifyContent: "center",
|
||||
"& div": {
|
||||
width: 150,
|
||||
"@media (max-width: 900px)": {
|
||||
flexFlow: "column",
|
||||
},
|
||||
},
|
||||
},
|
||||
factorElements: {
|
||||
display: "flex",
|
||||
justifyContent: "flex-start",
|
||||
marginLeft: 30,
|
||||
},
|
||||
sizeNumber: {
|
||||
fontSize: 35,
|
||||
fontWeight: 700,
|
||||
textAlign: "center",
|
||||
},
|
||||
sizeDescription: {
|
||||
fontSize: 14,
|
||||
color: "#777",
|
||||
textAlign: "center",
|
||||
},
|
||||
pageBox: {
|
||||
border: "1px solid #EAEAEA",
|
||||
borderTop: 0,
|
||||
},
|
||||
addPoolTitle: {
|
||||
border: "1px solid #EAEAEA",
|
||||
borderBottom: 0,
|
||||
},
|
||||
headTitle: {
|
||||
fontWeight: "bold",
|
||||
fontSize: 20,
|
||||
paddingLeft: 20,
|
||||
paddingBottom: 40,
|
||||
paddingTop: 8,
|
||||
textAlign: "end",
|
||||
},
|
||||
headIcon: {
|
||||
fontWeight: "bold",
|
||||
size: "50",
|
||||
},
|
||||
...formFieldStyles,
|
||||
...modalStyleUtils,
|
||||
});
|
||||
|
||||
const AddPolicyScreen = ({
|
||||
classes,
|
||||
setErrorSnackMessage,
|
||||
}: 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);
|
||||
history.push(`${IAM_PAGES.POLICIES}`);
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
setAddLoading(false);
|
||||
setErrorSnackMessage(err);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const resetForm = () => {
|
||||
setPolicyName("");
|
||||
setPolicyDefinition("");
|
||||
};
|
||||
|
||||
const validSave = policyName.trim() !== "";
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Grid item xs={12}>
|
||||
<PageHeader
|
||||
label={<BackLink to={IAM_PAGES.POLICIES} label={"Policies"} />}
|
||||
/>
|
||||
<PageLayout>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
container
|
||||
className={classes.title}
|
||||
align-items="stretch"
|
||||
>
|
||||
<Grid item className={classes.headIcon}>
|
||||
<AddAccessRuleIcon />
|
||||
</Grid>
|
||||
<Grid item className={classes.headTitle}>
|
||||
Create Policy
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<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>
|
||||
</PageLayout>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const mapDispatchToProps = {
|
||||
setErrorSnackMessage,
|
||||
};
|
||||
|
||||
const connector = connect(null, mapDispatchToProps);
|
||||
|
||||
export default withStyles(styles)(connector(AddPolicyScreen));
|
||||
@@ -51,7 +51,6 @@ import SearchBox from "../Common/SearchBox";
|
||||
import withSuspense from "../Common/Components/withSuspense";
|
||||
import RBIconButton from "../Buckets/BucketDetails/SummaryItems/RBIconButton";
|
||||
|
||||
const AddPolicy = withSuspense(React.lazy(() => import("./AddPolicy")));
|
||||
const DeletePolicy = withSuspense(React.lazy(() => import("./DeletePolicy")));
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
@@ -73,12 +72,9 @@ interface IPoliciesProps {
|
||||
const ListPolicies = ({ classes, setErrorSnackMessage }: IPoliciesProps) => {
|
||||
const [records, setRecords] = useState<Policy[]>([]);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [addScreenOpen, setAddScreenOpen] = useState<boolean>(false);
|
||||
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
|
||||
const [selectedPolicy, setSelectedPolicy] = useState<string>("");
|
||||
const [filterPolicies, setFilterPolicies] = useState<string>("");
|
||||
const [policyEdit, setPolicyEdit] = useState<any>(null);
|
||||
|
||||
const viewPolicy = hasPermission(CONSOLE_UI_RESOURCE, [
|
||||
IAM_SCOPES.ADMIN_GET_POLICY,
|
||||
]);
|
||||
@@ -132,14 +128,6 @@ const ListPolicies = ({ classes, setErrorSnackMessage }: IPoliciesProps) => {
|
||||
setLoading(true);
|
||||
};
|
||||
|
||||
const closeAddModalAndRefresh = (refresh: boolean) => {
|
||||
setAddScreenOpen(false);
|
||||
|
||||
if (refresh) {
|
||||
fetchRecords();
|
||||
}
|
||||
};
|
||||
|
||||
const closeDeleteModalAndRefresh = (refresh: boolean) => {
|
||||
setDeleteOpen(false);
|
||||
|
||||
@@ -177,13 +165,6 @@ const ListPolicies = ({ classes, setErrorSnackMessage }: IPoliciesProps) => {
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{addScreenOpen && (
|
||||
<AddPolicy
|
||||
open={addScreenOpen}
|
||||
closeModalAndRefresh={closeAddModalAndRefresh}
|
||||
policyEdit={policyEdit}
|
||||
/>
|
||||
)}
|
||||
{deleteOpen && (
|
||||
<DeletePolicy
|
||||
deleteOpen={deleteOpen}
|
||||
@@ -214,8 +195,7 @@ const ListPolicies = ({ classes, setErrorSnackMessage }: IPoliciesProps) => {
|
||||
color="primary"
|
||||
icon={<AddIcon />}
|
||||
onClick={() => {
|
||||
setAddScreenOpen(true);
|
||||
setPolicyEdit(null);
|
||||
history.push(`${IAM_PAGES.POLICY_ADD}`);
|
||||
}}
|
||||
/>
|
||||
</SecureComponent>
|
||||
|
||||
Reference in New Issue
Block a user