diff options
author | Phil Hughes <me@iamphill.com> | 2018-10-30 13:11:10 +0000 |
---|---|---|
committer | Phil Hughes <me@iamphill.com> | 2018-10-30 13:11:10 +0000 |
commit | 912741cfea06ead8dad95d20f2f0adb955a55732 (patch) | |
tree | 5c97a881bee0d96d056e710b31d9545b5060a5b4 | |
parent | 4845401f36bd4ad53c6864e7aceb6577752c0731 (diff) | |
parent | 15db499757a07a488be3caf2699134e7a7a20234 (diff) | |
download | gitlab-ce-912741cfea06ead8dad95d20f2f0adb955a55732.tar.gz |
Merge branch '53227-empty-list' into 'master'
Resolve "Empty list for links to changed pages in Review App from MR Widget"
Closes #53227
See merge request gitlab-org/gitlab-ce!22665
5 files changed, 111 insertions, 24 deletions
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue index 5e7a35e9396..57c52a2016a 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue @@ -10,6 +10,7 @@ import { visitUrl } from '../../lib/utils/url_utility'; import createFlash from '../../flash'; import MemoryUsage from './memory_usage.vue'; import StatusIcon from './mr_widget_status_icon.vue'; +import ReviewAppLink from './review_app_link.vue'; import MRWidgetService from '../services/mr_widget_service'; export default { @@ -21,6 +22,7 @@ export default { Icon, TooltipOnTruncate, FilteredSearchDropdown, + ReviewAppLink, }, directives: { tooltip, @@ -63,6 +65,12 @@ export default { deployedText() { return this.$options.deployedTextMap[this.deployment.status]; }, + shouldRenderDropdown() { + return ( + this.enableCiEnvironmentsStatusChanges && + (this.deployment.changes && this.deployment.changes.length > 0) + ); + }, }, methods: { stopEnvironment() { @@ -133,7 +141,7 @@ export default { <div> <template v-if="hasExternalUrls"> <filtered-search-dropdown - v-if="enableCiEnvironmentsStatusChanges" + v-if="shouldRenderDropdown" class="js-mr-wigdet-deployment-dropdown inline" :items="deployment.changes" :main-action-link="deployment.external_url" @@ -143,18 +151,10 @@ export default { slot="mainAction" slot-scope="slotProps" > - <a - :href="deployment.external_url" - target="_blank" - rel="noopener noreferrer nofollow" - class="deploy-link js-deploy-url inline" - :class="slotProps.className" - > - <span> - {{ __('View app') }} - <icon name="external-link" /> - </span> - </a> + <review-app-link + :link="deployment.external_url" + :css-class="`deploy-link js-deploy-url inline ${slotProps.className}`" + /> </template> <template @@ -177,18 +177,11 @@ export default { </a> </template> </filtered-search-dropdown> - <a + <review-app-link v-else - :href="deployment.external_url" - target="_blank" - rel="noopener noreferrer nofollow" - class="js-deploy-url js-deploy-url-feature-flag deploy-link btn btn-default btn-sm inline" - > - <span> - {{ __('View app') }} - <icon name="external-link" /> - </span> - </a> + :link="deployment.external_url" + css-class="js-deploy-url js-deploy-url-feature-flag deploy-link btn btn-default btn-sm inlin" + /> </template> <loading-button v-if="deployment.stop_url" diff --git a/app/assets/javascripts/vue_merge_request_widget/components/review_app_link.vue b/app/assets/javascripts/vue_merge_request_widget/components/review_app_link.vue new file mode 100644 index 00000000000..b007d4f4dcb --- /dev/null +++ b/app/assets/javascripts/vue_merge_request_widget/components/review_app_link.vue @@ -0,0 +1,30 @@ +<script> +import Icon from '~/vue_shared/components/icon.vue'; + +export default { + components: { + Icon, + }, + props: { + link: { + type: String, + required: true, + }, + cssClass: { + type: String, + required: true, + }, + }, +}; +</script> +<template> + <a + :href="link" + target="_blank" + rel="noopener noreferrer nofollow" + :class="cssClass" + > + {{ __('View app') }} + <icon name="external-link" /> + </a> +</template> diff --git a/changelogs/unreleased/53227-empty-list.yml b/changelogs/unreleased/53227-empty-list.yml new file mode 100644 index 00000000000..8b222145299 --- /dev/null +++ b/changelogs/unreleased/53227-empty-list.yml @@ -0,0 +1,6 @@ +--- +title: Only renders dropdown for review app changes when we have a list of files to + show. Otherwise will render the regular review app button +merge_request: +author: +type: other diff --git a/spec/javascripts/vue_mr_widget/components/deployment_spec.js b/spec/javascripts/vue_mr_widget/components/deployment_spec.js index d26ffa4b4a6..3d44af11153 100644 --- a/spec/javascripts/vue_mr_widget/components/deployment_spec.js +++ b/spec/javascripts/vue_mr_widget/components/deployment_spec.js @@ -211,6 +211,26 @@ describe('Deployment component', () => { }); }); + describe('without changes', () => { + beforeEach(() => { + window.gon = window.gon || {}; + window.gon.features = window.gon.features || {}; + window.gon.features.ciEnvironmentsStatusChanges = true; + delete deploymentMockData.changes; + + vm = mountComponent(Component, { deployment: { ...deploymentMockData } }); + }); + + afterEach(() => { + delete window.gon.features.ciEnvironmentsStatusChanges; + }); + + it('renders the link to the review app without dropdown', () => { + expect(vm.$el.querySelector('.js-mr-wigdet-deployment-dropdown')).toBeNull(); + expect(vm.$el.querySelector('.js-deploy-url-feature-flag')).not.toBeNull(); + }); + }); + describe('deployment status', () => { describe('running', () => { beforeEach(() => { diff --git a/spec/javascripts/vue_mr_widget/components/review_app_link_spec.js b/spec/javascripts/vue_mr_widget/components/review_app_link_spec.js new file mode 100644 index 00000000000..68a65bd21c6 --- /dev/null +++ b/spec/javascripts/vue_mr_widget/components/review_app_link_spec.js @@ -0,0 +1,38 @@ +import Vue from 'vue'; +import component from '~/vue_merge_request_widget/components/review_app_link.vue'; +import mountComponent from '../../helpers/vue_mount_component_helper'; + +describe('review app link', () => { + const Component = Vue.extend(component); + const props = { + link: '/review', + cssClass: 'js-link', + }; + let vm; + let el; + + beforeEach(() => { + vm = mountComponent(Component, props); + el = vm.$el; + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('renders provided link as href attribute', () => { + expect(el.getAttribute('href')).toEqual(props.link); + }); + + it('renders provided cssClass as class attribute', () => { + expect(el.getAttribute('class')).toEqual(props.cssClass); + }); + + it('renders View app text', () => { + expect(el.textContent.trim()).toEqual('View app'); + }); + + it('renders svg icon', () => { + expect(el.querySelector('svg')).not.toBeNull(); + }); +}); |