Commit c9e02b8a authored by Phil Hughes's avatar Phil Hughes

Merge branch 'pb-add-polling-to-widget-base-component' into 'master'

Add polling to MR widget base component

See merge request gitlab-org/gitlab!77605
parents ebc509a6 423dfa6d
......@@ -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