BigW Consortium Gitlab

environment_item.vue 15 KB
Newer Older
1
<script>
2
import Timeago from 'timeago.js';
3
import _ from 'underscore';
4
import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
5
import { humanize } from '../../lib/utils/text_utility';
6
import ActionsComponent from './environment_actions.vue';
7 8
import ExternalUrlComponent from './environment_external_url.vue';
import StopComponent from './environment_stop.vue';
9
import RollbackComponent from './environment_rollback.vue';
10
import TerminalButtonComponent from './environment_terminal_button.vue';
11
import MonitoringButtonComponent from './environment_monitoring.vue';
12
import CommitComponent from '../../vue_shared/components/commit.vue';
13
import eventHub from '../event_hub';
14 15 16 17 18 19 20 21

/**
 * Envrionment Item Component
 *
 * Renders a table row for each environment.
 */
const timeagoInstance = new Timeago();

22
export default {
23
  components: {
24
    userAvatarLink,
25
    'commit-component': CommitComponent,
26 27 28 29 30
    'actions-component': ActionsComponent,
    'external-url-component': ExternalUrlComponent,
    'stop-component': StopComponent,
    'rollback-component': RollbackComponent,
    'terminal-button-component': TerminalButtonComponent,
31
    'monitoring-button-component': MonitoringButtonComponent,
32 33 34 35 36 37 38 39
  },

  props: {
    model: {
      type: Object,
      required: true,
      default: () => ({}),
    },
40

41 42 43 44 45
    canCreateDeployment: {
      type: Boolean,
      required: false,
      default: false,
    },
46

47 48 49 50 51 52
    canReadEnvironment: {
      type: Boolean,
      required: false,
      default: false,
    },
  },
53

54 55 56 57 58 59 60 61 62
  computed: {
    /**
     * Verifies if `last_deployment` key exists in the current Envrionment.
     * This key is required to render most of the html - this method works has
     * an helper.
     *
     * @returns {Boolean}
     */
    hasLastDeploymentKey() {
63 64
      if (this.model &&
        this.model.last_deployment &&
65
        !_.isEmpty(this.model.last_deployment)) {
66 67 68 69 70 71 72 73 74 75 76 77
        return true;
      }
      return false;
    },

    /**
     * Verifies is the given environment has manual actions.
     * Used to verify if we should render them or nor.
     *
     * @returns {Boolean|Undefined}
     */
    hasManualActions() {
78 79 80 81
      return this.model &&
        this.model.last_deployment &&
        this.model.last_deployment.manual_actions &&
        this.model.last_deployment.manual_actions.length > 0;
82 83 84 85 86 87 88 89
    },

    /**
     * Returns the value of the `stop_action?` key provided in the response.
     *
     * @returns {Boolean}
     */
    hasStopAction() {
90
      return this.model && this.model['stop_action?'];
91 92 93 94 95 96 97 98 99
    },

    /**
     * Verifies if the `deployable` key is present in `last_deployment` key.
     * Used to verify whether we should or not render the rollback partial.
     *
     * @returns {Boolean|Undefined}
     */
    canRetry() {
100
      return this.model &&
Filipa Lacerda committed
101
        this.hasLastDeploymentKey &&
102 103
        this.model.last_deployment &&
        this.model.last_deployment.deployable;
104 105 106 107 108 109 110 111
    },

    /**
     * Verifies if the date to be shown is present.
     *
     * @returns {Boolean|Undefined}
     */
    canShowDate() {
112 113 114 115
      return this.model &&
        this.model.last_deployment &&
        this.model.last_deployment.deployable &&
        this.model.last_deployment.deployable !== undefined;
116 117 118 119 120 121 122 123
    },

    /**
     * Human readable date.
     *
     * @returns {String}
     */
    createdDate() {
124 125 126 127 128
      if (this.model &&
        this.model.last_deployment &&
        this.model.last_deployment.deployable &&
        this.model.last_deployment.deployable.created_at) {
        return timeagoInstance.format(this.model.last_deployment.deployable.created_at);
Filipa Lacerda committed
129 130
      }
      return '';
Filipa Lacerda committed
131 132
    },

133
    /**
134 135 136
     * Returns the manual actions with the name parsed.
     *
     * @returns {Array.<Object>|Undefined}
137
     */
138 139
    manualActions() {
      if (this.hasManualActions) {
140
        return this.model.last_deployment.manual_actions.map((action) => {
141
          const parsedAction = {
142
            name: humanize(action.name),
143
            play_path: action.play_path,
144
            playable: action.playable,
145 146 147
          };
          return parsedAction;
        });
148
      }
149
      return [];
150 151
    },

152 153 154 155 156 157
    /**
     * Builds the string used in the user image alt attribute.
     *
     * @returns {String}
     */
    userImageAltDescription() {
158 159 160 161 162
      if (this.model &&
        this.model.last_deployment &&
        this.model.last_deployment.user &&
        this.model.last_deployment.user.username) {
        return `${this.model.last_deployment.user.username}'s avatar'`;
163 164 165 166 167 168 169 170 171 172
      }
      return '';
    },

    /**
     * If provided, returns the commit tag.
     *
     * @returns {String|Undefined}
     */
    commitTag() {
173 174 175 176
      if (this.model &&
        this.model.last_deployment &&
        this.model.last_deployment.tag) {
        return this.model.last_deployment.tag;
177 178 179 180 181 182 183 184 185 186
      }
      return undefined;
    },

    /**
     * If provided, returns the commit ref.
     *
     * @returns {Object|Undefined}
     */
    commitRef() {
187 188 189 190
      if (this.model &&
        this.model.last_deployment &&
        this.model.last_deployment.ref) {
        return this.model.last_deployment.ref;
191 192 193 194 195 196 197 198 199 200
      }
      return undefined;
    },

    /**
     * If provided, returns the commit url.
     *
     * @returns {String|Undefined}
     */
    commitUrl() {
201 202 203 204 205
      if (this.model &&
        this.model.last_deployment &&
        this.model.last_deployment.commit &&
        this.model.last_deployment.commit.commit_path) {
        return this.model.last_deployment.commit.commit_path;
206 207 208 209 210 211 212 213 214 215
      }
      return undefined;
    },

    /**
     * If provided, returns the commit short sha.
     *
     * @returns {String|Undefined}
     */
    commitShortSha() {
216 217 218 219 220
      if (this.model &&
        this.model.last_deployment &&
        this.model.last_deployment.commit &&
        this.model.last_deployment.commit.short_id) {
        return this.model.last_deployment.commit.short_id;
221 222 223 224 225 226 227 228 229 230
      }
      return undefined;
    },

    /**
     * If provided, returns the commit title.
     *
     * @returns {String|Undefined}
     */
    commitTitle() {
231 232 233 234 235
      if (this.model &&
        this.model.last_deployment &&
        this.model.last_deployment.commit &&
        this.model.last_deployment.commit.title) {
        return this.model.last_deployment.commit.title;
236 237 238 239 240 241 242 243 244 245
      }
      return undefined;
    },

    /**
     * If provided, returns the commit tag.
     *
     * @returns {Object|Undefined}
     */
    commitAuthor() {
246 247 248 249 250
      if (this.model &&
        this.model.last_deployment &&
        this.model.last_deployment.commit &&
        this.model.last_deployment.commit.author) {
        return this.model.last_deployment.commit.author;
251 252 253 254 255 256 257 258 259 260 261
      }

      return undefined;
    },

    /**
     * Verifies if the `retry_path` key is present and returns its value.
     *
     * @returns {String|Undefined}
     */
    retryUrl() {
262 263 264 265 266
      if (this.model &&
        this.model.last_deployment &&
        this.model.last_deployment.deployable &&
        this.model.last_deployment.deployable.retry_path) {
        return this.model.last_deployment.deployable.retry_path;
267 268 269 270 271 272 273 274 275 276
      }
      return undefined;
    },

    /**
     * Verifies if the `last?` key is present and returns its value.
     *
     * @returns {Boolean|Undefined}
     */
    isLastDeployment() {
277 278
      return this.model && this.model.last_deployment &&
        this.model.last_deployment['last?'];
279 280 281 282 283 284 285 286
    },

    /**
     * Builds the name of the builds needed to display both the name and the id.
     *
     * @returns {String}
     */
    buildName() {
287 288 289 290
      if (this.model &&
        this.model.last_deployment &&
        this.model.last_deployment.deployable) {
        return `${this.model.last_deployment.deployable.name} #${this.model.last_deployment.deployable.id}`;
291 292 293
      }
      return '';
    },
294

295 296 297 298 299 300
    /**
     * Builds the needed string to show the internal id.
     *
     * @returns {String}
     */
    deploymentInternalId() {
301 302 303 304
      if (this.model &&
        this.model.last_deployment &&
        this.model.last_deployment.iid) {
        return `#${this.model.last_deployment.iid}`;
305 306 307 308 309 310 311 312 313 314
      }
      return '';
    },

    /**
     * Verifies if the user object is present under last_deployment object.
     *
     * @returns {Boolean}
     */
    deploymentHasUser() {
315
      return this.model &&
316 317
        !_.isEmpty(this.model.last_deployment) &&
        !_.isEmpty(this.model.last_deployment.user);
318 319 320 321 322 323 324 325 326
    },

    /**
     * Returns the user object nested with the last_deployment object.
     * Used to render the template.
     *
     * @returns {Object}
     */
    deploymentUser() {
327
      if (this.model &&
328 329
        !_.isEmpty(this.model.last_deployment) &&
        !_.isEmpty(this.model.last_deployment.user)) {
330
        return this.model.last_deployment.user;
331 332 333 334 335 336 337 338 339 340 341 342 343
      }
      return {};
    },

    /**
     * Verifies if the build name column should be rendered by verifing
     * if all the information needed is present
     * and if the environment is not a folder.
     *
     * @returns {Boolean}
     */
    shouldRenderBuildName() {
      return !this.model.isFolder &&
344 345
        !_.isEmpty(this.model.last_deployment) &&
        !_.isEmpty(this.model.last_deployment.deployable);
346 347
    },

Filipa Lacerda committed
348 349 350 351 352 353
    /**
     * Verifies the presence of all the keys needed to render the buil_path.
     *
     * @return {String}
     */
    buildPath() {
354 355 356 357 358
      if (this.model &&
        this.model.last_deployment &&
        this.model.last_deployment.deployable &&
        this.model.last_deployment.deployable.build_path) {
        return this.model.last_deployment.deployable.build_path;
Filipa Lacerda committed
359 360 361 362
      }

      return '';
    },
363

Filipa Lacerda committed
364 365 366 367 368 369
    /**
     * Verifies the presence of all the keys needed to render the external_url.
     *
     * @return {String}
     */
    externalURL() {
370 371
      if (this.model && this.model.external_url) {
        return this.model.external_url;
Filipa Lacerda committed
372 373 374 375 376
      }

      return '';
    },

377 378 379 380 381 382 383 384 385
    /**
     * Verifies if deplyment internal ID should be rendered by verifing
     * if all the information needed is present
     * and if the environment is not a folder.
     *
     * @returns {Boolean}
     */
    shouldRenderDeploymentID() {
      return !this.model.isFolder &&
386
        !_.isEmpty(this.model.last_deployment) &&
387
        this.model.last_deployment.iid !== undefined;
388
    },
Filipa Lacerda committed
389 390

    environmentPath() {
391 392
      if (this.model && this.model.environment_path) {
        return this.model.environment_path;
Filipa Lacerda committed
393 394 395 396
      }

      return '';
    },
Filipa Lacerda committed
397

398 399 400 401 402 403 404 405
    monitoringUrl() {
      if (this.model && this.model.metrics_path) {
        return this.model.metrics_path;
      }

      return '';
    },

406 407 408 409 410 411 412
    displayEnvironmentActions() {
      return this.hasManualActions ||
             this.externalURL ||
             this.monitoringUrl ||
             this.hasStopAction ||
             this.canRetry;
    },
413 414
  },

415 416
  methods: {
    onClickFolder() {
417
      eventHub.$emit('toggleFolder', this.model);
418 419
    },
  },
420 421 422
};
</script>
<template>
423
  <div
424 425 426 427 428
    class="gl-responsive-table-row"
    :class="{
      'js-child-row environment-child-row': model.isChildren,
      'folder-row': model.isFolder,
    }"
429
    role="row">
430 431 432
    <div class="table-section section-10" role="gridcell">
      <div
        v-if="!model.isFolder"
433 434
        class="table-mobile-header"
        role="rowheader">
435
        {{s__("Environments|Environment")}}
436
      </div>
437 438
      <a
        v-if="!model.isFolder"
439
        class="environment-name flex-truncate-parent table-mobile-content"
440
        :href="environmentPath">
441
        <span class="flex-truncate-child">{{model.name}}</span>
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
      </a>
      <span
        v-else
        class="folder-name"
        @click="onClickFolder"
        role="button">

        <span class="folder-icon">
          <i
            v-show="model.isOpen"
            class="fa fa-caret-down"
            aria-hidden="true" />
          <i
            v-show="!model.isOpen"
            class="fa fa-caret-right"
            aria-hidden="true"/>
458
        </span>
459

460 461 462 463
        <span class="folder-icon">
          <i
            class="fa fa-folder"
            aria-hidden="true" />
464 465
        </span>

466 467
        <span>
          {{model.folderName}}
468 469
        </span>

470 471
        <span class="badge">
          {{model.size}}
472
        </span>
473
      </span>
474
    </div>
475

476
    <div class="table-section section-10 deployment-column hidden-xs hidden-sm" role="gridcell">
477 478 479 480 481 482
      <span v-if="shouldRenderDeploymentID">
        {{deploymentInternalId}}
      </span>

      <span v-if="!model.isFolder && deploymentHasUser">
        by
483 484 485 486 487 488 489
        <user-avatar-link
          class="js-deploy-user-container"
          :link-href="deploymentUser.web_url"
          :img-src="deploymentUser.avatar_url"
          :img-alt="userImageAltDescription"
          :tooltip-text="deploymentUser.username"
        />
490
      </span>
491
    </div>
492

493
    <div class="table-section section-15 hidden-xs hidden-sm" role="gridcell">
494 495
      <a
        v-if="shouldRenderBuildName"
496
        class="build-link flex-truncate-parent"
497
        :href="buildPath">
498
        <span class="flex-truncate-child">{{buildName}}</span>
499
      </a>
500
    </div>
501

502 503 504
    <div
      v-if="!model.isFolder"
      class="table-section section-25" role="gridcell">
505
      <div
506
        role="rowheader"
507
        class="table-mobile-header">
508
        {{s__("Environments|Commit")}}
509
      </div>
510
      <div
511
        v-if="hasLastDeploymentKey"
512
        class="js-commit-component table-mobile-content">
513 514 515 516 517 518 519 520
        <commit-component
          :tag="commitTag"
          :commit-ref="commitRef"
          :commit-url="commitUrl"
          :short-sha="commitShortSha"
          :title="commitTitle"
          :author="commitAuthor"/>
      </div>
521
      <div
522
        v-if="!hasLastDeploymentKey"
523
        class="commit-title table-mobile-content">
524
        {{s__("Environments|No deployments yet")}}
525 526
      </div>
    </div>
527

528 529 530
    <div
      v-if="!model.isFolder"
      class="table-section section-10" role="gridcell">
531
      <div
532
        role="rowheader"
533
        class="table-mobile-header">
534
        {{s__("Environments|Updated")}}
535
      </div>
536
      <span
537
        v-if="canShowDate"
538
        class="environment-created-date-timeago table-mobile-content">
539 540
        {{createdDate}}
      </span>
541
    </div>
542

543 544 545 546 547
    <div
      v-if="!model.isFolder && displayEnvironmentActions"
      class="table-section section-30 table-button-footer"
      role="gridcell">

548
      <div
549
        class="btn-group table-action-buttons"
550 551 552 553
        role="group">

        <actions-component
          v-if="hasManualActions && canCreateDeployment"
554 555
          :actions="manualActions"
          />
556 557 558

        <external-url-component
          v-if="externalURL && canReadEnvironment"
559 560
          :external-url="externalURL"
          />
561 562 563

        <monitoring-button-component
          v-if="monitoringUrl && canReadEnvironment"
564 565
          :monitoring-url="monitoringUrl"
          />
566 567 568

        <terminal-button-component
          v-if="model && model.terminal_path"
569 570
          :terminal-path="model.terminal_path"
          />
571 572 573 574

        <stop-component
          v-if="hasStopAction && canCreateDeployment"
          :stop-url="model.stop_path"
575
          />
576 577 578 579 580

        <rollback-component
          v-if="canRetry && canCreateDeployment"
          :is-last-deployment="isLastDeployment"
          :retry-url="retryUrl"
581
          />
582
      </div>
583 584
    </div>
  </div>
585
</template>