diff options
Diffstat (limited to 'app/assets/javascripts/pipelines/components/graph')
5 files changed, 78 insertions, 51 deletions
diff --git a/app/assets/javascripts/pipelines/components/graph/constants.js b/app/assets/javascripts/pipelines/components/graph/constants.js new file mode 100644 index 00000000000..ba1922b6dae --- /dev/null +++ b/app/assets/javascripts/pipelines/components/graph/constants.js @@ -0,0 +1,3 @@ +export const DOWNSTREAM = 'downstream'; +export const MAIN = 'main'; +export const UPSTREAM = 'upstream'; diff --git a/app/assets/javascripts/pipelines/components/graph/graph_component.vue b/app/assets/javascripts/pipelines/components/graph/graph_component.vue index 0f5a8cb8fbf..16ce279a591 100644 --- a/app/assets/javascripts/pipelines/components/graph/graph_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/graph_component.vue @@ -5,6 +5,7 @@ import StageColumnComponent from './stage_column_component.vue'; import GraphWidthMixin from '../../mixins/graph_width_mixin'; import LinkedPipelinesColumn from './linked_pipelines_column.vue'; import GraphBundleMixin from '../../mixins/graph_pipeline_bundle_mixin'; +import { UPSTREAM, DOWNSTREAM, MAIN } from './constants'; export default { name: 'PipelineGraph', @@ -35,11 +36,11 @@ export default { type: { type: String, required: false, - default: 'main', + default: MAIN, }, }, - upstream: 'upstream', - downstream: 'downstream', + upstream: UPSTREAM, + downstream: DOWNSTREAM, data() { return { downstreamMarginTop: null, @@ -54,41 +55,41 @@ export default { graph() { return this.pipeline.details?.stages; }, - hasTriggeredBy() { + hasUpstream() { return ( this.type !== this.$options.downstream && - this.triggeredByPipelines && + this.upstreamPipelines && this.pipeline.triggered_by !== null ); }, - triggeredByPipelines() { + upstreamPipelines() { return this.pipeline.triggered_by; }, - hasTriggered() { + hasDownstream() { return ( this.type !== this.$options.upstream && - this.triggeredPipelines && + this.downstreamPipelines && this.pipeline.triggered.length > 0 ); }, - triggeredPipelines() { + downstreamPipelines() { return this.pipeline.triggered; }, - expandedTriggeredBy() { + expandedUpstream() { return ( this.pipeline.triggered_by && Array.isArray(this.pipeline.triggered_by) && this.pipeline.triggered_by.find(el => el.isExpanded) ); }, - expandedTriggered() { + expandedDownstream() { return this.pipeline.triggered && this.pipeline.triggered.find(el => el.isExpanded); }, pipelineTypeUpstream() { - return this.type !== this.$options.downstream && this.expandedTriggeredBy; + return this.type !== this.$options.downstream && this.expandedUpstream; }, pipelineTypeDownstream() { - return this.type !== this.$options.upstream && this.expandedTriggered; + return this.type !== this.$options.upstream && this.expandedDownstream; }, pipelineProjectId() { return this.pipeline.project.id; @@ -142,11 +143,11 @@ export default { * and we want to reset the pipeline store. Triggering the reset without * this condition would mean not allowing downstreams of downstreams to expand */ - if (this.expandedTriggered?.id !== pipeline.id) { - this.$emit('onResetTriggered', this.pipeline, pipeline); + if (this.expandedDownstream?.id !== pipeline.id) { + this.$emit('onResetDownstream', this.pipeline, pipeline); } - this.$emit('onClickTriggered', pipeline); + this.$emit('onClickDownstreamPipeline', pipeline); }, calculateMarginTop(downstreamNode, pixelDiff) { return `${downstreamNode.offsetTop - downstreamNode.offsetParent.offsetTop - pixelDiff}px`; @@ -154,8 +155,8 @@ export default { hasOnlyOneJob(stage) { return stage.groups.length === 1; }, - hasUpstream(index) { - return index === 0 && this.hasTriggeredBy; + hasUpstreamColumn(index) { + return index === 0 && this.hasUpstream; }, setJob(jobName) { this.jobName = jobName; @@ -192,30 +193,30 @@ export default { <pipeline-graph v-if="pipelineTypeUpstream" - type="upstream" + :type="$options.upstream" class="d-inline-block upstream-pipeline" - :class="`js-upstream-pipeline-${expandedTriggeredBy.id}`" + :class="`js-upstream-pipeline-${expandedUpstream.id}`" :is-loading="false" - :pipeline="expandedTriggeredBy" + :pipeline="expandedUpstream" :is-linked-pipeline="true" :mediator="mediator" - @onClickTriggeredBy="clickTriggeredByPipeline" + @onClickUpstreamPipeline="clickUpstreamPipeline" @refreshPipelineGraph="requestRefreshPipelineGraph" /> <linked-pipelines-column - v-if="hasTriggeredBy" - :linked-pipelines="triggeredByPipelines" + v-if="hasUpstream" + :type="$options.upstream" + :linked-pipelines="upstreamPipelines" :column-title="__('Upstream')" :project-id="pipelineProjectId" - graph-position="left" - @linkedPipelineClick="$emit('onClickTriggeredBy', $event)" + @linkedPipelineClick="$emit('onClickUpstreamPipeline', $event)" /> <ul v-if="!isLoading" :class="{ - 'inline js-has-linked-pipelines': hasTriggered || hasTriggeredBy, + 'inline js-has-linked-pipelines': hasDownstream || hasUpstream, }" class="stage-column-list align-top" > @@ -223,7 +224,7 @@ export default { v-for="(stage, index) in graph" :key="stage.name" :class="{ - 'has-upstream gl-ml-11': hasUpstream(index), + 'has-upstream gl-ml-11': hasUpstreamColumn(index), 'has-only-one-job': hasOnlyOneJob(stage), 'gl-mr-26': shouldAddRightMargin(index), }" @@ -231,7 +232,7 @@ export default { :groups="stage.groups" :stage-connector-class="stageConnectorClass(index, stage)" :is-first-column="isFirstColumn(index)" - :has-triggered-by="hasTriggeredBy" + :has-upstream="hasUpstream" :action="stage.status.action" :job-hovered="jobName" :pipeline-expanded="pipelineExpanded" @@ -240,11 +241,11 @@ export default { </ul> <linked-pipelines-column - v-if="hasTriggered" - :linked-pipelines="triggeredPipelines" + v-if="hasDownstream" + :type="$options.downstream" + :linked-pipelines="downstreamPipelines" :column-title="__('Downstream')" :project-id="pipelineProjectId" - graph-position="right" @linkedPipelineClick="handleClickedDownstream" @downstreamHovered="setJob" @pipelineExpandToggle="setPipelineExpanded" @@ -252,15 +253,15 @@ export default { <pipeline-graph v-if="pipelineTypeDownstream" - type="downstream" + :type="$options.downstream" class="d-inline-block" - :class="`js-downstream-pipeline-${expandedTriggered.id}`" + :class="`js-downstream-pipeline-${expandedDownstream.id}`" :is-loading="false" - :pipeline="expandedTriggered" + :pipeline="expandedDownstream" :is-linked-pipeline="true" :style="{ 'margin-top': downstreamMarginTop }" :mediator="mediator" - @onClickTriggered="clickTriggeredPipeline" + @onClickDownstreamPipeline="clickDownstreamPipeline" @refreshPipelineGraph="requestRefreshPipelineGraph" /> </div> diff --git a/app/assets/javascripts/pipelines/components/graph/job_item.vue b/app/assets/javascripts/pipelines/components/graph/job_item.vue index 7aee2573ce1..4ed0aae0d1e 100644 --- a/app/assets/javascripts/pipelines/components/graph/job_item.vue +++ b/app/assets/javascripts/pipelines/components/graph/job_item.vue @@ -119,6 +119,9 @@ export default { }, }, methods: { + hideTooltips() { + this.$root.$emit('bv::hide::tooltip'); + }, pipelineActionRequestComplete() { this.$emit('pipelineActionRequestComplete'); }, @@ -129,24 +132,26 @@ export default { <div class="ci-job-component" data-qa-selector="job_item_container"> <gl-link v-if="status.has_details" - v-gl-tooltip="{ boundary, placement: 'bottom' }" + v-gl-tooltip="{ boundary, placement: 'bottom', customClass: 'gl-pointer-events-none' }" :href="status.details_path" :title="tooltipText" :class="jobClasses" class="js-pipeline-graph-job-link qa-job-link menu-item" data-testid="job-with-link" - @click.stop + @click.stop="hideTooltips" + @mouseout="hideTooltips" > <job-name-component :name="job.name" :status="job.status" /> </gl-link> <div v-else - v-gl-tooltip="{ boundary, placement: 'bottom' }" + v-gl-tooltip="{ boundary, placement: 'bottom', customClass: 'gl-pointer-events-none' }" :title="tooltipText" :class="jobClasses" class="js-job-component-tooltip non-details-job-component" data-testid="job-without-link" + @mouseout="hideTooltips" > <job-name-component :name="job.name" :status="job.status" /> </div> diff --git a/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue b/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue index e359fc787c5..11f06a25984 100644 --- a/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue +++ b/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue @@ -2,6 +2,7 @@ import { GlTooltipDirective, GlButton, GlLink, GlLoadingIcon } from '@gitlab/ui'; import CiStatus from '~/vue_shared/components/ci_icon.vue'; import { __, sprintf } from '~/locale'; +import { UPSTREAM, DOWNSTREAM } from './constants'; export default { directives: { @@ -14,6 +15,10 @@ export default { GlLoadingIcon, }, props: { + columnTitle: { + type: String, + required: true, + }, pipeline: { type: Object, required: true, @@ -22,7 +27,7 @@ export default { type: Number, required: true, }, - columnTitle: { + type: { type: String, required: true, }, @@ -50,12 +55,10 @@ export default { return this.childPipeline ? __('child-pipeline') : this.pipeline.project.name; }, parentPipeline() { - // Refactor string match when BE returns Upstream/Downstream indicators - return this.projectId === this.pipeline.project.id && this.columnTitle === __('Upstream'); + return this.isUpstream && this.isSameProject; }, childPipeline() { - // Refactor string match when BE returns Upstream/Downstream indicators - return this.projectId === this.pipeline.project.id && this.isDownstream; + return this.isDownstream && this.isSameProject; }, label() { if (this.parentPipeline) { @@ -66,7 +69,13 @@ export default { return __('Multi-project'); }, isDownstream() { - return this.columnTitle === __('Downstream'); + return this.type === DOWNSTREAM; + }, + isUpstream() { + return this.type === UPSTREAM; + }, + isSameProject() { + return this.projectId === this.pipeline.project.id; }, sourceJobInfo() { return this.isDownstream @@ -74,13 +83,13 @@ export default { : ''; }, expandedIcon() { - if (this.parentPipeline) { + if (this.isUpstream) { return this.expanded ? 'angle-right' : 'angle-left'; } return this.expanded ? 'angle-left' : 'angle-right'; }, expandButtonPosition() { - return this.parentPipeline ? 'gl-left-0 gl-border-r-1!' : 'gl-right-0 gl-border-l-1!'; + return this.isUpstream ? 'gl-left-0 gl-border-r-1!' : 'gl-right-0 gl-border-l-1!'; }, }, methods: { @@ -116,7 +125,7 @@ export default { > <div class="gl-relative gl-bg-white gl-p-3 gl-border-solid gl-border-gray-100 gl-border-1" - :class="{ 'gl-pl-9': parentPipeline }" + :class="{ 'gl-pl-9': isUpstream }" > <div class="gl-display-flex"> <ci-status diff --git a/app/assets/javascripts/pipelines/components/graph/linked_pipelines_column.vue b/app/assets/javascripts/pipelines/components/graph/linked_pipelines_column.vue index 3ad28d88345..2ca33e6d33e 100644 --- a/app/assets/javascripts/pipelines/components/graph/linked_pipelines_column.vue +++ b/app/assets/javascripts/pipelines/components/graph/linked_pipelines_column.vue @@ -1,6 +1,6 @@ <script> import LinkedPipeline from './linked_pipeline.vue'; -import { __ } from '~/locale'; +import { UPSTREAM } from './constants'; export default { components: { @@ -15,7 +15,7 @@ export default { type: Array, required: true, }, - graphPosition: { + type: { type: String, required: true, }, @@ -32,9 +32,12 @@ export default { }; return `graph-position-${this.graphPosition} ${positionValues[this.graphPosition]}`; }, + graphPosition() { + return this.isUpstream ? 'left' : 'right'; + }, // Refactor string match when BE returns Upstream/Downstream indicators isUpstream() { - return this.columnTitle === __('Upstream'); + return this.type === UPSTREAM; }, }, methods: { @@ -45,6 +48,11 @@ export default { this.$emit('downstreamHovered', jobName); }, onPipelineExpandToggle(jobName, expanded) { + // Highlighting only applies to downstream pipelines + if (this.isUpstream) { + return; + } + this.$emit('pipelineExpandToggle', jobName, expanded); }, }, @@ -66,6 +74,7 @@ export default { :pipeline="pipeline" :column-title="columnTitle" :project-id="projectId" + :type="type" @pipelineClicked="onPipelineClick($event, pipeline, index)" @downstreamHovered="onDownstreamHovered" @pipelineExpandToggle="onPipelineExpandToggle" |