github.com/minio/console@v1.4.1/web-app/src/screens/Console/Policies/AddPolicyScreen.tsx (about)

     1  // This file is part of MinIO Console Server
     2  // Copyright (c) 2022 MinIO, Inc.
     3  //
     4  // This program is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Affero General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // This program is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  // GNU Affero General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Affero General Public License
    15  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16  
    17  import React, { Fragment, useEffect, useState } from "react";
    18  import {
    19    AddAccessRuleIcon,
    20    BackLink,
    21    Box,
    22    Button,
    23    FormLayout,
    24    Grid,
    25    InputBox,
    26    PageLayout,
    27  } from "mds";
    28  import AddPolicyHelpBox from "./AddPolicyHelpBox";
    29  import CodeMirrorWrapper from "../Common/FormComponents/CodeMirrorWrapper/CodeMirrorWrapper";
    30  import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper";
    31  import HelpMenu from "../HelpMenu";
    32  import { IAM_PAGES } from "../../../common/SecureComponent/permissions";
    33  import { setErrorSnackMessage, setHelpName } from "../../../systemSlice";
    34  import { useNavigate } from "react-router-dom";
    35  import { useAppDispatch } from "../../../store";
    36  import { emptyPolicy } from "./utils";
    37  import { api } from "../../../api";
    38  
    39  const AddPolicyScreen = () => {
    40    const dispatch = useAppDispatch();
    41    const navigate = useNavigate();
    42  
    43    const [addLoading, setAddLoading] = useState<boolean>(false);
    44    const [policyName, setPolicyName] = useState<string>("");
    45    const [policyDefinition, setPolicyDefinition] = useState<string>(emptyPolicy);
    46  
    47    const addRecord = (event: React.FormEvent) => {
    48      event.preventDefault();
    49      if (addLoading) {
    50        return;
    51      }
    52      setAddLoading(true);
    53      api.policies
    54        .addPolicy({
    55          name: policyName,
    56          policy: policyDefinition,
    57        })
    58        .then((res) => {
    59          setAddLoading(false);
    60          navigate(`${IAM_PAGES.POLICIES}`);
    61        })
    62        .catch((err) => {
    63          setAddLoading(false);
    64          dispatch(
    65            setErrorSnackMessage({
    66              errorMessage: "There was an error creating a Policy ",
    67              detailedError:
    68                "There was an error creating a Policy: " +
    69                (err.error.detailedMessage || "") +
    70                ". Please check Policy syntax.",
    71            }),
    72          );
    73        });
    74    };
    75  
    76    const resetForm = () => {
    77      setPolicyName("");
    78      setPolicyDefinition("");
    79    };
    80  
    81    const validatePolicyname = (policyName: string) => {
    82      if (policyName.indexOf(" ") !== -1) {
    83        return "Policy name cannot contain spaces";
    84      } else return "";
    85    };
    86  
    87    const validSave =
    88      policyName.trim() !== "" &&
    89      policyName.indexOf(" ") === -1 &&
    90      policyDefinition.trim() !== "";
    91  
    92    useEffect(() => {
    93      dispatch(setHelpName("add_policy"));
    94      // eslint-disable-next-line react-hooks/exhaustive-deps
    95    }, []);
    96    return (
    97      <Fragment>
    98        <Grid item xs={12}>
    99          <PageHeaderWrapper
   100            label={
   101              <BackLink
   102                label={"Policies"}
   103                onClick={() => navigate(IAM_PAGES.POLICIES)}
   104              />
   105            }
   106            actions={<HelpMenu />}
   107          />
   108          <PageLayout>
   109            <FormLayout
   110              title={"Create Policy"}
   111              icon={<AddAccessRuleIcon />}
   112              helpBox={<AddPolicyHelpBox />}
   113            >
   114              <form
   115                noValidate
   116                autoComplete="off"
   117                onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
   118                  addRecord(e);
   119                }}
   120              >
   121                <Grid container>
   122                  <Grid item xs={12}>
   123                    <InputBox
   124                      id="policy-name"
   125                      name="policy-name"
   126                      label="Policy Name"
   127                      autoFocus={true}
   128                      value={policyName}
   129                      error={validatePolicyname(policyName)}
   130                      onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
   131                        setPolicyName(e.target.value);
   132                      }}
   133                    />
   134                  </Grid>
   135                  <Grid item xs={12}>
   136                    <CodeMirrorWrapper
   137                      label={"Write Policy"}
   138                      value={policyDefinition}
   139                      onChange={(value) => {
   140                        setPolicyDefinition(value);
   141                      }}
   142                      editorHeight={"350px"}
   143                      helptip={
   144                        <Fragment>
   145                          <a
   146                            target="blank"
   147                            href="https://min.io/docs/minio/kubernetes/upstream/administration/identity-access-management/policy-based-access-control.html#policy-document-structure"
   148                          >
   149                            Guide to access policy structure
   150                          </a>
   151                        </Fragment>
   152                      }
   153                    />
   154                  </Grid>
   155                  <Grid item xs={12} sx={{ textAlign: "right" }}>
   156                    <Box
   157                      sx={{
   158                        display: "flex",
   159                        alignItems: "center",
   160                        justifyContent: "flex-end",
   161                        marginTop: "20px",
   162                        gap: "15px",
   163                      }}
   164                    >
   165                      <Button
   166                        id={"clear"}
   167                        type="button"
   168                        variant="regular"
   169                        onClick={resetForm}
   170                        label={"Clear"}
   171                      />
   172  
   173                      <Button
   174                        id={"save-policy"}
   175                        type="submit"
   176                        variant="callAction"
   177                        color="primary"
   178                        disabled={addLoading || !validSave}
   179                        label={"Save"}
   180                      />
   181                    </Box>
   182                  </Grid>
   183                </Grid>
   184              </form>
   185            </FormLayout>
   186          </PageLayout>
   187        </Grid>
   188      </Fragment>
   189    );
   190  };
   191  
   192  export default AddPolicyScreen;