github.com/minio/console@v1.4.1/web-app/src/screens/Console/IDP/AddIDPConfiguration.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, { useEffect, useState } from "react";
    18  import {
    19    BackLink,
    20    Button,
    21    FormLayout,
    22    Grid,
    23    InputBox,
    24    PageLayout,
    25    SectionTitle,
    26    Switch,
    27  } from "mds";
    28  import { useNavigate } from "react-router-dom";
    29  import { useAppDispatch } from "../../../store";
    30  import { modalStyleUtils } from "../Common/FormComponents/common/styleLibrary";
    31  import {
    32    setErrorSnackMessage,
    33    setHelpName,
    34    setServerNeedsRestart,
    35  } from "../../../systemSlice";
    36  import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper";
    37  import HelpMenu from "../HelpMenu";
    38  import { api } from "api";
    39  import { ApiError, HttpResponse, SetIDPResponse } from "api/consoleApi";
    40  import { errorToHandler } from "api/errors";
    41  
    42  type AddIDPConfigurationProps = {
    43    classes?: any;
    44    icon: React.ReactNode;
    45    helpBox: React.ReactNode;
    46    header: string;
    47    title: string;
    48    backLink: string;
    49    formFields: object;
    50  };
    51  
    52  const AddIDPConfiguration = ({
    53    icon,
    54    helpBox,
    55    header,
    56    backLink,
    57    title,
    58    formFields,
    59  }: AddIDPConfigurationProps) => {
    60    const extraFormFields = {
    61      name: {
    62        required: true,
    63        hasError: (s: string, editMode: boolean) => {
    64          return !s && editMode ? "Config Name is required" : "";
    65        },
    66        label: "Name",
    67        tooltip: "Name for identity provider configuration",
    68        placeholder: "Name",
    69        type: "text",
    70      },
    71      ...formFields,
    72    };
    73  
    74    const navigate = useNavigate();
    75    const dispatch = useAppDispatch();
    76  
    77    const [fields, setFields] = useState<any>({});
    78    const [loadingCreate, setLoadingCreate] = useState<boolean>(false);
    79  
    80    const validSave = () => {
    81      for (const [key, value] of Object.entries(extraFormFields)) {
    82        if (
    83          value.required &&
    84          !(
    85            fields[key] !== undefined &&
    86            fields[key] !== null &&
    87            fields[key] !== ""
    88          )
    89        ) {
    90          return false;
    91        }
    92      }
    93      return true;
    94    };
    95  
    96    const resetForm = () => {
    97      setFields({});
    98    };
    99  
   100    const addRecord = (event: React.FormEvent) => {
   101      setLoadingCreate(true);
   102      event.preventDefault();
   103      const name = fields["name"];
   104      let input = "";
   105      for (const key of Object.keys(formFields)) {
   106        if (fields[key]) {
   107          input += `${key}=${fields[key]} `;
   108        }
   109      }
   110  
   111      api.idp
   112        .createConfiguration("openid", { name, input })
   113        .then((res: HttpResponse<SetIDPResponse, ApiError>) => {
   114          navigate(backLink);
   115          dispatch(setServerNeedsRestart(res.data.restart === true));
   116        })
   117        .catch((res: HttpResponse<SetIDPResponse, ApiError>) => {
   118          dispatch(setErrorSnackMessage(errorToHandler(res.error)));
   119        })
   120        .finally(() => setLoadingCreate(false));
   121    };
   122  
   123    const renderFormField = (key: string, value: any) => {
   124      switch (value.type) {
   125        case "toggle":
   126          return (
   127            <Switch
   128              indicatorLabels={["Enabled", "Disabled"]}
   129              checked={fields[key] === "on" ? true : false}
   130              value={"is-field-enabled"}
   131              id={"is-field-enabled"}
   132              name={"is-field-enabled"}
   133              label={value.label}
   134              tooltip={value.tooltip}
   135              onChange={(e) =>
   136                setFields({ ...fields, [key]: e.target.checked ? "on" : "off" })
   137              }
   138              description=""
   139            />
   140          );
   141        default:
   142          return (
   143            <InputBox
   144              id={key}
   145              required={value.required}
   146              name={key}
   147              label={value.label}
   148              tooltip={value.tooltip}
   149              error={value.hasError(fields[key], true)}
   150              value={fields[key] ? fields[key] : ""}
   151              onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
   152                setFields({ ...fields, [key]: e.target.value })
   153              }
   154              placeholder={value.placeholder}
   155              type={value.type}
   156            />
   157          );
   158      }
   159    };
   160  
   161    useEffect(() => {
   162      dispatch(setHelpName("add_idp_config"));
   163      // eslint-disable-next-line react-hooks/exhaustive-deps
   164    }, []);
   165  
   166    return (
   167      <Grid item xs={12}>
   168        <PageHeaderWrapper
   169          label={<BackLink onClick={() => navigate(backLink)} label={header} />}
   170          actions={<HelpMenu />}
   171        />
   172        <PageLayout>
   173          <FormLayout helpBox={helpBox}>
   174            <SectionTitle icon={icon}>{title}</SectionTitle>
   175            <form
   176              noValidate
   177              autoComplete="off"
   178              onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
   179                addRecord(e);
   180              }}
   181            >
   182              <Grid container>
   183                <Grid xs={12} item>
   184                  {Object.entries(extraFormFields).map(([key, value]) =>
   185                    renderFormField(key, value),
   186                  )}
   187                  <Grid item xs={12} sx={modalStyleUtils.modalButtonBar}>
   188                    <Button
   189                      id={"clear"}
   190                      type="button"
   191                      variant="regular"
   192                      onClick={resetForm}
   193                      label={"Clear"}
   194                    />
   195  
   196                    <Button
   197                      id={"save-key"}
   198                      type="submit"
   199                      variant="callAction"
   200                      color="primary"
   201                      disabled={loadingCreate || !validSave()}
   202                      label={"Save"}
   203                    />
   204                  </Grid>
   205                </Grid>
   206              </Grid>
   207            </form>
   208          </FormLayout>
   209        </PageLayout>
   210      </Grid>
   211    );
   212  };
   213  
   214  export default AddIDPConfiguration;