github.com/argoproj/argo-cd@v1.8.7/ui/src/app/applications/components/application-operation-state/application-operation-state.tsx (about)

     1  import {Duration, NotificationType, Ticker} from 'argo-ui';
     2  import * as moment from 'moment';
     3  import * as PropTypes from 'prop-types';
     4  import * as React from 'react';
     5  
     6  import {ErrorNotification, Revision, Timestamp} from '../../../shared/components';
     7  import {AppContext} from '../../../shared/context';
     8  import * as models from '../../../shared/models';
     9  import {services} from '../../../shared/services';
    10  import * as utils from '../utils';
    11  
    12  require('./application-operation-state.scss');
    13  
    14  interface Props {
    15      application: models.Application;
    16      operationState: models.OperationState;
    17  }
    18  
    19  export const ApplicationOperationState: React.StatelessComponent<Props> = ({application, operationState}, ctx: AppContext) => {
    20      const operationAttributes = [
    21          {title: 'OPERATION', value: utils.getOperationType(application)},
    22          {title: 'PHASE', value: operationState.phase},
    23          ...(operationState.message ? [{title: 'MESSAGE', value: operationState.message}] : []),
    24          {title: 'STARTED AT', value: <Timestamp date={operationState.startedAt} />},
    25          {
    26              title: 'DURATION',
    27              value: (
    28                  <Ticker>
    29                      {time => <Duration durationMs={((operationState.finishedAt && moment(operationState.finishedAt)) || time).diff(moment(operationState.startedAt)) / 1000} />}
    30                  </Ticker>
    31              )
    32          }
    33      ];
    34  
    35      if (operationState.finishedAt && operationState.phase !== 'Running') {
    36          operationAttributes.push({title: 'FINISHED AT', value: <Timestamp date={operationState.finishedAt} />});
    37      } else if (operationState.phase !== 'Terminating') {
    38          operationAttributes.push({
    39              title: '',
    40              value: (
    41                  <button
    42                      className='argo-button argo-button--base'
    43                      onClick={async () => {
    44                          const confirmed = await ctx.apis.popup.confirm('Terminate operation', 'Are you sure you want to terminate operation?');
    45                          if (confirmed) {
    46                              try {
    47                                  await services.applications.terminateOperation(application.metadata.name);
    48                              } catch (e) {
    49                                  ctx.apis.notifications.show({
    50                                      content: <ErrorNotification title='Unable to terminate operation' e={e} />,
    51                                      type: NotificationType.Error
    52                                  });
    53                              }
    54                          }
    55                      }}>
    56                      Terminate
    57                  </button>
    58              )
    59          });
    60      }
    61      if (operationState.syncResult) {
    62          operationAttributes.push({title: 'REVISION', value: <Revision repoUrl={application.spec.source.repoURL} revision={operationState.syncResult.revision} />});
    63      }
    64      let initiator = '';
    65      if (operationState.operation.initiatedBy) {
    66          if (operationState.operation.initiatedBy.automated) {
    67              initiator = 'automated sync policy';
    68          } else {
    69              initiator = operationState.operation.initiatedBy.username;
    70          }
    71      }
    72      operationAttributes.push({title: 'INITIATED BY', value: initiator || 'Unknown'});
    73  
    74      const resultAttributes: {title: string; value: string}[] = [];
    75      const syncResult = operationState.syncResult;
    76      if (operationState.finishedAt) {
    77          if (syncResult) {
    78              (syncResult.resources || []).forEach(res => {
    79                  resultAttributes.push({
    80                      title: `${res.namespace}/${res.kind}:${res.name}`,
    81                      value: res.message
    82                  });
    83              });
    84          }
    85      }
    86  
    87      return (
    88          <div>
    89              <div className='white-box'>
    90                  <div className='white-box__details'>
    91                      {operationAttributes.map(attr => (
    92                          <div className='row white-box__details-row' key={attr.title}>
    93                              <div className='columns small-3'>{attr.title}</div>
    94                              <div className='columns small-9'>{attr.value}</div>
    95                          </div>
    96                      ))}
    97                  </div>
    98              </div>
    99              {syncResult && syncResult.resources && syncResult.resources.length > 0 && (
   100                  <React.Fragment>
   101                      <h4>Result:</h4>
   102                      <div className='argo-table-list'>
   103                          <div className='argo-table-list__head'>
   104                              <div className='row'>
   105                                  <div className='columns large-1 show-for-large application-operation-state__icons_container_padding'>KIND</div>
   106                                  <div className='columns large-2 show-for-large'>NAMESPACE</div>
   107                                  <div className='columns large-2 small-2'>NAME</div>
   108                                  <div className='columns large-1 small-2'>STATUS</div>
   109                                  <div className='columns large-1 show-for-large'>HOOK</div>
   110                                  <div className='columns large-4 small-8'>MESSAGE</div>
   111                              </div>
   112                          </div>
   113                          {syncResult.resources.map((resource, i) => (
   114                              <div className='argo-table-list__row' key={i}>
   115                                  <div className='row'>
   116                                      <div className='columns large-1 show-for-large application-operation-state__icons_container_padding'>
   117                                          <div className='application-operation-state__icons_container'>
   118                                              {resource.hookType && <i title='Resource lifecycle hook' className='fa fa-anchor' />}
   119                                          </div>
   120                                          <span title={getKind(resource)}>{getKind(resource)}</span>
   121                                      </div>
   122                                      <div className='columns large-2 show-for-large' title={resource.namespace}>
   123                                          {resource.namespace}
   124                                      </div>
   125                                      <div className='columns large-2 small-2' title={resource.name}>
   126                                          {resource.name}
   127                                      </div>
   128                                      <div className='columns large-1 small-2' title={getStatus(resource)}>
   129                                          <utils.ResourceResultIcon resource={resource} /> {getStatus(resource)}
   130                                      </div>
   131                                      <div className='columns large-1 show-for-large' title={resource.hookType}>
   132                                          {resource.hookType}
   133                                      </div>
   134                                      <div className='columns large-4 small-8' title={resource.message}>
   135                                          <div className='application-operation-state__message'>{resource.message}</div>
   136                                      </div>
   137                                  </div>
   138                              </div>
   139                          ))}
   140                      </div>
   141                  </React.Fragment>
   142              )}
   143          </div>
   144      );
   145  };
   146  
   147  const getKind = (resource: models.ResourceResult): string => {
   148      return (resource.group ? `${resource.group}/${resource.version}` : resource.version) + `/${resource.kind}`;
   149  };
   150  
   151  const getStatus = (resource: models.ResourceResult): string => {
   152      return resource.hookType ? resource.hookPhase : resource.status;
   153  };
   154  
   155  ApplicationOperationState.contextTypes = {
   156      apis: PropTypes.object
   157  };