diff options
author | James Lopez <james@gitlab.com> | 2017-04-04 10:30:36 +0000 |
---|---|---|
committer | James Lopez <james@gitlab.com> | 2017-04-04 10:30:36 +0000 |
commit | 956ed72e7417e494d22cb0f89482a1b9d7d44702 (patch) | |
tree | 22227856b9c7b8e4a76d6238308550938d0e4e0e | |
parent | 4eb27a395902c001d1883c0379516cc79dc65402 (diff) | |
parent | 93b08c8ce384b9a31830fddbe6164f8848e540b3 (diff) | |
download | gitlab-ce-956ed72e7417e494d22cb0f89482a1b9d7d44702.tar.gz |
Merge branch '29539-fix-pipelines-container-width-with-parallel-diff-for-9-0-stable-merge' into '9-0-stable'
Reset container width when switching to pipelines MR tab -- `9-0-stable` merge edition
See merge request !10424
-rw-r--r-- | app/assets/javascripts/commit/pipelines/pipelines_bundle.js | 5 | ||||
-rw-r--r-- | app/assets/javascripts/commit/pipelines/pipelines_table.js | 142 | ||||
-rw-r--r-- | app/assets/javascripts/merge_request_tabs.js | 36 | ||||
-rw-r--r-- | app/assets/javascripts/vue_pipelines_index/pipelines.js | 5 | ||||
-rw-r--r-- | app/assets/javascripts/vue_shared/components/pipelines_table.js | 72 | ||||
-rw-r--r-- | lib/tasks/karma.rake | 5 | ||||
-rw-r--r-- | spec/javascripts/commit/pipelines/pipelines_spec.js | 32 | ||||
-rw-r--r-- | spec/javascripts/fixtures/merge_requests.rb | 12 | ||||
-rw-r--r-- | spec/javascripts/merge_request_tabs_spec.js | 40 | ||||
-rw-r--r-- | spec/javascripts/vue_shared/components/pipelines_table_spec.js | 15 |
10 files changed, 217 insertions, 147 deletions
diff --git a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js index b5a988df897..87a9cc13a7e 100644 --- a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js +++ b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js @@ -2,7 +2,8 @@ /* global Vue, CommitsPipelineStore, PipelinesService, Flash */ window.Vue = require('vue'); -require('./pipelines_table'); +const PipelinesTable = require('./pipelines_table'); + /** * Commits View > Pipelines Tab > Pipelines Table. * Merge Request View > Pipelines Tab > Pipelines Table. @@ -21,7 +22,7 @@ $(() => { } const pipelineTableViewEl = document.querySelector('#commit-pipeline-table-view'); - gl.commits.pipelines.PipelinesTableBundle = new gl.commits.pipelines.PipelinesTableView(); + gl.commits.pipelines.PipelinesTableBundle = new PipelinesTable(); if (pipelineTableViewEl && pipelineTableViewEl.dataset.disableInitialization === undefined) { gl.commits.pipelines.PipelinesTableBundle.$mount(pipelineTableViewEl); diff --git a/app/assets/javascripts/commit/pipelines/pipelines_table.js b/app/assets/javascripts/commit/pipelines/pipelines_table.js index 631ed34851c..4e770ab7c31 100644 --- a/app/assets/javascripts/commit/pipelines/pipelines_table.js +++ b/app/assets/javascripts/commit/pipelines/pipelines_table.js @@ -5,9 +5,9 @@ window.Vue = require('vue'); window.Vue.use(require('vue-resource')); require('../../lib/utils/common_utils'); require('../../vue_shared/vue_resource_interceptor'); -require('../../vue_shared/components/pipelines_table'); require('./pipelines_service'); const PipelineStore = require('./pipelines_store'); +const PipelinesTableComponent = require('../../vue_shared/components/pipelines_table'); /** * @@ -19,86 +19,78 @@ const PipelineStore = require('./pipelines_store'); * Necessary SVG in the table are provided as props. This should be refactored * as soon as we have Webpack and can load them directly into JS files. */ +module.exports = Vue.component('pipelines-table', { + components: { + 'pipelines-table-component': PipelinesTableComponent, + }, -(() => { - window.gl = window.gl || {}; - gl.commits = gl.commits || {}; - gl.commits.pipelines = gl.commits.pipelines || {}; + /** + * Accesses the DOM to provide the needed data. + * Returns the necessary props to render `pipelines-table-component` component. + * + * @return {Object} + */ + data() { + const store = new PipelineStore(); - gl.commits.pipelines.PipelinesTableView = Vue.component('pipelines-table', { + return { + endpoint: null, + store, + state: store.state, + isLoading: false, + }; + }, - components: { - 'pipelines-table-component': gl.pipelines.PipelinesTableComponent, - }, + /** + * When the component is about to be mounted, tell the service to fetch the data + * + * A request to fetch the pipelines will be made. + * In case of a successfull response we will store the data in the provided + * store, in case of a failed response we need to warn the user. + * + */ + beforeMount() { + this.endpoint = this.$el.dataset.endpoint; + const pipelinesService = new gl.commits.pipelines.PipelinesService(this.endpoint); - /** - * Accesses the DOM to provide the needed data. - * Returns the necessary props to render `pipelines-table-component` component. - * - * @return {Object} - */ - data() { - const pipelinesTableData = document.querySelector('#commit-pipeline-table-view').dataset; - const store = new PipelineStore(); + this.isLoading = true; + return pipelinesService.all() + .then(response => response.json()) + .then((json) => { + // depending of the endpoint the response can either bring a `pipelines` key or not. + const pipelines = json.pipelines || json; + this.store.storePipelines(pipelines); + this.isLoading = false; + }) + .catch(() => { + this.isLoading = false; + new Flash('An error occurred while fetching the pipelines, please reload the page again.', 'alert'); + }); + }, - return { - endpoint: pipelinesTableData.endpoint, - store, - state: store.state, - isLoading: false, - }; - }, + beforeUpdate() { + if (this.state.pipelines.length && this.$children) { + PipelineStore.startTimeAgoLoops.call(this, Vue); + } + }, - /** - * When the component is about to be mounted, tell the service to fetch the data - * - * A request to fetch the pipelines will be made. - * In case of a successfull response we will store the data in the provided - * store, in case of a failed response we need to warn the user. - * - */ - beforeMount() { - const pipelinesService = new gl.commits.pipelines.PipelinesService(this.endpoint); - - this.isLoading = true; - return pipelinesService.all() - .then(response => response.json()) - .then((json) => { - // depending of the endpoint the response can either bring a `pipelines` key or not. - const pipelines = json.pipelines || json; - this.store.storePipelines(pipelines); - this.isLoading = false; - }) - .catch(() => { - this.isLoading = false; - new Flash('An error occurred while fetching the pipelines, please reload the page again.', 'alert'); - }); - }, - - beforeUpdate() { - if (this.state.pipelines.length && this.$children) { - PipelineStore.startTimeAgoLoops.call(this, Vue); - } - }, - - template: ` - <div class="pipelines"> - <div class="realtime-loading" v-if="isLoading"> - <i class="fa fa-spinner fa-spin"></i> - </div> + template: ` + <div class="pipelines"> + <div class="realtime-loading" v-if="isLoading"> + <i class="fa fa-spinner fa-spin"></i> + </div> - <div class="blank-state blank-state-no-icon" - v-if="!isLoading && state.pipelines.length === 0"> - <h2 class="blank-state-title js-blank-state-title"> - No pipelines to show - </h2> - </div> + <div class="blank-state blank-state-no-icon" + v-if="!isLoading && state.pipelines.length === 0"> + <h2 class="blank-state-title js-blank-state-title"> + No pipelines to show + </h2> + </div> - <div class="table-holder pipelines" - v-if="!isLoading && state.pipelines.length > 0"> - <pipelines-table-component :pipelines="state.pipelines"/> - </div> + <div class="table-holder pipelines" + v-if="!isLoading && state.pipelines.length > 0"> + <pipelines-table-component :pipelines="state.pipelines"/> </div> - `, - }); -})(); + </div> + `, +}); diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js index 190336dbd20..3f0ad6490b5 100644 --- a/app/assets/javascripts/merge_request_tabs.js +++ b/app/assets/javascripts/merge_request_tabs.js @@ -3,9 +3,12 @@ /* global Cookies */ /* global Flash */ -require('./breakpoints'); -window.Cookies = require('js-cookie'); -require('./flash'); +import Cookies from 'js-cookie'; + +import './breakpoints'; +import './flash'; + +const PipelinesTable = require('./commit/pipelines/pipelines_table'); /* eslint-disable max-len */ // MergeRequestTabs @@ -97,6 +100,13 @@ require('./flash'); .off('click', this.clickTab); } + destroy() { + this.unbindEvents(); + if (this.commitPipelinesTable) { + this.commitPipelinesTable.$destroy(); + } + } + showTab(e) { e.preventDefault(); this.activateTab($(e.target).data('action')); @@ -131,12 +141,8 @@ require('./flash'); offset: 0, }); } else if (action === 'pipelines') { - if (this.pipelinesLoaded) { - return; - } - const pipelineTableViewEl = document.querySelector('#commit-pipeline-table-view'); - gl.commits.pipelines.PipelinesTableBundle.$mount(pipelineTableViewEl); - this.pipelinesLoaded = true; + this.resetViewContainer(); + this.loadPipelines(); } else { this.expandView(); this.resetViewContainer(); @@ -225,6 +231,18 @@ require('./flash'); }); } + loadPipelines() { + if (this.pipelinesLoaded) { + return; + } + const pipelineTableViewEl = document.querySelector('#commit-pipeline-table-view'); + // Could already be mounted from the `pipelines_bundle` + if (pipelineTableViewEl) { + this.commitPipelinesTable = new PipelinesTable().$mount(pipelineTableViewEl); + } + this.pipelinesLoaded = true; + } + loadDiff(source) { if (this.diffsLoaded) { return; diff --git a/app/assets/javascripts/vue_pipelines_index/pipelines.js b/app/assets/javascripts/vue_pipelines_index/pipelines.js index 601ef41e917..4732092ab14 100644 --- a/app/assets/javascripts/vue_pipelines_index/pipelines.js +++ b/app/assets/javascripts/vue_pipelines_index/pipelines.js @@ -2,17 +2,18 @@ /* eslint-disable no-param-reassign */ window.Vue = require('vue'); + require('../vue_shared/components/table_pagination'); require('./store'); -require('../vue_shared/components/pipelines_table'); const CommitPipelinesStoreWithTimeAgo = require('../commit/pipelines/pipelines_store'); +const PipelinesTableComponent = require('../vue_shared/components/pipelines_table'); ((gl) => { gl.VuePipelines = Vue.extend({ components: { 'gl-pagination': gl.VueGlPagination, - 'pipelines-table-component': gl.pipelines.PipelinesTableComponent, + 'pipelines-table-component': PipelinesTableComponent, }, data() { diff --git a/app/assets/javascripts/vue_shared/components/pipelines_table.js b/app/assets/javascripts/vue_shared/components/pipelines_table.js index 0d8f85db965..c534bb85bf1 100644 --- a/app/assets/javascripts/vue_shared/components/pipelines_table.js +++ b/app/assets/javascripts/vue_shared/components/pipelines_table.js @@ -8,45 +8,39 @@ require('./pipelines_table_row'); * Given an array of objects, renders a table. */ -(() => { - window.gl = window.gl || {}; - gl.pipelines = gl.pipelines || {}; - - gl.pipelines.PipelinesTableComponent = Vue.component('pipelines-table-component', { - - props: { - pipelines: { - type: Array, - required: true, - default: () => ([]), - }, - +module.exports = { + props: { + pipelines: { + type: Array, + required: true, + default: () => ([]), }, - components: { - 'pipelines-table-row-component': gl.pipelines.PipelinesTableRowComponent, - }, + }, + + components: { + 'pipelines-table-row-component': gl.pipelines.PipelinesTableRowComponent, + }, - template: ` - <table class="table ci-table"> - <thead> - <tr> - <th class="js-pipeline-status pipeline-status">Status</th> - <th class="js-pipeline-info pipeline-info">Pipeline</th> - <th class="js-pipeline-commit pipeline-commit">Commit</th> - <th class="js-pipeline-stages pipeline-stages">Stages</th> - <th class="js-pipeline-date pipeline-date"></th> - <th class="js-pipeline-actions pipeline-actions"></th> - </tr> - </thead> - <tbody> - <template v-for="model in pipelines" - v-bind:model="model"> - <tr is="pipelines-table-row-component" - :pipeline="model"></tr> - </template> - </tbody> - </table> - `, - }); -})(); + template: ` + <table class="table ci-table"> + <thead> + <tr> + <th class="js-pipeline-status pipeline-status">Status</th> + <th class="js-pipeline-info pipeline-info">Pipeline</th> + <th class="js-pipeline-commit pipeline-commit">Commit</th> + <th class="js-pipeline-stages pipeline-stages">Stages</th> + <th class="js-pipeline-date pipeline-date"></th> + <th class="js-pipeline-actions pipeline-actions"></th> + </tr> + </thead> + <tbody> + <template v-for="model in pipelines" + v-bind:model="model"> + <tr is="pipelines-table-row-component" + :pipeline="model"></tr> + </template> + </tbody> + </table> + `, +}; diff --git a/lib/tasks/karma.rake b/lib/tasks/karma.rake index 40465ea3bf0..62a12174efa 100644 --- a/lib/tasks/karma.rake +++ b/lib/tasks/karma.rake @@ -1,9 +1,10 @@ unless Rails.env.production? namespace :karma do desc 'GitLab | Karma | Generate fixtures for JavaScript tests' - RSpec::Core::RakeTask.new(:fixtures) do |t| + RSpec::Core::RakeTask.new(:fixtures, [:pattern]) do |t, args| + args.with_defaults(pattern: 'spec/javascripts/fixtures/*.rb') ENV['NO_KNAPSACK'] = 'true' - t.pattern = 'spec/javascripts/fixtures/*.rb' + t.pattern = args[:pattern] t.rspec_opts = '--format documentation' end diff --git a/spec/javascripts/commit/pipelines/pipelines_spec.js b/spec/javascripts/commit/pipelines/pipelines_spec.js index f09c57978a1..5b76e2303ab 100644 --- a/spec/javascripts/commit/pipelines/pipelines_spec.js +++ b/spec/javascripts/commit/pipelines/pipelines_spec.js @@ -1,15 +1,18 @@ /* global pipeline, Vue */ +const PipelinesTable = require('~/commit/pipelines/pipelines_table'); + require('~/flash'); require('~/commit/pipelines/pipelines_store'); require('~/commit/pipelines/pipelines_service'); -require('~/commit/pipelines/pipelines_table'); require('~/vue_shared/vue_resource_interceptor'); const pipeline = require('./mock_data'); describe('Pipelines table in Commits and Merge requests', () => { preloadFixtures('static/pipelines_table.html.raw'); + let component; + beforeEach(() => { loadFixtures('static/pipelines_table.html.raw'); }); @@ -24,19 +27,20 @@ describe('Pipelines table in Commits and Merge requests', () => { beforeEach(() => { Vue.http.interceptors.push(pipelinesEmptyResponse); + + component = new PipelinesTable({ + el: document.querySelector('#commit-pipeline-table-view'), + }); }); afterEach(() => { Vue.http.interceptors = _.without( Vue.http.interceptors, pipelinesEmptyResponse, ); + component.$destroy(); }); it('should render the empty state', (done) => { - const component = new gl.commits.pipelines.PipelinesTableView({ - el: document.querySelector('#commit-pipeline-table-view'), - }); - setTimeout(() => { expect(component.$el.querySelector('.js-blank-state-title').textContent).toContain('No pipelines to show'); done(); @@ -53,19 +57,20 @@ describe('Pipelines table in Commits and Merge requests', () => { beforeEach(() => { Vue.http.interceptors.push(pipelinesResponse); + + component = new PipelinesTable({ + el: document.querySelector('#commit-pipeline-table-view'), + }); }); afterEach(() => { Vue.http.interceptors = _.without( Vue.http.interceptors, pipelinesResponse, ); + component.$destroy(); }); it('should render a table with the received pipelines', (done) => { - const component = new gl.commits.pipelines.PipelinesTableView({ - el: document.querySelector('#commit-pipeline-table-view'), - }); - setTimeout(() => { expect(component.$el.querySelectorAll('table > tbody > tr').length).toEqual(1); done(); @@ -83,19 +88,20 @@ describe('Pipelines table in Commits and Merge requests', () => { beforeEach(() => { Vue.http.interceptors.push(pipelinesErrorResponse); + + component = new PipelinesTable({ + el: document.querySelector('#commit-pipeline-table-view'), + }); }); afterEach(() => { Vue.http.interceptors = _.without( Vue.http.interceptors, pipelinesErrorResponse, ); + component.$destroy(); }); it('should render empty state', (done) => { - const component = new gl.commits.pipelines.PipelinesTableView({ - el: document.querySelector('#commit-pipeline-table-view'), - }); - setTimeout(() => { expect(component.$el.querySelector('.js-blank-state-title').textContent).toContain('No pipelines to show'); done(); diff --git a/spec/javascripts/fixtures/merge_requests.rb b/spec/javascripts/fixtures/merge_requests.rb index ee893b76c84..fddeaaf504d 100644 --- a/spec/javascripts/fixtures/merge_requests.rb +++ b/spec/javascripts/fixtures/merge_requests.rb @@ -6,6 +6,15 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont let(:admin) { create(:admin) } let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} let(:project) { create(:project, namespace: namespace, path: 'merge-requests-project') } + let(:merge_request) { create(:merge_request, :with_diffs, source_project: project, target_project: project, description: '- [ ] Task List Item') } + let(:pipeline) do + create( + :ci_pipeline, + project: merge_request.source_project, + ref: merge_request.source_branch, + sha: merge_request.diff_head_sha + ) + end render_views @@ -18,7 +27,8 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont end it 'merge_requests/merge_request_with_task_list.html.raw' do |example| - merge_request = create(:merge_request, :with_diffs, source_project: project, target_project: project, description: '- [ ] Task List Item') + create(:ci_build, :pending, pipeline: pipeline) + render_merge_request(example.description, merge_request) end diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js index 7506e6ab49e..7b9632be84e 100644 --- a/spec/javascripts/merge_request_tabs_spec.js +++ b/spec/javascripts/merge_request_tabs_spec.js @@ -38,6 +38,10 @@ require('vendor/jquery.scrollTo'); } }); + afterEach(function () { + this.class.destroy(); + }); + describe('#activateTab', function () { beforeEach(function () { spyOn($, 'ajax').and.callFake(function () {}); @@ -200,6 +204,42 @@ require('vendor/jquery.scrollTo'); expect(this.subject('show')).toBe('/foo/bar/merge_requests/1'); }); }); + + describe('#tabShown', () => { + beforeEach(function () { + loadFixtures('merge_requests/merge_request_with_task_list.html.raw'); + }); + + describe('with "Side-by-side"/parallel diff view', () => { + beforeEach(function () { + this.class.diffViewType = () => 'parallel'; + }); + + it('maintains `container-limited` for pipelines tab', function (done) { + const asyncClick = function (selector) { + return new Promise((resolve) => { + setTimeout(() => { + document.querySelector(selector).click(); + resolve(); + }); + }); + }; + + asyncClick('.merge-request-tabs .pipelines-tab a') + .then(() => asyncClick('.merge-request-tabs .diffs-tab a')) + .then(() => asyncClick('.merge-request-tabs .pipelines-tab a')) + .then(() => { + const hasContainerLimitedClass = document.querySelector('.content-wrapper .container-fluid').classList.contains('container-limited'); + expect(hasContainerLimitedClass).toBe(true); + }) + .then(done) + .catch((err) => { + done.fail(`Something went wrong clicking MR tabs: ${err.message}\n${err.stack}`); + }); + }); + }); + }); + describe('#loadDiff', function () { it('requires an absolute pathname', function () { spyOn($, 'ajax').and.callFake(function (options) { diff --git a/spec/javascripts/vue_shared/components/pipelines_table_spec.js b/spec/javascripts/vue_shared/components/pipelines_table_spec.js index 54d81e2ea7d..905ac0ec723 100644 --- a/spec/javascripts/vue_shared/components/pipelines_table_spec.js +++ b/spec/javascripts/vue_shared/components/pipelines_table_spec.js @@ -1,6 +1,9 @@ -require('~/vue_shared/components/pipelines_table'); require('~/lib/utils/datetime_utility'); +const Vue = require('vue'); const pipeline = require('../../commit/pipelines/mock_data'); +const PipelinesTable = require('~/vue_shared/components/pipelines_table'); + +const PipelinesTableComponent = Vue.extend(PipelinesTable); describe('Pipelines Table', () => { preloadFixtures('static/environments/element.html.raw'); @@ -12,7 +15,7 @@ describe('Pipelines Table', () => { describe('table', () => { let component; beforeEach(() => { - component = new gl.pipelines.PipelinesTableComponent({ + component = new PipelinesTableComponent({ el: document.querySelector('.test-dom-element'), propsData: { pipelines: [], @@ -21,6 +24,10 @@ describe('Pipelines Table', () => { }); }); + afterEach(() => { + component.$destroy(); + }); + it('should render a table', () => { expect(component.$el).toEqual('TABLE'); }); @@ -37,7 +44,7 @@ describe('Pipelines Table', () => { describe('without data', () => { it('should render an empty table', () => { - const component = new gl.pipelines.PipelinesTableComponent({ + const component = new PipelinesTableComponent({ el: document.querySelector('.test-dom-element'), propsData: { pipelines: [], @@ -50,7 +57,7 @@ describe('Pipelines Table', () => { describe('with data', () => { it('should render rows', () => { - const component = new gl.pipelines.PipelinesTableComponent({ + const component = new PipelinesTableComponent({ el: document.querySelector('.test-dom-element'), propsData: { pipelines: [pipeline], |