diff options
Diffstat (limited to 'app/assets/javascripts/vue_merge_request_widget')
3 files changed, 157 insertions, 0 deletions
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_terraform_plan.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_terraform_plan.vue new file mode 100644 index 00000000000..edf90085a5b --- /dev/null +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_terraform_plan.vue @@ -0,0 +1,152 @@ +<script> +import { __ } from '~/locale'; +import { GlIcon, GlLoadingIcon, GlSprintf } from '@gitlab/ui'; +import axios from '~/lib/utils/axios_utils'; +import CiIcon from '../../vue_shared/components/ci_icon.vue'; +import flash from '~/flash'; +import Poll from '~/lib/utils/poll'; +import Visibility from 'visibilityjs'; + +export default { + name: 'MRWidgetTerraformPlan', + components: { + CiIcon, + GlIcon, + GlLoadingIcon, + GlSprintf, + }, + props: { + endpoint: { + type: String, + required: true, + }, + }, + data() { + return { + loading: true, + plans: {}, + }; + }, + computed: { + addNum() { + return Number(this.plan.create); + }, + changeNum() { + return Number(this.plan.update); + }, + deleteNum() { + return Number(this.plan.delete); + }, + iconStatusObj() { + return { + group: 'warning', + icon: 'status_warning', + }; + }, + logUrl() { + return this.plan.job_path; + }, + plan() { + return this.plans['tfplan.json'] || {}; + }, + validPlanValues() { + return this.addNum + this.changeNum + this.deleteNum >= 0; + }, + }, + created() { + this.fetchPlans(); + }, + methods: { + fetchPlans() { + this.loading = true; + + const poll = new Poll({ + resource: { + fetchPlans: () => axios.get(this.endpoint), + }, + data: this.endpoint, + method: 'fetchPlans', + successCallback: ({ data }) => { + this.plans = data; + this.loading = false; + }, + errorCallback: () => { + this.plans = {}; + this.loading = false; + flash(__('An error occurred while loading terraform report')); + }, + }); + + if (!Visibility.hidden()) { + poll.makeRequest(); + } + + Visibility.change(() => { + if (!Visibility.hidden()) { + poll.restart(); + } else { + poll.stop(); + } + }); + }, + }, +}; +</script> + +<template> + <section class="mr-widget-section"> + <div class="mr-widget-body media d-flex flex-row"> + <span class="append-right-default align-self-start align-self-lg-center"> + <ci-icon :status="iconStatusObj" :size="24" /> + </span> + + <div class="d-flex flex-fill flex-column flex-md-row"> + <div class="terraform-mr-plan-text normal d-flex flex-column flex-lg-row"> + <p class="m-0 pr-1">{{ __('A terraform report was generated in your pipelines.') }}</p> + + <gl-loading-icon v-if="loading" size="md" /> + + <p v-else-if="validPlanValues" class="m-0"> + <gl-sprintf + :message=" + __( + 'Reported Resource Changes: %{addNum} to add, %{changeNum} to change, %{deleteNum} to delete', + ) + " + > + <template #addNum> + <strong>{{ addNum }}</strong> + </template> + + <template #changeNum> + <strong>{{ changeNum }}</strong> + </template> + + <template #deleteNum> + <strong>{{ deleteNum }}</strong> + </template> + </gl-sprintf> + </p> + + <p v-else class="m-0">{{ __('Changes are unknown') }}</p> + </div> + + <div class="terraform-mr-plan-actions"> + <a + v-if="logUrl" + :href="logUrl" + target="_blank" + data-track-event="click_terraform_mr_plan_button" + data-track-label="mr_widget_terraform_mr_plan_button" + data-track-property="terraform_mr_plan_button" + class="btn btn-sm js-terraform-report-link" + rel="noopener" + > + {{ __('View full log') }} + <gl-icon name="external-link" /> + </a> + </div> + </div> + </div> + </section> +</template> diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue index 084deee042b..1bc28b15f74 100644 --- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue +++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue @@ -36,6 +36,7 @@ import CheckingState from './components/states/mr_widget_checking.vue'; import eventHub from './event_hub'; import notify from '~/lib/utils/notify'; import SourceBranchRemovalStatus from './components/source_branch_removal_status.vue'; +import TerraformPlan from './components/mr_widget_terraform_plan.vue'; import GroupedTestReportsApp from '../reports/components/grouped_test_reports_app.vue'; import { setFaviconOverlay } from '../lib/utils/common_utils'; @@ -74,6 +75,7 @@ export default { 'mr-widget-rebase': RebaseState, SourceBranchRemovalStatus, GroupedTestReportsApp, + TerraformPlan, }, props: { mrData: { @@ -379,6 +381,8 @@ export default { :endpoint="mr.testResultsPath" /> + <terraform-plan v-if="mr.terraformReportsPath" :endpoint="mr.terraformReportsPath" /> + <div class="mr-widget-section"> <component :is="componentName" :mr="mr" :service="service" /> diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js index 321b9270dde..9f001dda540 100644 --- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js +++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js @@ -101,6 +101,7 @@ export default class MergeRequestStore { this.isPipelineActive = data.pipeline ? data.pipeline.active : false; this.isPipelineBlocked = pipelineStatus ? pipelineStatus.group === 'manual' : false; this.ciStatusFaviconPath = pipelineStatus ? pipelineStatus.favicon : null; + this.terraformReportsPath = data.terraform_reports_path; this.testResultsPath = data.test_reports_path; this.exposedArtifactsPath = data.exposed_artifacts_path; this.cancelAutoMergePath = data.cancel_auto_merge_path; |