Skip to content
Snippets Groups Projects
Commit 9de94015 authored by Eric Eastwood's avatar Eric Eastwood
Browse files

Reset container width when switching to pipelines MR tab

Fixes https://gitlab.com/gitlab-org/gitlab-ce/issues/29539

Conflicts:
	app/assets/javascripts/commit/pipelines/pipelines_table.js
	app/assets/javascripts/merge_request_tabs.js
	spec/javascripts/commit/pipelines/pipelines_spec.js
parent 36cfb0a7
No related branches found
No related tags found
No related merge requests found
Pipeline #
/* eslint-disable no-new, no-param-reassign */
/* global Vue, CommitsPipelineStore, PipelinesService, Flash */
 
import PipelinesTableComponent from '../../vue_shared/components/pipelines_table';
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');
 
Loading
Loading
@@ -19,86 +20,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.
*/
export default Vue.component('pipelines-table', {
components: {
'pipelines-table-component': PipelinesTableComponent,
},
 
(() => {
window.gl = window.gl || {};
gl.commits = gl.commits || {};
gl.commits.pipelines = gl.commits.pipelines || {};
gl.commits.pipelines.PipelinesTableView = Vue.component('pipelines-table', {
components: {
'pipelines-table-component': gl.pipelines.PipelinesTableComponent,
},
/**
* 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();
 
/**
* 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();
return {
endpoint: null,
store,
state: store.state,
isLoading: false,
};
},
 
return {
endpoint: pipelinesTableData.endpoint,
store,
state: store.state,
isLoading: false,
};
},
/**
* 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);
 
/**
* 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');
});
},
 
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);
}
},
 
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>
`,
});
Loading
Loading
@@ -3,9 +3,12 @@
/* global Cookies */
/* global Flash */
 
require('./breakpoints');
window.Cookies = require('js-cookie');
require('./flash');
import Cookies from 'js-cookie';
import CommitPipelinesTable from './commit/pipelines/pipelines_table';
import './breakpoints';
import './flash';
 
/* eslint-disable max-len */
// MergeRequestTabs
Loading
Loading
@@ -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'));
Loading
Loading
@@ -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();
Loading
Loading
@@ -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 CommitPipelinesTable().$mount(pipelineTableViewEl);
}
this.pipelinesLoaded = true;
}
loadDiff(source) {
if (this.diffsLoaded) {
return;
Loading
Loading
/* global Vue, gl */
/* eslint-disable no-param-reassign */
 
import PipelinesTableComponent from '../vue_shared/components/pipelines_table';
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');
 
((gl) => {
Loading
Loading
@@ -12,7 +13,7 @@ const CommitPipelinesStoreWithTimeAgo = require('../commit/pipelines/pipelines_s
 
components: {
'gl-pagination': gl.VueGlPagination,
'pipelines-table-component': gl.pipelines.PipelinesTableComponent,
'pipelines-table-component': PipelinesTableComponent,
},
 
data() {
Loading
Loading
Loading
Loading
@@ -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: () => ([]),
},
export default {
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>
`,
};
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
 
Loading
Loading
/* global pipeline, Vue */
 
import PipelinesTable from '~/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');
});
Loading
Loading
@@ -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();
Loading
Loading
@@ -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();
Loading
Loading
@@ -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();
Loading
Loading
Loading
Loading
@@ -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
 
Loading
Loading
@@ -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
 
Loading
Loading
Loading
Loading
@@ -38,6 +38,10 @@ require('vendor/jquery.scrollTo');
}
});
 
afterEach(function () {
this.class.destroy();
});
describe('#activateTab', function () {
beforeEach(function () {
spyOn($, 'ajax').and.callFake(function () {});
Loading
Loading
@@ -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) {
Loading
Loading
require('~/vue_shared/components/pipelines_table');
import PipelinesTableComponent from '~/vue_shared/components/pipelines_table';
require('~/lib/utils/datetime_utility');
const pipeline = require('../../commit/pipelines/mock_data');
 
Loading
Loading
@@ -12,7 +13,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: [],
Loading
Loading
@@ -21,6 +22,10 @@ describe('Pipelines Table', () => {
});
});
 
afterEach(() => {
component.$destroy();
});
it('should render a table', () => {
expect(component.$el).toEqual('TABLE');
});
Loading
Loading
@@ -37,7 +42,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: [],
Loading
Loading
@@ -50,7 +55,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],
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment