diff --git a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view.vue b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view.vue index 93e3cfba309c2555da973b265d6a1bba34ac2e4d..f3209d1a02f050b0be817bf082e68b97ae441b5e 100644 --- a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view.vue +++ b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view.vue @@ -1,17 +1,11 @@ + diff --git a/app/assets/stylesheets/page_bundles/labels.scss b/app/assets/stylesheets/page_bundles/labels.scss index bc0bf4bc4903cc90e87cf382c5169dc75a915415..3204e678986278ffbd9c6a0f7496bba3cfe62185 100644 --- a/app/assets/stylesheets/page_bundles/labels.scss +++ b/app/assets/stylesheets/page_bundles/labels.scss @@ -1,54 +1,5 @@ @import 'mixins_and_variables_and_functions'; -.suggest-colors { - padding-top: 3px; - - a { - border-radius: 4px; - width: 30px; - height: 30px; - display: inline-block; - margin-right: 10px; - margin-bottom: 10px; - text-decoration: none; - - &:focus, - &:focus:active { - position: relative; - z-index: 1; - @include gl-focus; - } - } - - &.suggest-colors-dropdown { - margin-top: 10px; - margin-bottom: 10px; - - a { - border-radius: 0; - width: (100% / 7); - margin-right: 0; - margin-bottom: -5px; - - &:first-of-type { - border-top-left-radius: $gl-border-radius-base; - } - - &:nth-of-type(7) { - border-top-right-radius: $gl-border-radius-base; - } - - &:nth-last-child(7) { - border-bottom-left-radius: $gl-border-radius-base; - } - - &:last-of-type { - border-bottom-right-radius: $gl-border-radius-base; - } - } - } -} - .labels-select-contents-create { .dropdown-input { margin-bottom: 4px; diff --git a/app/assets/stylesheets/pages/colors.scss b/app/assets/stylesheets/pages/colors.scss index 85c1f7da07fdc928327055de0979b33ef722e54e..aeaf2d7c1b348aa616d19970872162361aa61932 100644 --- a/app/assets/stylesheets/pages/colors.scss +++ b/app/assets/stylesheets/pages/colors.scss @@ -29,3 +29,52 @@ .danger-title { color: var(--red-500, $red-500); } + +.suggest-colors { + padding-top: 3px; + + a { + border-radius: 4px; + width: 30px; + height: 30px; + display: inline-block; + margin-right: 10px; + margin-bottom: 10px; + text-decoration: none; + + &:focus, + &:focus:active { + position: relative; + z-index: 1; + @include gl-focus; + } + } + + &.suggest-colors-dropdown { + margin-top: 10px; + margin-bottom: 10px; + + a { + border-radius: 0; + width: (100% / 7); + margin-right: 0; + margin-bottom: -5px; + + &:first-of-type { + border-top-left-radius: $gl-border-radius-base; + } + + &:nth-of-type(7) { + border-top-right-radius: $gl-border-radius-base; + } + + &:nth-last-child(7) { + border-bottom-left-radius: $gl-border-radius-base; + } + + &:last-of-type { + border-bottom-right-radius: $gl-border-radius-base; + } + } + } +} diff --git a/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view_spec.js b/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view_spec.js index 5e2ff73878f98e4944b55e04645264b50513640f..7180e10e7b103f8c1e0177dc0db665444f4d9ea6 100644 --- a/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view_spec.js +++ b/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view_spec.js @@ -1,4 +1,4 @@ -import { GlAlert, GlLoadingIcon, GlLink } from '@gitlab/ui'; +import { GlAlert, GlLoadingIcon } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import Vue, { nextTick } from 'vue'; import VueApollo from 'vue-apollo'; @@ -7,6 +7,7 @@ import waitForPromises from 'helpers/wait_for_promises'; import { createAlert } from '~/alert'; import { workspaceLabelsQueries, workspaceCreateLabelMutation } from '~/sidebar/queries/constants'; import DropdownContentsCreateView from '~/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view.vue'; +import SibebarColorPicker from '~/sidebar/components/sidebar_color_picker.vue'; import { DEFAULT_LABEL_COLOR } from '~/sidebar/components/labels/labels_select_widget/constants'; import { mockCreateLabelResponse as createAbuseReportLabelSuccessfulResponse, @@ -14,7 +15,6 @@ import { } from '../../../../admin/abuse_report/mock_data'; import { mockRegularLabel, - mockSuggestedColors, createLabelSuccessfulResponse, workspaceLabelsQueryResponse, workspaceLabelsQueryEmptyResponse, @@ -22,8 +22,6 @@ import { jest.mock('~/alert'); -const colors = Object.keys(mockSuggestedColors); - Vue.use(VueApollo); const userRecoverableError = { @@ -51,9 +49,7 @@ const createLabelErrorHandler = jest.fn().mockRejectedValue('Houston, we have a describe('DropdownContentsCreateView', () => { let wrapper; - const findAllColors = () => wrapper.findAllComponents(GlLink); - const findSelectedColor = () => wrapper.find('[data-testid="selected-color"]'); - const findSelectedColorText = () => wrapper.find('[data-testid="selected-color-text"]'); + const findSibebarColorPicker = () => wrapper.findComponent(SibebarColorPicker); const findCreateButton = () => wrapper.find('[data-testid="create-button"]'); const findCancelButton = () => wrapper.find('[data-testid="cancel-button"]'); const findLabelTitleInput = () => wrapper.find('[data-testid="label-title-input"]'); @@ -62,7 +58,7 @@ describe('DropdownContentsCreateView', () => { const fillLabelAttributes = () => { findLabelTitleInput().vm.$emit('input', 'Test title'); - findAllColors().at(0).vm.$emit('click', new Event('mouseclick')); + findSibebarColorPicker().vm.$emit('input', '#009966'); }; const createComponent = ({ @@ -94,38 +90,9 @@ describe('DropdownContentsCreateView', () => { }); }; - beforeEach(() => { - gon.suggested_label_colors = mockSuggestedColors; - }); - - it('renders a palette of 21 colors', () => { - createComponent(); - expect(findAllColors()).toHaveLength(21); - }); - - it('selects a color after clicking on colored block', async () => { - createComponent(); - expect(findSelectedColorText().attributes('value')).toBe(DEFAULT_LABEL_COLOR); - - findAllColors().at(0).vm.$emit('click', new Event('mouseclick')); - await nextTick(); - - expect(findSelectedColor().attributes('value')).toBe('#009966'); - }); - - it('shows correct color hex code after selecting a color', async () => { - createComponent(); - expect(findSelectedColorText().attributes('value')).toBe(DEFAULT_LABEL_COLOR); - - findAllColors().at(0).vm.$emit('click', new Event('mouseclick')); - await nextTick(); - - expect(findSelectedColorText().attributes('value')).toBe(colors[0]); - }); - it('disables a Create button if label title is not set', async () => { createComponent(); - findAllColors().at(0).vm.$emit('click', new Event('mouseclick')); + findSibebarColorPicker().vm.$emit('input', '#fff'); await nextTick(); expect(findCreateButton().props('disabled')).toBe(true); @@ -134,7 +101,7 @@ describe('DropdownContentsCreateView', () => { it('disables a Create button if color is not set', async () => { createComponent(); findLabelTitleInput().vm.$emit('input', 'Test title'); - findSelectedColorText().vm.$emit('input', ''); + findSibebarColorPicker().vm.$emit('input', ''); await nextTick(); expect(findCreateButton().props('disabled')).toBe(true); diff --git a/spec/frontend/sidebar/components/labels/labels_select_widget/mock_data.js b/spec/frontend/sidebar/components/labels/labels_select_widget/mock_data.js index 5039f00fe4b2d6b71d64788a8b7ed7b3765b6be8..eb7ab2953c6eb9ed3719b73fde911b7f309eb2be 100644 --- a/spec/frontend/sidebar/components/labels/labels_select_widget/mock_data.js +++ b/spec/frontend/sidebar/components/labels/labels_select_widget/mock_data.js @@ -58,30 +58,6 @@ export const mockConfig = { attrWorkspacePath: 'test', }; -export const mockSuggestedColors = { - '#009966': 'Green-cyan', - '#8fbc8f': 'Dark sea green', - '#3cb371': 'Medium sea green', - '#00b140': 'Green screen', - '#013220': 'Dark green', - '#6699cc': 'Blue-gray', - '#0000ff': 'Blue', - '#e6e6fa': 'Lavender', - '#9400d3': 'Dark violet', - '#330066': 'Deep violet', - '#808080': 'Gray', - '#36454f': 'Charcoal grey', - '#f7e7ce': 'Champagne', - '#c21e56': 'Rose red', - '#cc338b': 'Magenta-pink', - '#dc143c': 'Crimson', - '#ff0000': 'Red', - '#cd5b45': 'Dark coral', - '#eee600': 'Titanium yellow', - '#ed9121': 'Carrot orange', - '#c39953': 'Aztec Gold', -}; - export const createLabelSuccessfulResponse = { data: { labelCreate: { diff --git a/spec/frontend/sidebar/components/mock_data.js b/spec/frontend/sidebar/components/mock_data.js index a9a00b3cfdf1e1653591b8c64b1558ac5c2612bb..b1b52674eb5061af89504738e8e01eaaa6167e8b 100644 --- a/spec/frontend/sidebar/components/mock_data.js +++ b/spec/frontend/sidebar/components/mock_data.js @@ -56,3 +56,27 @@ export const issueCrmContactsUpdateResponse = { }, }, }; + +export const mockSuggestedColors = { + '#009966': 'Green-cyan', + '#8fbc8f': 'Dark sea green', + '#3cb371': 'Medium sea green', + '#00b140': 'Green screen', + '#013220': 'Dark green', + '#6699cc': 'Blue-gray', + '#0000ff': 'Blue', + '#e6e6fa': 'Lavender', + '#9400d3': 'Dark violet', + '#330066': 'Deep violet', + '#808080': 'Gray', + '#36454f': 'Charcoal grey', + '#f7e7ce': 'Champagne', + '#c21e56': 'Rose red', + '#cc338b': 'Magenta-pink', + '#dc143c': 'Crimson', + '#ff0000': 'Red', + '#cd5b45': 'Dark coral', + '#eee600': 'Titanium yellow', + '#ed9121': 'Carrot orange', + '#c39953': 'Aztec Gold', +}; diff --git a/spec/frontend/sidebar/components/sidebar_color_picker_spec.js b/spec/frontend/sidebar/components/sidebar_color_picker_spec.js new file mode 100644 index 0000000000000000000000000000000000000000..7ce556fe36899a2a3b6571623545c598d9bc6475 --- /dev/null +++ b/spec/frontend/sidebar/components/sidebar_color_picker_spec.js @@ -0,0 +1,58 @@ +import { GlFormInput, GlLink } from '@gitlab/ui'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import SibebarColorPicker from '~/sidebar/components/sidebar_color_picker.vue'; +import { mockSuggestedColors } from './mock_data'; + +describe('SibebarColorPicker', () => { + let wrapper; + const findAllColors = () => wrapper.findAllComponents(GlLink); + const findFirstColor = () => findAllColors().at(0); + const findColorPicker = () => wrapper.findComponent(GlFormInput); + const findColorPickerText = () => wrapper.findByTestId('selected-color-text'); + + const createComponent = ({ value = '' } = {}) => { + wrapper = shallowMountExtended(SibebarColorPicker, { + propsData: { + value, + }, + }); + }; + + beforeEach(() => { + gon.suggested_label_colors = mockSuggestedColors; + }); + + it('renders a palette of 21 colors', () => { + createComponent(); + expect(findAllColors()).toHaveLength(21); + }); + + it('renders value of the color in textbox', () => { + createComponent({ value: '#343434' }); + expect(findColorPickerText().attributes('value')).toBe('#343434'); + }); + + describe('color picker', () => { + beforeEach(() => { + createComponent(); + }); + + it('emits color on click of suggested color link', () => { + findFirstColor().vm.$emit('click', new Event('mouseclick')); + + expect(wrapper.emitted('input')).toEqual([['#009966']]); + }); + + it('emits color on selecting color from picker', () => { + findColorPicker().vm.$emit('input', '#ffffff'); + + expect(wrapper.emitted('input')).toEqual([['#ffffff']]); + }); + + it('emits color on typing the hex code in the input', () => { + findColorPickerText().vm.$emit('input', '#000000'); + + expect(wrapper.emitted('input')).toEqual([['#000000']]); + }); + }); +});