github.com/hernad/nomad@v1.6.112/ui/app/controllers/clients/index.js (about)

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