Commit 15ca592f authored by Jacob Schatz's avatar Jacob Schatz

Merge branch '5983-poll-changes' into 'master'

Adds restart method and auxiliar callback to polling class

See merge request !10223
parents 387f2c43 81ed06cb
...@@ -5,23 +5,37 @@ import httpStatusCodes from './http_status'; ...@@ -5,23 +5,37 @@ import httpStatusCodes from './http_status';
* Service for vue resouce and method need to be provided as props * Service for vue resouce and method need to be provided as props
* *
* @example * @example
* new poll({ * new Poll({
* resource: resource, * resource: resource,
* method: 'name', * method: 'name',
* data: {page: 1, scope: 'all'}, * data: {page: 1, scope: 'all'}, // optional
* successCallback: () => {}, * successCallback: () => {},
* errorCallback: () => {}, * errorCallback: () => {},
* notificationCallback: () => {}, // optional
* }).makeRequest(); * }).makeRequest();
* *
* this.service = new BoardsService(endpoint); * Usage in pipelines table with visibility lib:
* new poll({
* resource: this.service,
* method: 'get',
* data: {page: 1, scope: 'all'},
* successCallback: () => {},
* errorCallback: () => {},
* }).makeRequest();
* *
* const poll = new Poll({
* resource: this.service,
* method: 'getPipelines',
* data: { page: pageNumber, scope },
* successCallback: this.successCallback,
* errorCallback: this.errorCallback,
* notificationCallback: this.updateLoading,
* });
*
* if (!Visibility.hidden()) {
* poll.makeRequest();
* }
*
* Visibility.change(() => {
* if (!Visibility.hidden()) {
* poll.restart();
* } else {
* poll.stop();
* }
* });
* *
* 1. Checks for response and headers before start polling * 1. Checks for response and headers before start polling
* 2. Interval is provided by `Poll-Interval` header. * 2. Interval is provided by `Poll-Interval` header.
...@@ -34,6 +48,8 @@ export default class Poll { ...@@ -34,6 +48,8 @@ export default class Poll {
constructor(options = {}) { constructor(options = {}) {
this.options = options; this.options = options;
this.options.data = options.data || {}; this.options.data = options.data || {};
this.options.notificationCallback = options.notificationCallback ||
function notificationCallback() {};
this.intervalHeader = 'POLL-INTERVAL'; this.intervalHeader = 'POLL-INTERVAL';
this.timeoutID = null; this.timeoutID = null;
...@@ -42,7 +58,7 @@ export default class Poll { ...@@ -42,7 +58,7 @@ export default class Poll {
checkConditions(response) { checkConditions(response) {
const headers = gl.utils.normalizeHeaders(response.headers); const headers = gl.utils.normalizeHeaders(response.headers);
const pollInterval = headers[this.intervalHeader]; const pollInterval = parseInt(headers[this.intervalHeader], 10);
if (pollInterval > 0 && response.status === httpStatusCodes.OK && this.canPoll) { if (pollInterval > 0 && response.status === httpStatusCodes.OK && this.canPoll) {
this.timeoutID = setTimeout(() => { this.timeoutID = setTimeout(() => {
...@@ -54,11 +70,14 @@ export default class Poll { ...@@ -54,11 +70,14 @@ export default class Poll {
} }
makeRequest() { makeRequest() {
const { resource, method, data, errorCallback } = this.options; const { resource, method, data, errorCallback, notificationCallback } = this.options;
// It's called everytime a new request is made. Useful to update the status.
notificationCallback(true);
return resource[method](data) return resource[method](data)
.then(response => this.checkConditions(response)) .then(response => this.checkConditions(response))
.catch(error => errorCallback(error)); .catch(error => errorCallback(error));
} }
/** /**
...@@ -70,4 +89,12 @@ export default class Poll { ...@@ -70,4 +89,12 @@ export default class Poll {
this.canPoll = false; this.canPoll = false;
clearTimeout(this.timeoutID); clearTimeout(this.timeoutID);
} }
/**
* Restarts polling after it has been stoped
*/
restart() {
this.canPoll = true;
this.makeRequest();
}
} }
...@@ -160,4 +160,44 @@ describe('Poll', () => { ...@@ -160,4 +160,44 @@ describe('Poll', () => {
Vue.http.interceptors = _.without(Vue.http.interceptors, pollInterceptor); Vue.http.interceptors = _.without(Vue.http.interceptors, pollInterceptor);
}); });
}); });
describe('restart', () => {
it('should restart polling when its called', (done) => {
const pollInterceptor = (request, next) => {
next(request.respondWith(JSON.stringify([]), { status: 200, headers: { 'poll-interval': 2 } }));
};
Vue.http.interceptors.push(pollInterceptor);
const service = new ServiceMock('endpoint');
spyOn(service, 'fetch').and.callThrough();
const Polling = new Poll({
resource: service,
method: 'fetch',
data: { page: 1 },
successCallback: () => {
Polling.stop();
setTimeout(() => {
Polling.restart();
}, 0);
},
errorCallback: callbacks.error,
});
spyOn(Polling, 'stop').and.callThrough();
Polling.makeRequest();
setTimeout(() => {
expect(service.fetch.calls.count()).toEqual(2);
expect(service.fetch).toHaveBeenCalledWith({ page: 1 });
expect(Polling.stop).toHaveBeenCalled();
done();
}, 10);
Vue.http.interceptors = _.without(Vue.http.interceptors, pollInterceptor);
});
});
}); });
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment