github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/app/controllers/clients/index.js (about)

     1  /* eslint-disable ember/no-incorrect-calls-with-inline-anonymous-functions */
     2  import { alias, readOnly } from '@ember/object/computed';
     3  import { inject as service } from '@ember/service';
     4  import Controller, { inject as controller } from '@ember/controller';
     5  import { action, computed } from '@ember/object';
     6  import { scheduleOnce } from '@ember/runloop';
     7  import intersection from 'lodash.intersection';
     8  import SortableFactory from 'nomad-ui/mixins/sortable-factory';
     9  import Searchable from 'nomad-ui/mixins/searchable';
    10  import {
    11    serialize,
    12    deserializedQueryParam as selection,
    13  } from 'nomad-ui/utils/qp-serialize';
    14  import classic from 'ember-classic-decorator';
    15  
    16  @classic
    17  export default class IndexController extends Controller.extend(
    18    SortableFactory(['id', 'name', 'compositeStatus', 'datacenter', 'version']),
    19    Searchable
    20  ) {
    21    @service userSettings;
    22    @controller('clients') clientsController;
    23  
    24    @alias('model.nodes') nodes;
    25    @alias('model.agents') agents;
    26  
    27    queryParams = [
    28      {
    29        currentPage: 'page',
    30      },
    31      {
    32        searchTerm: 'search',
    33      },
    34      {
    35        sortProperty: 'sort',
    36      },
    37      {
    38        sortDescending: 'desc',
    39      },
    40      {
    41        qpClass: 'class',
    42      },
    43      {
    44        qpState: 'state',
    45      },
    46      {
    47        qpDatacenter: 'dc',
    48      },
    49      {
    50        qpVersion: 'version',
    51      },
    52      {
    53        qpVolume: 'volume',
    54      },
    55    ];
    56  
    57    currentPage = 1;
    58    @readOnly('userSettings.pageSize') pageSize;
    59  
    60    sortProperty = 'modifyIndex';
    61    sortDescending = true;
    62  
    63    @computed
    64    get searchProps() {
    65      return ['id', 'name', 'datacenter'];
    66    }
    67  
    68    qpClass = '';
    69    qpState = '';
    70    qpDatacenter = '';
    71    qpVersion = '';
    72    qpVolume = '';
    73  
    74    @selection('qpClass') selectionClass;
    75    @selection('qpState') selectionState;
    76    @selection('qpDatacenter') selectionDatacenter;
    77    @selection('qpVersion') selectionVersion;
    78    @selection('qpVolume') selectionVolume;
    79  
    80    @computed('nodes.[]', 'selectionClass')
    81    get optionsClass() {
    82      const classes = Array.from(new Set(this.nodes.mapBy('nodeClass')))
    83        .compact()
    84        .without('');
    85  
    86      // Remove any invalid node classes from the query param/selection
    87      scheduleOnce('actions', () => {
    88        // eslint-disable-next-line ember/no-side-effects
    89        this.set(
    90          'qpClass',
    91          serialize(intersection(classes, this.selectionClass))
    92        );
    93      });
    94  
    95      return classes.sort().map((dc) => ({ key: dc, label: dc }));
    96    }
    97  
    98    @computed
    99    get optionsState() {
   100      return [
   101        { key: 'initializing', label: 'Initializing' },
   102        { key: 'ready', label: 'Ready' },
   103        { key: 'down', label: 'Down' },
   104        { key: 'ineligible', label: 'Ineligible' },
   105        { key: 'draining', label: 'Draining' },
   106        { key: 'disconnected', label: 'Disconnected' },
   107      ];
   108    }
   109  
   110    @computed('nodes.[]', 'selectionDatacenter')
   111    get optionsDatacenter() {
   112      const datacenters = Array.from(
   113        new Set(this.nodes.mapBy('datacenter'))
   114      ).compact();
   115  
   116      // Remove any invalid datacenters from the query param/selection
   117      scheduleOnce('actions', () => {
   118        // eslint-disable-next-line ember/no-side-effects
   119        this.set(
   120          'qpDatacenter',
   121          serialize(intersection(datacenters, this.selectionDatacenter))
   122        );
   123      });
   124  
   125      return datacenters.sort().map((dc) => ({ key: dc, label: dc }));
   126    }
   127  
   128    @computed('nodes.[]', 'selectionVersion')
   129    get optionsVersion() {
   130      const versions = Array.from(new Set(this.nodes.mapBy('version'))).compact();
   131  
   132      // Remove any invalid versions from the query param/selection
   133      scheduleOnce('actions', () => {
   134        // eslint-disable-next-line ember/no-side-effects
   135        this.set(
   136          'qpVersion',
   137          serialize(intersection(versions, this.selectionVersion))
   138        );
   139      });
   140  
   141      return versions.sort().map((v) => ({ key: v, label: v }));
   142    }
   143  
   144    @computed('nodes.[]', 'selectionVolume')
   145    get optionsVolume() {
   146      const flatten = (acc, val) => acc.concat(val.toArray());
   147  
   148      const allVolumes = this.nodes.mapBy('hostVolumes').reduce(flatten, []);
   149      const volumes = Array.from(new Set(allVolumes.mapBy('name')));
   150  
   151      scheduleOnce('actions', () => {
   152        // eslint-disable-next-line ember/no-side-effects
   153        this.set(
   154          'qpVolume',
   155          serialize(intersection(volumes, this.selectionVolume))
   156        );
   157      });
   158  
   159      return volumes.sort().map((volume) => ({ key: volume, label: volume }));
   160    }
   161  
   162    @computed(
   163      'nodes.[]',
   164      'selectionClass',
   165      'selectionState',
   166      'selectionDatacenter',
   167      'selectionVersion',
   168      'selectionVolume'
   169    )
   170    get filteredNodes() {
   171      const {
   172        selectionClass: classes,
   173        selectionState: states,
   174        selectionDatacenter: datacenters,
   175        selectionVersion: versions,
   176        selectionVolume: volumes,
   177      } = this;
   178  
   179      const onlyIneligible = states.includes('ineligible');
   180      const onlyDraining = states.includes('draining');
   181  
   182      // states is a composite of node status and other node states
   183      const statuses = states.without('ineligible').without('draining');
   184  
   185      return this.nodes.filter((node) => {
   186        if (classes.length && !classes.includes(node.get('nodeClass')))
   187          return false;
   188        if (statuses.length && !statuses.includes(node.get('status')))
   189          return false;
   190        if (datacenters.length && !datacenters.includes(node.get('datacenter')))
   191          return false;
   192        if (versions.length && !versions.includes(node.get('version')))
   193          return false;
   194        if (
   195          volumes.length &&
   196          !node.hostVolumes.find((volume) => volumes.includes(volume.name))
   197        )
   198          return false;
   199  
   200        if (onlyIneligible && node.get('isEligible')) return false;
   201        if (onlyDraining && !node.get('isDraining')) return false;
   202  
   203        return true;
   204      });
   205    }
   206  
   207    @alias('filteredNodes') listToSort;
   208    @alias('listSorted') listToSearch;
   209    @alias('listSearched') sortedNodes;
   210  
   211    @alias('clientsController.isForbidden') isForbidden;
   212  
   213    setFacetQueryParam(queryParam, selection) {
   214      this.set(queryParam, serialize(selection));
   215    }
   216  
   217    @action
   218    gotoNode(node) {
   219      this.transitionToRoute('clients.client', node);
   220    }
   221  }