github.com/hernad/nomad@v1.6.112/ui/app/components/job-dispatch.js (about)

     1  /**
     2   * Copyright (c) HashiCorp, Inc.
     3   * SPDX-License-Identifier: MPL-2.0
     4   */
     5  
     6  import Component from '@glimmer/component';
     7  import { tracked } from '@glimmer/tracking';
     8  import { inject as service } from '@ember/service';
     9  import { action } from '@ember/object';
    10  import { A } from '@ember/array';
    11  import { task } from 'ember-concurrency';
    12  import { noCase } from 'no-case';
    13  import { titleCase } from 'title-case';
    14  import messageFromAdapterError from 'nomad-ui/utils/message-from-adapter-error';
    15  
    16  class MetaField {
    17    @tracked value;
    18    @tracked error;
    19  
    20    name;
    21    required;
    22    title;
    23  
    24    constructor(meta) {
    25      this.name = meta.name;
    26      this.required = meta.required;
    27      this.title = meta.title;
    28      this.value = meta.value;
    29      this.error = meta.error;
    30    }
    31  
    32    validate() {
    33      this.error = '';
    34  
    35      if (this.required && !this.value) {
    36        this.error = `Missing required meta parameter "${this.name}".`;
    37      }
    38    }
    39  }
    40  
    41  export default class JobDispatch extends Component {
    42    @service router;
    43    @service config;
    44  
    45    @tracked metaFields = [];
    46    @tracked payload = '';
    47    @tracked payloadHasError = false;
    48  
    49    errors = A([]);
    50  
    51    constructor() {
    52      super(...arguments);
    53  
    54      // Helper for mapping the params into a useable form.
    55      const mapper = (values, required) =>
    56        values.map(
    57          (x) =>
    58            new MetaField({
    59              name: x,
    60              required,
    61              title: titleCase(noCase(x)),
    62              value: this.args.job.meta ? this.args.job.meta.get(x) : '',
    63            })
    64        );
    65  
    66      // Fetch the different types of parameters.
    67      const required = mapper(
    68        this.args.job.parameterizedDetails.MetaRequired || [],
    69        true
    70      );
    71      const optional = mapper(
    72        this.args.job.parameterizedDetails.MetaOptional || [],
    73        false
    74      );
    75  
    76      // Merge them, required before optional.
    77      this.metaFields = required.concat(optional);
    78    }
    79  
    80    get hasPayload() {
    81      return this.args.job.parameterizedDetails.Payload !== 'forbidden';
    82    }
    83  
    84    get payloadRequired() {
    85      return this.args.job.parameterizedDetails.Payload === 'required';
    86    }
    87  
    88    @action
    89    dispatch() {
    90      this.validateForm();
    91      if (this.errors.length > 0) {
    92        this.scrollToError();
    93        return;
    94      }
    95  
    96      this.onDispatched.perform();
    97    }
    98  
    99    @action
   100    cancel() {
   101      this.router.transitionTo('jobs.job');
   102    }
   103  
   104    @task({ drop: true }) *onDispatched() {
   105      // Try to create the dispatch.
   106      try {
   107        let paramValues = {};
   108        this.metaFields.forEach((m) => (paramValues[m.name] = m.value));
   109        const dispatch = yield this.args.job.dispatch(paramValues, this.payload);
   110  
   111        // Navigate to the newly created instance.
   112        const namespaceId = this.args.job.belongsTo('namespace').id();
   113        const jobId = namespaceId
   114          ? `${dispatch.DispatchedJobID}@${namespaceId}`
   115          : dispatch.DispatchedJobID;
   116  
   117        this.router.transitionTo('jobs.job', jobId);
   118      } catch (err) {
   119        const error = messageFromAdapterError(err) || 'Could not dispatch job';
   120        this.errors.pushObject(error);
   121        this.scrollToError();
   122      }
   123    }
   124  
   125    scrollToError() {
   126      if (!this.config.isTest) {
   127        window.scrollTo(0, 0);
   128      }
   129    }
   130  
   131    resetErrors() {
   132      this.payloadHasError = false;
   133      this.errors.clear();
   134    }
   135  
   136    validateForm() {
   137      this.resetErrors();
   138  
   139      // Make sure that we have all of the meta fields that we need.
   140      this.metaFields.forEach((f) => {
   141        f.validate();
   142        if (f.error) {
   143          this.errors.pushObject(f.error);
   144        }
   145      });
   146  
   147      // Validate payload.
   148      if (this.payloadRequired && !this.payload) {
   149        this.errors.pushObject('Missing required payload.');
   150        this.payloadHasError = true;
   151      }
   152    }
   153  }