pipelines_table_row.vue 9.62 KB
Newer Older
1
<script>
2 3 4 5 6 7 8 9 10 11 12
import eventHub from '../event_hub';
import PipelinesActionsComponent from './pipelines_actions.vue';
import PipelinesArtifactsComponent from './pipelines_artifacts.vue';
import CiBadge from '../../vue_shared/components/ci_badge_link.vue';
import PipelineStage from './stage.vue';
import PipelineUrl from './pipeline_url.vue';
import PipelinesTimeago from './time_ago.vue';
import CommitComponent from '../../vue_shared/components/commit.vue';
import LoadingButton from '../../vue_shared/components/loading_button.vue';
import Icon from '../../vue_shared/components/icon.vue';
import { PIPELINES_TABLE } from '../constants';
13

14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
/**
 * Pipeline table row.
 *
 * Given the received object renders a table row in the pipelines' table.
 */
export default {
  components: {
    PipelinesActionsComponent,
    PipelinesArtifactsComponent,
    CommitComponent,
    PipelineStage,
    PipelineUrl,
    CiBadge,
    PipelinesTimeago,
    LoadingButton,
    Icon,
  },
  props: {
    pipeline: {
      type: Object,
      required: true,
35
    },
36 37 38 39
    updateGraphDropdown: {
      type: Boolean,
      required: false,
      default: false,
40
    },
41 42 43
    autoDevopsHelpPath: {
      type: String,
      required: true,
44
    },
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
    viewType: {
      type: String,
      required: true,
    },
    cancelingPipeline: {
      type: String,
      required: false,
      default: null,
    },
  },
  pipelinesTable: PIPELINES_TABLE,
  data() {
    return {
      isRetrying: false,
    };
  },
  computed: {
62 63 64
    actions() {
      return [...this.pipeline.details.manual_actions, ...this.pipeline.details.scheduled_actions];
    },
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
    /**
     * If provided, returns the commit tag.
     * Needed to render the commit component column.
     *
     * This field needs a lot of verification, because of different possible cases:
     *
     * 1. person who is an author of a commit might be a GitLab user
     * 2. if person who is an author of a commit is a GitLab user he/she can have a GitLab avatar
     * 3. If GitLab user does not have avatar he/she might have a Gravatar
     * 4. If committer is not a GitLab User he/she can have a Gravatar
     * 5. We do not have consistent API object in this case
     * 6. We should improve API and the code
     *
     * @returns {Object|Undefined}
     */
    commitAuthor() {
      let commitAuthorInformation;
82

83 84 85
      if (!this.pipeline || !this.pipeline.commit) {
        return null;
      }
86

87 88 89 90 91 92
      // 1. person who is an author of a commit might be a GitLab user
      if (this.pipeline.commit.author) {
        // 2. if person who is an author of a commit is a GitLab user
        // he/she can have a GitLab avatar
        if (this.pipeline.commit.author.avatar_url) {
          commitAuthorInformation = this.pipeline.commit.author;
93

94 95 96
          // 3. If GitLab user does not have avatar he/she might have a Gravatar
        } else if (this.pipeline.commit.author_gravatar_url) {
          commitAuthorInformation = Object.assign({}, this.pipeline.commit.author, {
97
            avatar_url: this.pipeline.commit.author_gravatar_url,
98
          });
99
        }
100 101 102 103 104 105 106 107
        // 4. If committer is not a GitLab User he/she can have a Gravatar
      } else {
        commitAuthorInformation = {
          avatar_url: this.pipeline.commit.author_gravatar_url,
          path: `mailto:${this.pipeline.commit.author_email}`,
          username: this.pipeline.commit.author_name,
        };
      }
108

109 110
      return commitAuthorInformation;
    },
111

112 113 114 115 116 117 118 119 120 121 122 123
    /**
     * If provided, returns the commit tag.
     * Needed to render the commit component column.
     *
     * @returns {String|Undefined}
     */
    commitTag() {
      if (this.pipeline.ref && this.pipeline.ref.tag) {
        return this.pipeline.ref.tag;
      }
      return undefined;
    },
124

125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
    /**
     * If provided, returns the commit ref.
     * Needed to render the commit component column.
     *
     * Matches `path` prop sent in the API to `ref_url` prop needed
     * in the commit component.
     *
     * @returns {Object|Undefined}
     */
    commitRef() {
      if (this.pipeline.ref) {
        return Object.keys(this.pipeline.ref).reduce((accumulator, prop) => {
          if (prop === 'path') {
            accumulator.ref_url = this.pipeline.ref[prop];
          } else {
            accumulator[prop] = this.pipeline.ref[prop];
          }
          return accumulator;
        }, {});
      }
145

146 147
      return undefined;
    },
148

149 150 151 152 153 154 155 156 157 158 159 160
    /**
     * If provided, returns the commit url.
     * Needed to render the commit component column.
     *
     * @returns {String|Undefined}
     */
    commitUrl() {
      if (this.pipeline.commit && this.pipeline.commit.commit_path) {
        return this.pipeline.commit.commit_path;
      }
      return undefined;
    },
161

162 163 164 165 166 167 168 169 170 171 172 173
    /**
     * If provided, returns the commit short sha.
     * Needed to render the commit component column.
     *
     * @returns {String|Undefined}
     */
    commitShortSha() {
      if (this.pipeline.commit && this.pipeline.commit.short_id) {
        return this.pipeline.commit.short_id;
      }
      return undefined;
    },
174

175 176 177 178 179 180 181 182 183 184 185 186
    /**
     * If provided, returns the commit title.
     * Needed to render the commit component column.
     *
     * @returns {String|Undefined}
     */
    commitTitle() {
      if (this.pipeline.commit && this.pipeline.commit.title) {
        return this.pipeline.commit.title;
      }
      return undefined;
    },
Filipa Lacerda's avatar
Filipa Lacerda committed
187

188 189 190 191 192 193 194 195 196
    /**
     * Timeago components expects a number
     *
     * @return {type}  description
     */
    pipelineDuration() {
      if (this.pipeline.details && this.pipeline.details.duration) {
        return this.pipeline.details.duration;
      }
Filipa Lacerda's avatar
Filipa Lacerda committed
197

198 199
      return 0;
    },
Filipa Lacerda's avatar
Filipa Lacerda committed
200

201 202 203 204 205 206 207 208 209
    /**
     * Timeago component expects a String.
     *
     * @return {String}
     */
    pipelineFinishedAt() {
      if (this.pipeline.details && this.pipeline.details.finished_at) {
        return this.pipeline.details.finished_at;
      }
Filipa Lacerda's avatar
Filipa Lacerda committed
210

211 212
      return '';
    },
213

214 215 216 217 218 219
    pipelineStatus() {
      if (this.pipeline.details && this.pipeline.details.status) {
        return this.pipeline.details.status;
      }
      return {};
    },
220

221 222 223 224 225 226 227 228
    displayPipelineActions() {
      return (
        this.pipeline.flags.retryable ||
        this.pipeline.flags.cancelable ||
        this.pipeline.details.manual_actions.length ||
        this.pipeline.details.artifacts.length
      );
    },
229

230 231 232
    isChildView() {
      return this.viewType === 'child';
    },
233

234 235
    isCancelling() {
      return this.cancelingPipeline === this.pipeline.id;
236
    },
237
  },
238

239 240 241 242 243 244 245 246 247 248
  methods: {
    handleCancelClick() {
      eventHub.$emit('openConfirmationModal', {
        pipelineId: this.pipeline.id,
        endpoint: this.pipeline.cancel_path,
      });
    },
    handleRetryClick() {
      this.isRetrying = true;
      eventHub.$emit('retryPipeline', this.pipeline.retry_path);
249
    },
250 251
  },
};
252 253
</script>
<template>
254 255
  <div class="commit gl-responsive-table-row">
    <div class="table-section section-10 commit-link">
Filipa Lacerda's avatar
Filipa Lacerda committed
256 257
      <div
        class="table-mobile-header"
258 259
        role="rowheader"
      >
260 261 262
        Status
      </div>
      <div class="table-mobile-content">
263 264 265
        <ci-badge
          :status="pipelineStatus"
          :show-text="!isChildView"
Filipa Lacerda's avatar
Filipa Lacerda committed
266
        />
267 268
      </div>
    </div>
269

270 271 272
    <pipeline-url
      :pipeline="pipeline"
      :auto-devops-help-path="autoDevopsHelpPath"
Filipa Lacerda's avatar
Filipa Lacerda committed
273
    />
274

275
    <div class="table-section section-20">
276 277 278 279 280 281 282 283 284 285 286 287
      <div
        class="table-mobile-header"
        role="rowheader">
        Commit
      </div>
      <div class="table-mobile-content">
        <commit-component
          :tag="commitTag"
          :commit-ref="commitRef"
          :commit-url="commitUrl"
          :short-sha="commitShortSha"
          :title="commitTitle"
288 289
          :author="commitAuthor"
          :show-branch="!isChildView"
Filipa Lacerda's avatar
Filipa Lacerda committed
290
        />
291 292
      </div>
    </div>
293

294
    <div class="table-section section-wrap section-20 stage-cell">
295 296 297 298 299 300
      <div
        class="table-mobile-header"
        role="rowheader">
        Stages
      </div>
      <div class="table-mobile-content">
Filipa Lacerda's avatar
Filipa Lacerda committed
301 302 303
        <template v-if="pipeline.details.stages.length > 0">
          <div
            v-for="(stage, index) in pipeline.details.stages"
304 305
            :key="index"
            class="stage-container dropdown js-mini-pipeline-graph">
Filipa Lacerda's avatar
Filipa Lacerda committed
306
            <pipeline-stage
307
              :type="$options.pipelinesTable"
Filipa Lacerda's avatar
Filipa Lacerda committed
308 309
              :stage="stage"
              :update-dropdown="updateGraphDropdown"
310
            />
Filipa Lacerda's avatar
Filipa Lacerda committed
311 312
          </div>
        </template>
313
      </div>
314
    </div>
315

316 317 318
    <pipelines-timeago
      :duration="pipelineDuration"
      :finished-time="pipelineFinishedAt"
Filipa Lacerda's avatar
Filipa Lacerda committed
319
    />
320

321 322
    <div
      v-if="displayPipelineActions"
323 324
      class="table-section section-20 table-button-footer pipeline-actions"
    >
325
      <div class="btn-group table-action-buttons">
326
        <pipelines-actions-component
327 328
          v-if="actions.length > 0"
          :actions="actions"
Filipa Lacerda's avatar
Filipa Lacerda committed
329
        />
330

331 332 333
        <pipelines-artifacts-component
          v-if="pipeline.details.artifacts.length"
          :artifacts="pipeline.details.artifacts"
334
          class="d-md-block"
Filipa Lacerda's avatar
Filipa Lacerda committed
335
        />
336

337
        <loading-button
338
          v-if="pipeline.flags.retryable"
339 340
          :loading="isRetrying"
          :disabled="isRetrying"
341 342
          container-class="js-pipelines-retry-button btn btn-default btn-retry"
          @click="handleRetryClick"
343 344 345
        >
          <icon name="repeat" />
        </loading-button>
346

347
        <loading-button
348
          v-if="pipeline.flags.cancelable"
349 350
          :loading="isCancelling"
          :disabled="isCancelling"
351
          data-toggle="modal"
352
          data-target="#confirmation-modal"
353
          container-class="js-pipelines-cancel-button btn btn-remove"
354
          @click="handleCancelClick"
355 356 357
        >
          <icon name="close" />
        </loading-button>
358
      </div>
359 360
    </div>
  </div>
361
</template>