github.com/argoproj/argo-cd/v2@v2.10.9/ui/src/app/shared/components/editable-panel/editable-panel.tsx (about)

     1  import {ErrorNotification, NotificationType} from 'argo-ui';
     2  import * as classNames from 'classnames';
     3  import * as React from 'react';
     4  import {Form, FormApi} from 'react-form';
     5  import {helpTip} from '../../../applications/components/utils';
     6  import {Consumer} from '../../context';
     7  import {Spinner} from '../spinner';
     8  
     9  export interface EditablePanelItem {
    10      title: string;
    11      customTitle?: string | React.ReactNode;
    12      key?: string;
    13      before?: React.ReactNode;
    14      view: string | React.ReactNode;
    15      edit?: (formApi: FormApi) => React.ReactNode;
    16      titleEdit?: (formApi: FormApi) => React.ReactNode;
    17  }
    18  
    19  export interface EditablePanelProps<T> {
    20      title?: string | React.ReactNode;
    21      values: T;
    22      validate?: (values: T) => any;
    23      save?: (input: T, query: {validate?: boolean}) => Promise<any>;
    24      items: EditablePanelItem[];
    25      onModeSwitch?: () => any;
    26      noReadonlyMode?: boolean;
    27      view?: string | React.ReactNode;
    28      edit?: (formApi: FormApi) => React.ReactNode;
    29      hasMultipleSources?: boolean;
    30  }
    31  
    32  interface EditablePanelState {
    33      edit: boolean;
    34      saving: boolean;
    35  }
    36  
    37  require('./editable-panel.scss');
    38  
    39  export class EditablePanel<T = {}> extends React.Component<EditablePanelProps<T>, EditablePanelState> {
    40      private formApi: FormApi;
    41  
    42      constructor(props: EditablePanelProps<T>) {
    43          super(props);
    44          this.state = {edit: !!props.noReadonlyMode, saving: false};
    45      }
    46  
    47      public UNSAFE_componentWillReceiveProps(nextProps: EditablePanelProps<T>) {
    48          if (this.formApi && JSON.stringify(this.props.values) !== JSON.stringify(nextProps.values)) {
    49              if (!!nextProps.noReadonlyMode) {
    50                  this.formApi.setAllValues(nextProps.values);
    51              }
    52          }
    53      }
    54  
    55      public render() {
    56          return (
    57              <Consumer>
    58                  {ctx => (
    59                      <div className={classNames('white-box editable-panel', {'editable-panel--disabled': this.state.saving})}>
    60                          <div className='white-box__details'>
    61                              {!this.props.noReadonlyMode && this.props.save && (
    62                                  <div className='editable-panel__buttons'>
    63                                      {!this.state.edit && (
    64                                          <button
    65                                              onClick={() => {
    66                                                  this.setState({edit: true});
    67                                                  this.onModeSwitch();
    68                                              }}
    69                                              disabled={this.props.hasMultipleSources}
    70                                              className='argo-button argo-button--base'>
    71                                              {this.props.hasMultipleSources &&
    72                                                  helpTip('Parameters are not editable for applications with multiple sources. You can edit them in the "Manifest" tab.')}{' '}
    73                                              Edit
    74                                          </button>
    75                                      )}
    76                                      {this.state.edit && (
    77                                          <React.Fragment>
    78                                              <button
    79                                                  disabled={this.state.saving}
    80                                                  onClick={() => !this.state.saving && this.formApi.submitForm(null)}
    81                                                  className='argo-button argo-button--base'>
    82                                                  <Spinner show={this.state.saving} style={{marginRight: '5px'}} />
    83                                                  Save
    84                                              </button>{' '}
    85                                              <button
    86                                                  onClick={() => {
    87                                                      this.setState({edit: false});
    88                                                      this.onModeSwitch();
    89                                                  }}
    90                                                  className='argo-button argo-button--base-o'>
    91                                                  Cancel
    92                                              </button>
    93                                          </React.Fragment>
    94                                      )}
    95                                  </div>
    96                              )}
    97                              {this.props.title && <p>{this.props.title}</p>}
    98                              {(!this.state.edit && (
    99                                  <React.Fragment>
   100                                      {this.props.view}
   101                                      {this.props.items
   102                                          .filter(item => item.view)
   103                                          .map(item => (
   104                                              <React.Fragment key={item.key || item.title}>
   105                                                  {item.before}
   106                                                  <div className='row white-box__details-row'>
   107                                                      <div className='columns small-3'>{item.customTitle || item.title}</div>
   108                                                      <div className='columns small-9'>{item.view}</div>
   109                                                  </div>
   110                                              </React.Fragment>
   111                                          ))}
   112                                  </React.Fragment>
   113                              )) || (
   114                                  <Form
   115                                      getApi={api => (this.formApi = api)}
   116                                      formDidUpdate={async form => {
   117                                          if (this.props.noReadonlyMode && this.props.save) {
   118                                              await this.props.save(form.values as any, {});
   119                                          }
   120                                      }}
   121                                      onSubmit={async input => {
   122                                          try {
   123                                              this.setState({saving: true});
   124                                              await this.props.save(input as any, {});
   125                                              this.setState({edit: false, saving: false});
   126                                              this.onModeSwitch();
   127                                          } catch (e) {
   128                                              ctx.notifications.show({
   129                                                  content: <ErrorNotification title='Unable to save changes' e={e} />,
   130                                                  type: NotificationType.Error
   131                                              });
   132                                          } finally {
   133                                              this.setState({saving: false});
   134                                          }
   135                                      }}
   136                                      defaultValues={this.props.values}
   137                                      validateError={this.props.validate}>
   138                                      {api => (
   139                                          <React.Fragment>
   140                                              {this.props.edit && this.props.edit(api)}
   141                                              {this.props.items.map(item => (
   142                                                  <React.Fragment key={item.key || item.title}>
   143                                                      {item.before}
   144                                                      <div className='row white-box__details-row'>
   145                                                          <div className='columns small-3'>{(item.titleEdit && item.titleEdit(api)) || item.customTitle || item.title}</div>
   146                                                          <div className='columns small-9'>{(item.edit && item.edit(api)) || item.view}</div>
   147                                                      </div>
   148                                                  </React.Fragment>
   149                                              ))}
   150                                          </React.Fragment>
   151                                      )}
   152                                  </Form>
   153                              )}
   154                          </div>
   155                      </div>
   156                  )}
   157              </Consumer>
   158          );
   159      }
   160  
   161      private onModeSwitch() {
   162          if (this.props.onModeSwitch) {
   163              this.props.onModeSwitch();
   164          }
   165      }
   166  }