2019-12-21 20:55:43 +05:30
|
|
|
<script>
|
2022-07-16 23:28:13 +05:30
|
|
|
import {
|
|
|
|
GlBadge,
|
|
|
|
GlButton,
|
|
|
|
GlLink,
|
|
|
|
GlLoadingIcon,
|
|
|
|
GlTooltip,
|
|
|
|
GlTooltipDirective,
|
|
|
|
} from '@gitlab/ui';
|
|
|
|
import { convertToGraphQLId } from '~/graphql_shared/utils';
|
2021-03-11 19:13:27 +05:30
|
|
|
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
|
2020-07-28 23:09:34 +05:30
|
|
|
import { __, sprintf } from '~/locale';
|
2022-07-16 23:28:13 +05:30
|
|
|
import CancelPipelineMutation from '~/pipelines/graphql/mutations/cancel_pipeline.mutation.graphql';
|
|
|
|
import RetryPipelineMutation from '~/pipelines/graphql/mutations/retry_pipeline.mutation.graphql';
|
2021-03-11 19:13:27 +05:30
|
|
|
import CiStatus from '~/vue_shared/components/ci_icon.vue';
|
2022-07-16 23:28:13 +05:30
|
|
|
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
|
|
|
import { PIPELINE_GRAPHQL_TYPE } from '../../constants';
|
2021-04-29 21:17:54 +05:30
|
|
|
import { reportToSentry } from '../../utils';
|
2022-07-16 23:28:13 +05:30
|
|
|
import { ACTION_FAILURE, DOWNSTREAM, UPSTREAM } from './constants';
|
2019-12-21 20:55:43 +05:30
|
|
|
|
|
|
|
export default {
|
|
|
|
directives: {
|
|
|
|
GlTooltip: GlTooltipDirective,
|
|
|
|
},
|
|
|
|
components: {
|
|
|
|
CiStatus,
|
2022-04-04 11:22:00 +05:30
|
|
|
GlBadge,
|
2020-10-24 23:57:45 +05:30
|
|
|
GlButton,
|
2020-11-24 15:15:51 +05:30
|
|
|
GlLink,
|
|
|
|
GlLoadingIcon,
|
2022-07-16 23:28:13 +05:30
|
|
|
GlTooltip,
|
2019-12-21 20:55:43 +05:30
|
|
|
},
|
2022-07-16 23:28:13 +05:30
|
|
|
styles: {
|
|
|
|
actionSizeClasses: ['gl-h-7 gl-w-7'],
|
|
|
|
flatLeftBorder: ['gl-rounded-bottom-left-none!', 'gl-rounded-top-left-none!'],
|
|
|
|
flatRightBorder: ['gl-rounded-bottom-right-none!', 'gl-rounded-top-right-none!'],
|
|
|
|
},
|
|
|
|
mixins: [glFeatureFlagMixin()],
|
2019-12-21 20:55:43 +05:30
|
|
|
props: {
|
2021-01-29 00:20:46 +05:30
|
|
|
columnTitle: {
|
|
|
|
type: String,
|
|
|
|
required: true,
|
|
|
|
},
|
2021-02-22 17:27:13 +05:30
|
|
|
expanded: {
|
|
|
|
type: Boolean,
|
2019-12-21 20:55:43 +05:30
|
|
|
required: true,
|
|
|
|
},
|
2022-04-04 11:22:00 +05:30
|
|
|
isLoading: {
|
|
|
|
type: Boolean,
|
|
|
|
required: true,
|
|
|
|
},
|
2021-02-22 17:27:13 +05:30
|
|
|
pipeline: {
|
|
|
|
type: Object,
|
2020-03-13 15:44:24 +05:30
|
|
|
required: true,
|
|
|
|
},
|
2021-01-29 00:20:46 +05:30
|
|
|
type: {
|
2020-03-13 15:44:24 +05:30
|
|
|
type: String,
|
|
|
|
required: true,
|
|
|
|
},
|
2020-11-24 15:15:51 +05:30
|
|
|
},
|
2022-07-16 23:28:13 +05:30
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
hasActionTooltip: false,
|
|
|
|
isActionLoading: false,
|
|
|
|
};
|
|
|
|
},
|
2019-12-21 20:55:43 +05:30
|
|
|
computed: {
|
2022-07-16 23:28:13 +05:30
|
|
|
action() {
|
|
|
|
if (this.glFeatures?.downstreamRetryAction && this.isDownstream) {
|
|
|
|
if (this.isCancelable) {
|
|
|
|
return {
|
|
|
|
icon: 'cancel',
|
|
|
|
method: this.cancelPipeline,
|
|
|
|
ariaLabel: __('Cancel downstream pipeline'),
|
|
|
|
};
|
|
|
|
} else if (this.isRetryable) {
|
|
|
|
return {
|
|
|
|
icon: 'retry',
|
|
|
|
method: this.retryPipeline,
|
|
|
|
ariaLabel: __('Retry downstream pipeline'),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
|
|
|
},
|
|
|
|
buttonBorderClasses() {
|
|
|
|
return this.isUpstream
|
|
|
|
? ['gl-border-r-0!', ...this.$options.styles.flatRightBorder]
|
|
|
|
: ['gl-border-l-0!', ...this.$options.styles.flatLeftBorder];
|
2019-12-21 20:55:43 +05:30
|
|
|
},
|
|
|
|
buttonId() {
|
|
|
|
return `js-linked-pipeline-${this.pipeline.id}`;
|
|
|
|
},
|
2022-07-16 23:28:13 +05:30
|
|
|
cardClasses() {
|
|
|
|
return this.isDownstream
|
|
|
|
? this.$options.styles.flatRightBorder
|
|
|
|
: this.$options.styles.flatLeftBorder;
|
2019-12-21 20:55:43 +05:30
|
|
|
},
|
2022-04-04 11:22:00 +05:30
|
|
|
expandedIcon() {
|
|
|
|
if (this.isUpstream) {
|
|
|
|
return this.expanded ? 'angle-right' : 'angle-left';
|
|
|
|
}
|
|
|
|
return this.expanded ? 'angle-left' : 'angle-right';
|
|
|
|
},
|
|
|
|
childPipeline() {
|
|
|
|
return this.isDownstream && this.isSameProject;
|
2019-12-21 20:55:43 +05:30
|
|
|
},
|
2020-07-28 23:09:34 +05:30
|
|
|
downstreamTitle() {
|
2021-09-04 01:27:46 +05:30
|
|
|
return this.childPipeline ? this.sourceJobName : this.pipeline.project.name;
|
2020-07-28 23:09:34 +05:30
|
|
|
},
|
2022-04-04 11:22:00 +05:30
|
|
|
flexDirection() {
|
|
|
|
return this.isUpstream ? 'gl-flex-direction-row-reverse' : 'gl-flex-direction-row';
|
2020-03-13 15:44:24 +05:30
|
|
|
},
|
2022-07-16 23:28:13 +05:30
|
|
|
graphqlPipelineId() {
|
|
|
|
return convertToGraphQLId(PIPELINE_GRAPHQL_TYPE, this.pipeline.id);
|
|
|
|
},
|
|
|
|
hasUpdatePipelinePermissions() {
|
|
|
|
return Boolean(this.pipeline?.userPermissions?.updatePipeline);
|
|
|
|
},
|
|
|
|
isCancelable() {
|
|
|
|
return Boolean(this.pipeline?.cancelable && this.hasUpdatePipelinePermissions);
|
|
|
|
},
|
2022-04-04 11:22:00 +05:30
|
|
|
isDownstream() {
|
|
|
|
return this.type === DOWNSTREAM;
|
|
|
|
},
|
2022-07-16 23:28:13 +05:30
|
|
|
isRetryable() {
|
|
|
|
return Boolean(this.pipeline?.retryable && this.hasUpdatePipelinePermissions);
|
|
|
|
},
|
2022-04-04 11:22:00 +05:30
|
|
|
isSameProject() {
|
|
|
|
return !this.pipeline.multiproject;
|
|
|
|
},
|
|
|
|
isUpstream() {
|
|
|
|
return this.type === UPSTREAM;
|
2020-03-13 15:44:24 +05:30
|
|
|
},
|
|
|
|
label() {
|
2020-07-28 23:09:34 +05:30
|
|
|
if (this.parentPipeline) {
|
|
|
|
return __('Parent');
|
|
|
|
} else if (this.childPipeline) {
|
|
|
|
return __('Child');
|
|
|
|
}
|
|
|
|
return __('Multi-project');
|
2020-03-13 15:44:24 +05:30
|
|
|
},
|
2022-04-04 11:22:00 +05:30
|
|
|
parentPipeline() {
|
|
|
|
return this.isUpstream && this.isSameProject;
|
|
|
|
},
|
2021-02-22 17:27:13 +05:30
|
|
|
pipelineIsLoading() {
|
|
|
|
return Boolean(this.isLoading || this.pipeline.isLoading);
|
|
|
|
},
|
2022-04-04 11:22:00 +05:30
|
|
|
pipelineStatus() {
|
|
|
|
return this.pipeline.status;
|
2021-01-29 00:20:46 +05:30
|
|
|
},
|
2022-04-04 11:22:00 +05:30
|
|
|
projectName() {
|
|
|
|
return this.pipeline.project.name;
|
2021-02-22 17:27:13 +05:30
|
|
|
},
|
2022-07-16 23:28:13 +05:30
|
|
|
showAction() {
|
|
|
|
return Boolean(this.action?.method && this.action?.icon && this.action?.ariaLabel);
|
|
|
|
},
|
|
|
|
showCardTooltip() {
|
|
|
|
return !this.hasActionTooltip;
|
|
|
|
},
|
2021-02-22 17:27:13 +05:30
|
|
|
sourceJobName() {
|
2021-11-11 11:23:49 +05:30
|
|
|
return this.pipeline.sourceJob?.name ?? '';
|
2020-03-13 15:44:24 +05:30
|
|
|
},
|
2020-07-28 23:09:34 +05:30
|
|
|
sourceJobInfo() {
|
2021-02-22 17:27:13 +05:30
|
|
|
return this.isDownstream ? sprintf(__('Created by %{job}'), { job: this.sourceJobName }) : '';
|
2020-03-13 15:44:24 +05:30
|
|
|
},
|
2022-07-16 23:28:13 +05:30
|
|
|
cardTooltipText() {
|
2022-04-04 11:22:00 +05:30
|
|
|
return `${this.downstreamTitle} #${this.pipeline.id} - ${this.pipelineStatus.label} -
|
|
|
|
${this.sourceJobInfo}`;
|
2020-11-24 15:15:51 +05:30
|
|
|
},
|
2019-12-21 20:55:43 +05:30
|
|
|
},
|
2021-03-08 18:12:59 +05:30
|
|
|
errorCaptured(err, _vm, info) {
|
|
|
|
reportToSentry('linked_pipeline', `error: ${err}, info: ${info}`);
|
|
|
|
},
|
2019-12-21 20:55:43 +05:30
|
|
|
methods: {
|
2022-07-16 23:28:13 +05:30
|
|
|
cancelPipeline() {
|
|
|
|
this.executePipelineAction(CancelPipelineMutation);
|
|
|
|
},
|
|
|
|
async executePipelineAction(mutation) {
|
|
|
|
try {
|
|
|
|
this.isActionLoading = true;
|
|
|
|
|
|
|
|
await this.$apollo.mutate({
|
|
|
|
mutation,
|
|
|
|
variables: {
|
|
|
|
id: this.graphqlPipelineId,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
this.$emit('refreshPipelineGraph');
|
|
|
|
} catch {
|
|
|
|
this.$emit('error', { type: ACTION_FAILURE });
|
|
|
|
} finally {
|
|
|
|
this.isActionLoading = false;
|
|
|
|
}
|
|
|
|
},
|
2022-04-04 11:22:00 +05:30
|
|
|
hideTooltips() {
|
|
|
|
this.$root.$emit(BV_HIDE_TOOLTIP);
|
|
|
|
},
|
2019-12-21 20:55:43 +05:30
|
|
|
onClickLinkedPipeline() {
|
2021-02-22 17:27:13 +05:30
|
|
|
this.hideTooltips();
|
2020-03-13 15:44:24 +05:30
|
|
|
this.$emit('pipelineClicked', this.$refs.linkedPipeline);
|
2021-02-22 17:27:13 +05:30
|
|
|
this.$emit('pipelineExpandToggle', this.sourceJobName, !this.expanded);
|
2020-03-13 15:44:24 +05:30
|
|
|
},
|
2020-07-28 23:09:34 +05:30
|
|
|
onDownstreamHovered() {
|
2021-02-22 17:27:13 +05:30
|
|
|
this.$emit('downstreamHovered', this.sourceJobName);
|
2020-07-28 23:09:34 +05:30
|
|
|
},
|
|
|
|
onDownstreamHoverLeave() {
|
|
|
|
this.$emit('downstreamHovered', '');
|
|
|
|
},
|
2022-07-16 23:28:13 +05:30
|
|
|
retryPipeline() {
|
|
|
|
this.executePipelineAction(RetryPipelineMutation);
|
|
|
|
},
|
|
|
|
setActionTooltip(flag) {
|
|
|
|
this.hasActionTooltip = flag;
|
|
|
|
},
|
2019-12-21 20:55:43 +05:30
|
|
|
},
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
2021-02-22 17:27:13 +05:30
|
|
|
<div
|
2020-03-13 15:44:24 +05:30
|
|
|
ref="linkedPipeline"
|
2022-07-16 23:28:13 +05:30
|
|
|
class="gl-h-full gl-display-flex!"
|
2022-04-04 11:22:00 +05:30
|
|
|
:class="flexDirection"
|
2022-06-21 17:19:12 +05:30
|
|
|
data-qa-selector="linked_pipeline_container"
|
2020-07-28 23:09:34 +05:30
|
|
|
@mouseover="onDownstreamHovered"
|
|
|
|
@mouseleave="onDownstreamHoverLeave"
|
2020-03-13 15:44:24 +05:30
|
|
|
>
|
2022-07-16 23:28:13 +05:30
|
|
|
<gl-tooltip v-if="showCardTooltip" :target="() => $refs.linkedPipeline">
|
|
|
|
{{ cardTooltipText }}
|
|
|
|
</gl-tooltip>
|
|
|
|
<div class="gl-bg-white gl-border gl-p-3 gl-rounded-lg gl-w-full" :class="cardClasses">
|
|
|
|
<div class="gl-display-flex gl-gap-x-3">
|
|
|
|
<ci-status v-if="!pipelineIsLoading" :status="pipelineStatus" :size="24" css-classes="" />
|
2022-04-04 11:22:00 +05:30
|
|
|
<div v-else class="gl-pr-3"><gl-loading-icon size="sm" inline /></div>
|
2022-07-16 23:28:13 +05:30
|
|
|
<div
|
|
|
|
class="gl-display-flex gl-downstream-pipeline-job-width gl-flex-direction-column gl-line-height-normal"
|
|
|
|
>
|
2021-09-04 01:27:46 +05:30
|
|
|
<span class="gl-text-truncate" data-testid="downstream-title">
|
2020-11-24 15:15:51 +05:30
|
|
|
{{ downstreamTitle }}
|
|
|
|
</span>
|
|
|
|
<div class="gl-text-truncate">
|
2022-07-16 23:28:13 +05:30
|
|
|
<gl-link
|
|
|
|
class="gl-text-blue-500! gl-font-sm"
|
|
|
|
:href="pipeline.path"
|
|
|
|
data-testid="pipelineLink"
|
2020-11-24 15:15:51 +05:30
|
|
|
>#{{ pipeline.id }}</gl-link
|
|
|
|
>
|
|
|
|
</div>
|
|
|
|
</div>
|
2022-07-16 23:28:13 +05:30
|
|
|
<gl-button
|
|
|
|
v-if="showAction"
|
|
|
|
v-gl-tooltip
|
|
|
|
:title="action.ariaLabel"
|
|
|
|
:loading="isActionLoading"
|
|
|
|
:icon="action.icon"
|
|
|
|
class="gl-rounded-full!"
|
|
|
|
:class="$options.styles.actionSizeClasses"
|
|
|
|
:aria-label="action.ariaLabel"
|
|
|
|
@click="action.method"
|
|
|
|
@mouseover="setActionTooltip(true)"
|
|
|
|
@mouseout="setActionTooltip(false)"
|
|
|
|
/>
|
|
|
|
<div v-else :class="$options.styles.actionSizeClasses"></div>
|
2020-11-24 15:15:51 +05:30
|
|
|
</div>
|
2020-07-28 23:09:34 +05:30
|
|
|
<div class="gl-pt-2">
|
2021-03-08 18:12:59 +05:30
|
|
|
<gl-badge size="sm" variant="info" data-testid="downstream-pipeline-label">
|
|
|
|
{{ label }}
|
|
|
|
</gl-badge>
|
2020-03-13 15:44:24 +05:30
|
|
|
</div>
|
2022-04-04 11:22:00 +05:30
|
|
|
</div>
|
|
|
|
<div class="gl-display-flex">
|
2020-11-24 15:15:51 +05:30
|
|
|
<gl-button
|
|
|
|
:id="buttonId"
|
2022-07-16 23:28:13 +05:30
|
|
|
class="gl-border! gl-shadow-none! gl-rounded-lg!"
|
|
|
|
:class="[`js-pipeline-expand-${pipeline.id}`, buttonBorderClasses]"
|
2020-11-24 15:15:51 +05:30
|
|
|
:icon="expandedIcon"
|
2021-04-29 21:17:54 +05:30
|
|
|
:aria-label="__('Expand pipeline')"
|
2021-02-22 17:27:13 +05:30
|
|
|
data-testid="expand-pipeline-button"
|
2022-06-21 17:19:12 +05:30
|
|
|
data-qa-selector="expand_linked_pipeline_button"
|
2020-11-24 15:15:51 +05:30
|
|
|
@click="onClickLinkedPipeline"
|
|
|
|
/>
|
|
|
|
</div>
|
2021-02-22 17:27:13 +05:30
|
|
|
</div>
|
2019-12-21 20:55:43 +05:30
|
|
|
</template>
|