summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/environments
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-01-03 09:07:33 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-01-03 09:07:33 +0000
commitc0d8f9f3f962df6bfcc70440432da55d67307189 (patch)
tree457666705fbbd4f517d201680113406163829fcc /app/assets/javascripts/environments
parent2cfa1fc75dd4bd6d1f70d5fee1a824410694f297 (diff)
downloadgitlab-ce-c0d8f9f3f962df6bfcc70440432da55d67307189.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/environments')
-rw-r--r--app/assets/javascripts/environments/components/environment_item.vue190
-rw-r--r--app/assets/javascripts/environments/components/environment_pin.vue37
-rw-r--r--app/assets/javascripts/environments/components/environments_table.vue21
-rw-r--r--app/assets/javascripts/environments/mixins/environments_mixin.js20
4 files changed, 206 insertions, 62 deletions
diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue
index 428dfe5fcf7..3096ccad0aa 100644
--- a/app/assets/javascripts/environments/components/environment_item.vue
+++ b/app/assets/javascripts/environments/components/environment_item.vue
@@ -1,22 +1,23 @@
<script>
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
-import { format } from 'timeago.js';
import _ from 'underscore';
import { GlTooltipDirective } from '@gitlab/ui';
-import environmentItemMixin from 'ee_else_ce/environments/mixins/environment_item_mixin';
+import { __, sprintf } from '~/locale';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import timeagoMixin from '~/vue_shared/mixins/timeago';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
+import CommitComponent from '~/vue_shared/components/commit.vue';
import Icon from '~/vue_shared/components/icon.vue';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
-import { __, sprintf } from '~/locale';
+import environmentItemMixin from 'ee_else_ce/environments/mixins/environment_item_mixin';
+import eventHub from '../event_hub';
import ActionsComponent from './environment_actions.vue';
import ExternalUrlComponent from './environment_external_url.vue';
-import StopComponent from './environment_stop.vue';
+import MonitoringButtonComponent from './environment_monitoring.vue';
+import PinComponent from './environment_pin.vue';
import RollbackComponent from './environment_rollback.vue';
+import StopComponent from './environment_stop.vue';
import TerminalButtonComponent from './environment_terminal_button.vue';
-import MonitoringButtonComponent from './environment_monitoring.vue';
-import CommitComponent from '../../vue_shared/components/commit.vue';
-import eventHub from '../event_hub';
-import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
/**
* Environment Item Component
@@ -26,21 +27,22 @@ import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
export default {
components: {
- CommitComponent,
- Icon,
ActionsComponent,
+ CommitComponent,
ExternalUrlComponent,
- StopComponent,
+ Icon,
+ MonitoringButtonComponent,
+ PinComponent,
RollbackComponent,
+ StopComponent,
TerminalButtonComponent,
- MonitoringButtonComponent,
TooltipOnTruncate,
UserAvatarLink,
},
directives: {
GlTooltip: GlTooltipDirective,
},
- mixins: [environmentItemMixin],
+ mixins: [environmentItemMixin, timeagoMixin],
props: {
canReadEnvironment: {
@@ -52,7 +54,12 @@ export default {
model: {
type: Object,
required: true,
- default: () => ({}),
+ },
+
+ shouldShowAutoStopDate: {
+ type: Boolean,
+ required: false,
+ default: false,
},
tableData: {
@@ -77,6 +84,16 @@ export default {
},
/**
+ * Checkes whether the row displayed is a folder.
+ *
+ * @returns {Boolean}
+ */
+
+ isFolder() {
+ return this.model.isFolder;
+ },
+
+ /**
* Checkes whether the environment is protected.
* (`is_protected` currently only set in EE)
*
@@ -112,24 +129,64 @@ export default {
},
/**
- * Verifies if the date to be shown is present.
+ * 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.
*
* @returns {Boolean|Undefined}
*/
- canShowDate() {
+ canShowDeploymentDate() {
return this.model && this.model.last_deployment && this.model.last_deployment.deployed_at;
},
/**
- * Human readable date.
+ * Human readable deployment date.
*
* @returns {String}
*/
deployedDate() {
- if (this.canShowDate) {
- return format(this.model.last_deployment.deployed_at);
+ if (this.canShowDeploymentDate) {
+ return {
+ formatted: this.timeFormatted(this.model.last_deployment.deployed_at),
+ tooltip: this.tooltipTitle(this.model.last_deployment.deployed_at),
+ };
}
- return '';
+ return {
+ formatted: '',
+ tooltip: '',
+ };
},
actions() {
@@ -345,6 +402,15 @@ export default {
},
/**
+ * Checkes whether to display no deployment text.
+ *
+ * @returns {Boolean}
+ */
+ showNoDeployments() {
+ return !this.hasLastDeploymentKey && !this.isFolder;
+ },
+
+ /**
* 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.
@@ -353,7 +419,7 @@ export default {
*/
shouldRenderBuildName() {
return (
- !this.model.isFolder &&
+ !this.isFolder &&
!_.isEmpty(this.model.last_deployment) &&
!_.isEmpty(this.model.last_deployment.deployable)
);
@@ -383,11 +449,7 @@ export default {
* @return {String}
*/
externalURL() {
- if (this.model && this.model.external_url) {
- return this.model.external_url;
- }
-
- return '';
+ return this.model.external_url || '';
},
/**
@@ -399,26 +461,22 @@ export default {
*/
shouldRenderDeploymentID() {
return (
- !this.model.isFolder &&
+ !this.isFolder &&
!_.isEmpty(this.model.last_deployment) &&
this.model.last_deployment.iid !== undefined
);
},
environmentPath() {
- if (this.model && this.model.environment_path) {
- return this.model.environment_path;
- }
-
- return '';
+ return this.model.environment_path || '';
},
monitoringUrl() {
- if (this.model && this.model.metrics_path) {
- return this.model.metrics_path;
- }
+ return this.model.metrics_path || '';
+ },
- return '';
+ autoStopUrl() {
+ return this.model.cancel_auto_stop_path || '';
},
displayEnvironmentActions() {
@@ -447,7 +505,7 @@ export default {
<div
:class="{
'js-child-row environment-child-row': model.isChildren,
- 'folder-row': model.isFolder,
+ 'folder-row': isFolder,
}"
class="gl-responsive-table-row"
role="row"
@@ -457,7 +515,7 @@ export default {
:class="tableData.name.spacing"
role="gridcell"
>
- <div v-if="!model.isFolder" class="table-mobile-header" role="rowheader">
+ <div v-if="!isFolder" class="table-mobile-header" role="rowheader">
{{ tableData.name.title }}
</div>
@@ -466,7 +524,7 @@ export default {
</span>
<span
- v-if="!model.isFolder"
+ v-if="!isFolder"
v-gl-tooltip
:title="model.name"
class="environment-name table-mobile-content"
@@ -506,7 +564,7 @@ export default {
{{ deploymentInternalId }}
</span>
- <span v-if="!model.isFolder && deploymentHasUser" class="text-break-word">
+ <span v-if="!isFolder && deploymentHasUser" class="text-break-word">
by
<user-avatar-link
:link-href="deploymentUser.web_url"
@@ -516,6 +574,10 @@ export default {
class="js-deploy-user-container float-none"
/>
</span>
+
+ <div v-if="showNoDeployments" class="commit-title table-mobile-content">
+ {{ s__('Environments|No deployments yet') }}
+ </div>
</div>
<div
@@ -536,14 +598,8 @@ export default {
</a>
</div>
- <div
- v-if="!model.isFolder"
- class="table-section"
- :class="tableData.commit.spacing"
- role="gridcell"
- >
+ <div v-if="!isFolder" class="table-section" :class="tableData.commit.spacing" role="gridcell">
<div role="rowheader" class="table-mobile-header">{{ tableData.commit.title }}</div>
-
<div v-if="hasLastDeploymentKey" class="js-commit-component table-mobile-content">
<commit-component
:tag="commitTag"
@@ -554,31 +610,51 @@ export default {
:author="commitAuthor"
/>
</div>
- <div v-if="!hasLastDeploymentKey" class="commit-title table-mobile-content">
- {{ s__('Environments|No deployments yet') }}
- </div>
+ </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>
</div>
<div
- v-if="!model.isFolder"
+ v-if="!isFolder && shouldShowAutoStopDate"
class="table-section"
- :class="tableData.date.spacing"
+ :class="tableData.autoStop.spacing"
role="gridcell"
>
- <div role="rowheader" class="table-mobile-header">{{ tableData.date.title }}</div>
-
- <span v-if="canShowDate" class="environment-created-date-timeago table-mobile-content">
- {{ deployedDate }}
+ <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>
</span>
</div>
<div
- v-if="!model.isFolder && displayEnvironmentActions"
+ v-if="!isFolder && displayEnvironmentActions"
class="table-section table-button-footer"
:class="tableData.actions.spacing"
role="gridcell"
>
<div class="btn-group table-action-buttons" role="group">
+ <pin-component
+ v-if="canShowAutoStopDate && shouldShowAutoStopDate"
+ :auto-stop-url="autoStopUrl"
+ />
+
<external-url-component
v-if="externalURL && canReadEnvironment"
:external-url="externalURL"
diff --git a/app/assets/javascripts/environments/components/environment_pin.vue b/app/assets/javascripts/environments/components/environment_pin.vue
new file mode 100644
index 00000000000..7908928a7ac
--- /dev/null
+++ b/app/assets/javascripts/environments/components/environment_pin.vue
@@ -0,0 +1,37 @@
+<script>
+/**
+ * Renders a prevent auto-stop button.
+ * Used in environments table.
+ */
+import { GlButton, GlTooltipDirective } from '@gitlab/ui';
+import Icon from '~/vue_shared/components/icon.vue';
+import { __ } from '~/locale';
+import eventHub from '../event_hub';
+
+export default {
+ components: {
+ Icon,
+ GlButton,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ autoStopUrl: {
+ type: String,
+ required: true,
+ },
+ },
+ methods: {
+ onPinClick() {
+ eventHub.$emit('cancelAutoStop', this.autoStopUrl);
+ },
+ },
+ title: __('Prevent environment from auto-stopping'),
+};
+</script>
+<template>
+ <gl-button v-gl-tooltip :title="$options.title" :aria-label="$options.title" @click="onPinClick">
+ <icon name="thumbtack" />
+ </gl-button>
+</template>
diff --git a/app/assets/javascripts/environments/components/environments_table.vue b/app/assets/javascripts/environments/components/environments_table.vue
index 453e7610e21..30299ccc7bc 100644
--- a/app/assets/javascripts/environments/components/environments_table.vue
+++ b/app/assets/javascripts/environments/components/environments_table.vue
@@ -6,6 +6,7 @@ import { GlLoadingIcon } from '@gitlab/ui';
import _ from 'underscore';
import environmentTableMixin from 'ee_else_ce/environments/mixins/environments_table_mixin';
import { s__ } from '~/locale';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import EnvironmentItem from './environment_item.vue';
export default {
@@ -16,7 +17,7 @@ export default {
CanaryDeploymentCallout: () =>
import('ee_component/environments/components/canary_deployment_callout.vue'),
},
- mixins: [environmentTableMixin],
+ mixins: [environmentTableMixin, glFeatureFlagsMixin()],
props: {
environments: {
type: Array,
@@ -42,6 +43,9 @@ export default {
: env,
);
},
+ shouldShowAutoStopDate() {
+ return this.glFeatures.autoStopEnvironments;
+ },
tableData() {
return {
// percent spacing for cols, should add up to 100
@@ -65,8 +69,12 @@ export default {
title: s__('Environments|Updated'),
spacing: 'section-10',
},
+ autoStop: {
+ title: s__('Environments|Auto stop in'),
+ spacing: 'section-5',
+ },
actions: {
- spacing: 'section-30',
+ spacing: this.shouldShowAutoStopDate ? 'section-25' : 'section-30',
},
};
},
@@ -123,6 +131,14 @@ export default {
<div class="table-section" :class="tableData.date.spacing" role="columnheader">
{{ tableData.date.title }}
</div>
+ <div
+ v-if="shouldShowAutoStopDate"
+ class="table-section"
+ :class="tableData.autoStop.spacing"
+ role="columnheader"
+ >
+ {{ tableData.autoStop.title }}
+ </div>
</div>
<template v-for="(model, i) in sortedEnvironments" :model="model">
<div
@@ -130,6 +146,7 @@ export default {
:key="`environment-item-${i}`"
:model="model"
:can-read-environment="canReadEnvironment"
+ :should-show-auto-stop-date="shouldShowAutoStopDate"
:table-data="tableData"
/>
diff --git a/app/assets/javascripts/environments/mixins/environments_mixin.js b/app/assets/javascripts/environments/mixins/environments_mixin.js
index 31347d95a25..34374e306a4 100644
--- a/app/assets/javascripts/environments/mixins/environments_mixin.js
+++ b/app/assets/javascripts/environments/mixins/environments_mixin.js
@@ -90,16 +90,19 @@ export default {
Flash(s__('Environments|An error occurred while fetching the environments.'));
},
- postAction({ endpoint, errorMessage }) {
+ postAction({
+ endpoint,
+ errorMessage = s__('Environments|An error occurred while making the request.'),
+ }) {
if (!this.isMakingRequest) {
this.isLoading = true;
this.service
.postAction(endpoint)
.then(() => this.fetchEnvironments())
- .catch(() => {
+ .catch(err => {
this.isLoading = false;
- Flash(errorMessage || s__('Environments|An error occurred while making the request.'));
+ Flash(_.isFunction(errorMessage) ? errorMessage(err.response.data) : errorMessage);
});
}
},
@@ -138,6 +141,13 @@ export default {
);
this.postAction({ endpoint: retryUrl, errorMessage });
},
+
+ cancelAutoStop(autoStopPath) {
+ const errorMessage = ({ message }) =>
+ message ||
+ s__('Environments|An error occurred while canceling the auto stop, please try again');
+ this.postAction({ endpoint: autoStopPath, errorMessage });
+ },
},
computed: {
@@ -199,6 +209,8 @@ export default {
eventHub.$on('requestRollbackEnvironment', this.updateRollbackModal);
eventHub.$on('rollbackEnvironment', this.rollbackEnvironment);
+
+ eventHub.$on('cancelAutoStop', this.cancelAutoStop);
},
beforeDestroy() {
@@ -208,5 +220,7 @@ export default {
eventHub.$off('requestRollbackEnvironment', this.updateRollbackModal);
eventHub.$off('rollbackEnvironment', this.rollbackEnvironment);
+
+ eventHub.$off('cancelAutoStop', this.cancelAutoStop);
},
};