github.com/argoproj/argo-cd/v2@v2.10.9/ui/src/app/settings/components/cluster-details/cluster-details.tsx (about)

     1  import * as classNames from 'classnames';
     2  import * as moment from 'moment';
     3  import * as React from 'react';
     4  import {FieldApi, FormField as ReactFormField, Text} from 'react-form';
     5  import {RouteComponentProps} from 'react-router-dom';
     6  import {from, timer} from 'rxjs';
     7  import {mergeMap} from 'rxjs/operators';
     8  
     9  import {FormField, Ticker} from 'argo-ui';
    10  import {ConnectionStateIcon, DataLoader, EditablePanel, Page, Timestamp, MapInputField} from '../../../shared/components';
    11  import {Cluster} from '../../../shared/models';
    12  import {services} from '../../../shared/services';
    13  
    14  function isRefreshRequested(cluster: Cluster): boolean {
    15      return cluster.info.connectionState.attemptedAt && cluster.refreshRequestedAt && moment(cluster.info.connectionState.attemptedAt).isBefore(moment(cluster.refreshRequestedAt));
    16  }
    17  
    18  export const NamespacesEditor = ReactFormField((props: {fieldApi: FieldApi; className: string}) => {
    19      const val = (props.fieldApi.getValue() || []).join(',');
    20      return <input className={props.className} value={val} onChange={event => props.fieldApi.setValue(event.target.value.split(','))} />;
    21  });
    22  
    23  export const ClusterDetails = (props: RouteComponentProps<{server: string}>) => {
    24      const server = decodeURIComponent(props.match.params.server);
    25      const loaderRef = React.useRef<DataLoader>();
    26      const [updating, setUpdating] = React.useState(false);
    27      return (
    28          <DataLoader ref={loaderRef} input={server} load={(url: string) => timer(0, 1000).pipe(mergeMap(() => from(services.clusters.get(url, ''))))}>
    29              {(cluster: Cluster) => (
    30                  <Page
    31                      title='Clusters'
    32                      toolbar={{
    33                          breadcrumbs: [{title: 'Settings', path: '/settings'}, {title: 'Clusters', path: '/settings/clusters'}, {title: server}],
    34                          actionMenu: {
    35                              items: [
    36                                  {
    37                                      iconClassName: classNames('fa fa-redo', {'status-icon--spin': isRefreshRequested(cluster)}),
    38                                      title: 'Invalidate Cache',
    39                                      disabled: isRefreshRequested(cluster) || updating,
    40                                      action: async () => {
    41                                          setUpdating(true);
    42                                          try {
    43                                              const updated = await services.clusters.invalidateCache(props.match.params.server);
    44                                              loaderRef.current.setData(updated);
    45                                          } finally {
    46                                              setUpdating(false);
    47                                          }
    48                                      }
    49                                  }
    50                              ]
    51                          }
    52                      }}>
    53                      <p />
    54  
    55                      <div className='argo-container'>
    56                          <EditablePanel
    57                              values={cluster}
    58                              save={async updated => {
    59                                  const item = await services.clusters.get(updated.server, '');
    60                                  item.name = updated.name;
    61                                  item.namespaces = updated.namespaces;
    62                                  item.labels = updated.labels;
    63                                  item.annotations = updated.annotations;
    64                                  loaderRef.current.setData(await services.clusters.update(item, 'name', 'namespaces', 'labels', 'annotations'));
    65                              }}
    66                              title='GENERAL'
    67                              items={[
    68                                  {
    69                                      title: 'SERVER',
    70                                      view: cluster.server
    71                                  },
    72                                  {
    73                                      title: 'CREDENTIALS TYPE',
    74                                      view:
    75                                          (cluster.config.awsAuthConfig && `IAM AUTH (cluster name: ${cluster.config.awsAuthConfig.clusterName})`) ||
    76                                          (cluster.config.execProviderConfig && `External provider (command: ${cluster.config.execProviderConfig.command})`) ||
    77                                          'Token/Basic Auth'
    78                                  },
    79                                  {
    80                                      title: 'NAME',
    81                                      view: cluster.name,
    82                                      edit: formApi => <FormField formApi={formApi} field='name' component={Text} />
    83                                  },
    84                                  {
    85                                      title: 'NAMESPACES',
    86                                      view: ((cluster.namespaces || []).length === 0 && 'All namespaces') || cluster.namespaces.join(', '),
    87                                      edit: formApi => <FormField formApi={formApi} field='namespaces' component={NamespacesEditor} />
    88                                  },
    89                                  {
    90                                      title: 'LABELS',
    91                                      view: Object.keys(cluster.labels || [])
    92                                          .map(label => `${label}=${cluster.labels[label]}`)
    93                                          .join(' '),
    94                                      edit: formApi => <FormField formApi={formApi} field='labels' component={MapInputField} />
    95                                  },
    96                                  {
    97                                      title: 'ANNOTATIONS',
    98                                      view: Object.keys(cluster.annotations || [])
    99                                          .map(annotation => `${annotation}=${cluster.annotations[annotation]}`)
   100                                          .join(' '),
   101                                      edit: formApi => <FormField formApi={formApi} field='annotations' component={MapInputField} />
   102                                  }
   103                              ]}
   104                          />
   105                          <div className='white-box'>
   106                              <p>CONNECTION STATE</p>
   107                              <div className='white-box__details'>
   108                                  <div className='row white-box__details-row'>
   109                                      <div className='columns small-3'>STATUS:</div>
   110                                      <div className='columns small-9'>
   111                                          <ConnectionStateIcon state={cluster.info.connectionState} /> {cluster.info.connectionState.status}
   112                                      </div>
   113                                  </div>
   114                                  <div className='row white-box__details-row'>
   115                                      <div className='columns small-3'>VERSION:</div>
   116                                      <div className='columns small-9'> {cluster.info.serverVersion}</div>
   117                                  </div>
   118                                  <div className='row white-box__details-row'>
   119                                      <div className='columns small-3'>DETAILS:</div>
   120                                      <div className='columns small-9'> {cluster.info.connectionState.message} </div>
   121                                  </div>
   122                                  <div className='row white-box__details-row'>
   123                                      <div className='columns small-3'>MODIFIED AT:</div>
   124                                      <div className='columns small-9'>
   125                                          <Ticker>
   126                                              {now => {
   127                                                  if (!cluster.info.connectionState.attemptedAt) {
   128                                                      return <span>Never (next refresh in few seconds)</span>;
   129                                                  }
   130                                                  const secondsBeforeRefresh = Math.round(Math.max(10 - now.diff(moment(cluster.info.connectionState.attemptedAt)) / 1000, 1));
   131                                                  return (
   132                                                      <React.Fragment>
   133                                                          <Timestamp date={cluster.info.connectionState.attemptedAt} /> (next refresh in {secondsBeforeRefresh} seconds)
   134                                                      </React.Fragment>
   135                                                  );
   136                                              }}
   137                                          </Ticker>
   138                                      </div>
   139                                  </div>
   140                              </div>
   141                          </div>
   142  
   143                          <div className='white-box'>
   144                              <p>CACHE INFO</p>
   145                              <div className='white-box__details'>
   146                                  <Ticker>
   147                                      {() => (
   148                                          <div className='row white-box__details-row'>
   149                                              <div className='columns small-3'>RE-SYNCHRONIZED:</div>
   150                                              <div className='columns small-9'>
   151                                                  <Timestamp date={cluster.info.cacheInfo.lastCacheSyncTime} />
   152                                              </div>
   153                                          </div>
   154                                      )}
   155                                  </Ticker>
   156                                  <div className='row white-box__details-row'>
   157                                      <div className='columns small-3'>APIs COUNT:</div>
   158                                      <div className='columns small-9'> {cluster.info.cacheInfo.apisCount} </div>
   159                                  </div>
   160                                  <div className='row white-box__details-row'>
   161                                      <div className='columns small-3'>RESOURCES COUNT:</div>
   162                                      <div className='columns small-9'> {cluster.info.cacheInfo.resourcesCount} </div>
   163                                  </div>
   164                                  <div className='row white-box__details-row'>
   165                                      <div className='columns small-3'>APPLICATIONS COUNT:</div>
   166                                      <div className='columns small-9'> {cluster.info.applicationsCount} </div>
   167                                  </div>
   168                              </div>
   169                          </div>
   170                      </div>
   171                  </Page>
   172              )}
   173          </DataLoader>
   174      );
   175  };