github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/app/components/job-dispatch.js (about)

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