Commit b05afd5e authored by Nicolò Maria Mezzopera's avatar Nicolò Maria Mezzopera Committed by Illya Klymov

Add new settings block component

- source
- test
- snapshots
parent 3068cf8b
import Vue from 'vue';
import Translate from '~/vue_shared/translate';
import { parseBoolean } from '~/lib/utils/common_utils';
import SettingsApp from './components/group_settings_app.vue';
import { apolloProvider } from './graphql';
......@@ -13,6 +14,10 @@ export default () => {
return new Vue({
el,
apolloProvider,
provide: {
defaultExpanded: parseBoolean(el.dataset.defaultExpanded),
groupPath: el.dataset.groupPath,
},
render(createElement) {
return createElement(SettingsApp);
},
......
<script>
import { GlSprintf, GlLink } from '@gitlab/ui';
import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue';
import {
PACKAGE_SETTINGS_HEADER,
PACKAGE_SETTINGS_DESCRIPTION,
PACKAGES_DOCS_PATH,
} from '../constants';
import getGroupPackagesSettingsQuery from '../graphql/queries/get_group_packages_settings.query.graphql';
export default {
name: 'GroupSettingsApp',
i18n: {
PACKAGE_SETTINGS_HEADER,
PACKAGE_SETTINGS_DESCRIPTION,
},
links: {
PACKAGES_DOCS_PATH,
},
components: {
GlSprintf,
GlLink,
SettingsBlock,
},
inject: {
defaultExpanded: {
type: Boolean,
default: false,
required: true,
},
groupPath: {
type: String,
required: true,
},
},
apollo: {
packageSettings: {
query: getGroupPackagesSettingsQuery,
variables() {
return {
fullPath: this.groupPath,
};
},
update(data) {
return data.group?.packageSettings;
},
},
},
data() {
return {
packageSettings: {},
};
},
};
</script>
<template>
<section></section>
<div>
<settings-block :default-expanded="defaultExpanded">
<template #title> {{ $options.i18n.PACKAGE_SETTINGS_HEADER }}</template>
<template #description>
<span data-testid="description">
<gl-sprintf :message="$options.i18n.PACKAGE_SETTINGS_DESCRIPTION">
<template #link="{ content }">
<gl-link :href="$options.links.PACKAGES_DOCS_PATH" target="_blank">{{
content
}}</gl-link>
</template>
</gl-sprintf>
</span>
</template>
</settings-block>
</div>
</template>
import { s__ } from '~/locale';
import { helpPagePath } from '~/helpers/help_page_helper';
export const PACKAGE_SETTINGS_HEADER = s__('PackageRegistry|Package Registry');
export const PACKAGE_SETTINGS_DESCRIPTION = s__(
'PackageRegistry|GitLab Packages allows organizations to utilize GitLab as a private repository for a variety of common package formats. %{linkStart}More Information%{linkEnd}',
);
export const PACKAGES_DOCS_PATH = helpPagePath('user/packages');
mutation updateNamespacePackageSettings($input: UpdateNamespacePackageSettingsInput!) {
updateNamespacePackageSettings(input: $input) {
packageSettings {
mavenDuplicatesAllowed
mavenDuplicateExceptionRegex
}
errors
}
}
query getGroupPackagesSettings($fullPath: ID!) {
group(fullPath: $fullPath) {
packageSettings {
mavenDuplicatesAllowed
mavenDuplicateExceptionRegex
}
}
}
<script>
import { GlButton } from '@gitlab/ui';
import { __ } from '~/locale';
export default {
components: { GlButton },
props: {
defaultExpanded: {
type: Boolean,
default: false,
required: false,
},
},
data() {
return {
sectionExpanded: false,
};
},
computed: {
expanded() {
return this.defaultExpanded || this.sectionExpanded;
},
toggleText() {
return this.expanded ? __('Collapse') : __('Expand');
},
},
};
</script>
<template>
<section class="settings no-animate" :class="{ expanded }">
<div class="settings-header">
<h4><slot name="title"></slot></h4>
<gl-button @click="sectionExpanded = !sectionExpanded">
{{ toggleText }}
</gl-button>
<p>
<slot name="description"></slot>
</p>
</div>
<div class="settings-content">
<slot></slot>
</div>
</section>
</template>
......@@ -2,4 +2,4 @@
- page_title _('Packages & Registries')
- @content_class = 'limit-container-width' unless fluid_layout
%section#js-packages-and-registries-settings
%section#js-packages-and-registries-settings{ data: { default_expanded: expanded_by_default?.to_s, group_path: @group.path } }
......@@ -20316,6 +20316,9 @@ msgstr ""
msgid "PackageRegistry|Generic"
msgstr ""
msgid "PackageRegistry|GitLab Packages allows organizations to utilize GitLab as a private repository for a variety of common package formats. %{linkStart}More Information%{linkEnd}"
msgstr ""
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
......
......@@ -47,6 +47,13 @@ RSpec.describe 'Group Packages & Registries settings' do
sidebar = find('.nav-sidebar')
expect(sidebar).to have_link _('Packages & Registries')
end
it 'has a Package Registry section', :js do
visit_settings_page
expect(page).to have_content('Package Registry')
expect(page).to have_button('Collapse')
end
end
def find_settings_menu
......
import { shallowMount, createLocalVue } from '@vue/test-utils';
import { GlSprintf, GlLink } from '@gitlab/ui';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import component from '~/packages_and_registries/settings/group/components/group_settings_app.vue';
import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue';
import {
PACKAGE_SETTINGS_HEADER,
PACKAGE_SETTINGS_DESCRIPTION,
PACKAGES_DOCS_PATH,
} from '~/packages_and_registries/settings/group/constants';
import getGroupPackagesSettingsQuery from '~/packages_and_registries/settings/group/graphql/queries/get_group_packages_settings.query.graphql';
import { groupPackageSettingsMock } from '../mock_data';
const localVue = createLocalVue();
describe('Group Settings App', () => {
let wrapper;
let apolloProvider;
const defaultProvide = {
defaultExpanded: false,
groupPath: 'foo_group_path',
};
const mountComponent = ({
provide = defaultProvide,
resolver = jest.fn().mockResolvedValue(groupPackageSettingsMock),
} = {}) => {
localVue.use(VueApollo);
const requestHandlers = [[getGroupPackagesSettingsQuery, resolver]];
apolloProvider = createMockApollo(requestHandlers);
wrapper = shallowMount(component, {
localVue,
apolloProvider,
provide,
stubs: {
GlSprintf,
SettingsBlock,
},
});
};
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
const findSettingsBlock = () => wrapper.find(SettingsBlock);
const findDescription = () => wrapper.find('[data-testid="description"');
const findLink = () => wrapper.find(GlLink);
it('renders a settings block', () => {
mountComponent();
expect(findSettingsBlock().exists()).toBe(true);
});
it('passes the correct props to settings block', () => {
mountComponent();
expect(findSettingsBlock().props('defaultExpanded')).toBe(false);
});
it('has the correct header text', () => {
mountComponent();
expect(wrapper.text()).toContain(PACKAGE_SETTINGS_HEADER);
});
it('has the correct description text', () => {
mountComponent();
expect(findDescription().text()).toMatchInterpolatedText(PACKAGE_SETTINGS_DESCRIPTION);
});
it('has the correct link', () => {
mountComponent();
expect(findLink().attributes()).toMatchObject({
href: PACKAGES_DOCS_PATH,
target: '_blank',
});
expect(findLink().text()).toBe('More Information');
});
it('calls the graphql API with the proper variables', () => {
const resolver = jest.fn().mockResolvedValue(groupPackageSettingsMock);
mountComponent({ resolver });
expect(resolver).toHaveBeenCalledWith({
fullPath: defaultProvide.groupPath,
});
});
});
export const groupPackageSettingsMock = {
data: {
group: {
packageSettings: {
mavenDuplicatesAllowed: true,
mavenDuplicateExceptionRegex: '',
__typename: 'PackageSettings',
},
__typename: 'Group',
},
},
};
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Settings Block renders the correct markup 1`] = `
<section
class="settings no-animate"
>
<div
class="settings-header"
>
<h4>
<div
data-testid="title-slot"
/>
</h4>
<gl-button-stub
buttontextclasses=""
category="primary"
icon=""
size="medium"
variant="default"
>
Expand
</gl-button-stub>
<p>
<div
data-testid="description-slot"
/>
</p>
</div>
<div
class="settings-content"
>
<div
data-testid="default-slot"
/>
</div>
</section>
`;
import { shallowMount } from '@vue/test-utils';
import { GlButton } from '@gitlab/ui';
import component from '~/vue_shared/components/settings/settings_block.vue';
describe('Settings Block', () => {
let wrapper;
const mountComponent = (propsData) => {
wrapper = shallowMount(component, {
propsData,
slots: {
title: '<div data-testid="title-slot"></div>',
description: '<div data-testid="description-slot"></div>',
default: '<div data-testid="default-slot"></div>',
},
});
};
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
const findDefaultSlot = () => wrapper.find('[data-testid="default-slot"]');
const findTitleSlot = () => wrapper.find('[data-testid="title-slot"]');
const findDescriptionSlot = () => wrapper.find('[data-testid="description-slot"]');
const findExpandButton = () => wrapper.find(GlButton);
it('renders the correct markup', () => {
mountComponent();
expect(wrapper.element).toMatchSnapshot();
});
it('has a default slot', () => {
mountComponent();
expect(findDefaultSlot().exists()).toBe(true);
});
it('has a title slot', () => {
mountComponent();
expect(findTitleSlot().exists()).toBe(true);
});
it('has a description slot', () => {
mountComponent();
expect(findDescriptionSlot().exists()).toBe(true);
});
describe('expanded behaviour', () => {
it('is collapsed by default', () => {
mountComponent();
expect(wrapper.classes('expanded')).toBe(false);
});
it('adds expanded class when the expand button is clicked', async () => {
mountComponent();
expect(wrapper.classes('expanded')).toBe(false);
expect(findExpandButton().text()).toBe('Expand');
await findExpandButton().vm.$emit('click');
expect(wrapper.classes('expanded')).toBe(true);
expect(findExpandButton().text()).toBe('Collapse');
});
it('is expanded when `defaultExpanded` is true no matter what', async () => {
mountComponent({ defaultExpanded: true });
expect(wrapper.classes('expanded')).toBe(true);
await findExpandButton().vm.$emit('click');
expect(wrapper.classes('expanded')).toBe(true);
await findExpandButton().vm.$emit('click');
expect(wrapper.classes('expanded')).toBe(true);
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment