diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-12-21 09:13:16 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-12-21 09:13:16 +0300 |
commit | d1f4ef3cb7ff63c92dc17589a05848938251c7f1 (patch) | |
tree | eec6efa4e5a995bd171d4b263db25559b41d3194 | |
parent | 064902dfbd83a3598595a37e19ae3371eb828b54 (diff) |
Add latest changes from gitlab-org/gitlab@master
9 files changed, 163 insertions, 4 deletions
diff --git a/app/assets/javascripts/integrations/constants.js b/app/assets/javascripts/integrations/constants.js index 84656bd41bb..7d32fafdf92 100644 --- a/app/assets/javascripts/integrations/constants.js +++ b/app/assets/javascripts/integrations/constants.js @@ -23,3 +23,6 @@ export const I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE = s__( ); export const I18N_DEFAULT_ERROR_MESSAGE = __('Something went wrong on our end.'); export const I18N_SUCCESSFUL_CONNECTION_MESSAGE = s__('Integrations|Connection successful.'); + +export const settingsTabTitle = __('Settings'); +export const overridesTabTitle = s__('Integrations|Projects using custom settings'); diff --git a/app/assets/javascripts/integrations/overrides/components/integration_overrides.vue b/app/assets/javascripts/integrations/overrides/components/integration_overrides.vue index 3fc554c5371..f2d3e6489ee 100644 --- a/app/assets/javascripts/integrations/overrides/components/integration_overrides.vue +++ b/app/assets/javascripts/integrations/overrides/components/integration_overrides.vue @@ -11,6 +11,8 @@ import { __, s__ } from '~/locale'; import ProjectAvatar from '~/vue_shared/components/project_avatar.vue'; import UrlSync from '~/vue_shared/components/url_sync.vue'; +import IntegrationTabs from './integration_tabs.vue'; + const DEFAULT_PAGE = 1; export default { @@ -23,6 +25,7 @@ export default { GlAlert, ProjectAvatar, UrlSync, + IntegrationTabs, }, props: { overridesPath: { @@ -46,6 +49,9 @@ export default { }; }, computed: { + overridesCount() { + return this.isLoading ? null : this.totalItems; + }, showPagination() { return this.totalItems > this.$options.DEFAULT_PER_PAGE && this.overrides.length > 0; }, @@ -100,6 +106,7 @@ export default { <template> <div> + <integration-tabs :project-overrides-count="overridesCount" /> <gl-alert v-if="errorMessage" variant="danger" :dismissible="false"> {{ errorMessage }} </gl-alert> diff --git a/app/assets/javascripts/integrations/overrides/components/integration_tabs.vue b/app/assets/javascripts/integrations/overrides/components/integration_tabs.vue new file mode 100644 index 00000000000..3f67c987231 --- /dev/null +++ b/app/assets/javascripts/integrations/overrides/components/integration_tabs.vue @@ -0,0 +1,52 @@ +<script> +import { GlBadge, GlNavItem, GlTabs, GlTab } from '@gitlab/ui'; +import { settingsTabTitle, overridesTabTitle } from '~/integrations/constants'; + +export default { + components: { + GlBadge, + GlNavItem, + GlTabs, + GlTab, + }, + inject: { + editPath: { + default: '', + }, + }, + props: { + projectOverridesCount: { + type: [Number, String], + required: false, + default: null, + }, + }, + i18n: { + settingsTabTitle, + overridesTabTitle, + }, +}; +</script> + +<template> + <gl-tabs> + <template #tabs-start> + <gl-nav-item role="presentation" link-classes="gl-tab-nav-item" :href="editPath">{{ + $options.i18n.settingsTabTitle + }}</gl-nav-item> + </template> + + <gl-tab active> + <template #title> + {{ $options.i18n.overridesTabTitle }} + <gl-badge + v-if="projectOverridesCount !== null" + variant="muted" + size="sm" + class="gl-tab-counter-badge" + >{{ projectOverridesCount }}</gl-badge + > + </template> + </gl-tab> + </gl-tabs> +</template> diff --git a/app/assets/javascripts/integrations/overrides/index.js b/app/assets/javascripts/integrations/overrides/index.js index 0f03b23ba21..f289a2d3d1a 100644 --- a/app/assets/javascripts/integrations/overrides/index.js +++ b/app/assets/javascripts/integrations/overrides/index.js @@ -8,10 +8,13 @@ export default () => { return null; } - const { overridesPath } = el.dataset; + const { editPath, overridesPath } = el.dataset; return new Vue({ el, + provide: { + editPath, + }, render(createElement) { return createElement(IntegrationOverrides, { props: { diff --git a/app/helpers/integrations_helper.rb b/app/helpers/integrations_helper.rb index c5e767c6f64..539d1f27574 100644 --- a/app/helpers/integrations_helper.rb +++ b/app/helpers/integrations_helper.rb @@ -101,8 +101,9 @@ module IntegrationsHelper form_data end - def integration_overrides_data(integration) + def integration_overrides_data(integration, project: nil, group: nil) { + edit_path: scoped_edit_integration_path(integration, project: project, group: group), overrides_path: scoped_overrides_integration_path(integration, format: :json) } end diff --git a/app/views/shared/integrations/overrides.html.haml b/app/views/shared/integrations/overrides.html.haml index b8585fdef1f..4619675cfef 100644 --- a/app/views/shared/integrations/overrides.html.haml +++ b/app/views/shared/integrations/overrides.html.haml @@ -6,5 +6,4 @@ %h3.page-title = @integration.title -= render 'shared/integrations/tabs', integration: @integration, active_tab: 'overrides' do - .js-vue-integration-overrides{ data: integration_overrides_data(@integration) } +.js-vue-integration-overrides{ data: integration_overrides_data(@integration, project: @project, group: @group) } diff --git a/spec/frontend/integrations/overrides/components/integration_overrides_spec.js b/spec/frontend/integrations/overrides/components/integration_overrides_spec.js index 8abd83887f7..6aa3e661677 100644 --- a/spec/frontend/integrations/overrides/components/integration_overrides_spec.js +++ b/spec/frontend/integrations/overrides/components/integration_overrides_spec.js @@ -5,6 +5,8 @@ import MockAdapter from 'axios-mock-adapter'; import waitForPromises from 'helpers/wait_for_promises'; import { DEFAULT_PER_PAGE } from '~/api'; import IntegrationOverrides from '~/integrations/overrides/components/integration_overrides.vue'; +import IntegrationTabs from '~/integrations/overrides/components/integration_tabs.vue'; + import axios from '~/lib/utils/axios_utils'; import httpStatus from '~/lib/utils/http_status'; import ProjectAvatar from '~/vue_shared/components/project_avatar.vue'; @@ -49,6 +51,7 @@ describe('IntegrationOverrides', () => { const findGlTable = () => wrapper.findComponent(GlTable); const findPagination = () => wrapper.findComponent(GlPagination); + const findIntegrationTabs = () => wrapper.findComponent(IntegrationTabs); const findRowsAsModel = () => findGlTable() .findAllComponents(GlLink) @@ -72,6 +75,12 @@ describe('IntegrationOverrides', () => { expect(table.exists()).toBe(true); expect(table.attributes('busy')).toBe('true'); }); + + it('renders IntegrationTabs with count as `null`', () => { + createComponent(); + + expect(findIntegrationTabs().props('projectOverridesCount')).toBe(null); + }); }); describe('when initial request is successful', () => { @@ -84,6 +93,13 @@ describe('IntegrationOverrides', () => { expect(table.attributes('busy')).toBeFalsy(); }); + it('renders IntegrationTabs with count', async () => { + createComponent(); + await waitForPromises(); + + expect(findIntegrationTabs().props('projectOverridesCount')).toBe(mockOverrides.length); + }); + describe('table template', () => { beforeEach(async () => { createComponent({ mountFn: mount }); diff --git a/spec/frontend/integrations/overrides/components/integration_tabs_spec.js b/spec/frontend/integrations/overrides/components/integration_tabs_spec.js new file mode 100644 index 00000000000..a728b4d391f --- /dev/null +++ b/spec/frontend/integrations/overrides/components/integration_tabs_spec.js @@ -0,0 +1,64 @@ +import { mount, shallowMount } from '@vue/test-utils'; +import { GlBadge, GlTab } from '@gitlab/ui'; + +import IntegrationTabs from '~/integrations/overrides/components/integration_tabs.vue'; +import { settingsTabTitle, overridesTabTitle } from '~/integrations/constants'; + +describe('IntegrationTabs', () => { + let wrapper; + + const editPath = 'mock/edit'; + + const createComponent = ({ mountFn = shallowMount, props = {} } = {}) => { + wrapper = mountFn(IntegrationTabs, { + propsData: props, + provide: { + editPath, + }, + stubs: { + GlTab, + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + const findGlBadge = () => wrapper.findComponent(GlBadge); + const findGlTab = () => wrapper.findComponent(GlTab); + const findSettingsLink = () => wrapper.find('a'); + + describe('template', () => { + it('renders "Settings" tab as a link', () => { + createComponent({ mountFn: mount }); + + expect(findSettingsLink().text()).toMatchInterpolatedText(settingsTabTitle); + expect(findSettingsLink().attributes('href')).toBe(editPath); + }); + + it('renders "Projects using custom settings" tab as active', () => { + const projectOverridesCount = '1'; + + createComponent({ + props: { projectOverridesCount }, + }); + + expect(findGlTab().exists()).toBe(true); + expect(findGlTab().text()).toMatchInterpolatedText( + `${overridesTabTitle} ${projectOverridesCount}`, + ); + expect(findGlBadge().text()).toBe(projectOverridesCount); + }); + + describe('when count is `null', () => { + it('renders "Projects using custom settings" tab without count', () => { + createComponent(); + + expect(findGlTab().exists()).toBe(true); + expect(findGlTab().text()).toMatchInterpolatedText(overridesTabTitle); + expect(findGlBadge().exists()).toBe(false); + }); + }); + }); +}); diff --git a/spec/helpers/integrations_helper_spec.rb b/spec/helpers/integrations_helper_spec.rb index 3a7d4d12513..df5f9be3800 100644 --- a/spec/helpers/integrations_helper_spec.rb +++ b/spec/helpers/integrations_helper_spec.rb @@ -70,6 +70,20 @@ RSpec.describe IntegrationsHelper do end end + describe '#integration_overrides_data' do + let(:integration) { build_stubbed(:jira_integration) } + let(:fields) do + [ + edit_path: edit_admin_application_settings_integration_path(integration), + overrides_path: overrides_admin_application_settings_integration_path(integration, format: :json) + ] + end + + subject { helper.integration_overrides_data(integration) } + + it { is_expected.to include(*fields) } + end + describe '#scoped_reset_integration_path' do let(:integration) { build_stubbed(:jira_integration) } let(:group) { nil } |