Commit 8ef5ee8e authored by Filipa Lacerda's avatar Filipa Lacerda Committed by Kamil Trzciński

Recursively renders upstream/downstream:

Transforms the graph component to recursively
render both upstream and downstream pipelines
parent c0257f10
......@@ -43,20 +43,17 @@ export default () => {
props: {
isLoading: this.mediator.state.isLoading,
pipeline: this.mediator.store.state.pipeline,
// EE-only start
triggeredPipelines: this.mediator.store.state.triggeredPipelines,
triggered: this.mediator.store.state.triggered,
triggeredByPipelines: this.mediator.store.state.triggeredByPipelines,
triggeredBy: this.mediator.store.state.triggeredBy,
// EE-only end
mediator: this.mediator,
},
on: {
refreshPipelineGraph: this.requestRefreshPipelineGraph,
// EE-only start
// refreshTriggeredPipelineGraph: this.mediator.refreshTriggeredByPipelineGraph,
// refreshTriggeredByPipelineGraph: this.mediator.refreshTriggeredByPipelineGraph,
onClickTriggeredBy: pipeline => this.clickTriggeredByPipeline(pipeline),
onClickTriggered: pipeline => this.clickTriggeredPipeline(pipeline),
onClickTriggeredBy: (parentPipeline, pipeline) =>
this.clickTriggeredByPipeline(parentPipeline, pipeline),
onClickTriggered: (parentPipeline, pipeline) =>
this.clickTriggeredPipeline(parentPipeline, pipeline),
// EE-only end
},
});
......
......@@ -4,6 +4,7 @@ import { GlLoadingIcon } from '@gitlab/ui';
import LinkedPipelinesColumn from 'ee/pipelines/components/graph/linked_pipelines_column.vue';
import EEGraphMixin from 'ee/pipelines/mixins/graph_component_mixin';
import StageColumnComponent from '~/pipelines/components/graph/stage_column_component.vue';
import GraphEEMixin from 'ee/pipelines/mixins/graph_pipeline_bundle_mixin'; // eslint-disable-line import/order
export default {
name: 'PipelineGraph',
......@@ -12,7 +13,7 @@ export default {
StageColumnComponent,
GlLoadingIcon,
},
mixins: [EEGraphMixin],
mixins: [EEGraphMixin, GraphEEMixin],
props: {
isLoading: {
type: Boolean,
......@@ -22,6 +23,19 @@ export default {
type: Object,
required: true,
},
isLinkedPipeline: {
type: Boolean,
default: false,
},
mediator: {
type: Object,
required: true,
},
type: {
type: String,
required: false,
default: 'main',
},
},
computed: {
graph() {
......@@ -29,6 +43,7 @@ export default {
},
},
methods: {
// todo filipa: move this into a ce mixin
capitalizeStageName(name) {
const escapedName = _.escape(name);
return escapedName.charAt(0).toUpperCase() + escapedName.slice(1);
......@@ -60,15 +75,31 @@ export default {
</script>
<template>
<div class="build-content middle-block js-pipeline-graph">
<div class="pipeline-visualization pipeline-graph pipeline-tab-content">
<div class="text-center"><gl-loading-icon v-if="isLoading" :size="3" /></div>
<div
class="pipeline-visualization pipeline-graph"
:class="{ 'pipeline-tab-content': !isLinkedPipeline }"
>
<div class="text-center" v-if="isLoading"><gl-loading-icon :size="3" /></div>
<pipeline-graph
type="upstream"
class="d-inline-block upstream-pipeline"
v-if="expandedTriggeredBy && type !== 'downstream'"
:is-loading="false"
:pipeline="expandedTriggeredBy"
:is-linked-pipeline="true"
:mediator="mediator"
@onClickTriggeredBy="
(parentPipeline, pipeline) => this.clickTriggeredByPipeline(parentPipeline, pipeline)
"
/>
<linked-pipelines-column
v-if="hasTriggeredBy"
:linked-pipelines="triggeredByPipelines"
:column-title="__('Upstream')"
graph-position="left"
@linkedPipelineClick="pipeline => $emit('onClickTriggeredBy', pipeline)"
@linkedPipelineClick="pipeline => $emit('onClickTriggeredBy', this.pipeline, pipeline)"
/>
<ul
......@@ -102,6 +133,20 @@ export default {
graph-position="right"
@linkedPipelineClick="handleClickedDownstream"
/>
<pipeline-graph
type="downstream"
class="d-inline-block"
v-if="expandedTriggered && type !== 'upstream'"
:is-loading="false"
:pipeline="expandedTriggered"
:is-linked-pipeline="true"
:style="{ 'margin-top': marginTop }"
@onClickTriggered="
(parentPipeline, pipeline) => this.clickTriggeredPipeline(parentPipeline, pipeline)
"
:mediator="mediator"
/>
</div>
</div>
</template>
......@@ -28,7 +28,7 @@ export default {
return this.pipeline.details.status;
},
projectName() {
return this.pipeline.project.name;
return this.pipeline.project && this.pipeline.project.name;
},
},
methods: {
......
// todo filipa: move this to the ee graph component
import _ from 'underscore';
export default {
data() {
return {
......@@ -6,17 +9,34 @@ export default {
},
computed: {
hasTriggeredBy() {
return this.pipeline.triggered_by && this.pipeline.triggered_by != null;
return (
this.type !== 'downstream' &&
this.pipeline.triggered_by &&
this.pipeline.triggered_by != null
);
},
triggeredByPipelines() {
return this.pipeline.triggered_by;
},
hasTriggered() {
return this.pipeline.triggered && this.pipeline.triggered.length > 0;
return (
this.type !== 'upstream' && this.pipeline.triggered && this.pipeline.triggered.length > 0
);
},
triggeredPipelines() {
return this.pipeline.triggered;
},
expandedTriggeredBy() {
return (
this.pipeline.triggered_by &&
_.isArray(this.pipeline.triggered_by) &&
this.pipeline.triggered_by.find(el => el.isExpanded)
);
},
expandedTriggered() {
return this.pipeline.triggered && this.pipeline.triggered.find(el => el.isExpanded);
},
/**
* Calculates the margin top of the clicked downstream pipeline by
* adding the height of each linked pipeline and the margin
......@@ -34,8 +54,9 @@ export default {
this.$emit('refreshTriggeredByPipelineGraph');
},
handleClickedDownstream(pipeline, clickedIndex) {
//filipa: figure out the clickIndex thing
this.triggeredTopIndex = clickedIndex;
this.$emit('onClickTriggered', pipeline);
this.$emit('onClickTriggered', this.pipeline, pipeline);
},
},
};
import keys from '../constants';
export default {
methods: {
/**
......@@ -13,19 +11,28 @@ export default {
* @param {String} resetStoreKey Store key for the visible pipeline that will need to be reset
* @param {Object} pipeline The clicked pipeline
*/
clickPipeline(pipeline, method) {
debugger;
clickPipeline(parentPipeline, pipeline, openMethod, closeMethod) {
if (!pipeline.isExpanded) {
this.mediator.store[method](pipeline);
this.mediator.store[openMethod](parentPipeline, pipeline);
} else {
this.mediator.store.closePipeline(pipeline);
this.mediator.store[closeMethod](pipeline);
}
},
clickTriggeredByPipeline(pipeline) {
this.clickPipeline(pipeline, 'openTriggeredByPipeline');
clickTriggeredByPipeline(parentPipeline, pipeline) {
this.clickPipeline(
parentPipeline,
pipeline,
'openTriggeredByPipeline',
'closeTriggeredByPipeline',
);
},
clickTriggeredPipeline(pipeline) {
this.clickPipeline(pipeline, 'openTriggeredPipeline');
clickTriggeredPipeline(parentPipeline, pipeline) {
this.clickPipeline(
parentPipeline,
pipeline,
'openTriggeredPipeline',
'closeTriggeredPipeline',
);
},
},
};
import _ from 'underscore';
import CePipelineStore from '~/pipelines/stores/pipeline_store';
import data from '../mock.json';
import Vue from 'vue';
......@@ -11,9 +12,9 @@ export default class PipelineStore extends CePipelineStore {
}
/**
* For the triggered pipelines, parses them to add `isLoading` and `isExpanded` keys
* For the triggered pipelines adds the `isExpanded` key
*
* For the triggered_by pipeline, parsed the object to add `isLoading` and `isExpanded` keys
* For the triggered_by pipeline adds the `isExpanded` key
* and saves it as an array
*
* @param {Object} pipeline
......@@ -24,13 +25,12 @@ export default class PipelineStore extends CePipelineStore {
if (pipeline.triggered_by) {
this.state.pipeline.triggered_by = [pipeline.triggered_by];
this.parseTriggeredByPipelines(this.state.pipeline, pipeline.triggered_by);
this.parseTriggeredByPipelines(this.state.pipeline.triggered_by[0]);
}
if (pipeline.triggered && pipeline.triggered.length) {
this.state.triggeredPipelines = pipeline.triggered.map(triggered =>
this.parseTriggeredPipelines(this.state.pipeline, triggered),
);
this.state.pipeline.triggered.forEach(el => this.parseTriggeredPipelines(el));
}
}
......@@ -44,40 +44,51 @@ export default class PipelineStore extends CePipelineStore {
* @param {Array} parentPipeline
* @param {Object} pipeline
*/
parseTriggeredByPipelines(parentPipeline, pipeline) {
parseTriggeredByPipelines(pipeline) {
// keep old value in case it's opened because we're polling
Vue.set(pipeline, 'isExpanded', pipeline.isExpanded || false);
if (pipeline.triggered_by) {
pipeline.triggered_by = [pipeline.triggered_by];
this.parseTriggeredByPipelines(pipeline, pipeline.triggered_by);
if (!_.isArray(pipeline.triggered_by)) {
pipeline.triggered_by = [pipeline.triggered_by];
}
this.parseTriggeredByPipelines(pipeline.triggered_by[0]);
}
// if (pipeline.triggered && pipeline.triggered.length) {
// pipeline.triggered.forEach(el => this.parseTriggeredPipelines(el));
// }
}
parsePipeline(pipeline) {}
/**
* Recursively parses the triggered pipelines
* @param {Array} parentPipeline
* @param {Object} pipeline
*/
parseTriggeredPipelines(parentPipeline, pipeline) {
parseTriggeredPipelines(pipeline) {
// keep old value in case it's opened because we're polling
Vue.set(pipeline, 'isExpanded', pipeline.isExpanded || false);
if (pipeline.triggered && pipeline.triggered.length > 0) {
pipeline.triggered.forEach(el => this.parseTriggeredPipelines(el));
}
// if (pipeline.triggered_by) {
// pipeline.triggered_by = [pipeline.triggered_by];
// this.parseTriggeredByPipelines(pipeline.triggered_by[0]);
// }
}
/**
* Recursively resets all triggered by pipelines
*
*
* @param {Object} pipeline
*/
resetTriggeredByPipeline(pipeline) {
this.closePipeline(pipeline);
resetTriggeredByPipeline(parentPipeline, pipeline) {
parentPipeline.triggered_by.forEach(el => this.closePipeline(el));
if (pipeline.triggered_by && pipeline.triggered_by) {
this.resetTriggeredByPipeline(pipeline.triggered_by);
this.resetTriggeredByPipeline(pipeline, pipeline.triggered_by);
}
}
......@@ -85,15 +96,39 @@ export default class PipelineStore extends CePipelineStore {
* Opens the clicked pipeline and closes all other ones.
* @param {Object} pipeline
*/
openTriggeredByPipeline(pipeline) {
openTriggeredByPipeline(parentPipeline, pipeline) {
// first we need to reset all triggeredBy pipelines
this.resetTriggeredByPipeline(pipeline);
this.resetTriggeredByPipeline(parentPipeline, pipeline);
this.openPipeline(pipeline);
}
/**
* Closes the given pipeline
* On click, will close the given pipeline and all nested triggered by pipelines
*
* @param {Object} pipeline
*/
closeTriggeredByPipeline(pipeline) {
this.closePipeline(pipeline);
if (pipeline.triggered_by && pipeline.triggered_by.length) {
pipeline.triggered_by.forEach(triggeredBy => this.closeTriggeredByPipeline(triggeredBy));
}
}
/**
* On click, will close the given pipeline and all the nested triggered ones
* @param {Object} pipeline
*/
closeTriggeredPipeline(pipeline) {
this.closePipeline(pipeline);
if (pipeline.triggered && pipeline.triggered.length) {
pipeline.triggered.forEach(triggered => this.closeTriggeredPipeline(triggered));
}
}
/**
* Utility function, Closes the given pipeline
* @param {Object} pipeline
*/
closePipeline(pipeline) {
......@@ -101,19 +136,20 @@ export default class PipelineStore extends CePipelineStore {
}
/**
* Closes the given pipeline
* Utility function, Opens the given pipeline
* @param {Object} pipeline
*/
openPipeline(pipeline) {
Vue.set(pipeline, 'isExpanded', true);
}
/**
* Opens the clicked triggered pipeline and closes all other ones.
*
* @param {Object} pipeline
*/
openTriggeredPipeline(pipeline) {
this.resetTriggeredPipelines(pipeline);
openTriggeredPipeline(parentPipeline, pipeline) {
this.resetTriggeredPipelines(parentPipeline, pipeline);
this.openPipeline(pipeline);
}
......@@ -122,11 +158,11 @@ export default class PipelineStore extends CePipelineStore {
*
* @param {Object} pipeline
*/
resetTriggeredPipelines(pipeline) {
this.closePipeline(pipeline);
resetTriggeredPipelines(parentPipeline, pipeline) {
parentPipeline.triggered.forEach(el => this.closePipeline(el));
if (pipeline.triggered && pipeline.triggered.length) {
pipeline.triggered.forEach(el => this.resetTriggeredPipelines(el));
pipeline.triggered.forEach(el => this.resetTriggeredPipelines(pipeline, el));
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment