github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/app/adapters/application.js (about) 1 import { inject as service } from '@ember/service'; 2 import { computed } from '@ember/object'; 3 import { camelize } from '@ember/string'; 4 import RESTAdapter from '@ember-data/adapter/rest'; 5 import codesForError from '../utils/codes-for-error'; 6 import removeRecord from '../utils/remove-record'; 7 import { default as NoLeaderError, NO_LEADER } from '../utils/no-leader-error'; 8 import classic from 'ember-classic-decorator'; 9 10 export const namespace = 'v1'; 11 12 @classic 13 export default class ApplicationAdapter extends RESTAdapter { 14 namespace = namespace; 15 16 @service system; 17 @service token; 18 19 @computed('token.secret') 20 get headers() { 21 const token = this.get('token.secret'); 22 if (token) { 23 return { 24 'X-Nomad-Token': token, 25 }; 26 } 27 28 return undefined; 29 } 30 31 handleResponse(status, headers, payload) { 32 if (status === 500 && payload === NO_LEADER) { 33 return new NoLeaderError(); 34 } 35 return super.handleResponse(...arguments); 36 } 37 38 findAll() { 39 return super.findAll(...arguments).catch((error) => { 40 const errorCodes = codesForError(error); 41 42 const isNotImplemented = errorCodes.includes('501'); 43 44 if (isNotImplemented) { 45 return []; 46 } 47 48 // Rethrow to be handled downstream 49 throw error; 50 }); 51 } 52 53 ajaxOptions(url, verb, options = {}) { 54 options.data || (options.data = {}); 55 if (this.get('system.shouldIncludeRegion')) { 56 // Region should only ever be a query param. The default ajaxOptions 57 // behavior is to include data attributes in the requestBody for PUT 58 // and POST requests. This works around that. 59 const region = this.get('system.activeRegion'); 60 if (region) { 61 url = associateRegion(url, region); 62 } 63 } 64 return super.ajaxOptions(url, verb, options); 65 } 66 67 // In order to remove stale records from the store, findHasMany has to unload 68 // all records related to the request in question. 69 findHasMany(store, snapshot, link, relationship) { 70 return super.findHasMany(...arguments).then((payload) => { 71 const relationshipType = relationship.type; 72 const inverse = snapshot.record.inverseFor(relationship.key); 73 if (inverse) { 74 store 75 .peekAll(relationshipType) 76 .filter((record) => record.get(`${inverse.name}.id`) === snapshot.id) 77 .forEach((record) => { 78 removeRecord(store, record); 79 }); 80 } 81 return payload; 82 }); 83 } 84 85 // Single record requests deviate from REST practice by using 86 // the singular form of the resource name. 87 // 88 // REST: /some-resources/:id 89 // Nomad: /some-resource/:id 90 // 91 // This is the original implementation of _buildURL 92 // without the pluralization of modelName 93 urlForFindRecord(id, modelName) { 94 let path; 95 let url = []; 96 let host = this.host; 97 let prefix = this.urlPrefix(); 98 99 if (modelName) { 100 path = camelize(modelName); 101 if (path) { 102 url.push(path); 103 } 104 } 105 106 if (id) { 107 url.push(encodeURIComponent(id)); 108 } 109 110 if (prefix) { 111 url.unshift(prefix); 112 } 113 114 url = url.join('/'); 115 if (!host && url && url.charAt(0) !== '/') { 116 url = '/' + url; 117 } 118 119 return url; 120 } 121 122 urlForUpdateRecord() { 123 return this.urlForFindRecord(...arguments); 124 } 125 } 126 127 function associateRegion(url, region) { 128 return url.indexOf('?') !== -1 129 ? `${url}®ion=${region}` 130 : `${url}?region=${region}`; 131 }