2017-08-17 22:00:37 +05:30
|
|
|
<script>
|
2022-06-21 17:19:12 +05:30
|
|
|
import {
|
|
|
|
GlDropdown,
|
|
|
|
GlTooltipDirective,
|
|
|
|
GlIcon,
|
|
|
|
GlLink,
|
|
|
|
GlSprintf,
|
|
|
|
GlBadge,
|
|
|
|
GlAvatar,
|
|
|
|
GlAvatarLink,
|
|
|
|
} from '@gitlab/ui';
|
2021-03-11 19:13:27 +05:30
|
|
|
import { isEmpty } from 'lodash';
|
2020-03-13 15:44:24 +05:30
|
|
|
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
|
2021-03-11 19:13:27 +05:30
|
|
|
import { __, s__, sprintf } from '~/locale';
|
|
|
|
import CiIcon from '~/vue_shared/components/ci_icon.vue';
|
2020-03-13 15:44:24 +05:30
|
|
|
import CommitComponent from '~/vue_shared/components/commit.vue';
|
2022-01-26 12:08:38 +05:30
|
|
|
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
|
2021-03-11 19:13:27 +05:30
|
|
|
import timeagoMixin from '~/vue_shared/mixins/timeago';
|
2020-03-13 15:44:24 +05:30
|
|
|
import eventHub from '../event_hub';
|
2018-11-18 11:00:15 +05:30
|
|
|
import ActionsComponent from './environment_actions.vue';
|
2021-03-11 19:13:27 +05:30
|
|
|
import DeleteComponent from './environment_delete.vue';
|
2018-11-18 11:00:15 +05:30
|
|
|
import ExternalUrlComponent from './environment_external_url.vue';
|
2020-03-13 15:44:24 +05:30
|
|
|
import MonitoringButtonComponent from './environment_monitoring.vue';
|
|
|
|
import PinComponent from './environment_pin.vue';
|
2020-04-22 19:07:51 +05:30
|
|
|
import RollbackComponent from './environment_rollback.vue';
|
2021-03-11 19:13:27 +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-13 15:44:24 +05:30
|
|
|
CommitComponent,
|
2018-11-18 11:00:15 +05:30
|
|
|
ExternalUrlComponent,
|
2021-11-18 22:05:49 +05:30
|
|
|
GlDropdown,
|
2022-03-02 08:16:31 +05:30
|
|
|
GlBadge,
|
2020-11-24 15:15:51 +05:30
|
|
|
GlIcon,
|
2021-02-22 17:27:13 +05:30
|
|
|
GlLink,
|
2021-11-11 11:23:49 +05:30
|
|
|
GlSprintf,
|
2020-03-13 15:44:24 +05:30
|
|
|
MonitoringButtonComponent,
|
|
|
|
PinComponent,
|
2020-04-22 19:07:51 +05:30
|
|
|
DeleteComponent,
|
2018-11-18 11:00:15 +05:30
|
|
|
RollbackComponent,
|
2020-03-13 15:44:24 +05:30
|
|
|
StopComponent,
|
2018-11-18 11:00:15 +05:30
|
|
|
TerminalButtonComponent,
|
2020-01-01 13:55:28 +05:30
|
|
|
TooltipOnTruncate,
|
2022-06-21 17:19:12 +05:30
|
|
|
GlAvatar,
|
|
|
|
GlAvatarLink,
|
2021-02-22 17:27:13 +05:30
|
|
|
CiIcon,
|
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-05-24 23:13:21 +05:30
|
|
|
mixins: [timeagoMixin],
|
2018-11-18 11:00:15 +05:30
|
|
|
|
|
|
|
props: {
|
|
|
|
model: {
|
|
|
|
type: Object,
|
|
|
|
required: true,
|
2020-03-13 15:44:24 +05:30
|
|
|
},
|
|
|
|
|
2020-01-01 13:55:28 +05:30
|
|
|
tableData: {
|
|
|
|
type: Object,
|
|
|
|
required: true,
|
2018-11-18 11:00:15 +05:30
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
computed: {
|
2020-05-24 23:13:21 +05:30
|
|
|
deployIconName() {
|
|
|
|
return this.model.isDeployBoardVisible ? 'chevron-down' : 'chevron-right';
|
|
|
|
},
|
2018-11-18 11:00:15 +05:30
|
|
|
/**
|
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() {
|
2020-04-22 19:07:51 +05:30
|
|
|
if (this.model && this.model.last_deployment && !isEmpty(this.model.last_deployment)) {
|
2018-11-18 11:00:15 +05:30
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
|
2021-02-22 17:27:13 +05:30
|
|
|
/**
|
|
|
|
* @returns {Object|Undefined} The `upcoming_deployment` object if it exists.
|
|
|
|
* Otherwise, `undefined`.
|
|
|
|
*/
|
|
|
|
upcomingDeployment() {
|
|
|
|
return this.model?.upcoming_deployment;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @returns {String} Text that will be shown in the tooltip when
|
|
|
|
* the user hovers over the upcoming deployment's status icon.
|
|
|
|
*/
|
|
|
|
upcomingDeploymentTooltipText() {
|
|
|
|
return sprintf(s__('Environments|Deployment %{status}'), {
|
|
|
|
status: this.upcomingDeployment.deployable.status.text,
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2020-03-13 15:44:24 +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;
|
|
|
|
},
|
|
|
|
|
2020-04-22 19:07:51 +05:30
|
|
|
/**
|
|
|
|
* Returns whether the environment can be deleted.
|
|
|
|
*
|
|
|
|
* @returns {Boolean}
|
|
|
|
*/
|
|
|
|
canDeleteEnvironment() {
|
|
|
|
return Boolean(this.model && this.model.can_delete && this.model.delete_path);
|
|
|
|
},
|
|
|
|
|
2018-11-18 11:00:15 +05:30
|
|
|
/**
|
|
|
|
* 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-13 15:44:24 +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-13 15:44:24 +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-13 15:44:24 +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-13 15:44:24 +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-13 15:44:24 +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 || []);
|
2021-03-08 18:12:59 +05:30
|
|
|
return combinedActions.map((action) => ({
|
2018-12-13 13:39:08 +05:30
|
|
|
...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
|
|
|
},
|
|
|
|
|
2020-05-24 23:13:21 +05:30
|
|
|
shouldRenderDeployBoard() {
|
|
|
|
return this.model.hasDeployBoard;
|
|
|
|
},
|
|
|
|
|
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 '';
|
|
|
|
},
|
|
|
|
|
2021-02-22 17:27:13 +05:30
|
|
|
/**
|
|
|
|
* Same as `userImageAltDescription`, but for the
|
|
|
|
* upcoming deployment's user
|
|
|
|
*
|
|
|
|
* @returns {String}
|
|
|
|
*/
|
|
|
|
upcomingDeploymentUserImageAltDescription() {
|
|
|
|
return sprintf(__("%{username}'s avatar"), {
|
|
|
|
username: this.upcomingDeployment.user.username,
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2018-11-18 11:00:15 +05:30
|
|
|
/**
|
|
|
|
* 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
|
2020-04-22 19:07:51 +05:30
|
|
|
// eslint-disable-next-line @gitlab/require-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 '';
|
|
|
|
},
|
|
|
|
|
2021-02-22 17:27:13 +05:30
|
|
|
/**
|
|
|
|
* Same as `deploymentInternalId`, but for the upcoming deployment
|
|
|
|
*
|
|
|
|
* @returns {String}
|
|
|
|
*/
|
|
|
|
upcomingDeploymentInternalId() {
|
|
|
|
return `#${this.upcomingDeployment.iid}`;
|
|
|
|
},
|
|
|
|
|
2018-11-18 11:00:15 +05:30
|
|
|
/**
|
|
|
|
* Verifies if the user object is present under last_deployment object.
|
|
|
|
*
|
|
|
|
* @returns {Boolean}
|
|
|
|
*/
|
|
|
|
deploymentHasUser() {
|
|
|
|
return (
|
|
|
|
this.model &&
|
2020-04-22 19:07:51 +05:30
|
|
|
!isEmpty(this.model.last_deployment) &&
|
|
|
|
!isEmpty(this.model.last_deployment.user)
|
2018-11-18 11:00:15 +05:30
|
|
|
);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the user object nested with the last_deployment object.
|
|
|
|
* Used to render the template.
|
|
|
|
*
|
|
|
|
* @returns {Object}
|
|
|
|
*/
|
|
|
|
deploymentUser() {
|
|
|
|
if (
|
|
|
|
this.model &&
|
2020-04-22 19:07:51 +05:30
|
|
|
!isEmpty(this.model.last_deployment) &&
|
|
|
|
!isEmpty(this.model.last_deployment.user)
|
2018-11-18 11:00:15 +05:30
|
|
|
) {
|
|
|
|
return this.model.last_deployment.user;
|
|
|
|
}
|
|
|
|
return {};
|
|
|
|
},
|
|
|
|
|
2020-03-13 15:44:24 +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-13 15:44:24 +05:30
|
|
|
!this.isFolder &&
|
2020-04-22 19:07:51 +05:30
|
|
|
!isEmpty(this.model.last_deployment) &&
|
|
|
|
!isEmpty(this.model.last_deployment.deployable)
|
2018-11-18 11:00:15 +05:30
|
|
|
);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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-13 15:44:24 +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-13 15:44:24 +05:30
|
|
|
!this.isFolder &&
|
2020-04-22 19:07:51 +05:30
|
|
|
!isEmpty(this.model.last_deployment) &&
|
2018-11-18 11:00:15 +05:30
|
|
|
this.model.last_deployment.iid !== undefined
|
|
|
|
);
|
|
|
|
},
|
|
|
|
|
|
|
|
environmentPath() {
|
2020-03-13 15:44:24 +05:30
|
|
|
return this.model.environment_path || '';
|
2018-11-18 11:00:15 +05:30
|
|
|
},
|
|
|
|
|
|
|
|
monitoringUrl() {
|
2020-03-13 15:44:24 +05:30
|
|
|
return this.model.metrics_path || '';
|
|
|
|
},
|
2018-11-18 11:00:15 +05:30
|
|
|
|
2021-11-18 22:05:49 +05:30
|
|
|
terminalPath() {
|
|
|
|
return this.model?.terminal_path ?? '';
|
|
|
|
},
|
|
|
|
|
2020-03-13 15:44:24 +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 ||
|
2020-04-22 19:07:51 +05:30
|
|
|
this.canDeleteEnvironment ||
|
2018-11-18 11:00:15 +05:30
|
|
|
this.canRetry
|
|
|
|
);
|
|
|
|
},
|
2018-12-13 13:39:08 +05:30
|
|
|
|
|
|
|
folderIconName() {
|
|
|
|
return this.model.isOpen ? 'chevron-down' : 'chevron-right';
|
|
|
|
},
|
2021-02-22 17:27:13 +05:30
|
|
|
|
|
|
|
upcomingDeploymentCellClasses() {
|
|
|
|
return [
|
|
|
|
this.tableData.upcoming.spacing,
|
2021-03-11 19:13:27 +05:30
|
|
|
{ 'gl-display-none gl-md-display-block': !this.upcomingDeployment },
|
2021-02-22 17:27:13 +05:30
|
|
|
];
|
|
|
|
},
|
2021-09-30 23:02:18 +05:30
|
|
|
tableNameSpacingClass() {
|
|
|
|
return this.isFolder ? 'section-100' : this.tableData.name.spacing;
|
|
|
|
},
|
2021-11-18 22:05:49 +05:30
|
|
|
hasExtraActions() {
|
|
|
|
return Boolean(
|
|
|
|
this.canRetry ||
|
|
|
|
this.canShowAutoStopDate ||
|
|
|
|
this.monitoringUrl ||
|
|
|
|
this.terminalPath ||
|
|
|
|
this.canDeleteEnvironment,
|
|
|
|
);
|
|
|
|
},
|
2018-11-18 11:00:15 +05:30
|
|
|
},
|
|
|
|
|
|
|
|
methods: {
|
2020-05-24 23:13:21 +05:30
|
|
|
toggleDeployBoard() {
|
|
|
|
eventHub.$emit('toggleDeployBoard', this.model);
|
|
|
|
},
|
2018-11-18 11:00:15 +05:30
|
|
|
onClickFolder() {
|
|
|
|
eventHub.$emit('toggleFolder', this.model);
|
|
|
|
},
|
2021-02-22 17:27:13 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the field title that will be shown in the field's row
|
|
|
|
* in the mobile view.
|
|
|
|
*
|
|
|
|
* @returns `field.mobileTitle` if present;
|
|
|
|
* if not, falls back to `field.title`.
|
|
|
|
*/
|
|
|
|
getMobileViewTitleForField(fieldName) {
|
|
|
|
const field = this.tableData[fieldName];
|
|
|
|
|
|
|
|
return field.mobileTitle || field.title;
|
|
|
|
},
|
2018-11-18 11:00:15 +05:30
|
|
|
},
|
|
|
|
};
|
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-13 15:44:24 +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"
|
2021-09-30 23:02:18 +05:30
|
|
|
:class="tableNameSpacingClass"
|
2020-01-01 13:55:28 +05:30
|
|
|
role="gridcell"
|
2021-09-30 23:02:18 +05:30
|
|
|
data-testid="environment-name-cell"
|
2020-01-01 13:55:28 +05:30
|
|
|
>
|
2020-03-13 15:44:24 +05:30
|
|
|
<div v-if="!isFolder" class="table-mobile-header" role="rowheader">
|
2021-02-22 17:27:13 +05:30
|
|
|
{{ getMobileViewTitleForField('name') }}
|
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">
|
2020-11-24 15:15:51 +05:30
|
|
|
<gl-icon :name="deployIconName" />
|
2019-07-07 11:18:12 +05:30
|
|
|
</span>
|
|
|
|
|
|
|
|
<span
|
2020-03-13 15:44:24 +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>
|
2022-03-02 08:16:31 +05:30
|
|
|
<gl-badge v-if="isProtected" variant="success">{{
|
|
|
|
s__('Environments|protected')
|
|
|
|
}}</gl-badge>
|
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"
|
|
|
|
>
|
2020-11-24 15:15:51 +05:30
|
|
|
<gl-icon :name="folderIconName" class="folder-icon" />
|
2017-08-17 22:00:37 +05:30
|
|
|
|
2020-11-24 15:15:51 +05:30
|
|
|
<gl-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
|
|
|
|
2022-03-02 08:16:31 +05:30
|
|
|
<gl-badge>{{ model.size }}</gl-badge>
|
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
|
2021-09-30 23:02:18 +05:30
|
|
|
v-if="!isFolder"
|
2021-01-03 14:25:43 +05:30
|
|
|
class="table-section deployment-column d-none d-md-block"
|
2020-01-01 13:55:28 +05:30
|
|
|
:class="tableData.deploy.spacing"
|
2018-03-17 18:26:18 +05:30
|
|
|
role="gridcell"
|
2022-06-21 17:19:12 +05:30
|
|
|
data-testid="environment-deployment-id-cell"
|
2018-03-17 18:26:18 +05:30
|
|
|
>
|
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
|
|
|
|
2022-06-21 17:19:12 +05:30
|
|
|
<span
|
|
|
|
v-if="!isFolder && deploymentHasUser"
|
|
|
|
class="text-break-word gl-display-inline-flex gl-align-items-center"
|
|
|
|
>
|
2021-11-11 11:23:49 +05:30
|
|
|
<gl-sprintf :message="s__('Environments|by %{avatar}')">
|
|
|
|
<template #avatar>
|
2022-06-21 17:19:12 +05:30
|
|
|
<gl-avatar-link :href="deploymentUser.web_url" class="gl-ml-2">
|
|
|
|
<gl-avatar
|
|
|
|
:src="deploymentUser.avatar_url"
|
|
|
|
:entity-name="deploymentUser.username"
|
|
|
|
:title="deploymentUser.username"
|
|
|
|
:alt="userImageAltDescription"
|
|
|
|
:size="24"
|
|
|
|
/>
|
|
|
|
</gl-avatar-link>
|
2021-11-11 11:23:49 +05:30
|
|
|
</template>
|
|
|
|
</gl-sprintf>
|
2017-08-17 22:00:37 +05:30
|
|
|
</span>
|
2020-03-13 15:44:24 +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
|
|
|
|
2021-09-30 23:02:18 +05:30
|
|
|
<div
|
|
|
|
v-if="!isFolder"
|
|
|
|
class="table-section d-none d-md-block"
|
|
|
|
:class="tableData.build.spacing"
|
|
|
|
role="gridcell"
|
|
|
|
data-testid="environment-build-cell"
|
|
|
|
>
|
2020-01-01 13:55:28 +05:30
|
|
|
<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-13 15:44:24 +05:30
|
|
|
<div v-if="!isFolder" class="table-section" :class="tableData.commit.spacing" role="gridcell">
|
2021-02-22 17:27:13 +05:30
|
|
|
<div role="rowheader" class="table-mobile-header">
|
|
|
|
{{ getMobileViewTitleForField('commit') }}
|
|
|
|
</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-13 15:44:24 +05:30
|
|
|
</div>
|
|
|
|
|
|
|
|
<div v-if="!isFolder" class="table-section" :class="tableData.date.spacing" role="gridcell">
|
2021-02-22 17:27:13 +05:30
|
|
|
<div role="rowheader" class="table-mobile-header">
|
|
|
|
{{ getMobileViewTitleForField('date') }}
|
|
|
|
</div>
|
2020-03-13 15:44:24 +05:30
|
|
|
<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
|
|
|
|
2021-02-22 17:27:13 +05:30
|
|
|
<div
|
|
|
|
v-if="!isFolder"
|
|
|
|
class="table-section"
|
|
|
|
:class="upcomingDeploymentCellClasses"
|
|
|
|
role="gridcell"
|
|
|
|
data-testid="upcoming-deployment"
|
|
|
|
>
|
|
|
|
<div role="rowheader" class="table-mobile-header">
|
|
|
|
{{ getMobileViewTitleForField('upcoming') }}
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
v-if="upcomingDeployment"
|
|
|
|
class="gl-w-full gl-display-flex gl-flex-direction-row gl-md-flex-direction-column! gl-justify-content-end"
|
|
|
|
data-testid="upcoming-deployment-content"
|
|
|
|
>
|
|
|
|
<div class="gl-display-flex gl-align-items-center">
|
|
|
|
<span class="gl-mr-2">{{ upcomingDeploymentInternalId }}</span>
|
|
|
|
<gl-link
|
|
|
|
v-if="upcomingDeployment.deployable"
|
|
|
|
v-gl-tooltip
|
|
|
|
:href="upcomingDeployment.deployable.build_path"
|
|
|
|
:title="upcomingDeploymentTooltipText"
|
|
|
|
data-testid="upcoming-deployment-status-link"
|
|
|
|
>
|
|
|
|
<ci-icon class="gl-mr-2" :status="upcomingDeployment.deployable.status" />
|
|
|
|
</gl-link>
|
|
|
|
</div>
|
2022-06-21 17:19:12 +05:30
|
|
|
<span
|
|
|
|
v-if="upcomingDeployment.user"
|
|
|
|
class="text-break-word gl-display-inline-flex gl-align-items-center gl-mt-2"
|
|
|
|
>
|
|
|
|
<gl-sprintf :message="s__('Environments|by %{avatar}')">
|
|
|
|
<template #avatar>
|
|
|
|
<gl-avatar-link :href="upcomingDeployment.user.web_url" class="gl-ml-2">
|
|
|
|
<gl-avatar
|
|
|
|
:src="upcomingDeployment.user.avatar_url"
|
|
|
|
:alt="upcomingDeploymentUserImageAltDescription"
|
|
|
|
:entity-name="upcomingDeployment.user.username"
|
|
|
|
:title="upcomingDeployment.user.username"
|
|
|
|
:size="24"
|
2021-11-11 11:23:49 +05:30
|
|
|
/>
|
2022-06-21 17:19:12 +05:30
|
|
|
</gl-avatar-link>
|
|
|
|
</template>
|
|
|
|
</gl-sprintf>
|
|
|
|
</span>
|
2021-02-22 17:27:13 +05:30
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
2020-04-22 19:07:51 +05:30
|
|
|
<div v-if="!isFolder" class="table-section" :class="tableData.autoStop.spacing" role="gridcell">
|
2021-02-22 17:27:13 +05:30
|
|
|
<div role="rowheader" class="table-mobile-header">
|
|
|
|
{{ getMobileViewTitleForField('autoStop') }}
|
|
|
|
</div>
|
2020-03-13 15:44:24 +05:30
|
|
|
<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-13 15:44:24 +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">
|
2017-08-17 22:00:37 +05:30
|
|
|
<external-url-component
|
2021-11-11 11:23:49 +05:30
|
|
|
v-if="externalURL"
|
2017-08-17 22:00:37 +05:30
|
|
|
:external-url="externalURL"
|
2021-10-27 15:23:28 +05:30
|
|
|
data-track-action="click_button"
|
|
|
|
data-track-label="environment_url"
|
2018-03-17 18:26:18 +05:30
|
|
|
/>
|
2017-08-17 22:00:37 +05:30
|
|
|
|
2021-10-27 15:23:28 +05:30
|
|
|
<actions-component
|
|
|
|
v-if="actions.length > 0"
|
|
|
|
:actions="actions"
|
|
|
|
data-track-action="click_dropdown"
|
|
|
|
data-track-label="environment_actions"
|
|
|
|
/>
|
2018-11-18 11:00:15 +05:30
|
|
|
|
2021-10-27 15:23:28 +05:30
|
|
|
<stop-component
|
|
|
|
v-if="canStopEnvironment"
|
|
|
|
:environment="model"
|
2021-11-18 22:05:49 +05:30
|
|
|
class="gl-z-index-2"
|
2021-10-27 15:23:28 +05:30
|
|
|
data-track-action="click_button"
|
|
|
|
data-track-label="environment_stop"
|
|
|
|
/>
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2021-11-18 22:05:49 +05:30
|
|
|
<gl-dropdown
|
|
|
|
v-if="hasExtraActions"
|
|
|
|
icon="ellipsis_v"
|
|
|
|
text-sr-only
|
|
|
|
:text="__('More actions')"
|
|
|
|
category="secondary"
|
|
|
|
no-caret
|
|
|
|
>
|
|
|
|
<rollback-component
|
|
|
|
v-if="canRetry"
|
|
|
|
:environment="model"
|
|
|
|
:is-last-deployment="isLastDeployment"
|
|
|
|
:retry-url="retryUrl"
|
|
|
|
data-track-action="click_button"
|
|
|
|
data-track-label="environment_rollback"
|
|
|
|
/>
|
|
|
|
|
|
|
|
<pin-component
|
|
|
|
v-if="canShowAutoStopDate"
|
|
|
|
:auto-stop-url="autoStopUrl"
|
|
|
|
data-track-action="click_button"
|
|
|
|
data-track-label="environment_pin"
|
|
|
|
/>
|
|
|
|
|
|
|
|
<monitoring-button-component
|
|
|
|
v-if="monitoringUrl"
|
|
|
|
:monitoring-url="monitoringUrl"
|
|
|
|
data-track-action="click_button"
|
|
|
|
data-track-label="environment_monitoring"
|
|
|
|
/>
|
|
|
|
|
|
|
|
<terminal-button-component
|
|
|
|
v-if="terminalPath"
|
|
|
|
:terminal-path="terminalPath"
|
|
|
|
data-track-action="click_button"
|
|
|
|
data-track-label="environment_terminal"
|
|
|
|
/>
|
|
|
|
|
|
|
|
<delete-component
|
|
|
|
v-if="canDeleteEnvironment"
|
|
|
|
:environment="model"
|
|
|
|
data-track-action="click_button"
|
|
|
|
data-track-label="environment_delete"
|
|
|
|
/>
|
|
|
|
</gl-dropdown>
|
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>
|