mr_widget_pipeline.vue 7.2 KB
Newer Older
1
<script>
2
/* eslint-disable vue/require-default-prop, vue/no-v-html */
3
import { GlIcon, GlLink, GlLoadingIcon, GlSprintf, GlTooltipDirective } from '@gitlab/ui';
4
import mrWidgetPipelineMixin from 'ee_else_ce/vue_merge_request_widget/mixins/mr_widget_pipeline';
5
import { s__ } from '~/locale';
6
import PipelineStage from '~/pipelines/components/pipelines_list/stage.vue';
7
import CiIcon from '~/vue_shared/components/ci_icon.vue';
8
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
9

10 11 12 13
export default {
  name: 'MRWidgetPipeline',
  components: {
    CiIcon,
14
    GlLink,
15 16 17 18 19
    GlLoadingIcon,
    GlIcon,
    GlSprintf,
    PipelineStage,
    TooltipOnTruncate,
20 21
    LinkedPipelinesMiniList: () =>
      import('ee_component/vue_shared/components/linked_pipelines_mini_list.vue'),
22
  },
23 24 25
  directives: {
    GlTooltip: GlTooltipDirective,
  },
26
  mixins: [mrWidgetPipelineMixin],
27 28 29 30
  props: {
    pipeline: {
      type: Object,
      required: true,
F
Filipa Lacerda 已提交
31
    },
32 33 34 35
    pipelineCoverageDelta: {
      type: String,
      required: false,
    },
36 37 38 39 40
    // This prop needs to be camelCase, html attributes are case insensive
    // https://vuejs.org/v2/guide/components.html#camelCase-vs-kebab-case
    hasCi: {
      type: Boolean,
      required: false,
41
    },
42 43 44
    ciStatus: {
      type: String,
      required: false,
45
    },
46 47 48 49
    pipelineMustSucceed: {
      type: Boolean,
      required: false,
    },
50 51 52 53
    sourceBranchLink: {
      type: String,
      required: false,
    },
54 55 56 57
    sourceBranch: {
      type: String,
      required: false,
    },
58 59 60 61 62
    mrTroubleshootingDocsPath: {
      type: String,
      required: true,
    },
    ciTroubleshootingDocsPath: {
63
      type: String,
F
Filipa Lacerda 已提交
64
      required: true,
65
    },
66 67 68 69 70 71
  },
  computed: {
    hasPipeline() {
      return this.pipeline && Object.keys(this.pipeline).length > 0;
    },
    hasCIError() {
72
      return this.hasPipeline && !this.ciStatus;
73 74 75 76 77 78 79 80 81 82 83 84 85 86
    },
    status() {
      return this.pipeline.details && this.pipeline.details.status
        ? this.pipeline.details.status
        : {};
    },
    hasStages() {
      return (
        this.pipeline.details && this.pipeline.details.stages && this.pipeline.details.stages.length
      );
    },
    hasCommitInfo() {
      return this.pipeline.commit && Object.keys(this.pipeline.commit).length > 0;
    },
87 88 89
    isMergeRequestPipeline() {
      return Boolean(this.pipeline.flags && this.pipeline.flags.merge_request_pipeline);
    },
90 91 92
    showSourceBranch() {
      return Boolean(this.pipeline.ref.branch);
    },
93 94 95 96 97 98 99 100 101 102
    coverageDeltaClass() {
      const delta = this.pipelineCoverageDelta;
      if (delta && parseFloat(delta) > 0) {
        return 'text-success';
      }
      if (delta && parseFloat(delta) < 0) {
        return 'text-danger';
      }
      return '';
    },
103
  },
104 105 106 107
  errorText: s__(
    'Pipeline|Could not retrieve the pipeline status. For troubleshooting steps, read the %{linkStart}documentation%{linkEnd}.',
  ),
  monitoringPipelineText: s__('Pipeline|Checking pipeline status.'),
108
};
109 110
</script>
<template>
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
  <div class="ci-widget media">
    <template v-if="hasCIError">
      <gl-icon name="status_failed" class="gl-text-red-500" :size="24" />
      <div
        class="gl-flex-fill-1 gl-ml-5"
        tabindex="0"
        role="text"
        :aria-label="$options.errorText"
        data-testid="ci-error-message"
      >
        <gl-sprintf :message="$options.errorText">
          <template #link="{content}">
            <gl-link :href="mrTroubleshootingDocsPath">{{ content }}</gl-link>
          </template>
        </gl-sprintf>
      </div>
    </template>
    <template v-else-if="!hasPipeline">
      <gl-loading-icon size="md" />
      <div class="gl-flex-fill-1 gl-display-flex gl-ml-5" data-testid="monitoring-pipeline-message">
        <span tabindex="0" role="text" :aria-label="$options.monitoringPipelineText">
          <gl-sprintf :message="$options.monitoringPipelineText" />
        </span>
        <gl-link
          :href="ciTroubleshootingDocsPath"
          target="_blank"
          class="gl-display-flex gl-align-items-center gl-ml-2"
          tabindex="0"
        >
          <gl-icon
            name="question"
            :small="12"
            tabindex="0"
            role="text"
            :aria-label="__('Link to go to GitLab pipeline documentation')"
          />
        </gl-link>
148 149 150
      </div>
    </template>
    <template v-else-if="hasPipeline">
151
      <a :href="status.details_path" class="align-self-start gl-mr-3">
152
        <ci-icon :status="status" :size="24" :borderless="true" class="add-border" />
153 154 155 156
      </a>
      <div class="ci-widget-container d-flex">
        <div class="ci-widget-content">
          <div class="media-body">
157
            <div
158 159
              class="gl-font-weight-bold"
              data-testid="pipeline-info-container"
160 161
              data-qa-selector="merge_request_pipeline_info_content"
            >
162
              {{ pipeline.details.name }}
163 164
              <gl-link
                :href="pipeline.path"
165 166
                class="pipeline-id gl-font-weight-normal pipeline-number"
                data-testid="pipeline-id"
167
                data-qa-selector="pipeline_link"
168 169
                >#{{ pipeline.id }}</gl-link
              >
170 171
              {{ pipeline.details.status.label }}
              <template v-if="hasCommitInfo">
172 173
                {{ s__('Pipeline|for') }}
                <gl-link
174
                  :href="pipeline.commit.commit_path"
175 176
                  class="commit-sha gl-font-weight-normal"
                  data-testid="commit-link"
177
                  >{{ pipeline.commit.short_id }}</gl-link
178
                >
179 180
              </template>
              <template v-if="showSourceBranch">
181
                {{ s__('Pipeline|on') }}
182 183 184
                <tooltip-on-truncate
                  :title="sourceBranch"
                  truncate-target="child"
185
                  class="label-branch label-truncate gl-font-weight-normal"
186 187 188
                  v-html="sourceBranchLink"
                />
              </template>
189
            </div>
190
            <div v-if="pipeline.coverage" class="coverage" data-testid="pipeline-coverage">
191
              {{ s__('Pipeline|Coverage') }} {{ pipeline.coverage }}%
192 193 194 195

              <span
                v-if="pipelineCoverageDelta"
                :class="coverageDeltaClass"
196
                data-testid="pipeline-coverage-delta"
197 198 199
              >
                ({{ pipelineCoverageDelta }}%)
              </span>
200
            </div>
201
          </div>
202 203 204
        </div>
        <div>
          <span class="mr-widget-pipeline-graph">
205 206 207 208 209 210 211 212 213
            <span class="stage-cell">
              <linked-pipelines-mini-list v-if="triggeredBy.length" :triggered-by="triggeredBy" />
              <template v-if="hasStages">
                <div
                  v-for="(stage, i) in pipeline.details.stages"
                  :key="i"
                  :class="{
                    'has-downstream': hasDownstream(i),
                  }"
214 215
                  class="stage-container dropdown mr-widget-pipeline-stages"
                  data-testid="widget-mini-pipeline-graph"
216 217 218 219
                >
                  <pipeline-stage :stage="stage" />
                </div>
              </template>
220
            </span>
221
            <linked-pipelines-mini-list v-if="triggered.length" :triggered="triggered" />
222
          </span>
223
        </div>
224 225
      </div>
    </template>
226 227
  </div>
</template>