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

     1  import {ErrorNotification, NotificationType} from 'argo-ui';
     2  import * as React from 'react';
     3  import {Form, FormApi} from 'react-form';
     4  import {ContextApis} from '../../context';
     5  import {EditablePanelItem} from './editable-panel';
     6  import {Spinner} from '../spinner';
     7  import {helpTip} from '../../../applications/components/utils';
     8  
     9  export interface EditableSectionProps<T> {
    10      title?: string | React.ReactNode;
    11      uniqueId: string;
    12      values: T;
    13      validate?: (values: T) => any;
    14      save?: (input: T, query: {validate?: boolean}) => Promise<any>;
    15      items: EditablePanelItem[];
    16      onModeSwitch?: () => any;
    17      noReadonlyMode?: boolean;
    18      view?: string | React.ReactNode;
    19      edit?: (formApi: FormApi) => React.ReactNode;
    20      collapsible?: boolean;
    21      ctx: ContextApis;
    22      isTopSection?: boolean;
    23      disabledState?: boolean;
    24      disabledDelete?: boolean;
    25      updateButtons?: (pressed: boolean) => void;
    26      deleteSource?: () => void;
    27  }
    28  
    29  interface EditableSectionState {
    30      isEditing: boolean;
    31      isSaving: boolean;
    32  }
    33  
    34  // Similar to editable-panel but it should be part of a white-box, editable-panel HOC and it can be reused one after another
    35  export class EditableSection<T = {}> extends React.Component<EditableSectionProps<T>, EditableSectionState> {
    36      private formApi: FormApi;
    37  
    38      constructor(props: EditableSectionProps<T>) {
    39          super(props);
    40          this.state = {isEditing: !!props.noReadonlyMode, isSaving: false};
    41      }
    42  
    43      public UNSAFE_componentWillReceiveProps(nextProps: EditableSectionProps<T>) {
    44          if (this.formApi && JSON.stringify(this.props.values) !== JSON.stringify(nextProps.values)) {
    45              if (nextProps.noReadonlyMode) {
    46                  this.formApi.setAllValues(nextProps.values);
    47              }
    48          }
    49      }
    50  
    51      public render() {
    52          return (
    53              <div key={this.props.uniqueId}>
    54                  {!this.props.noReadonlyMode && this.props.save && (
    55                      <div
    56                          key={this.props.uniqueId + '__panel__buttons'}
    57                          className={this.props.isTopSection ? 'editable-panel__buttons' : 'row white-box__details-row editable-panel__buttons-relative'}
    58                          style={{
    59                              top: this.props.isTopSection ? '25px' : '',
    60                              right: this.props.isTopSection ? (this.props.collapsible ? '4.5em' : '3.5em') : this.props.collapsible ? '1.0em' : '0em'
    61                          }}>
    62                          {!this.state.isEditing && (
    63                              <div className='editable-panel__buttons-relative-button'>
    64                                  <button
    65                                      key={'edit_button_' + this.props.uniqueId}
    66                                      onClick={() => {
    67                                          this.setState({isEditing: true});
    68                                          this.props.updateButtons(true);
    69                                          this.props.onModeSwitch();
    70                                      }}
    71                                      disabled={this.props.disabledState}
    72                                      className='argo-button argo-button--base'>
    73                                      Edit
    74                                  </button>{' '}
    75                                  {this.props.isTopSection && this.props.deleteSource && (
    76                                      <button
    77                                          key={'delete_button_' + this.props.uniqueId}
    78                                          onClick={() => {
    79                                              this.props.deleteSource();
    80                                          }}
    81                                          disabled={this.props.disabledDelete}
    82                                          className='argo-button argo-button--base'>
    83                                          {helpTip('Delete the source from the sources field')}
    84                                          <span style={{marginRight: '8px'}} />
    85                                          Delete
    86                                      </button>
    87                                  )}
    88                              </div>
    89                          )}
    90                          {this.state.isEditing && (
    91                              <div key={'buttons_' + this.props.uniqueId} className={!this.props.isTopSection ? 'editable-panel__buttons-relative-button' : ''}>
    92                                  <React.Fragment key={'fragment_' + this.props.uniqueId}>
    93                                      <button
    94                                          key={'save_button_' + this.props.uniqueId}
    95                                          disabled={this.state.isSaving}
    96                                          onClick={() => !this.state.isSaving && this.formApi.submitForm(null)}
    97                                          className='argo-button argo-button--base'>
    98                                          <Spinner show={this.state.isSaving} style={{marginRight: '5px'}} />
    99                                          Save
   100                                      </button>{' '}
   101                                      <button
   102                                          key={'cancel_button_' + this.props.uniqueId}
   103                                          onClick={() => {
   104                                              this.setState({isEditing: false});
   105                                              this.props.updateButtons(false);
   106                                              this.props.onModeSwitch();
   107                                          }}
   108                                          className='argo-button argo-button--base-o'>
   109                                          Cancel
   110                                      </button>
   111                                  </React.Fragment>
   112                              </div>
   113                          )}
   114                      </div>
   115                  )}
   116  
   117                  {this.props.title && (
   118                      <div className='row white-box__details-row'>
   119                          <p>{this.props.title}</p>
   120                      </div>
   121                  )}
   122  
   123                  {(!this.state.isEditing && (
   124                      <React.Fragment key={'read_' + this.props.uniqueId}>
   125                          {this.props.view}
   126                          {this.props.items
   127                              .filter(item => item.view)
   128                              .map(item => (
   129                                  <React.Fragment key={'read_' + this.props.uniqueId + '_' + (item.key || item.title)}>
   130                                      {item.before}
   131                                      <div className='row white-box__details-row'>
   132                                          <div className='columns small-3'>{item.customTitle || item.title}</div>
   133                                          <div className='columns small-9'>{item.view}</div>
   134                                      </div>
   135                                  </React.Fragment>
   136                              ))}
   137                      </React.Fragment>
   138                  )) || (
   139                      <Form
   140                          getApi={api => (this.formApi = api)}
   141                          formDidUpdate={async form => {
   142                              if (this.props.noReadonlyMode && this.props.save) {
   143                                  await this.props.save(form.values as any, {});
   144                              }
   145                          }}
   146                          onSubmit={async input => {
   147                              try {
   148                                  this.setState({isSaving: true});
   149                                  await this.props.save(input as any, {});
   150                                  this.setState({isEditing: false, isSaving: false});
   151                                  this.props.onModeSwitch();
   152                              } catch (e) {
   153                                  this.props.ctx.notifications.show({
   154                                      content: <ErrorNotification title='Unable to save changes' e={e} />,
   155                                      type: NotificationType.Error
   156                                  });
   157                              } finally {
   158                                  this.setState({isSaving: false});
   159                              }
   160                          }}
   161                          defaultValues={this.props.values}
   162                          validateError={this.props.validate}>
   163                          {api => (
   164                              <React.Fragment key={'edit_' + this.props.uniqueId}>
   165                                  {this.props.edit && this.props.edit(api)}
   166                                  {this.props.items?.map(item => (
   167                                      <React.Fragment key={'edit_' + this.props.uniqueId + '_' + (item.key || item.title)}>
   168                                          {item.before}
   169                                          <div className='row white-box__details-row'>
   170                                              <div className='columns small-3'>{(item.titleEdit && item.titleEdit(api)) || item.customTitle || item.title}</div>
   171                                              <div className='columns small-9'>{(item.edit && item.edit(api)) || item.view}</div>
   172                                          </div>
   173                                      </React.Fragment>
   174                                  ))}
   175                              </React.Fragment>
   176                          )}
   177                      </Form>
   178                  )}
   179              </div>
   180          );
   181      }
   182  }