github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/app/controllers/allocations/allocation/index.js (about) 1 /* eslint-disable ember/no-observers */ 2 import Controller from '@ember/controller'; 3 import { inject as service } from '@ember/service'; 4 import { action, computed } from '@ember/object'; 5 import { observes } from '@ember-decorators/object'; 6 import { computed as overridable } from 'ember-overridable-computed'; 7 import { alias } from '@ember/object/computed'; 8 import { task } from 'ember-concurrency'; 9 import Sortable from 'nomad-ui/mixins/sortable'; 10 import { lazyClick } from 'nomad-ui/helpers/lazy-click'; 11 import { watchRecord } from 'nomad-ui/utils/properties/watch'; 12 import messageForError from 'nomad-ui/utils/message-from-adapter-error'; 13 import classic from 'ember-classic-decorator'; 14 import { union } from '@ember/object/computed'; 15 import { tracked } from '@glimmer/tracking'; 16 17 @classic 18 export default class IndexController extends Controller.extend(Sortable) { 19 @service token; 20 @service store; 21 22 queryParams = [ 23 { 24 sortProperty: 'sort', 25 }, 26 { 27 sortDescending: 'desc', 28 }, 29 { 30 activeServiceID: 'service', 31 }, 32 ]; 33 34 sortProperty = 'name'; 35 sortDescending = false; 36 37 @alias('model.states') listToSort; 38 @alias('listSorted') sortedStates; 39 40 // Set in the route 41 preempter = null; 42 43 @overridable(function () { 44 // { title, description } 45 return null; 46 }) 47 error; 48 49 @computed('model.allocatedResources.ports.@each.label') 50 get ports() { 51 return (this.get('model.allocatedResources.ports') || []).sortBy('label'); 52 } 53 54 @computed('model.states.@each.task') 55 get tasks() { 56 return this.get('model.states').mapBy('task') || []; 57 } 58 59 @computed('tasks.@each.services') 60 get taskServices() { 61 return this.get('tasks') 62 .map((t) => ((t && t.services) || []).toArray()) 63 .flat() 64 .compact(); 65 } 66 67 @computed('model.taskGroup.services.@each.name') 68 get groupServices() { 69 return (this.get('model.taskGroup.services') || []).sortBy('name'); 70 } 71 72 @union('taskServices', 'groupServices') services; 73 74 @computed('model.{healthChecks,id}', 'services') 75 get servicesWithHealthChecks() { 76 return this.services.map((service) => { 77 if (this.model.healthChecks) { 78 const healthChecks = Object.values(this.model.healthChecks)?.filter( 79 (check) => { 80 const refPrefix = 81 check.Task || check.Group.split('.')[1].split('[')[0]; 82 const currentServiceName = `${refPrefix}-${check.Service}`; 83 return currentServiceName === service.refID; 84 } 85 ); 86 healthChecks.forEach((check) => { 87 service.healthChecks.pushObject(check); 88 }); 89 } 90 // Contextualize healthchecks for the allocation we're in 91 service.healthChecks = service.healthChecks.filterBy( 92 'Alloc', 93 this.model.id 94 ); 95 return service; 96 }); 97 } 98 99 onDismiss() { 100 this.set('error', null); 101 } 102 103 @watchRecord('allocation') watchNext; 104 105 @observes('model.nextAllocation.clientStatus') 106 observeWatchNext() { 107 const nextAllocation = this.model.nextAllocation; 108 if (nextAllocation && nextAllocation.content) { 109 this.watchNext.perform(nextAllocation); 110 } else { 111 this.watchNext.cancelAll(); 112 } 113 } 114 115 @task(function* () { 116 try { 117 yield this.model.stop(); 118 // Eagerly update the allocation clientStatus to avoid flickering 119 this.model.set('clientStatus', 'complete'); 120 } catch (err) { 121 this.set('error', { 122 title: 'Could Not Stop Allocation', 123 description: messageForError(err, 'manage allocation lifecycle'), 124 }); 125 } 126 }) 127 stopAllocation; 128 129 @task(function* () { 130 try { 131 yield this.model.restart(); 132 } catch (err) { 133 this.set('error', { 134 title: 'Could Not Restart Allocation', 135 description: messageForError(err, 'manage allocation lifecycle'), 136 }); 137 } 138 }) 139 restartAllocation; 140 141 @task(function* () { 142 try { 143 yield this.model.restartAll(); 144 } catch (err) { 145 this.set('error', { 146 title: 'Could Not Restart All Tasks', 147 description: messageForError(err, 'manage allocation lifecycle'), 148 }); 149 console.error(err); 150 } 151 }) 152 restartAll; 153 154 @action 155 gotoTask(allocation, task) { 156 this.transitionToRoute('allocations.allocation.task', task); 157 } 158 159 @action 160 taskClick(allocation, task, event) { 161 lazyClick([() => this.send('gotoTask', allocation, task), event]); 162 } 163 164 //#region Services 165 166 @tracked activeServiceID = null; 167 168 @action handleServiceClick(service) { 169 this.set('activeServiceID', service.refID); 170 } 171 172 @computed('activeServiceID', 'services') 173 get activeService() { 174 return this.services.findBy('refID', this.activeServiceID); 175 } 176 177 @action closeSidebar() { 178 this.set('activeServiceID', null); 179 } 180 181 keyCommands = [ 182 { 183 label: 'Close Evaluations Sidebar', 184 pattern: ['Escape'], 185 action: () => this.closeSidebar(), 186 }, 187 ]; 188 189 //#endregion Services 190 }