diff --git a/app/assets/javascripts/merge_request_dashboard/components/collapsible_section.stories.js b/app/assets/javascripts/merge_request_dashboard/components/collapsible_section.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..0db6f4642b9a1cd8e35a789f679aa27970367b1e --- /dev/null +++ b/app/assets/javascripts/merge_request_dashboard/components/collapsible_section.stories.js @@ -0,0 +1,20 @@ +import CollapsibleSection from './collapsible_section.vue'; + +const Template = (_, { argTypes }) => { + return { + components: { CollapsibleSection }, + props: Object.keys(argTypes), + template: '<collapsible-section v-bind="$props">Opened</collapsible-section>', + }; +}; + +export default { + component: CollapsibleSection, + title: 'merge_requests_dashboard/collapsible_section', +}; + +export const Default = Template.bind({}); +Default.args = { title: 'Approved', count: 3 }; + +export const ClosedByDefault = Template.bind({}); +ClosedByDefault.args = { ...Default.args, count: 0 }; diff --git a/app/assets/javascripts/merge_request_dashboard/components/collapsible_section.vue b/app/assets/javascripts/merge_request_dashboard/components/collapsible_section.vue new file mode 100644 index 0000000000000000000000000000000000000000..c77eae6f16e065f04606b06234e98a03f96e8e59 --- /dev/null +++ b/app/assets/javascripts/merge_request_dashboard/components/collapsible_section.vue @@ -0,0 +1,67 @@ +<script> +import { GlButton, GlBadge } from '@gitlab/ui'; +import { __, sprintf } from '~/locale'; + +export default { + components: { + GlButton, + GlBadge, + }, + props: { + title: { + type: String, + required: true, + }, + count: { + type: Number, + required: true, + }, + }, + data() { + return { + open: this.count > 0, + }; + }, + computed: { + toggleButtonIcon() { + return this.open ? 'chevron-down' : 'chevron-right'; + }, + toggleButtonLabel() { + return sprintf( + this.open + ? __('Collapse %{section} merge requests') + : __('Expand %{section} merge requests'), + { + section: this.title.toLowerCase(), + }, + ); + }, + }, + methods: { + toggleOpen() { + this.open = !this.open; + }, + }, +}; +</script> + +<template> + <section class="gl-bg-gray-50 gl-p-4 gl-rounded-base"> + <header class="gl-display-flex gl-align-items-center"> + <gl-button + :icon="toggleButtonIcon" + size="small" + category="tertiary" + class="gl-mr-3" + :aria-label="toggleButtonLabel" + data-testid="section-toggle-button" + @click="toggleOpen" + /> + <strong>{{ title }}</strong> + <gl-badge class="gl-ml-3" variant="neutral" size="sm">{{ count }}</gl-badge> + </header> + <div v-if="open" class="gl-mt-3" data-testid="section-content"> + <slot></slot> + </div> + </section> +</template> diff --git a/locale/gitlab.pot b/locale/gitlab.pot index d1f4bf53cdd5086b96151911d01eab3cd1ad6eb9..f5a2710ba2bf6d4a64b53c267cb5b879961aed0d 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -12630,6 +12630,9 @@ msgstr "" msgid "Collapse" msgstr "" +msgid "Collapse %{section} merge requests" +msgstr "" + msgid "Collapse eligible approvers" msgstr "" @@ -21082,6 +21085,9 @@ msgstr "" msgid "Expand" msgstr "" +msgid "Expand %{section} merge requests" +msgstr "" + msgid "Expand Readme" msgstr "" diff --git a/spec/frontend/merge_request_dashboard/components/__snapshots__/collapsible_section_spec.js.snap b/spec/frontend/merge_request_dashboard/components/__snapshots__/collapsible_section_spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..66e40e29b7610535f49f9ea08c13f39a85611d78 --- /dev/null +++ b/spec/frontend/merge_request_dashboard/components/__snapshots__/collapsible_section_spec.js.snap @@ -0,0 +1,39 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Merge request dashboard collapsible section renders section 1`] = ` +<section + class="gl-bg-gray-50 gl-p-4 gl-rounded-base" +> + <header + class="gl-align-items-center gl-display-flex" + > + <gl-button-stub + aria-label="Collapse approved merge requests" + buttontextclasses="" + category="tertiary" + class="gl-mr-3" + data-testid="section-toggle-button" + icon="chevron-down" + size="small" + variant="default" + /> + <strong> + Approved + </strong> + <gl-badge-stub + class="gl-ml-3" + iconsize="md" + size="sm" + variant="neutral" + > + 3 + </gl-badge-stub> + </header> + <div + class="gl-mt-3" + data-testid="section-content" + > + content + </div> +</section> +`; diff --git a/spec/frontend/merge_request_dashboard/components/collapsible_section_spec.js b/spec/frontend/merge_request_dashboard/components/collapsible_section_spec.js new file mode 100644 index 0000000000000000000000000000000000000000..b7923d3cef0d5fbfd5780eaf5a453920f4ddcce3 --- /dev/null +++ b/spec/frontend/merge_request_dashboard/components/collapsible_section_spec.js @@ -0,0 +1,42 @@ +import { nextTick } from 'vue'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import CollapsibleSection from '~/merge_request_dashboard/components/collapsible_section.vue'; + +describe('Merge request dashboard collapsible section', () => { + let wrapper; + + function createComponent(count = 3) { + wrapper = shallowMountExtended(CollapsibleSection, { + slots: { + default: 'content', + }, + propsData: { + title: 'Approved', + count, + }, + }); + } + + it('renders section', () => { + createComponent(); + + expect(wrapper.element).toMatchSnapshot(); + }); + + it('collapses by default', () => { + createComponent(0); + + expect(wrapper.findByTestId('section-content').exists()).toBe(false); + }); + + it('expands collapsed content', async () => { + createComponent(0); + + wrapper.findByTestId('section-toggle-button').vm.$emit('click'); + + await nextTick(); + + expect(wrapper.findByTestId('section-content').exists()).toBe(true); + expect(wrapper.findByTestId('section-content').text()).toContain('content'); + }); +});