github.com/argoproj/argo-cd@v1.8.7/ui/src/app/settings/components/project-sync-windows-edit/project-sync-windows-edit.tsx (about)

     1  import {Tooltip} from 'argo-ui';
     2  import * as React from 'react';
     3  import * as ReactForm from 'react-form';
     4  import {SyncWindow} from '../../../shared/models';
     5  
     6  interface ProjectSyncWindowProps {
     7      projName: string;
     8      window: SyncWindow;
     9      formApi: ReactForm.FormApi;
    10  }
    11  
    12  function helpTip(text: string) {
    13      return (
    14          <Tooltip content={text}>
    15              <span style={{fontSize: 'smaller'}}>
    16                  {' '}
    17                  <i className='fa fa-question-circle' />
    18              </span>
    19          </Tooltip>
    20      );
    21  }
    22  
    23  export const ProjectSyncWindowApplicationsEdit = (props: ProjectSyncWindowProps) => (
    24      <React.Fragment>
    25          <h6>Applications</h6>
    26          <div>Manage applications assigned to this window ("*" for any)</div>
    27          <div className='argo-table-list__row'>
    28              {(props.window.applications || []).map((a, i) => (
    29                  <Attribute
    30                      key={i}
    31                      field={['window.applications', i]}
    32                      formApi={props.formApi}
    33                      projName={props.projName}
    34                      deleteApp={() => props.formApi.setValue('window.applications', removeEl(props.window.applications, i))}
    35                  />
    36              ))}
    37              <div className='row'>
    38                  <div className='columns small-6'>
    39                      <a
    40                          onClick={() => {
    41                              const newA = '';
    42                              props.formApi.setValue('window.applications', (props.formApi.values.window.applications || []).concat(newA));
    43                          }}>
    44                          Add Application
    45                      </a>
    46                  </div>
    47              </div>
    48          </div>
    49      </React.Fragment>
    50  );
    51  
    52  export const ProjectSyncWindowNamespaceEdit = (props: ProjectSyncWindowProps) => (
    53      <React.Fragment>
    54          <h6>Namespaces</h6>
    55          <div>Manage namespaces assigned to this window ("*" for any)</div>
    56          <div className='argo-table-list__row'>
    57              {(props.window.namespaces || []).map((n, i) => (
    58                  <Attribute
    59                      key={i}
    60                      field={['window.namespaces', i]}
    61                      formApi={props.formApi}
    62                      projName={props.projName}
    63                      deleteApp={() => props.formApi.setValue('window.namespaces', removeEl(props.window.namespaces, i))}
    64                  />
    65              ))}
    66              <div className='row'>
    67                  <div className='columns small-6'>
    68                      <a
    69                          onClick={() => {
    70                              const newN = '';
    71                              props.formApi.setValue('window.namespaces', (props.formApi.values.window.namespaces || []).concat(newN));
    72                          }}>
    73                          Add Namespace
    74                      </a>
    75                  </div>
    76              </div>
    77          </div>
    78      </React.Fragment>
    79  );
    80  
    81  export const ProjectSyncWindowClusterEdit = (props: ProjectSyncWindowProps) => (
    82      <React.Fragment>
    83          <h6>Clusters</h6>
    84          <div>Manage clusters assigned to this window ("*" for any)</div>
    85          <div className='argo-table-list__row'>
    86              {(props.window.clusters || []).map((c, i) => (
    87                  <Attribute
    88                      key={i}
    89                      field={['window.clusters', i]}
    90                      formApi={props.formApi}
    91                      projName={props.projName}
    92                      deleteApp={() => props.formApi.setValue('window.clusters', removeEl(props.window.clusters, i))}
    93                  />
    94              ))}
    95              <div className='row'>
    96                  <div className='columns small-6'>
    97                      <a
    98                          onClick={() => {
    99                              const newC = '';
   100                              props.formApi.setValue('window.clusters', (props.formApi.values.window.clusters || []).concat(newC));
   101                          }}>
   102                          Add Cluster
   103                      </a>
   104                  </div>
   105              </div>
   106          </div>
   107      </React.Fragment>
   108  );
   109  
   110  interface AttributeProps {
   111      projName: string;
   112      roleName: string;
   113      fieldApi: ReactForm.FieldApi;
   114      deleteApp: () => void;
   115  }
   116  
   117  function removeEl(items: any[], index: number) {
   118      items.splice(index, 1);
   119      return items;
   120  }
   121  
   122  class AttributeWrapper extends React.Component<AttributeProps, any> {
   123      public render() {
   124          return (
   125              <div className='row'>
   126                  <div className='columns small-6'>
   127                      <input
   128                          className='argo-field'
   129                          value={this.getApplication()}
   130                          onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
   131                              this.setApplication(e.target.value);
   132                          }}
   133                      />
   134                  </div>
   135                  <div className='columns small-1'>
   136                      <i className='fa fa-times' onClick={() => this.props.deleteApp()} style={{cursor: 'pointer'}} />
   137                  </div>
   138              </div>
   139          );
   140      }
   141  
   142      private getApplication(): string {
   143          return this.props.fieldApi.getValue();
   144      }
   145  
   146      private setApplication(application: string) {
   147          this.props.fieldApi.setValue(application);
   148      }
   149  }
   150  
   151  const Attribute = ReactForm.FormField(AttributeWrapper);
   152  
   153  function generateSchedule(minute?: string, hour?: string, dom?: string, month?: string, dow?: string): string {
   154      return `${minute} ${hour} ${dom} ${month} ${dow}`;
   155  }
   156  
   157  export const ProjectSyncWindowScheduleEdit = (props: ProjectSyncWindowProps) => (
   158      <React.Fragment>
   159          <h6>Schedule</h6>
   160          <div className='argo-table-list__head'>
   161              <div className='row'>
   162                  <div className='columns small-2'>Minute{helpTip('The minute/minutes assigned to the schedule')}</div>
   163                  <div className='columns small-2'>Hour{helpTip('The hour/hours assigned to the schedule')}</div>
   164                  <div className='columns small-2'>Day Of The Month{helpTip('The day/days of the month assigned to the schedule')}</div>
   165                  <div className='columns small-2'>Month{helpTip('The month/months assigned to the schedule.')}</div>
   166                  <div className='columns small-2'>Day Of the Week{helpTip('The day/days of the week assigned to the schedule')}</div>
   167              </div>
   168          </div>
   169          <div className='row project-sync-windows-panel__form-row'>
   170              <Schedule key='schedule' field={'window.schedule'} formApi={props.formApi} />
   171          </div>
   172      </React.Fragment>
   173  );
   174  
   175  interface ScheduleProps {
   176      fieldApi: ReactForm.FieldApi;
   177  }
   178  
   179  function generateRange(limit: number, zeroStart: boolean): string[] {
   180      const range: string[] = new Array(limit);
   181      for (let i = 0; i < limit; i++) {
   182          if (zeroStart) {
   183              range[i] = i.toString();
   184          } else {
   185              range[i] = (i + 1).toString();
   186          }
   187      }
   188      return range;
   189  }
   190  
   191  function getRanges(config: string): string[] {
   192      const values = [];
   193      const fields = config.split(',');
   194      for (const f of fields) {
   195          if (f.search(/-/) !== -1) {
   196              const r = f.split('-');
   197              for (let i = parseInt(r[0], 10); i <= parseInt(r[1], 10); i++) {
   198                  values.push(i.toString());
   199              }
   200          } else {
   201              values.push(f);
   202          }
   203      }
   204      return values;
   205  }
   206  
   207  function setRanges(config: string[]): string {
   208      const values = [];
   209      const ranges = [];
   210  
   211      config.sort((n1, n2) => parseInt(n1, 10) - parseInt(n2, 10));
   212  
   213      for (let i = 0; i < config.length; i++) {
   214          if (ranges.length === 0) {
   215              ranges[0] = [config[i]];
   216          } else {
   217              if (parseInt(config[i], 10) - 1 === parseInt(config[i - 1], 10)) {
   218                  ranges[ranges.length - 1].push(config[i]);
   219              } else {
   220                  ranges[ranges.length] = [config[i]];
   221              }
   222          }
   223      }
   224  
   225      if (ranges.length > 0) {
   226          for (const r of ranges) {
   227              if (r.length > 1) {
   228                  values.push(r[0] + '-' + r[r.length - 1]);
   229              } else {
   230                  values.push(r[0]);
   231              }
   232          }
   233      }
   234      return values.join(',');
   235  }
   236  
   237  class ScheduleWrapper extends React.Component<ScheduleProps, any> {
   238      public render() {
   239          return (
   240              <React.Fragment>
   241                  <div className='columns small-2'>
   242                      <select
   243                          className='argo-field'
   244                          size={8}
   245                          name='minute'
   246                          multiple={true}
   247                          value={this.getValues(0)}
   248                          onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
   249                              const minuteOptions = e.target.options;
   250                              const minuteValues = [];
   251                              for (let i = 0, l = minuteOptions.length; i < l; i++) {
   252                                  if (minuteOptions[i].selected) {
   253                                      minuteValues.push(minuteOptions[i].value);
   254                                  }
   255                              }
   256                              this.setValues(minuteValues, 0);
   257                          }}>
   258                          <option key='wildcard' value='*'>
   259                              Every Minute
   260                          </option>
   261                          {generateRange(60, true).map(m => (
   262                              <option key={m}>{m}</option>
   263                          ))}
   264                      </select>
   265                  </div>
   266                  <div className='columns small-2'>
   267                      <select
   268                          className='argo-field'
   269                          size={8}
   270                          name='hours'
   271                          multiple={true}
   272                          value={this.getValues(1)}
   273                          onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
   274                              const hourOptions = e.target.options;
   275                              const hourValues = [];
   276                              for (let i = 0, l = hourOptions.length; i < l; i++) {
   277                                  if (hourOptions[i].selected) {
   278                                      hourValues.push(hourOptions[i].value);
   279                                  }
   280                              }
   281                              this.setValues(hourValues, 1);
   282                          }}>
   283                          <option key='wildcard' value='*'>
   284                              Every Hour
   285                          </option>
   286                          {generateRange(24, true).map(m => (
   287                              <option key={m}>{m}</option>
   288                          ))}
   289                      </select>
   290                  </div>
   291                  <div className='columns small-2'>
   292                      <select
   293                          className='argo-field'
   294                          size={8}
   295                          name='dom'
   296                          multiple={true}
   297                          value={this.getValues(2)}
   298                          onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
   299                              const domOptions = e.target.options;
   300                              const domValues = [];
   301                              for (let i = 0, l = domOptions.length; i < l; i++) {
   302                                  if (domOptions[i].selected) {
   303                                      domValues.push(domOptions[i].value);
   304                                  }
   305                              }
   306                              this.setValues(domValues, 2);
   307                          }}>
   308                          <option key='wildcard' value='*'>
   309                              Every Day
   310                          </option>
   311                          {generateRange(31, false).map(m => (
   312                              <option key={m}>{m}</option>
   313                          ))}
   314                      </select>
   315                  </div>
   316                  <div className='columns small-2'>
   317                      <select
   318                          className='argo-field'
   319                          size={8}
   320                          name='month'
   321                          multiple={true}
   322                          value={this.getValues(3)}
   323                          onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
   324                              const monthOptions = e.target.options;
   325                              const monthValues = [];
   326                              for (let i = 0, l = monthOptions.length; i < l; i++) {
   327                                  if (monthOptions[i].selected) {
   328                                      monthValues.push(monthOptions[i].value);
   329                                  }
   330                              }
   331                              this.setValues(monthValues, 3);
   332                          }}>
   333                          <option key='wildcard' value='*'>
   334                              Every Month
   335                          </option>
   336                          <option key='1' value='1'>
   337                              Jan
   338                          </option>
   339                          <option key='2' value='2'>
   340                              Feb
   341                          </option>
   342                          <option key='3' value='3'>
   343                              Mar
   344                          </option>
   345                          <option key='4' value='4'>
   346                              Apr
   347                          </option>
   348                          <option key='5' value='5'>
   349                              May
   350                          </option>
   351                          <option key='6' value='6'>
   352                              Jun
   353                          </option>
   354                          <option key='7' value='7'>
   355                              Jul
   356                          </option>
   357                          <option key='8' value='8'>
   358                              Aug
   359                          </option>
   360                          <option key='9' value='9'>
   361                              Sep
   362                          </option>
   363                          <option key='10' value='10'>
   364                              Oct
   365                          </option>
   366                          <option key='11' value='11'>
   367                              Nov
   368                          </option>
   369                          <option key='12' value='12'>
   370                              Dec
   371                          </option>
   372                      </select>
   373                  </div>
   374                  <div className='columns small-2'>
   375                      <select
   376                          className='argo-field'
   377                          size={8}
   378                          name='dow'
   379                          multiple={true}
   380                          value={this.getValues(4)}
   381                          onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
   382                              const dowOptions = e.target.options;
   383                              const dowValues = [];
   384                              for (let i = 0, l = dowOptions.length; i < l; i++) {
   385                                  if (dowOptions[i].selected) {
   386                                      dowValues.push(dowOptions[i].value);
   387                                  }
   388                              }
   389                              this.setValues(dowValues, 4);
   390                          }}>
   391                          <option key='wildcard' value='*'>
   392                              Sunday-Saturday
   393                          </option>
   394                          <option key='0' value='0'>
   395                              Sun
   396                          </option>
   397                          <option key='1' value='1'>
   398                              Mon
   399                          </option>
   400                          <option key='2' value='2'>
   401                              Tue
   402                          </option>
   403                          <option key='3' value='3'>
   404                              Wed
   405                          </option>
   406                          <option key='4' value='4'>
   407                              Thu
   408                          </option>
   409                          <option key='5' value='5'>
   410                              Fri
   411                          </option>
   412                          <option key='6' value='6'>
   413                              Sat
   414                          </option>
   415                      </select>
   416                  </div>
   417              </React.Fragment>
   418          );
   419      }
   420  
   421      private getValues(f: number): string[] {
   422          if (this.props.fieldApi.getValue() !== undefined) {
   423              const fields = (this.props.fieldApi.getValue() as string).split(' ');
   424              const subFields = getRanges(fields[f]);
   425              return subFields;
   426          }
   427          return ['*'];
   428      }
   429  
   430      private setValues(values: string[], f: number) {
   431          if (this.props.fieldApi.getValue() !== undefined) {
   432              const fields = (this.props.fieldApi.getValue() as string).split(' ');
   433              fields[f] = setRanges(values);
   434              this.props.fieldApi.setValue(fields.join(' '));
   435          } else {
   436              switch (f) {
   437                  case 0:
   438                      this.props.fieldApi.setValue(generateSchedule(values.join(','), '*', '*', '*', '*'));
   439                      break;
   440                  case 1:
   441                      this.props.fieldApi.setValue(generateSchedule('*', values.join(','), '*', '*', '*'));
   442                      break;
   443                  case 2:
   444                      this.props.fieldApi.setValue(generateSchedule('*', '*', values.join(','), '*', '*'));
   445                      break;
   446                  case 3:
   447                      this.props.fieldApi.setValue(generateSchedule('*', '*', '*', values.join(','), '*'));
   448                      break;
   449                  case 4:
   450                      this.props.fieldApi.setValue(generateSchedule('*', '*', '*', '*', values.join(',')));
   451                      break;
   452              }
   453          }
   454          return;
   455      }
   456  }
   457  
   458  const Schedule = ReactForm.FormField(ScheduleWrapper);