debian-mirror-gitlab/app/assets/javascripts/environments/components/environment_item.vue

687 lines
18 KiB
Vue
Raw Normal View History

2017-08-17 22:00:37 +05:30
<script>
2019-10-12 21:52:04 +05:30
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
2018-11-18 11:00:15 +05:30
import _ from 'underscore';
2019-02-15 15:39:39 +05:30
import { GlTooltipDirective } from '@gitlab/ui';
2020-03-09 13:42:32 +05:30
import { __, sprintf } from '~/locale';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import timeagoMixin from '~/vue_shared/mixins/timeago';
2018-11-18 11:00:15 +05:30
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
2020-03-09 13:42:32 +05:30
import CommitComponent from '~/vue_shared/components/commit.vue';
2018-12-13 13:39:08 +05:30
import Icon from '~/vue_shared/components/icon.vue';
2020-01-01 13:55:28 +05:30
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
2020-03-09 13:42:32 +05:30
import environmentItemMixin from 'ee_else_ce/environments/mixins/environment_item_mixin';
import eventHub from '../event_hub';
2018-11-18 11:00:15 +05:30
import ActionsComponent from './environment_actions.vue';
import ExternalUrlComponent from './environment_external_url.vue';
2020-03-09 13:42:32 +05:30
import MonitoringButtonComponent from './environment_monitoring.vue';
import PinComponent from './environment_pin.vue';
2018-11-18 11:00:15 +05:30
import RollbackComponent from './environment_rollback.vue';
2020-03-09 13:42:32 +05:30
import StopComponent from './environment_stop.vue';
2018-11-18 11:00:15 +05:30
import TerminalButtonComponent from './environment_terminal_button.vue';
/**
2018-12-13 13:39:08 +05:30
* Environment Item Component
2018-11-18 11:00:15 +05:30
*
* Renders a table row for each environment.
*/
export default {
components: {
ActionsComponent,
2020-03-09 13:42:32 +05:30
CommitComponent,
2018-11-18 11:00:15 +05:30
ExternalUrlComponent,
2020-03-09 13:42:32 +05:30
Icon,
MonitoringButtonComponent,
PinComponent,
2018-11-18 11:00:15 +05:30
RollbackComponent,
2020-03-09 13:42:32 +05:30
StopComponent,
2018-11-18 11:00:15 +05:30
TerminalButtonComponent,
2020-01-01 13:55:28 +05:30
TooltipOnTruncate,
UserAvatarLink,
2018-11-18 11:00:15 +05:30
},
directives: {
2019-02-15 15:39:39 +05:30
GlTooltip: GlTooltipDirective,
2018-11-18 11:00:15 +05:30
},
2020-03-09 13:42:32 +05:30
mixins: [environmentItemMixin, timeagoMixin],
2018-11-18 11:00:15 +05:30
props: {
2020-01-01 13:55:28 +05:30
canReadEnvironment: {
type: Boolean,
required: false,
default: false,
},
2018-11-18 11:00:15 +05:30
model: {
type: Object,
required: true,
2020-03-09 13:42:32 +05:30
},
shouldShowAutoStopDate: {
type: Boolean,
required: false,
default: false,
2018-11-18 11:00:15 +05:30
},
2020-01-01 13:55:28 +05:30
tableData: {
type: Object,
required: true,
2018-11-18 11:00:15 +05:30
},
},
computed: {
/**
2018-12-13 13:39:08 +05:30
* Verifies if `last_deployment` key exists in the current Environment.
2018-11-18 11:00:15 +05:30
* This key is required to render most of the html - this method works has
* an helper.
*
* @returns {Boolean}
*/
hasLastDeploymentKey() {
if (this.model && this.model.last_deployment && !_.isEmpty(this.model.last_deployment)) {
return true;
}
return false;
},
2020-03-09 13:42:32 +05:30
/**
* Checkes whether the row displayed is a folder.
*
* @returns {Boolean}
*/
isFolder() {
return this.model.isFolder;
},
2018-11-18 11:00:15 +05:30
/**
* Checkes whether the environment is protected.
* (`is_protected` currently only set in EE)
*
* @returns {Boolean}
*/
isProtected() {
return this.model && this.model.is_protected;
},
/**
* Returns whether the environment can be stopped.
*
* @returns {Boolean}
*/
canStopEnvironment() {
return this.model && this.model.can_stop;
},
/**
* 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() {
return (
this.model &&
this.hasLastDeploymentKey &&
this.model.last_deployment &&
this.model.last_deployment.deployable &&
this.model.last_deployment.deployable.retry_path
);
},
/**
2020-03-09 13:42:32 +05:30
* Verifies if the autostop date is present.
*
* @returns {Boolean}
*/
canShowAutoStopDate() {
if (!this.model.auto_stop_at) {
return false;
}
const autoStopDate = new Date(this.model.auto_stop_at);
const now = new Date();
return now < autoStopDate;
},
/**
* Human readable deployment date.
*
* @returns {String}
*/
autoStopDate() {
if (this.canShowAutoStopDate) {
return {
formatted: this.timeFormatted(this.model.auto_stop_at),
tooltip: this.tooltipTitle(this.model.auto_stop_at),
};
}
return {
formatted: '',
tooltip: '',
};
},
/**
* Verifies if the deployment date is present.
2018-11-18 11:00:15 +05:30
*
* @returns {Boolean|Undefined}
*/
2020-03-09 13:42:32 +05:30
canShowDeploymentDate() {
2019-12-04 20:38:33 +05:30
return this.model && this.model.last_deployment && this.model.last_deployment.deployed_at;
2018-11-18 11:00:15 +05:30
},
/**
2020-03-09 13:42:32 +05:30
* Human readable deployment date.
2018-11-18 11:00:15 +05:30
*
* @returns {String}
*/
2019-12-04 20:38:33 +05:30
deployedDate() {
2020-03-09 13:42:32 +05:30
if (this.canShowDeploymentDate) {
return {
formatted: this.timeFormatted(this.model.last_deployment.deployed_at),
tooltip: this.tooltipTitle(this.model.last_deployment.deployed_at),
};
2018-11-18 11:00:15 +05:30
}
2020-03-09 13:42:32 +05:30
return {
formatted: '',
tooltip: '',
};
2018-11-18 11:00:15 +05:30
},
2018-12-13 13:39:08 +05:30
actions() {
2019-03-02 22:35:43 +05:30
if (!this.model || !this.model.last_deployment) {
2018-12-13 13:39:08 +05:30
return [];
2018-11-18 11:00:15 +05:30
}
2018-12-13 13:39:08 +05:30
const { manualActions, scheduledActions } = convertObjectPropsToCamelCase(
this.model.last_deployment,
{ deep: true },
);
const combinedActions = (manualActions || []).concat(scheduledActions || []);
return combinedActions.map(action => ({
...action,
2019-07-07 11:18:12 +05:30
name: action.name,
2018-12-13 13:39:08 +05:30
}));
2018-11-18 11:00:15 +05:30
},
/**
* Builds the string used in the user image alt attribute.
*
* @returns {String}
*/
userImageAltDescription() {
if (
this.model &&
this.model.last_deployment &&
this.model.last_deployment.user &&
this.model.last_deployment.user.username
) {
2019-09-30 21:07:59 +05:30
return sprintf(__("%{username}'s avatar"), {
username: this.model.last_deployment.user.username,
});
2018-11-18 11:00:15 +05:30
}
return '';
},
/**
* If provided, returns the commit tag.
*
* @returns {String|Undefined}
*/
commitTag() {
if (this.model && this.model.last_deployment && this.model.last_deployment.tag) {
return this.model.last_deployment.tag;
}
return undefined;
},
/**
* If provided, returns the commit ref.
*
* @returns {Object|Undefined}
*/
commitRef() {
if (this.model && this.model.last_deployment && this.model.last_deployment.ref) {
return this.model.last_deployment.ref;
}
return undefined;
},
/**
* If provided, returns the commit url.
*
* @returns {String|Undefined}
*/
commitUrl() {
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;
}
return undefined;
},
/**
* If provided, returns the commit short sha.
*
* @returns {String|Undefined}
*/
commitShortSha() {
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;
}
return undefined;
},
/**
* If provided, returns the commit title.
*
* @returns {String|Undefined}
*/
commitTitle() {
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;
}
return undefined;
},
/**
* If provided, returns the commit tag.
*
* @returns {Object|Undefined}
*/
commitAuthor() {
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;
}
return undefined;
},
/**
* Verifies if the `retry_path` key is present and returns its value.
*
* @returns {String|Undefined}
*/
retryUrl() {
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;
}
return undefined;
},
/**
* Verifies if the `last?` key is present and returns its value.
*
* @returns {Boolean|Undefined}
*/
isLastDeployment() {
2019-09-30 21:07:59 +05:30
// name: 'last?' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26#possible-false-positives
2019-12-04 20:38:33 +05:30
// Vue i18n ESLint rules issue: https://gitlab.com/gitlab-org/gitlab-foss/issues/63560
2019-10-12 21:52:04 +05:30
// eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
2018-11-18 11:00:15 +05:30
return this.model && this.model.last_deployment && this.model.last_deployment['last?'];
},
/**
* Builds the name of the builds needed to display both the name and the id.
*
* @returns {String}
*/
buildName() {
if (this.model && this.model.last_deployment && this.model.last_deployment.deployable) {
const { deployable } = this.model.last_deployment;
return `${deployable.name} #${deployable.id}`;
}
return '';
},
/**
* Builds the needed string to show the internal id.
*
* @returns {String}
*/
deploymentInternalId() {
if (this.model && this.model.last_deployment && this.model.last_deployment.iid) {
return `#${this.model.last_deployment.iid}`;
}
return '';
},
/**
* Verifies if the user object is present under last_deployment object.
*
* @returns {Boolean}
*/
deploymentHasUser() {
return (
this.model &&
!_.isEmpty(this.model.last_deployment) &&
!_.isEmpty(this.model.last_deployment.user)
);
},
/**
* Returns the user object nested with the last_deployment object.
* Used to render the template.
*
* @returns {Object}
*/
deploymentUser() {
if (
this.model &&
!_.isEmpty(this.model.last_deployment) &&
!_.isEmpty(this.model.last_deployment.user)
) {
return this.model.last_deployment.user;
}
return {};
},
2020-03-09 13:42:32 +05:30
/**
* Checkes whether to display no deployment text.
*
* @returns {Boolean}
*/
showNoDeployments() {
return !this.hasLastDeploymentKey && !this.isFolder;
},
2018-11-18 11:00:15 +05:30
/**
* 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 (
2020-03-09 13:42:32 +05:30
!this.isFolder &&
2018-11-18 11:00:15 +05:30
!_.isEmpty(this.model.last_deployment) &&
!_.isEmpty(this.model.last_deployment.deployable)
);
},
/**
* Verifies the presence of all the keys needed to render the buil_path.
*
* @return {String}
*/
buildPath() {
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;
}
return '';
},
/**
* Verifies the presence of all the keys needed to render the external_url.
*
* @return {String}
*/
externalURL() {
2020-03-09 13:42:32 +05:30
return this.model.external_url || '';
2018-11-18 11:00:15 +05:30
},
/**
* 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 (
2020-03-09 13:42:32 +05:30
!this.isFolder &&
2018-11-18 11:00:15 +05:30
!_.isEmpty(this.model.last_deployment) &&
this.model.last_deployment.iid !== undefined
);
},
environmentPath() {
2020-03-09 13:42:32 +05:30
return this.model.environment_path || '';
2018-11-18 11:00:15 +05:30
},
monitoringUrl() {
2020-03-09 13:42:32 +05:30
return this.model.metrics_path || '';
},
2018-11-18 11:00:15 +05:30
2020-03-09 13:42:32 +05:30
autoStopUrl() {
return this.model.cancel_auto_stop_path || '';
2018-11-18 11:00:15 +05:30
},
displayEnvironmentActions() {
return (
2018-12-13 13:39:08 +05:30
this.actions.length > 0 ||
2018-11-18 11:00:15 +05:30
this.externalURL ||
this.monitoringUrl ||
this.canStopEnvironment ||
this.canRetry
);
},
2018-12-13 13:39:08 +05:30
folderIconName() {
return this.model.isOpen ? 'chevron-down' : 'chevron-right';
},
2018-11-18 11:00:15 +05:30
},
methods: {
onClickFolder() {
eventHub.$emit('toggleFolder', this.model);
},
},
};
2017-08-17 22:00:37 +05:30
</script>
<template>
2017-09-10 17:25:29 +05:30
<div
2018-03-17 18:26:18 +05:30
:class="{
'js-child-row environment-child-row': model.isChildren,
2020-03-09 13:42:32 +05:30
'folder-row': isFolder,
2018-03-17 18:26:18 +05:30
}"
2018-11-08 19:23:39 +05:30
class="gl-responsive-table-row"
2019-02-15 15:39:39 +05:30
role="row"
>
2020-01-01 13:55:28 +05:30
<div
class="table-section section-wrap text-truncate"
:class="tableData.name.spacing"
role="gridcell"
>
2020-03-09 13:42:32 +05:30
<div v-if="!isFolder" class="table-mobile-header" role="rowheader">
2020-01-01 13:55:28 +05:30
{{ tableData.name.title }}
2017-09-10 17:25:29 +05:30
</div>
2019-07-07 11:18:12 +05:30
<span v-if="shouldRenderDeployBoard" class="deploy-board-icon" @click="toggleDeployBoard">
<icon :name="deployIconName" />
</span>
<span
2020-03-09 13:42:32 +05:30
v-if="!isFolder"
2019-07-07 11:18:12 +05:30
v-gl-tooltip
:title="model.name"
class="environment-name table-mobile-content"
>
<a class="qa-environment-link" :href="environmentPath">
<span v-if="model.size === 1">{{ model.name }}</span>
<span v-else>{{ model.name_without_type }}</span>
</a>
<span v-if="isProtected" class="badge badge-success">
{{ s__('Environments|protected') }}
</span>
2018-11-18 11:00:15 +05:30
</span>
2019-07-07 11:18:12 +05:30
<span
v-else
v-gl-tooltip
:title="model.folderName"
class="folder-name"
role="button"
@click="onClickFolder"
>
2019-02-15 15:39:39 +05:30
<icon :name="folderIconName" class="folder-icon" />
2017-08-17 22:00:37 +05:30
2019-02-15 15:39:39 +05:30
<icon name="folder" class="folder-icon" />
2017-08-17 22:00:37 +05:30
2019-02-15 15:39:39 +05:30
<span> {{ model.folderName }} </span>
2017-08-17 22:00:37 +05:30
2019-02-15 15:39:39 +05:30
<span class="badge badge-pill"> {{ model.size }} </span>
2017-08-17 22:00:37 +05:30
</span>
2017-09-10 17:25:29 +05:30
</div>
2017-08-17 22:00:37 +05:30
2018-03-17 18:26:18 +05:30
<div
2020-01-01 13:55:28 +05:30
class="table-section deployment-column d-none d-sm-none d-md-block"
:class="tableData.deploy.spacing"
2018-03-17 18:26:18 +05:30
role="gridcell"
>
2019-07-31 22:56:46 +05:30
<span v-if="shouldRenderDeploymentID" class="text-break-word">
{{ deploymentInternalId }}
</span>
2017-08-17 22:00:37 +05:30
2020-03-09 13:42:32 +05:30
<span v-if="!isFolder && deploymentHasUser" class="text-break-word">
2017-08-17 22:00:37 +05:30
by
2017-09-10 17:25:29 +05:30
<user-avatar-link
:link-href="deploymentUser.web_url"
:img-src="deploymentUser.avatar_url"
:img-alt="userImageAltDescription"
:tooltip-text="deploymentUser.username"
2019-07-31 22:56:46 +05:30
class="js-deploy-user-container float-none"
2017-09-10 17:25:29 +05:30
/>
2017-08-17 22:00:37 +05:30
</span>
2020-03-09 13:42:32 +05:30
<div v-if="showNoDeployments" class="commit-title table-mobile-content">
{{ s__('Environments|No deployments yet') }}
</div>
2017-09-10 17:25:29 +05:30
</div>
2017-08-17 22:00:37 +05:30
2020-01-01 13:55:28 +05:30
<div
class="table-section d-none d-sm-none d-md-block"
:class="tableData.build.spacing"
role="gridcell"
>
<a v-if="shouldRenderBuildName" :href="buildPath" class="build-link cgray">
<tooltip-on-truncate
:title="buildName"
truncate-target="child"
class="flex-truncate-parent"
>
<span class="flex-truncate-child">
{{ buildName }}
</span>
</tooltip-on-truncate>
2017-08-17 22:00:37 +05:30
</a>
2017-09-10 17:25:29 +05:30
</div>
2017-08-17 22:00:37 +05:30
2020-03-09 13:42:32 +05:30
<div v-if="!isFolder" class="table-section" :class="tableData.commit.spacing" role="gridcell">
2020-01-01 13:55:28 +05:30
<div role="rowheader" class="table-mobile-header">{{ tableData.commit.title }}</div>
2019-02-15 15:39:39 +05:30
<div v-if="hasLastDeploymentKey" class="js-commit-component table-mobile-content">
2017-08-17 22:00:37 +05:30
<commit-component
:tag="commitTag"
:commit-ref="commitRef"
:commit-url="commitUrl"
:short-sha="commitShortSha"
:title="commitTitle"
2019-02-15 15:39:39 +05:30
:author="commitAuthor"
/>
2017-08-17 22:00:37 +05:30
</div>
2020-03-09 13:42:32 +05:30
</div>
<div v-if="!isFolder" class="table-section" :class="tableData.date.spacing" role="gridcell">
<div role="rowheader" class="table-mobile-header">{{ tableData.date.title }}</div>
<span
v-if="canShowDeploymentDate"
v-gl-tooltip
:title="deployedDate.tooltip"
class="environment-created-date-timeago table-mobile-content flex-truncate-parent"
>
<span class="flex-truncate-child">
{{ deployedDate.formatted }}
</span>
</span>
2017-09-10 17:25:29 +05:30
</div>
2017-08-17 22:00:37 +05:30
2020-01-01 13:55:28 +05:30
<div
2020-03-09 13:42:32 +05:30
v-if="!isFolder && shouldShowAutoStopDate"
2020-01-01 13:55:28 +05:30
class="table-section"
2020-03-09 13:42:32 +05:30
:class="tableData.autoStop.spacing"
2020-01-01 13:55:28 +05:30
role="gridcell"
>
2020-03-09 13:42:32 +05:30
<div role="rowheader" class="table-mobile-header">{{ tableData.autoStop.title }}</div>
<span
v-if="canShowAutoStopDate"
v-gl-tooltip
:title="autoStopDate.tooltip"
class="table-mobile-content flex-truncate-parent"
>
<span class="flex-truncate-child js-auto-stop">{{ autoStopDate.formatted }}</span>
2017-08-17 22:00:37 +05:30
</span>
2017-09-10 17:25:29 +05:30
</div>
<div
2020-03-09 13:42:32 +05:30
v-if="!isFolder && displayEnvironmentActions"
2020-01-01 13:55:28 +05:30
class="table-section table-button-footer"
:class="tableData.actions.spacing"
2019-02-15 15:39:39 +05:30
role="gridcell"
>
<div class="btn-group table-action-buttons" role="group">
2020-03-09 13:42:32 +05:30
<pin-component
v-if="canShowAutoStopDate && shouldShowAutoStopDate"
:auto-stop-url="autoStopUrl"
/>
2017-08-17 22:00:37 +05:30
<external-url-component
v-if="externalURL && canReadEnvironment"
:external-url="externalURL"
2018-03-17 18:26:18 +05:30
/>
2017-08-17 22:00:37 +05:30
<monitoring-button-component
v-if="monitoringUrl && canReadEnvironment"
:monitoring-url="monitoringUrl"
2018-03-17 18:26:18 +05:30
/>
2017-08-17 22:00:37 +05:30
2019-02-15 15:39:39 +05:30
<actions-component v-if="actions.length > 0" :actions="actions" />
2018-11-18 11:00:15 +05:30
2017-08-17 22:00:37 +05:30
<terminal-button-component
v-if="model && model.terminal_path"
:terminal-path="model.terminal_path"
2018-03-17 18:26:18 +05:30
/>
2017-08-17 22:00:37 +05:30
<rollback-component
2019-03-02 22:35:43 +05:30
v-if="canRetry"
2019-07-07 11:18:12 +05:30
:environment="model"
2017-08-17 22:00:37 +05:30
:is-last-deployment="isLastDeployment"
:retry-url="retryUrl"
2018-03-17 18:26:18 +05:30
/>
2018-11-18 11:00:15 +05:30
2019-02-15 15:39:39 +05:30
<stop-component v-if="canStopEnvironment" :environment="model" />
2017-08-17 22:00:37 +05:30
</div>
2017-09-10 17:25:29 +05:30
</div>
</div>
2017-08-17 22:00:37 +05:30
</template>