diff options
author | Igor Drozdov <idrozdov@gitlab.com> | 2019-08-26 02:53:04 +0300 |
---|---|---|
committer | Igor Drozdov <idrozdov@gitlab.com> | 2019-08-29 16:32:49 +0300 |
commit | 17b89ca525243a1d9733e3c9793f1582fa414c51 (patch) | |
tree | 0cdf4e252b167a5f2c0c5155254167407df5fc4c | |
parent | f7e3693435307b56e4da8d8584c6af01459e4813 (diff) | |
download | gitlab-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
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', () => { |