github.com/replicatedhq/ship@v0.55.0/web/init/src/components/application_settings/ApplicationSettings.jsx (about)

     1  import React from "react";
     2  
     3  import ErrorBoundary from "../../ErrorBoundary";
     4  
     5  import isEmpty from "lodash/isEmpty";
     6  
     7  import ConfigRender from "../config_render/ConfigRender";
     8  import Toast from "../shared/Toast";
     9  
    10  // var EDITABLE_ITEM_TYPES = [
    11  //   "select", "text", "textarea", "password", "file", "bool", "select_many", "select_one",
    12  // ];
    13  
    14  export default class ApplicationSettings extends React.Component {
    15  
    16    constructor(props) {
    17      super(props);
    18      this.state = {
    19        toastDetails: {
    20          opts: {}
    21        }
    22      };
    23    }
    24  
    25    componentDidUpdate(lastProps) {
    26      const { location, settingsFields } = this.props;
    27      if (this.props.settingsFields !== lastProps.settingsFields && !isEmpty(settingsFields)) {
    28        // this.setState({ groups: settingsFields });
    29        if (location.hash) {
    30          const el = document.getElementById(location.hash.replace("#", ""));
    31          if (!el) return;
    32          el.scrollIntoView({ behavior: "smooth", block: "start" });
    33        }
    34      }
    35    }
    36  
    37    componentDidMount() {
    38      if (!this.props.settingsFieldsList.length) {
    39        this.props.getApplicationSettings({item_values: null});
    40      }
    41    }
    42  
    43    // mergeItemData(groups, data) {
    44    //   const nextGroups = map(groups, function(group) {
    45    //     group.items = map(group.items, function(item) {
    46    //       if (item.name === data.name) {
    47    //         item.value = data.value;
    48    //         item.multi_value = data.multi_value;
    49    //         if (has(data, 'data')) {
    50    //           item.data = data.data;
    51    //         }
    52    //         if (has(data, 'multi_data')) {
    53    //           item.multi_data = data.multi_data;
    54    //         }
    55    //       } else {
    56    //         item.items = map(item.items, function(childItem) {
    57    //           if (childItem.name === data.name) {
    58    //             childItem.value = data.value;
    59    //             childItem.multi_value = data.multi_value;
    60    //             if (has(data, 'data')) {
    61    //               childItem.data = data.data;
    62    //             }
    63    //             if (has(data, 'multi_data')) {
    64    //               childItem.multi_data = data.multi_data;
    65    //             }
    66    //           }
    67    //           return childItem;
    68    //         });
    69    //       }
    70    //       return item;
    71    //     });
    72    //     return group;
    73    //   });
    74    //   return nextGroups;
    75    // }
    76  
    77    // mergeGroupItemData(groups, currentGroups) {
    78    //   const getItemData = (item) => {
    79    //     let data = {
    80    //       name: item.name,
    81    //       value: item.value,
    82    //       multi_value: item.multi_value,
    83    //     };
    84    //     if (has(item, 'data')) {
    85    //       data.data = item.data;
    86    //     }
    87    //     if (has(item, 'multi_data')) {
    88    //       data.multi_data = item.multi_data;
    89    //     }
    90    //     return data;
    91    //   };
    92  
    93    //   let nextGroups = _.cloneDeep(groups);
    94    //   forEach(currentGroups, (group) => {
    95    //     forEach(group.items, (item) => {
    96    //       if (includes(EDITABLE_ITEM_TYPES, item.type) && !item.readonly) {
    97    //         nextGroups = this.mergeItemData(nextGroups, getItemData(item));
    98    //       }
    99    //       forEach(item.items, (childItem) => {
   100    //         if (includes(EDITABLE_ITEM_TYPES, childItem.type) && !childItem.readonly) {
   101    //           nextGroups = this.mergeItemData(nextGroups, getItemData(childItem));
   102    //         }
   103    //       });
   104    //     });
   105    //   });
   106    //   return nextGroups;
   107    // }
   108  
   109    cancelToast = () => {
   110      let nextState = {};
   111      nextState.toastDetails = {
   112        showToast: false,
   113        title: "",
   114        subText: "",
   115        type: "default",
   116        opts: {}
   117      };
   118      this.setState(nextState)
   119    }
   120  
   121    onConfigSaved = (data) => {
   122      let nextState = {};
   123      if (data.RunStatusText === "Starting") {
   124        nextState.toastDetails = {
   125          showToast: true,
   126          title: "Settings Saved",
   127          subText: "The app is starting.",
   128          type: "success",
   129          opts: {
   130            showCancelButton: true,
   131            cancelButtonText: "Close",
   132            confirmButtonText: "Take me to the Dashboard",
   133            confirmAction: () => { false ? () => { return; } : window.location.href = "/dashboard"; } //TODO: pass isConfirm and then should should check !isConfirm instead of false
   134          }
   135        }
   136      } else if (data.NextAction.State === "") {
   137        nextState.toastDetails = {
   138          showToast: true,
   139          title: "Settings Saved",
   140          subText: "You can restart the app at any time to apply these changes.",
   141          type: "success",
   142        }
   143      } else {
   144        let alertMsg = (
   145          `You can ${data.NextAction.Title.toLowerCase()} the app at any time to apply these changes.`
   146        );
   147        if (false) { //TODO: Should check Config.applyEnabled
   148          alertMsg = (
   149            <p>
   150              {alertMsg}<br />
   151              <i>NOTE: Applying changes may result in the application services being restarted.</i>
   152            </p>
   153          );
   154        }
   155        nextState.toastDetails = {
   156          showToast: true,
   157          title: "Settings Saved",
   158          type: "success",
   159          subText: alertMsg,
   160          opts: {
   161            showCancelButton: true,
   162            cancelButtonText: "Close",
   163            confirmButtonText: false ? "Apply Changes" : "Restart Now", //TODO: Should check Config.applyEnabled
   164            confirmAction: () => { true ? this.cancelToast()  : this.props.setApplicationState(data.NextAction.State) } //TODO: pass isConfirm and then should should check !isConfirm instead of false
   165          }
   166        }
   167      }
   168      this.setState(nextState);
   169    }
   170  
   171    handleConfigSave = async () => {
   172      await this.props.saveApplicationSettings(this.state.itemData, false)
   173        .then((response) => {
   174          this.onConfigSaved(response);
   175        })
   176    }
   177  
   178    handleConfigChange = (data) => {
   179      this.setState({ itemData: data });
   180      // const itemValues = map(data, partialRight(omit, "data", "multi_data"));
   181      // await this.props.getApplicationSettings({item_values: itemValues}, false)
   182      // .then((response) => {
   183      //   this.setState({
   184      //     groups: this.mergeGroupItemData(this.props.settingsFields, this.state.groups)
   185      //   });
   186      // })
   187      // .catch(() => {
   188      //   return;
   189      // });
   190    }
   191  
   192    render() {
   193      const {
   194        dataLoading,
   195        settingsFields,
   196        settingsFieldsList
   197      } = this.props;
   198      const { toastDetails } = this.state;
   199  
   200      return (
   201        <ErrorBoundary>
   202          <div className="flex-column flex1">
   203            <div className="flex-column flex1 u-overflow--hidden u-position--relative">
   204              <Toast toast={toastDetails} onCancel={this.cancelToast} />
   205              <div className="flex-1-auto u-overflow--auto container u-paddingTop--30">
   206                {dataLoading.appSettingsFieldsLoading || isEmpty(settingsFields) ?
   207                  <p>loading</p>
   208                  :
   209                  <ConfigRender
   210                    fieldsList={settingsFieldsList}
   211                    fields={settingsFields}
   212                    handleChange={this.handleConfigChange}
   213                  />
   214                }
   215              </div>
   216              <div className="flex-auto flex justifyContent--flexEnd layout-footer-actions">
   217                <button type="button" disabled={dataLoading.saveAppSettingsLoading} onClick={this.handleConfigSave} className="btn primary">{dataLoading.saveAppSettingsLoading ? "Saving" : "Save changes"}</button>
   218              </div>
   219            </div>
   220          </div>
   221        </ErrorBoundary>
   222      );
   223    }
   224  }