diff --git a/app/assets/javascripts/issues/list/index.js b/app/assets/javascripts/issues/list/index.js index 60dded566c6d13d5a4e881dfd94a3229bfc06c53..8bbb77d11a2bd354a55d5f35d27ad05d3f812996 100644 --- a/app/assets/javascripts/issues/list/index.js +++ b/app/assets/javascripts/issues/list/index.js @@ -84,6 +84,7 @@ export async function mountIssuesListApp() { emailsHelpPagePath, exportCsvPath, fullPath, + groupId, groupPath, hasAnyIssues, hasAnyProjects, @@ -113,10 +114,10 @@ export async function mountIssuesListApp() { rssPath, showNewIssueLink, signInPath, - groupId = '', - reportAbusePath, - registerPath, - issuesListPath, + wiCanAdminLabel, + wiIssuesListPath, + wiLabelsManagePath, + wiReportAbusePath, } = el.dataset; return new Vue({ @@ -155,10 +156,8 @@ export async function mountIssuesListApp() { canReadCrmContact: parseBoolean(canReadCrmContact), canReadCrmOrganization: parseBoolean(canReadCrmOrganization), fullPath, - projectPath: fullPath, + groupId, groupPath, - reportAbusePath, - registerPath, hasAnyIssues: parseBoolean(hasAnyIssues), hasAnyProjects: parseBoolean(hasAnyProjects), hasBlockedIssuesFeature: parseBoolean(hasBlockedIssuesFeature), @@ -197,8 +196,11 @@ export async function mountIssuesListApp() { markdownHelpPath, quickActionsHelpPath, resetPath, - groupId, - issuesListPath, + // For work item modal + canAdminLabel: wiCanAdminLabel, + issuesListPath: wiIssuesListPath, + labelsManagePath: wiLabelsManagePath, + reportAbusePath: wiReportAbusePath, }, render: (createComponent) => createComponent(IssuesListApp), }); diff --git a/app/assets/javascripts/sidebar/components/sidebar_color_picker.vue b/app/assets/javascripts/sidebar/components/sidebar_color_picker.vue index dde2ed679c6bf584b83127d51f68febe70bd4bfa..f4e4d6e856ec1111137d4921928aae7bc8eac2ae 100644 --- a/app/assets/javascripts/sidebar/components/sidebar_color_picker.vue +++ b/app/assets/javascripts/sidebar/components/sidebar_color_picker.vue @@ -66,23 +66,23 @@ export default { <template> <div> <div - class="suggested-colors gl-display-flex gl-justify-content-space-between gl-flex-wrap gl-gap-2" + class="suggested-colors gl-grid gl-grid-cols-[repeat(auto-fill,2rem)] gl-justify-between gl-gap-2" > <gl-link v-for="(color, index) in suggestedColors" :key="index" v-gl-tooltip:tooltipcontainer - class="gl-block color-palette" + class="gl-block gl-h-7 gl-w-7 gl-rounded-base" :style="getStyle(color)" :title="getColorName(color)" @click.prevent="handleColorClick(getColorCode(color))" /> </div> - <div class="gl-display-flex"> - <gl-form-group class="gl-mb-0!"> + <div class="gl-flex"> + <gl-form-group class="gl-mb-0"> <gl-form-input v-model.trim="selectedColor" - class="-gl-mr-1 gl-mb-2 gl-w-8" + class="-gl-mr-1 gl-w-8 gl-rounded-e-none" type="color" :value="selectedColor" :placeholder="__('Select color')" @@ -92,11 +92,11 @@ export default { <gl-form-group :invalid-feedback="errorMessage" :state="validColor" - class="gl-mb-0! gl-flex-grow-1" + class="gl-mb-0 gl-flex-grow-1" > <gl-form-input v-model.trim="selectedColor" - class="gl-rounded-top-left-none gl-rounded-bottom-left-none gl-mb-2" + class="gl-rounded-s-none gl-mb-2" :placeholder="__('Use custom color #FF0000')" :autofocus="autofocus" :state="validColor" diff --git a/app/assets/javascripts/work_items/components/shared/work_item_sidebar_dropdown_widget.vue b/app/assets/javascripts/work_items/components/shared/work_item_sidebar_dropdown_widget.vue index 14250e2fa0607bf13ad4928a79ee976c66463583..4926934026e51c76dae59f9fcd25b2cb39c9a56f 100644 --- a/app/assets/javascripts/work_items/components/shared/work_item_sidebar_dropdown_widget.vue +++ b/app/assets/javascripts/work_items/components/shared/work_item_sidebar_dropdown_widget.vue @@ -218,6 +218,7 @@ export default { <gl-collapsible-listbox :id="inputId" ref="listbox" + class="work-item-sidebar-dropdown" :multiple="multiSelect" :searchable="searchable" start-opened @@ -233,7 +234,6 @@ export default { :selected="localSelectedItem" :reset-button-label="resetButton" :infinite-scroll-loading="infiniteScrollLoading" - toggle-class="work-item-sidebar-dropdown-toggle" @reset="unassignValue" @search="debouncedSearchKeyUpdate" @select="handleItemClick" diff --git a/app/assets/javascripts/work_items/components/work_item_labels.vue b/app/assets/javascripts/work_items/components/work_item_labels.vue index adb85e5e873cd752bb7e53f3daebe975484eee72..1d9057af3788f61af14f3d949ce243cc17289521 100644 --- a/app/assets/javascripts/work_items/components/work_item_labels.vue +++ b/app/assets/javascripts/work_items/components/work_item_labels.vue @@ -110,6 +110,12 @@ export default { allowsScopedLabels() { return this.labelsWidget?.allowsScopedLabels; }, + createLabelText() { + return this.isGroup ? __('Create group label') : __('Create project label'); + }, + manageLabelText() { + return this.isGroup ? __('Manage group labels') : __('Manage project labels'); + }, workspaceType() { return this.isGroup ? WORKSPACE_GROUP : WORKSPACE_PROJECT; }, @@ -282,23 +288,28 @@ export default { class="!gl-justify-start" block category="tertiary" - data-testid="create-project-label" + data-testid="create-label" @click="showLabelForm = true" > - {{ __('Create project label') }} + {{ createLabelText }} </gl-button> <gl-button class="!gl-justify-start !gl-mt-2" block category="tertiary" :href="labelsManagePath" - data-testid="manage-project-labels" + data-testid="manage-labels" > - {{ __('Manage project labels') }} + {{ manageLabelText }} </gl-button> </template> <template v-if="showLabelForm" #body> - <gl-disclosure-dropdown block start-opened :toggle-text="dropdownText"> + <gl-disclosure-dropdown + class="work-item-sidebar-dropdown" + block + start-opened + :toggle-text="dropdownText" + > <div class="gl-text-sm gl-font-bold gl-leading-24 gl-border-b gl-pt-2 gl-pb-3 gl-pl-4 gl-mb-4" > diff --git a/app/assets/javascripts/work_items/components/work_item_parent.vue b/app/assets/javascripts/work_items/components/work_item_parent.vue index bb3327d91f01476ebd9d35bb3b70cce78e1ea3bd..c659679d46f7f28064129117bc01684c3a929886 100644 --- a/app/assets/javascripts/work_items/components/work_item_parent.vue +++ b/app/assets/javascripts/work_items/components/work_item_parent.vue @@ -258,7 +258,7 @@ export default { <gl-collapsible-listbox id="$options.inputId" ref="input" - class="gl-block" + class="work-item-sidebar-dropdown gl-block" data-testid="work-item-parent-listbox" block searchable @@ -266,7 +266,6 @@ export default { is-check-centered category="primary" fluid-width - toggle-class="work-item-sidebar-dropdown-toggle" positioning-strategy="fixed" :searching="isLoading" :header-text="$options.i18n.assignParentLabel" diff --git a/app/assets/stylesheets/page_bundles/work_items.scss b/app/assets/stylesheets/page_bundles/work_items.scss index 6c1fdec71479bfea8e9e3aeb20a8868afefd0ff0..2b43a5ad7d77048b6c65acb3bc933d61b4477f5f 100644 --- a/app/assets/stylesheets/page_bundles/work_items.scss +++ b/app/assets/stylesheets/page_bundles/work_items.scss @@ -345,12 +345,7 @@ $disclosure-hierarchy-chevron-dimension: 1.2rem; } } -/** Ideally should be fixed in gitlab-ui but fixing it using classes for now **/ -.work-item-sidebar-dropdown-toggle { - justify-content: start !important; -} - -.work-item-sidebar-dropdown-toggle ~ .gl-new-dropdown-panel { +.work-item-sidebar-dropdown .gl-new-dropdown-panel { width: 100% !important; max-width: 19rem !important; } diff --git a/app/assets/stylesheets/pages/colors.scss b/app/assets/stylesheets/pages/colors.scss index c9952fbcc7ae8999aa2d3263e96612ab70c7357d..8cbf3e8cbb85e9983dcb13ea4cbd744146fbd0c8 100644 --- a/app/assets/stylesheets/pages/colors.scss +++ b/app/assets/stylesheets/pages/colors.scss @@ -67,7 +67,7 @@ &:nth-of-type(7) { border-top-right-radius: $gl-border-radius-base; } - + &:nth-last-child(7) { border-bottom-left-radius: $gl-border-radius-base; } @@ -78,11 +78,3 @@ } } } - -.suggested-colors { - .color-palette { - width: 28px; - height: 28px; - border-radius: 2px; - } -} diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index b1efa39fba10e1813d6e663b51715a95a9fdf460..36a61487a8ea519708dc70a475cddaf0fe0b1233 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -136,6 +136,7 @@ def common_issues_list_data(namespace, current_user) autocomplete_award_emojis_path: autocomplete_award_emojis_path, calendar_path: url_for(safe_params.merge(calendar_url_options)), full_path: namespace.full_path, + has_issue_date_filter_feature: has_issue_date_filter_feature?(namespace, current_user).to_s, initial_sort: current_user&.user_preference&.issues_sort, is_issue_repositioning_disabled: issue_repositioning_disabled?.to_s, is_public_visibility_restricted: @@ -143,7 +144,7 @@ def common_issues_list_data(namespace, current_user) is_signed_in: current_user.present?.to_s, rss_path: url_for(safe_params.merge(rss_url_options)), sign_in_path: new_user_session_path, - has_issue_date_filter_feature: has_issue_date_filter_feature?(namespace, current_user).to_s + wi: work_items_show_data(namespace) } end @@ -179,10 +180,7 @@ def project_issues_list_data(project, current_user) quick_actions_help_path: help_page_path('user/project/quick_actions'), releases_path: project_releases_path(project, format: :json), reset_path: new_issuable_address_project_path(project, issuable_type: 'issue'), - show_new_issue_link: show_new_issue_link?(project).to_s, - report_abuse_path: add_category_abuse_reports_path, - register_path: new_user_registration_path(redirect_to_referer: 'yes'), - issues_list_path: project_issues_path(project) + show_new_issue_link: show_new_issue_link?(project).to_s ) end @@ -191,11 +189,10 @@ def group_issues_list_data(group, current_user) can_create_projects: can?(current_user, :create_projects, group).to_s, can_read_crm_contact: can?(current_user, :read_crm_contact, group).to_s, can_read_crm_organization: can?(current_user, :read_crm_organization, group).to_s, + group_id: group.id, has_any_issues: @has_issues.to_s, has_any_projects: @has_projects.to_s, - new_project_path: new_project_path(namespace_id: group.id), - group_id: group.id, - issues_list_path: issues_group_path(group) + new_project_path: new_project_path(namespace_id: group.id) ) end diff --git a/ee/app/assets/javascripts/work_items/components/work_item_color.vue b/ee/app/assets/javascripts/work_items/components/work_item_color.vue index ea32784aedd71328cb99559892ce26c1448977d5..f2c7c5fc7ad9ed4e2ad60c65153784fbf417c33c 100644 --- a/ee/app/assets/javascripts/work_items/components/work_item_color.vue +++ b/ee/app/assets/javascripts/work_items/components/work_item_color.vue @@ -231,6 +231,7 @@ export default { </div> <gl-disclosure-dropdown :id="$options.inputId" + class="work-item-sidebar-dropdown" category="tertiary" :auto-close="false" start-opened @@ -265,7 +266,7 @@ export default { :autofocus="true" :suggested-colors="$options.suggestedColors" :error-message="errorMessage" - class="gl-px-2 gl-mt-2" + class="gl-px-3 gl-mt-3" /> </gl-disclosure-dropdown-item> </gl-disclosure-dropdown> diff --git a/spec/frontend/work_items/components/work_item_labels_spec.js b/spec/frontend/work_items/components/work_item_labels_spec.js index 2a4d90ce7cc375bfe7a5a893fb254db9e195f576..a8982ac76cd20ec0a850412c7ac5922ab1fc9b41 100644 --- a/spec/frontend/work_items/components/work_item_labels_spec.js +++ b/spec/frontend/work_items/components/work_item_labels_spec.js @@ -109,6 +109,8 @@ describe('WorkItemLabels component', () => { const findRegularLabel = () => findAllLabels().at(0); const findLabelWithDescription = () => findAllLabels().at(2); const findDropdownContentsCreateView = () => wrapper.findComponent(DropdownContentsCreateView); + const findCreateLabelButton = () => wrapper.findByTestId('create-label'); + const findManageLabelsButton = () => wrapper.findByTestId('manage-labels'); const showDropdown = () => { findWorkItemSidebarDropdownWidget().vm.$emit('dropdownShown'); @@ -422,71 +424,94 @@ describe('WorkItemLabels component', () => { }); }); - describe('creating project label', () => { - beforeEach(async () => { - createComponent(); + describe('create/manage label buttons', () => { + describe('when project context', () => { + beforeEach(() => { + createComponent({ isGroup: false }); + }); - wrapper.findByTestId('create-project-label').vm.$emit('click'); - await nextTick(); - }); + it('renders "Create project label" button', () => { + expect(findCreateLabelButton().text()).toBe('Create project label'); + }); - describe('when "Create project label" button is clicked', () => { - it('renders "Create label" dropdown', () => { - expect(findDisclosureDropdown().props()).toMatchObject({ - block: true, - startOpened: true, - toggleText: 'No labels', - }); - expect(findDropdownContentsCreateView().props()).toEqual({ - attrWorkspacePath: 'test-project-path', - fullPath: 'test-project-path', - labelCreateType: 'project', - searchKey: '', - workspaceType: 'project', - }); + it('renders "Manage project labels" link', () => { + expect(findManageLabelsButton().text()).toBe('Manage project labels'); + expect(findManageLabelsButton().attributes('href')).toBe('test-project-path/labels'); }); }); - describe('when "hideCreateView" event is emitted', () => { - it('hides dropdown', async () => { - expect(findDisclosureDropdown().exists()).toBe(true); - expect(findDropdownContentsCreateView().exists()).toBe(true); + describe('when group context', () => { + beforeEach(() => { + createComponent({ isGroup: true }); + }); - findDropdownContentsCreateView().vm.$emit('hideCreateView'); - await nextTick(); + it('renders "Create group label" button', () => { + expect(findCreateLabelButton().text()).toBe('Create group label'); + }); - expect(findDisclosureDropdown().exists()).toBe(false); - expect(findDropdownContentsCreateView().exists()).toBe(false); + it('renders "Manage group labels" link', () => { + expect(findManageLabelsButton().text()).toBe('Manage group labels'); + expect(findManageLabelsButton().attributes('href')).toBe('test-project-path/labels'); }); }); - describe('when "labelCreated" event is emitted', () => { - it('updates "createdLabelId" value and hides dropdown', async () => { - expect(findWorkItemSidebarDropdownWidget().props('createdLabelId')).toBe(undefined); - expect(findDisclosureDropdown().exists()).toBe(true); - expect(findDropdownContentsCreateView().exists()).toBe(true); + describe('creating project label', () => { + beforeEach(async () => { + createComponent(); - findDropdownContentsCreateView().vm.$emit('labelCreated', { - id: 'gid://gitlab/Label/55', - name: 'New label', - }); + findCreateLabelButton().vm.$emit('click'); await nextTick(); + }); - expect(findWorkItemSidebarDropdownWidget().props('createdLabelId')).toBe( - 'gid://gitlab/Label/55', - ); - expect(findDisclosureDropdown().exists()).toBe(false); - expect(findDropdownContentsCreateView().exists()).toBe(false); + describe('when "Create project label" button is clicked', () => { + it('renders "Create label" dropdown', () => { + expect(findDisclosureDropdown().props()).toMatchObject({ + block: true, + startOpened: true, + toggleText: 'No labels', + }); + expect(findDropdownContentsCreateView().props()).toEqual({ + attrWorkspacePath: 'test-project-path', + fullPath: 'test-project-path', + labelCreateType: 'project', + searchKey: '', + workspaceType: 'project', + }); + }); }); - }); - }); - it('renders "Manage project labels" link in dropdown', () => { - createComponent(); + describe('when "hideCreateView" event is emitted', () => { + it('hides dropdown', async () => { + expect(findDisclosureDropdown().exists()).toBe(true); + expect(findDropdownContentsCreateView().exists()).toBe(true); - expect(wrapper.findByTestId('manage-project-labels').text()).toBe('Manage project labels'); - expect(wrapper.findByTestId('manage-project-labels').attributes('href')).toBe( - 'test-project-path/labels', - ); + findDropdownContentsCreateView().vm.$emit('hideCreateView'); + await nextTick(); + + expect(findDisclosureDropdown().exists()).toBe(false); + expect(findDropdownContentsCreateView().exists()).toBe(false); + }); + }); + + describe('when "labelCreated" event is emitted', () => { + it('updates "createdLabelId" value and hides dropdown', async () => { + expect(findWorkItemSidebarDropdownWidget().props('createdLabelId')).toBe(undefined); + expect(findDisclosureDropdown().exists()).toBe(true); + expect(findDropdownContentsCreateView().exists()).toBe(true); + + findDropdownContentsCreateView().vm.$emit('labelCreated', { + id: 'gid://gitlab/Label/55', + name: 'New label', + }); + await nextTick(); + + expect(findWorkItemSidebarDropdownWidget().props('createdLabelId')).toBe( + 'gid://gitlab/Label/55', + ); + expect(findDisclosureDropdown().exists()).toBe(false); + expect(findDropdownContentsCreateView().exists()).toBe(false); + }); + }); + }); }); });