summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Drozdov <idrozdov@gitlab.com>2019-08-26 02:53:04 +0300
committerIgor Drozdov <idrozdov@gitlab.com>2019-08-29 16:32:49 +0300
commit17b89ca525243a1d9733e3c9793f1582fa414c51 (patch)
tree0cdf4e252b167a5f2c0c5155254167407df5fc4c
parentf7e3693435307b56e4da8d8584c6af01459e4813 (diff)
downloadgitlab-ce-id-load-mr-widget-async.tar.gz
Render MR widget info asyncid-load-mr-widget-async
Since we have an endpoint which returns MR widget info We can preload this info async which will paralel the rendering of the page
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/index.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue61
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js10
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js4
-rw-r--r--app/controllers/projects/merge_requests_controller.rb2
-rw-r--r--app/serializers/merge_request_widget_entity.rb8
-rw-r--r--app/views/projects/merge_requests/show.html.haml5
-rw-r--r--changelogs/unreleased/id-load-mr-widget-async.yml5
-rw-r--r--spec/javascripts/vue_mr_widget/mr_widget_options_spec.js14
9 files changed, 81 insertions, 30 deletions
diff --git a/app/assets/javascripts/vue_merge_request_widget/index.js b/app/assets/javascripts/vue_merge_request_widget/index.js
index 0cedbdbdfef..d8320a47769 100644
--- a/app/assets/javascripts/vue_merge_request_widget/index.js
+++ b/app/assets/javascripts/vue_merge_request_widget/index.js
@@ -5,8 +5,6 @@ import Translate from '../vue_shared/translate';
Vue.use(Translate);
export default () => {
- gl.mrWidgetData.gitlabLogo = gon.gitlab_logo;
-
const vm = new Vue(MrWidgetOptions);
window.gl.mrWidget = {
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index edd21a81f8b..c5b7165865f 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -78,13 +78,23 @@ export default {
required: false,
default: null,
},
+ mr: {
+ type: Object,
+ required: false,
+ default: null,
+ },
+ store: {
+ type: Object,
+ required: false,
+ default: null,
+ },
},
data() {
- const store = new MRWidgetStore(this.mrData || window.gl.mrWidgetData);
- const service = this.createService(store);
+ const data = this.mrData || window.gl.mrWidgetData;
+ const service = new MRWidgetService(data);
+
return {
- mr: store,
- state: store.state,
+ isLoaded: false,
service,
};
},
@@ -134,17 +144,26 @@ export default {
},
},
created() {
- this.initPolling();
- this.bindEventHubListeners();
- eventHub.$on('mr.discussion.updated', this.checkStatus);
- },
- mounted() {
- this.setFaviconHelper();
- this.initDeploymentsPolling();
+ this.service
+ .fetchWidgetData()
+ .then(({ data }) => {
+ this.init(data);
- if (this.shouldRenderMergedPipeline) {
- this.initPostMergeDeploymentsPolling();
- }
+ this.initPolling();
+
+ this.bindEventHubListeners();
+ eventHub.$on('mr.discussion.updated', this.checkStatus);
+
+ this.setFaviconHelper();
+ this.initDeploymentsPolling();
+
+ if (this.shouldRenderMergedPipeline) {
+ this.initPostMergeDeploymentsPolling();
+ }
+
+ this.isLoaded = true;
+ })
+ .catch(() => createFlash(__('Something went wrong. Please try again.')));
},
beforeDestroy() {
eventHub.$off('mr.discussion.updated', this.checkStatus);
@@ -156,6 +175,13 @@ export default {
}
},
methods: {
+ init(data) {
+ const store = new MRWidgetStore(data);
+
+ this.mr = store;
+ this.state = store.state;
+ this.service.addEndpoints(this.getServiceEndpoints(store));
+ },
getServiceEndpoints(store) {
return {
mergePath: store.mergePath,
@@ -165,15 +191,12 @@ export default {
sourceBranchPath: store.sourceBranchPath,
ciEnvironmentsStatusPath: store.ciEnvironmentsStatusPath,
mergeRequestBasicPath: store.mergeRequestBasicPath,
- mergeRequestWidgetPath: store.mergeRequestWidgetPath,
+ mergeRequestPollWidgetPath: store.mergeRequestPollWidgetPath,
mergeRequestCachedWidgetPath: store.mergeRequestCachedWidgetPath,
mergeActionsContentPath: store.mergeActionsContentPath,
rebasePath: store.rebasePath,
};
},
- createService(store) {
- return new MRWidgetService(this.getServiceEndpoints(store));
- },
checkStatus(cb, isRebased) {
return this.service
.checkStatus()
@@ -319,7 +342,7 @@ export default {
};
</script>
<template>
- <div class="mr-state-widget prepend-top-default">
+ <div v-if="isLoaded" class="mr-state-widget prepend-top-default">
<mr-widget-header :mr="mr" />
<mr-widget-pipeline-container
v-if="shouldRenderPipelines"
diff --git a/app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js b/app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js
index f637a44bf2d..1433b409eb2 100644
--- a/app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js
+++ b/app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js
@@ -5,6 +5,10 @@ export default class MRWidgetService {
this.endpoints = endpoints;
}
+ addEndpoints(endpoints) {
+ Object.assign(this.endpoints, endpoints);
+ }
+
merge(data) {
return axios.post(this.endpoints.mergePath, data);
}
@@ -29,6 +33,10 @@ export default class MRWidgetService {
});
}
+ fetchWidgetData() {
+ return axios.get(this.endpoints.mergeRequestWidgetPath);
+ }
+
poll() {
return axios.get(this.endpoints.mergeRequestBasicPath);
}
@@ -38,7 +46,7 @@ export default class MRWidgetService {
// one which is etag-cached and invalidated and another one which is not cached
// the idea is to move all the fields to etag-cached endpoint and then perform only one request
// https://gitlab.com/gitlab-org/gitlab-ce/issues/61559#note_188801390
- const getData = axios.get(this.endpoints.mergeRequestWidgetPath);
+ const getData = axios.get(this.endpoints.mergeRequestPollWidgetPath);
const getCachedData = axios.get(this.endpoints.mergeRequestCachedWidgetPath);
return axios
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
index 7843409f4a7..bb6e82c8b5f 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
@@ -8,7 +8,7 @@ import { ATMTWPS_MERGE_STRATEGY, MT_MERGE_STRATEGY, MWPS_MERGE_STRATEGY } from '
export default class MergeRequestStore {
constructor(data) {
this.sha = data.diff_head_sha;
- this.gitlabLogo = data.gitlabLogo;
+ this.gitlabLogo = gon.gitlab_logo;
this.setPaths(data);
@@ -157,7 +157,7 @@ export default class MergeRequestStore {
this.squashBeforeMergeHelpPath = data.squash_before_merge_help_path;
this.troubleshootingDocsPath = data.troubleshooting_docs_path;
this.mergeRequestBasicPath = data.merge_request_basic_path;
- this.mergeRequestWidgetPath = data.merge_request_widget_path;
+ this.mergeRequestPollWidgetPath = data.merge_request_widget_path;
this.mergeRequestCachedWidgetPath = data.merge_request_cached_widget_path;
this.emailPatchesPath = data.email_patches_path;
this.plainDiffPath = data.plain_diff_path;
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index d492c5227cf..40f392ec070 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -56,7 +56,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
format.json do
Gitlab::PollingInterval.set_header(response, interval: 10_000)
- render json: serializer.represent(@merge_request, serializer: params[:serializer])
+ render json: serializer.represent(@merge_request, serializer: params[:serializer], issues_links: true)
end
format.patch do
diff --git a/app/serializers/merge_request_widget_entity.rb b/app/serializers/merge_request_widget_entity.rb
index 2f2c42a7387..b3dd9e627a5 100644
--- a/app/serializers/merge_request_widget_entity.rb
+++ b/app/serializers/merge_request_widget_entity.rb
@@ -43,6 +43,14 @@ class MergeRequestWidgetEntity < Grape::Entity
help_page_path('ci/merge_request_pipelines/index.md')
end
+ expose :squash_before_merge_help_path do |merge_request|
+ help_page_path("user/project/merge_requests/squash_and_merge")
+ end
+
+ expose :troubleshooting_docs_path do |merge_request|
+ help_page_path('user/project/merge_requests/index.md', anchor: 'troubleshooting')
+ end
+
expose :ci_environments_status_path do |merge_request|
ci_environments_status_project_merge_request_path(merge_request.project, merge_request)
end
diff --git a/app/views/projects/merge_requests/show.html.haml b/app/views/projects/merge_requests/show.html.haml
index ea166d622eb..28f5c02ff05 100644
--- a/app/views/projects/merge_requests/show.html.haml
+++ b/app/views/projects/merge_requests/show.html.haml
@@ -20,10 +20,9 @@
= javascript_tag nonce: true do
:plain
window.gl = window.gl || {};
- window.gl.mrWidgetData = #{serialize_issuable(@merge_request, serializer: 'widget', issues_links: true)}
+ window.gl.mrWidgetData = window.gl.mrWidgetData || {}
- window.gl.mrWidgetData.squash_before_merge_help_path = '#{help_page_path("user/project/merge_requests/squash_and_merge")}';
- window.gl.mrWidgetData.troubleshooting_docs_path = '#{help_page_path('user/project/merge_requests/index.md', anchor: 'troubleshooting')}';
+ window.gl.mrWidgetData.mergeRequestWidgetPath = "#{project_merge_request_path(@merge_request.target_project, @merge_request, serializer: :widget, format: :json)}";
#js-vue-mr-widget.mr-widget
diff --git a/changelogs/unreleased/id-load-mr-widget-async.yml b/changelogs/unreleased/id-load-mr-widget-async.yml
new file mode 100644
index 00000000000..49fa9b05ecb
--- /dev/null
+++ b/changelogs/unreleased/id-load-mr-widget-async.yml
@@ -0,0 +1,5 @@
+---
+title: Render MR widget info asynchronously
+merge_request: 32190
+author:
+type: performance
diff --git a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
index 30e0504e4e1..92550b1ac3e 100644
--- a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
+++ b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
@@ -4,7 +4,9 @@ import eventHub from '~/vue_merge_request_widget/event_hub';
import notify from '~/lib/utils/notify';
import { stateKey } from '~/vue_merge_request_widget/stores/state_maps';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
+import MockAdapter from 'axios-mock-adapter';
import mockData from './mock_data';
+import axios from '~/lib/utils/axios_utils';
import { faviconDataUrl, overlayDataUrl } from '../lib/utils/mock_data';
const returnPromise = data =>
@@ -15,23 +17,31 @@ const returnPromise = data =>
});
describe('mrWidgetOptions', () => {
+ let axiosMock;
let vm;
let MrWidgetOptions;
+ const mergeRequestWidgetPath = '/merge/request/widget/path';
const COLLABORATION_MESSAGE = 'Allows commits from members who can merge to the target branch';
- beforeEach(() => {
+ beforeEach(done => {
// Prevent component mounting
delete mrWidgetOptions.el;
+ axiosMock = new MockAdapter(axios);
+ axiosMock.onGet(mergeRequestWidgetPath).reply(200, mockData);
+
MrWidgetOptions = Vue.extend(mrWidgetOptions);
vm = mountComponent(MrWidgetOptions, {
- mrData: { ...mockData },
+ mrData: { mergeRequestWidgetPath },
});
+
+ done();
});
afterEach(() => {
vm.$destroy();
+ axiosMock.restore();
});
describe('data', () => {