Prototype watching resources

- Service to manage X-Nomad-Index values
- Adapter method for reloading relationships with additional params
- Pattern for watching models and model relationships using EC
This commit is contained in:
Michael Lange
2018-02-08 15:06:10 -08:00
parent 66d0eabe34
commit 9b2080d41e
5 changed files with 133 additions and 3 deletions

View File

@@ -1,11 +1,11 @@
import { inject as service } from '@ember/service';
import { assign } from '@ember/polyfills';
import ApplicationAdapter from './application';
import Watchable from './watchable';
export default ApplicationAdapter.extend({
export default Watchable.extend({
system: service(),
shouldReloadAll: () => true,
// shouldReloadAll: () => true,
buildQuery() {
const namespace = this.get('system.activeNamespace.id');

View File

@@ -0,0 +1,60 @@
import { get } from '@ember/object';
import { assign } from '@ember/polyfills';
import { copy } from '@ember/object/internals';
import { inject as service } from '@ember/service';
import queryString from 'npm:query-string';
import ApplicationAdapter from './application';
export default ApplicationAdapter.extend({
watchList: service(),
store: service(),
findRecord(store, type, id, snapshot, additionalParams = {}) {
const params = copy(additionalParams, true);
const url = this.buildURL(type.modelName, id, snapshot, 'findRecord');
if (get(snapshot, 'adapterOptions.watch')) {
params.index = this.get('watchList').getIndexFor(url);
}
return this.ajax(url, 'GET', {
data: params,
});
},
reloadRelationship(model, relationshipName, watch = false) {
const relationship = model.relationshipFor(relationshipName);
if (relationship.kind !== 'belongsTo' && relationship.kind !== 'hasMany') {
throw new Error(
`${relationship.key} must be a belongsTo or hasMany, instead it was ${relationship.kind}`
);
} else {
const url = model[relationship.kind](relationship.key).link();
let params = {};
if (watch) {
params.index = this.get('watchList').getIndexFor(url);
}
if (url.includes('?')) {
params = assign(queryString.parse(url.split('?')[1]), params);
}
this.ajax(url, 'GET', {
data: params,
}).then(json => {
this.get('store').pushPayload(relationship.type, {
[relationship.type]: relationship.kind === 'hasMany' ? json : [json],
});
});
}
},
handleResponse(status, headers, payload, requestData) {
const newIndex = headers['x-nomad-index'];
if (newIndex) {
this.get('watchList').setIndexFor(requestData.url, newIndex);
}
return this._super(...arguments);
},
});

View File

@@ -2,9 +2,13 @@ import { inject as service } from '@ember/service';
import Route from '@ember/routing/route';
import RSVP from 'rsvp';
import notifyError from 'nomad-ui/utils/notify-error';
import { task } from 'ember-concurrency';
import wait from 'nomad-ui/utils/wait';
export default Route.extend({
store: service(),
token: service(),
watchList: service(),
serialize(model) {
return { job_name: model.get('plainId') };
@@ -21,4 +25,41 @@ export default Route.extend({
})
.catch(notifyError(this));
},
setupController(controller, model) {
controller.set('modelTask', this.get('watch').perform(model.get('id')));
controller.set('summaryTask', this.get('watchRelationship').perform(model, 'summary'));
controller.set('evaluationsTask', this.get('watchRelationship').perform(model, 'evaluations'));
controller.set('deploymentsTask', this.get('watchRelationship').perform(model, 'deployments'));
},
watch: task(function*(jobId) {
while (true) {
try {
yield RSVP.all([
this.store.findRecord('job', jobId, { reload: true, adapterOptions: { watch: true } }),
wait(2000),
]);
} catch (e) {
yield e;
break;
}
}
}),
watchRelationship: task(function*(job, relationshipName) {
while (true) {
try {
yield RSVP.all([
this.store
.adapterFor(job.get('modelName'))
.reloadRelationship(job, relationshipName, true),
wait(2000),
]);
} catch (e) {
yield e;
break;
}
}
}),
});

View File

@@ -0,0 +1,19 @@
import { readOnly } from '@ember/object/computed';
import { copy } from '@ember/object/internals';
import Service from '@ember/service';
const list = {};
export default Service.extend({
list: readOnly(function() {
return copy(list, true);
}),
getIndexFor(url) {
return list[url] || 0;
},
setIndexFor(url, value) {
list[url] = value;
},
});

10
ui/app/utils/wait.js Normal file
View File

@@ -0,0 +1,10 @@
import RSVP from 'rsvp';
// An always passing promise used to throttle other promises
export default function wait(duration) {
return new RSVP.Promise(resolve => {
setTimeout(() => {
resolve(`Waited ${duration}ms`);
}, duration);
});
}