github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/app/serializers/job.js (about) 1 import { assign } from '@ember/polyfills'; 2 import ApplicationSerializer from './application'; 3 import queryString from 'query-string'; 4 import classic from 'ember-classic-decorator'; 5 6 @classic 7 export default class JobSerializer extends ApplicationSerializer { 8 attrs = { 9 parameterized: 'ParameterizedJob', 10 }; 11 12 separateNanos = ['SubmitTime']; 13 14 normalize(typeHash, hash) { 15 hash.NamespaceID = hash.Namespace; 16 17 // ID is a composite of both the job ID and the namespace the job is in 18 hash.PlainId = hash.ID; 19 hash.ID = JSON.stringify([hash.ID, hash.NamespaceID || 'default']); 20 21 // ParentID comes in as "" instead of null 22 if (!hash.ParentID) { 23 hash.ParentID = null; 24 } else { 25 hash.ParentID = JSON.stringify([ 26 hash.ParentID, 27 hash.NamespaceID || 'default', 28 ]); 29 } 30 31 // Job Summary is always at /:job-id/summary, but since it can also come from 32 // the job list, it's better for Ember Data to be linked by ID association. 33 hash.SummaryID = hash.ID; 34 35 // Periodic is a boolean on list and an object on single 36 if (hash.Periodic instanceof Object) { 37 hash.PeriodicDetails = hash.Periodic; 38 hash.Periodic = true; 39 } 40 41 // Parameterized behaves like Periodic 42 if (hash.ParameterizedJob instanceof Object) { 43 hash.ParameterizedDetails = hash.ParameterizedJob; 44 hash.ParameterizedJob = true; 45 } 46 47 // If the hash contains summary information, push it into the store 48 // as a job-summary model. 49 if (hash.JobSummary) { 50 this.store.pushPayload('job-summary', { 51 'job-summary': [hash.JobSummary], 52 }); 53 } 54 55 return super.normalize(typeHash, hash); 56 } 57 58 extractRelationships(modelClass, hash) { 59 const namespace = 60 !hash.NamespaceID || hash.NamespaceID === 'default' 61 ? undefined 62 : hash.NamespaceID; 63 const { modelName } = modelClass; 64 65 const apiNamespace = this.store 66 .adapterFor(modelClass.modelName) 67 .get('namespace'); 68 69 const [jobURL] = this.store 70 .adapterFor(modelName) 71 .buildURL(modelName, hash.ID, hash, 'findRecord') 72 .split('?'); 73 74 const variableLookup = hash.ParentID 75 ? JSON.parse(hash.ParentID)[0] 76 : hash.PlainId; 77 78 return assign(super.extractRelationships(...arguments), { 79 allocations: { 80 links: { 81 related: buildURL(`${jobURL}/allocations`, { namespace }), 82 }, 83 }, 84 versions: { 85 links: { 86 related: buildURL(`${jobURL}/versions`, { namespace, diffs: true }), 87 }, 88 }, 89 deployments: { 90 links: { 91 related: buildURL(`${jobURL}/deployments`, { namespace }), 92 }, 93 }, 94 latestDeployment: { 95 links: { 96 related: buildURL(`${jobURL}/deployment`, { namespace }), 97 }, 98 }, 99 evaluations: { 100 links: { 101 related: buildURL(`${jobURL}/evaluations`, { namespace }), 102 }, 103 }, 104 services: { 105 links: { 106 related: buildURL(`${jobURL}/services`, { namespace }), 107 }, 108 }, 109 variables: { 110 links: { 111 related: buildURL(`/${apiNamespace}/vars`, { 112 prefix: `nomad/jobs/${variableLookup}`, 113 namespace, 114 }), 115 }, 116 }, 117 scaleState: { 118 links: { 119 related: buildURL(`${jobURL}/scale`, { namespace }), 120 }, 121 }, 122 recommendationSummaries: { 123 links: { 124 related: buildURL(`/${apiNamespace}/recommendations`, { 125 job: hash.PlainId, 126 namespace: hash.NamespaceID || 'default', 127 }), 128 }, 129 }, 130 }); 131 } 132 } 133 134 function buildURL(path, queryParams) { 135 const qpString = queryString.stringify(queryParams); 136 if (qpString) { 137 return `${path}?${qpString}`; 138 } 139 return path; 140 }