github.com/minio/console@v1.4.1/web-app/src/screens/Console/EventDestinations/CustomForms/EditConfiguration.tsx (about)

     1  // This file is part of MinIO Console Server
     2  // Copyright (c) 2021 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, useCallback, useEffect, useState } from "react";
    18  import get from "lodash/get";
    19  import { Box, Button, Grid, Loader } from "mds";
    20  import { useLocation, useNavigate } from "react-router-dom";
    21  import { useSelector } from "react-redux";
    22  import { api } from "api";
    23  import { Configuration, ConfigurationKV } from "api/consoleApi";
    24  import { errorToHandler } from "api/errors";
    25  import {
    26    fieldsConfigurations,
    27    overrideFields,
    28    removeEmptyFields,
    29  } from "../../Configurations/utils";
    30  import {
    31    IConfigurationElement,
    32    IElementValue,
    33    IOverrideEnv,
    34    KVField,
    35  } from "../../Configurations/types";
    36  import {
    37    configurationIsLoading,
    38    setErrorSnackMessage,
    39    setHelpName,
    40    setServerNeedsRestart,
    41    setSnackBarMessage,
    42  } from "../../../../systemSlice";
    43  import { AppState, useAppDispatch } from "../../../../store";
    44  import WebhookSettings from "../WebhookSettings/WebhookSettings";
    45  import ConfTargetGeneric from "../ConfTargetGeneric";
    46  import ResetConfigurationModal from "./ResetConfigurationModal";
    47  
    48  interface IAddNotificationEndpointProps {
    49    selectedConfiguration: IConfigurationElement;
    50    className?: string;
    51  }
    52  
    53  const EditConfiguration = ({
    54    selectedConfiguration,
    55    className = "",
    56  }: IAddNotificationEndpointProps) => {
    57    const dispatch = useAppDispatch();
    58    const navigate = useNavigate();
    59    const { pathname = "" } = useLocation();
    60  
    61    let selConfigTab = pathname.substring(pathname.lastIndexOf("/") + 1);
    62    selConfigTab = selConfigTab === "settings" ? "region" : selConfigTab;
    63  
    64    //Local States
    65    const [valuesObj, setValueObj] = useState<IElementValue[]>([]);
    66    const [saving, setSaving] = useState<boolean>(false);
    67    const [configValues, setConfigValues] = useState<IElementValue[]>([]);
    68    const [configSubsysList, setConfigSubsysList] = useState<Configuration[]>([]);
    69    const [resetConfigurationOpen, setResetConfigurationOpen] =
    70      useState<boolean>(false);
    71    const [overrideEnvs, setOverrideEnvs] = useState<IOverrideEnv>({});
    72  
    73    const loadingConfig = useSelector(
    74      (state: AppState) => state.system.loadingConfigurations,
    75    );
    76  
    77    useEffect(() => {
    78      dispatch(configurationIsLoading(true));
    79    }, [selConfigTab, dispatch]);
    80  
    81    useEffect(() => {
    82      if (loadingConfig) {
    83        const configId = get(selectedConfiguration, "configuration_id", false);
    84  
    85        if (configId) {
    86          api.configs
    87            .configInfo(configId)
    88            .then((res) => {
    89              setConfigSubsysList(res.data);
    90              let values: ConfigurationKV[] = get(res.data[0], "key_values", []);
    91  
    92              const fieldsConfig: KVField[] = fieldsConfigurations[configId];
    93  
    94              const keyVals: IElementValue[] = fieldsConfig.map((field) => {
    95                const includedValue = values.find(
    96                  (element: ConfigurationKV) => element.key === field.name,
    97                );
    98                const customValue = includedValue?.value || "";
    99  
   100                return {
   101                  key: field.name,
   102                  value: field.customValueProcess
   103                    ? field.customValueProcess(customValue)
   104                    : customValue,
   105                  env_override: includedValue?.env_override,
   106                };
   107              });
   108  
   109              setConfigValues(keyVals);
   110              setOverrideEnvs(overrideFields(keyVals));
   111              dispatch(configurationIsLoading(false));
   112            })
   113            .catch((err) => {
   114              dispatch(configurationIsLoading(false));
   115              dispatch(setErrorSnackMessage(errorToHandler(err.error)));
   116            });
   117  
   118          return;
   119        }
   120        dispatch(configurationIsLoading(false));
   121      }
   122    }, [loadingConfig, selectedConfiguration, dispatch]);
   123  
   124    useEffect(() => {
   125      if (saving) {
   126        const payload = {
   127          key_values: removeEmptyFields(valuesObj),
   128        };
   129        api.configs
   130          .setConfig(selectedConfiguration.configuration_id, payload)
   131          .then((res) => {
   132            setSaving(false);
   133            dispatch(setServerNeedsRestart(res.data.restart || false));
   134            dispatch(configurationIsLoading(true));
   135            if (!res.data.restart) {
   136              dispatch(setSnackBarMessage("Configuration saved successfully"));
   137            }
   138          })
   139          .catch((err) => {
   140            setSaving(false);
   141            dispatch(setErrorSnackMessage(errorToHandler(err.error)));
   142          });
   143      }
   144    }, [saving, dispatch, selectedConfiguration, valuesObj, navigate]);
   145  
   146    //Fetch Actions
   147    const submitForm = (event: React.FormEvent) => {
   148      event.preventDefault();
   149      setSaving(true);
   150    };
   151  
   152    const onValueChange = useCallback(
   153      (newValue: IElementValue[]) => {
   154        setValueObj(newValue);
   155      },
   156      [setValueObj],
   157    );
   158  
   159    const continueReset = (restart: boolean) => {
   160      setResetConfigurationOpen(false);
   161      dispatch(setServerNeedsRestart(restart));
   162      if (restart) {
   163        dispatch(configurationIsLoading(true));
   164      }
   165    };
   166  
   167    const resetConfigurationMOpen = () => {
   168      setResetConfigurationOpen(true);
   169    };
   170  
   171    return (
   172      <Fragment>
   173        <div
   174          onMouseMove={() => {
   175            dispatch(
   176              setHelpName(
   177                `settings_${selectedConfiguration.configuration_label}`,
   178              ),
   179            );
   180          }}
   181        >
   182          {resetConfigurationOpen && (
   183            <ResetConfigurationModal
   184              configurationName={selectedConfiguration.configuration_id}
   185              closeResetModalAndRefresh={continueReset}
   186              resetOpen={resetConfigurationOpen}
   187            />
   188          )}
   189          {loadingConfig ? (
   190            <Grid item xs={12} sx={{ textAlign: "center", paddingTop: "15px" }}>
   191              <Loader />
   192            </Grid>
   193          ) : (
   194            <Box
   195              sx={{
   196                padding: "15px",
   197                height: "100%",
   198              }}
   199            >
   200              {selectedConfiguration.configuration_id === "logger_webhook" ||
   201              selectedConfiguration.configuration_id === "audit_webhook" ? (
   202                <WebhookSettings
   203                  WebhookSettingslist={configSubsysList}
   204                  setResetConfigurationOpen={resetConfigurationMOpen}
   205                  type={selectedConfiguration.configuration_id}
   206                />
   207              ) : (
   208                <Fragment>
   209                  <form
   210                    noValidate
   211                    onSubmit={submitForm}
   212                    className={className}
   213                    style={{
   214                      height: "100%",
   215                      display: "flex",
   216                      flexFlow: "column",
   217                    }}
   218                  >
   219                    <Grid
   220                      item
   221                      xs={12}
   222                      sx={{
   223                        display: "grid",
   224                        gridTemplateColumns: "1fr",
   225                        gap: "10px",
   226                      }}
   227                    >
   228                      <ConfTargetGeneric
   229                        fields={
   230                          fieldsConfigurations[
   231                            selectedConfiguration.configuration_id
   232                          ]
   233                        }
   234                        onChange={onValueChange}
   235                        defaultVals={configValues}
   236                        overrideEnv={overrideEnvs}
   237                      />
   238                    </Grid>
   239                    <Grid
   240                      item
   241                      xs={12}
   242                      sx={{
   243                        paddingTop: "15px ",
   244                        textAlign: "right" as const,
   245                        maxHeight: "60px",
   246                        display: "flex",
   247                        alignItems: "center",
   248                        justifyContent: "flex-end",
   249                      }}
   250                    >
   251                      <Button
   252                        type={"button"}
   253                        id={"restore-defaults"}
   254                        variant="secondary"
   255                        onClick={resetConfigurationMOpen}
   256                        label={"Restore Defaults"}
   257                      />
   258                      &nbsp; &nbsp;
   259                      <Button
   260                        id={"save"}
   261                        type="submit"
   262                        variant="callAction"
   263                        disabled={saving}
   264                        label={"Save"}
   265                      />
   266                    </Grid>
   267                  </form>
   268                </Fragment>
   269              )}
   270            </Box>
   271          )}
   272        </div>
   273      </Fragment>
   274    );
   275  };
   276  
   277  export default EditConfiguration;