Skip to content
Snippets Groups Projects
Commit cad686cc authored by Filipa Lacerda's avatar Filipa Lacerda
Browse files

Creates a mediator for pipeline details vue in order to mount several vue apps with the same data

parent 8e2fefc6
No related branches found
No related tags found
No related merge requests found
<script>
/* global Flash */
import Visibility from 'visibilityjs';
import Poll from '../../../lib/utils/poll';
import PipelineService from '../../services/pipeline_service';
import PipelineStore from '../../stores/pipeline_store';
import stageColumnComponent from './stage_column_component.vue';
import loadingIcon from '../../../vue_shared/components/loading_icon.vue';
import '../../../flash';
 
export default {
props: {
isLoading: {
type: Boolean,
required: true,
},
pipeline: {
type: Object,
required: true,
},
},
components: {
stageColumnComponent,
loadingIcon,
},
 
data() {
const DOMdata = document.getElementById('js-pipeline-graph-vue').dataset;
const store = new PipelineStore();
return {
isLoading: false,
endpoint: DOMdata.endpoint,
store,
state: store.state,
};
},
created() {
this.service = new PipelineService(this.endpoint);
const poll = new Poll({
resource: this.service,
method: 'getPipeline',
successCallback: this.successCallback,
errorCallback: this.errorCallback,
});
if (!Visibility.hidden()) {
this.isLoading = true;
poll.makeRequest();
}
Visibility.change(() => {
if (!Visibility.hidden()) {
poll.restart();
} else {
poll.stop();
}
});
computed: {
graph() {
return this.pipeline.details && this.pipeline.details.stages;
},
},
 
methods: {
successCallback(response) {
const data = response.json();
this.isLoading = false;
this.store.storeGraph(data.details.stages);
},
errorCallback() {
this.isLoading = false;
return new Flash('An error occurred while fetching the pipeline.');
},
capitalizeStageName(name) {
return name.charAt(0).toUpperCase() + name.slice(1);
},
Loading
Loading
@@ -101,7 +65,7 @@
v-if="!isLoading"
class="stage-column-list">
<stage-column-component
v-for="(stage, index) in state.graph"
v-for="(stage, index) in graph"
:title="capitalizeStageName(stage.name)"
:jobs="stage.groups"
:key="stage.name"
Loading
Loading
import Vue from 'vue';
import pipelineGraph from './components/graph/graph_component.vue';
document.addEventListener('DOMContentLoaded', () => new Vue({
el: '#js-pipeline-graph-vue',
components: {
pipelineGraph,
},
render: createElement => createElement('pipeline-graph'),
}));
import Vue from 'vue';
import PipelinesMediator from './pipeline_details_mediatior';
import pipelineGraph from './components/graph/graph_component.vue';
document.addEventListener('DOMContentLoaded', () => {
const dataset = document.querySelector('.js-pipeline-details-vue').dataset;
const mediator = new PipelinesMediator({ endpoint: dataset.endpoint });
mediator.fetchPipeline();
const pipelineGraphApp = new Vue({
el: '#js-pipeline-graph-vue',
data: {
mediator,
},
components: {
pipelineGraph,
},
render(createElement) {
return createElement('pipeline-graph', {
props: {
isLoading: this.mediator.state.isLoading,
pipeline: this.mediator.store.state.pipeline,
},
});
},
});
return pipelineGraphApp;
});
/* global Flash */
import Visibility from 'visibilityjs';
import Poll from '../lib/utils/poll';
import PipelineStore from './stores/pipeline_store';
import PipelineService from './services/pipeline_service';
export default class pipelinesMediator {
constructor(options) {
this.options = options || {};
this.store = new PipelineStore();
this.service = new PipelineService(options.endpoint);
this.state = {};
this.state.isLoading = false;
}
fetchPipeline() {
this.poll = new Poll({
resource: this.service,
method: 'getPipeline',
successCallback: this.successCallback.bind(this),
errorCallback: this.errorCallback.bind(this),
});
if (!Visibility.hidden()) {
this.state.isLoading = true;
this.poll.makeRequest();
}
Visibility.change(() => {
if (!Visibility.hidden()) {
this.poll.restart();
} else {
this.poll.stop();
}
});
}
successCallback(response) {
const data = response.json();
this.state.isLoading = false;
this.store.storePipeline(data);
}
errorCallback() {
this.state.isLoading = false;
return new Flash('An error occurred while fetching the pipeline.');
}
}
Loading
Loading
@@ -2,10 +2,10 @@ export default class PipelineStore {
constructor() {
this.state = {};
 
this.state.graph = [];
this.state.pipeline = {};
}
 
storeGraph(graph = []) {
this.state.graph = graph;
storePipeline(pipeline = {}) {
this.state.pipeline = pipeline;
}
}
- failed_builds = @pipeline.statuses.latest.failed
 
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_vue')
= page_specific_javascript_bundle_tag('pipelines_graph')
.tabs-holder
%ul.pipelines-tabs.nav-links.no-top.no-bottom
%li.js-pipeline-tab-link
Loading
Loading
@@ -21,7 +17,7 @@
 
.tab-content
#js-tab-pipeline.tab-pane
#js-pipeline-graph-vue{ data: { endpoint: namespace_project_pipeline_path(@project.namespace, @project, @pipeline, format: :json) } }
#js-pipeline-graph-vue
 
#js-tab-builds.tab-pane
- if pipeline.yaml_errors.present?
Loading
Loading
Loading
Loading
@@ -7,3 +7,9 @@
= render "projects/pipelines/info"
 
= render "projects/pipelines/with_tabs", pipeline: @pipeline
.js-pipeline-details-vue{ data: { endpoint: namespace_project_pipeline_path(@project.namespace, @project, @pipeline, format: :json) } }
- content_for :page_specific_javascripts do
= webpack_bundle_tag('common_vue')
= webpack_bundle_tag('pipelines_details')
---
title: Creates a mediator for pipeline details vue in order to mount several vue apps
with the same data
merge_request:
author:
Loading
Loading
@@ -23,6 +23,7 @@ var config = {
},
context: path.join(ROOT_PATH, 'app/assets/javascripts'),
entry: {
balsamiq_viewer: './blob/balsamiq_viewer.js',
blob: './blob_edit/blob_bundle.js',
boards: './boards/boards_bundle.js',
common: './commons/index.js',
Loading
Loading
@@ -47,8 +48,7 @@ var config = {
notebook_viewer: './blob/notebook_viewer.js',
pdf_viewer: './blob/pdf_viewer.js',
pipelines: './pipelines/index.js',
balsamiq_viewer: './blob/balsamiq_viewer.js',
pipelines_graph: './pipelines/graph_bundle.js',
pipelines_details: './pipelines/pipeline_details_bundle.js',
profile: './profile/profile_bundle.js',
protected_branches: './protected_branches/protected_branches_bundle.js',
protected_tags: './protected_tags',
Loading
Loading
@@ -146,7 +146,7 @@ var config = {
'notebook_viewer',
'pdf_viewer',
'pipelines',
'pipelines_graph',
'pipelines_details',
'schedule_form',
'schedules_index',
'sidebar',
Loading
Loading
Loading
Loading
@@ -14,49 +14,42 @@ describe('graph component', () => {
 
describe('while is loading', () => {
it('should render a loading icon', () => {
const component = new GraphComponent().$mount('#js-pipeline-graph-vue');
const component = new GraphComponent({
propsData: {
isLoading: true,
pipeline: {},
},
}).$mount('#js-pipeline-graph-vue');
expect(component.$el.querySelector('.loading-icon')).toBeDefined();
});
});
 
describe('with a successfull response', () => {
const interceptor = (request, next) => {
next(request.respondWith(JSON.stringify(graphJSON), {
status: 200,
}));
};
describe('with data', () => {
it('should render the graph', () => {
const component = new GraphComponent({
propsData: {
isLoading: false,
pipeline: graphJSON,
},
}).$mount('#js-pipeline-graph-vue');
 
beforeEach(() => {
Vue.http.interceptors.push(interceptor);
});
afterEach(() => {
Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
});
it('should render the graph', (done) => {
const component = new GraphComponent().$mount('#js-pipeline-graph-vue');
setTimeout(() => {
expect(component.$el.classList.contains('js-pipeline-graph')).toEqual(true);
expect(component.$el.classList.contains('js-pipeline-graph')).toEqual(true);
 
expect(
component.$el.querySelector('.stage-column:first-child').classList.contains('no-margin'),
).toEqual(true);
expect(
component.$el.querySelector('.stage-column:first-child').classList.contains('no-margin'),
).toEqual(true);
 
expect(
component.$el.querySelector('.stage-column:nth-child(2)').classList.contains('left-margin'),
).toEqual(true);
expect(
component.$el.querySelector('.stage-column:nth-child(2)').classList.contains('left-margin'),
).toEqual(true);
 
expect(
component.$el.querySelector('.stage-column:nth-child(2) .build:nth-child(1)').classList.contains('left-connector'),
).toEqual(true);
expect(
component.$el.querySelector('.stage-column:nth-child(2) .build:nth-child(1)').classList.contains('left-connector'),
).toEqual(true);
 
expect(component.$el.querySelector('loading-icon')).toBe(null);
expect(component.$el.querySelector('loading-icon')).toBe(null);
 
expect(component.$el.querySelector('.stage-column-list')).toBeDefined();
done();
}, 0);
expect(component.$el.querySelector('.stage-column-list')).toBeDefined();
});
});
});
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