diff options
Diffstat (limited to 'app/assets/javascripts/environments/components/deploy_board.vue')
-rw-r--r-- | app/assets/javascripts/environments/components/deploy_board.vue | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/app/assets/javascripts/environments/components/deploy_board.vue b/app/assets/javascripts/environments/components/deploy_board.vue new file mode 100644 index 00000000000..07cb968d8d3 --- /dev/null +++ b/app/assets/javascripts/environments/components/deploy_board.vue @@ -0,0 +1,216 @@ +<script> +/* eslint-disable @gitlab/vue-require-i18n-strings */ +/** + * Renders a deploy board. + * + * A deploy board is composed by: + * - Information area with percentage of completion. + * - Instances with status. + * - Button Actions. + * [Mockup](https://gitlab.com/gitlab-org/gitlab-foss/uploads/2f655655c0eadf655d0ae7467b53002a/environments__deploy-graphic.png) + */ +import { isEmpty } from 'lodash'; +import { + GlIcon, + GlLoadingIcon, + GlLink, + GlTooltip, + GlTooltipDirective, + GlSafeHtmlDirective as SafeHtml, +} from '@gitlab/ui'; +import deployBoardSvg from '@gitlab/svgs/dist/illustrations/deploy-boards.svg'; +import instanceComponent from '~/vue_shared/components/deployment_instance.vue'; +import { n__ } from '~/locale'; +import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; +import { STATUS_MAP, CANARY_STATUS } from '../constants'; +import CanaryIngress from './canary_ingress.vue'; + +export default { + components: { + instanceComponent, + CanaryIngress, + GlIcon, + GlLoadingIcon, + GlLink, + GlTooltip, + }, + directives: { + GlTooltip: GlTooltipDirective, + SafeHtml, + }, + mixins: [glFeatureFlagsMixin()], + props: { + deployBoardData: { + type: Object, + required: true, + }, + deployBoardsHelpPath: { + type: String, + required: false, + default: '', + }, + isLoading: { + type: Boolean, + required: true, + }, + isEmpty: { + type: Boolean, + required: true, + }, + logsPath: { + type: String, + required: false, + default: '', + }, + }, + computed: { + canRenderDeployBoard() { + return !this.isEmpty && !isEmpty(this.deployBoardData); + }, + canRenderEmptyState() { + return this.isEmpty; + }, + canRenderCanaryWeight() { + return ( + this.glFeatures.canaryIngressWeightControl && !isEmpty(this.deployBoardData.canary_ingress) + ); + }, + instanceCount() { + const { instances } = this.deployBoardData; + + return Array.isArray(instances) ? instances.length : 0; + }, + instanceIsCompletedCount() { + const completionPercentage = this.deployBoardData.completion / 100; + const completionCount = Math.floor(completionPercentage * this.instanceCount); + + return Number.isNaN(completionCount) ? 0 : completionCount; + }, + instanceIsCompletedText() { + const title = n__('instance completed', 'instances completed', this.instanceIsCompletedCount); + + return `${this.instanceIsCompletedCount} ${title}`; + }, + instanceTitle() { + return n__('Instance', 'Instances', this.instanceCount); + }, + deployBoardSvg() { + return deployBoardSvg; + }, + deployBoardActions() { + return this.deployBoardData.rollback_url || this.deployBoardData.abort_url; + }, + statuses() { + // Canary is not a pod status but it needs to be in the legend. + // Hence adding it here. + return { + ...STATUS_MAP, + CANARY_STATUS, + }; + }, + }, + methods: { + changeCanaryWeight(weight) { + this.$emit('changeCanaryWeight', weight); + }, + }, +}; +</script> +<template> + <div class="js-deploy-board deploy-board"> + <gl-loading-icon v-if="isLoading" class="loading-icon" /> + <template v-else> + <div v-if="canRenderDeployBoard" class="deploy-board-information gl-p-5"> + <div class="deploy-board-information gl-w-full"> + <section class="deploy-board-status"> + <span v-gl-tooltip :title="instanceIsCompletedText"> + <span ref="percentage" class="gl-text-center text-plain gl-font-lg" + >{{ deployBoardData.completion }}%</span + > + <span class="text text-center text-secondary">{{ __('Complete') }}</span> + </span> + </section> + + <section class="deploy-board-instances"> + <div class="gl-font-base text-secondary"> + <span class="deploy-board-instances-text" + >{{ instanceTitle }} ({{ instanceCount }})</span + > + <span ref="legend-icon" data-testid="legend-tooltip-target"> + <gl-icon class="gl-text-blue-500 gl-ml-2" name="question" /> + </span> + <gl-tooltip :target="() => $refs['legend-icon']" boundary="#content-body"> + <div class="deploy-board-legend gl-display-flex gl-flex-direction-column"> + <div + v-for="status in statuses" + :key="status.text" + class="gl-display-flex gl-align-items-center" + > + <instance-component :status="status.class" :stable="status.stable" /> + <span class="legend-text gl-ml-3">{{ status.text }}</span> + </div> + </div> + </gl-tooltip> + </div> + + <div class="deploy-board-instances-container d-flex flex-wrap flex-row"> + <template v-for="(instance, i) in deployBoardData.instances"> + <instance-component + :key="i" + :status="instance.status" + :tooltip-text="instance.tooltip" + :pod-name="instance.pod_name" + :logs-path="logsPath" + :stable="instance.stable" + /> + </template> + </div> + </section> + + <canary-ingress + v-if="canRenderCanaryWeight" + class="deploy-board-canary-ingress" + :canary-ingress="deployBoardData.canary_ingress" + @change="changeCanaryWeight" + /> + + <section v-if="deployBoardActions" class="deploy-board-actions"> + <gl-link + v-if="deployBoardData.rollback_url" + :href="deployBoardData.rollback_url" + class="btn" + data-method="post" + rel="nofollow" + >{{ __('Rollback') }}</gl-link + > + <gl-link + v-if="deployBoardData.abort_url" + :href="deployBoardData.abort_url" + class="btn btn-danger btn-inverted" + data-method="post" + rel="nofollow" + >{{ __('Abort') }}</gl-link + > + </section> + </div> + </div> + + <div v-if="canRenderEmptyState" class="deploy-board-empty"> + <section v-safe-html="deployBoardSvg" class="deploy-board-empty-state-svg"></section> + + <section class="deploy-board-empty-state-text"> + <span class="deploy-board-empty-state-title d-flex">{{ + __('Kubernetes deployment not found') + }}</span> + <span> + To see deployment progress for your environments, make sure you are deploying to + <code>$KUBE_NAMESPACE</code> and annotating with + <code>app.gitlab.com/app=$CI_PROJECT_PATH_SLUG</code> + and + <code>app.gitlab.com/env=$CI_ENVIRONMENT_SLUG</code>. + </span> + </section> + </div> + </template> + </div> +</template> |