Commit 423dfa6d authored by Payton Burdette's avatar Payton Burdette Committed by Phil Hughes

Add polling to base component

Add polling ability to the MR widget
base component for extensions to use.
parent 00c39d32
......@@ -13,6 +13,7 @@ import * as Sentry from '@sentry/browser';
import api from '~/api';
import { sprintf, s__, __ } from '~/locale';
import SmartVirtualList from '~/vue_shared/components/smart_virtual_list.vue';
import Poll from '~/lib/utils/poll';
import { EXTENSION_ICON_CLASS, EXTENSION_ICONS } from '../../constants';
import StatusIcon from './status_icon.vue';
import Actions from './actions.vue';
......@@ -132,19 +133,50 @@ export default {
this.triggerRedisTracking();
},
initExtensionPolling() {
const poll = new Poll({
resource: {
fetchData: () => this.fetchCollapsedData(this.$props),
},
method: 'fetchData',
successCallback: (data) => {
if (Object.keys(data).length > 0) {
poll.stop();
this.setCollapsedData(data);
}
},
errorCallback: (e) => {
poll.stop();
this.setCollapsedError(e);
},
});
poll.makeRequest();
},
loadCollapsedData() {
this.loadingState = LOADING_STATES.collapsedLoading;
this.fetchCollapsedData(this.$props)
.then((data) => {
this.collapsedData = data;
this.loadingState = null;
})
.catch((e) => {
this.loadingState = LOADING_STATES.collapsedError;
if (this.$options.enablePolling) {
this.initExtensionPolling();
} else {
this.fetchCollapsedData(this.$props)
.then((data) => {
this.setCollapsedData(data);
})
.catch((e) => {
this.setCollapsedError(e);
});
}
},
setCollapsedData(data) {
this.collapsedData = data;
this.loadingState = null;
},
setCollapsedError(e) {
this.loadingState = LOADING_STATES.collapsedError;
Sentry.captureException(e);
});
Sentry.captureException(e);
},
loadAllData() {
if (this.hasFullData) return;
......
......@@ -13,6 +13,7 @@ export const registerExtension = (extension) => {
props: extension.props,
i18n: extension.i18n,
expandEvent: extension.expandEvent,
enablePolling: extension.enablePolling,
computed: {
...Object.keys(extension.computed).reduce(
(acc, computedKey) => ({
......
import { __, n__, s__, sprintf } from '~/locale';
import axios from '~/lib/utils/axios_utils';
import Poll from '~/lib/utils/poll';
import { EXTENSION_ICONS } from '../../constants';
export default {
name: 'WidgetTerraform',
enablePolling: true,
i18n: {
label: s__('Terraform|Terraform reports'),
loading: s__('Terraform|Loading Terraform reports...'),
......@@ -81,34 +81,17 @@ export default {
},
// Custom methods
fetchPlans() {
return new Promise((resolve) => {
const poll = new Poll({
resource: {
fetchPlans: () => axios.get(this.terraformReportsPath),
},
data: this.terraformReportsPath,
method: 'fetchPlans',
successCallback: ({ data }) => {
if (Object.keys(data).length > 0) {
poll.stop();
const result = Object.keys(data).map((key) => {
return data[key];
});
resolve(result);
}
},
errorCallback: () => {
const invalidData = { tf_report_error: 'api_error' };
poll.stop();
const result = [invalidData];
resolve(result);
},
return axios
.get(this.terraformReportsPath)
.then(({ data }) => {
return Object.keys(data).map((key) => {
return data[key];
});
})
.catch(() => {
const invalidData = { tf_report_error: 'api_error' };
return [invalidData];
});
poll.makeRequest();
});
},
createReportRow(report, iconName) {
const addNum = Number(report.create);
......
......@@ -9,6 +9,7 @@ import waitForPromises from 'helpers/wait_for_promises';
import { securityReportMergeRequestDownloadPathsQueryResponse } from 'jest/vue_shared/security_reports/mock_data';
import api from '~/api';
import axios from '~/lib/utils/axios_utils';
import Poll from '~/lib/utils/poll';
import { setFaviconOverlay } from '~/lib/utils/favicon';
import notify from '~/lib/utils/notify';
import SmartInterval from '~/smart_interval';
......@@ -28,6 +29,8 @@ import {
workingExtension,
collapsedDataErrorExtension,
fullDataErrorExtension,
pollingExtension,
pollingErrorExtension,
} from './test_extensions';
jest.mock('~/api.js');
......@@ -897,13 +900,19 @@ describe('MrWidgetOptions', () => {
});
describe('mock extension', () => {
let pollRequest;
beforeEach(() => {
pollRequest = jest.spyOn(Poll.prototype, 'makeRequest');
registerExtension(workingExtension);
createComponent();
});
afterEach(() => {
pollRequest.mockRestore();
registeredExtensions.extensions = [];
});
......@@ -957,6 +966,66 @@ describe('MrWidgetOptions', () => {
expect(collapsedSection.find(GlButton).exists()).toBe(true);
expect(collapsedSection.find(GlButton).text()).toBe('Full report');
});
it('extension polling is not called if enablePolling flag is not passed', () => {
// called one time due to parent component polling (mount)
expect(pollRequest).toHaveBeenCalledTimes(1);
});
});
describe('mock polling extension', () => {
let pollRequest;
let pollStop;
beforeEach(() => {
pollRequest = jest.spyOn(Poll.prototype, 'makeRequest');
pollStop = jest.spyOn(Poll.prototype, 'stop');
});
afterEach(() => {
pollRequest.mockRestore();
pollStop.mockRestore();
registeredExtensions.extensions = [];
});
describe('success', () => {
beforeEach(() => {
registerExtension(pollingExtension);
createComponent();
});
it('does not make additional requests after poll is successful', () => {
// called two times due to parent component polling (mount) and extension polling
expect(pollRequest).toHaveBeenCalledTimes(2);
expect(pollStop).toHaveBeenCalledTimes(1);
});
});
describe('error', () => {
let captureException;
beforeEach(() => {
captureException = jest.spyOn(Sentry, 'captureException');
registerExtension(pollingErrorExtension);
createComponent();
});
it('does not make additional requests after poll has failed', () => {
// called two times due to parent component polling (mount) and extension polling
expect(pollRequest).toHaveBeenCalledTimes(2);
expect(pollStop).toHaveBeenCalledTimes(1);
});
it('captures sentry error and displays error when poll has failed', () => {
expect(captureException).toHaveBeenCalledTimes(1);
expect(captureException).toHaveBeenCalledWith(new Error('Fetch error'));
expect(wrapper.findComponent(StatusIcon).props('iconName')).toBe('error');
});
});
});
describe('mock extension errors', () => {
......
......@@ -97,3 +97,13 @@ export const fullDataErrorExtension = {
},
},
};
export const pollingExtension = {
...workingExtension,
enablePolling: true,
};
export const pollingErrorExtension = {
...collapsedDataErrorExtension,
enablePolling: true,
};
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