Commit a3889650 authored by David O'Regan's avatar David O'Regan

Merge branch '287755-make-alert-details-sidebar-components-reuseable' into 'master'

Remove/Override .right-sidebar influence

See merge request gitlab-org/gitlab!60960
parents cfb83973 5ddc506c
...@@ -64,6 +64,7 @@ export default { ...@@ -64,6 +64,7 @@ export default {
<sidebar-status <sidebar-status
:project-path="projectPath" :project-path="projectPath"
:alert="alert" :alert="alert"
:sidebar-collapsed="sidebarStatus"
@toggle-sidebar="$emit('toggle-sidebar')" @toggle-sidebar="$emit('toggle-sidebar')"
@alert-error="$emit('alert-error', $event)" @alert-error="$emit('alert-error', $event)"
/> />
......
...@@ -192,21 +192,34 @@ export default { ...@@ -192,21 +192,34 @@ export default {
</script> </script>
<template> <template>
<div class="block alert-assignees"> <div
<div ref="assignees" class="sidebar-collapsed-icon" @click="$emit('toggle-sidebar')"> class="alert-assignees gl-py-5 gl-w-70p"
<gl-icon name="user" :size="14" /> :class="{ 'gl-border-b-1 gl-border-b-solid gl-border-b-gray-100': !sidebarCollapsed }"
<gl-loading-icon v-if="isUpdating" /> style="width: 70%"
</div> >
<gl-tooltip :target="() => $refs.assignees" boundary="viewport" placement="left"> <template v-if="sidebarCollapsed">
<gl-sprintf :message="$options.i18n.ASSIGNEES_BLOCK"> <div
<template #assignees> ref="assignees"
{{ userName }} class="gl-mb-6 gl-ml-6"
</template> data-testid="assignees-icon"
</gl-sprintf> @click="$emit('toggle-sidebar')"
</gl-tooltip> >
<gl-icon name="user" />
<gl-loading-icon v-if="isUpdating" />
</div>
<gl-tooltip :target="() => $refs.assignees" boundary="viewport" placement="left">
<gl-sprintf :message="$options.i18n.ASSIGNEES_BLOCK">
<template #assignees>
{{ userName }}
</template>
</gl-sprintf>
</gl-tooltip>
</template>
<div class="hide-collapsed"> <div v-else>
<p class="title gl-display-flex gl-justify-content-space-between"> <p
class="gl-text-gray-900 gl-mb-2 gl-line-height-20 gl-display-flex gl-justify-content-space-between"
>
{{ __('Assignee') }} {{ __('Assignee') }}
<a <a
v-if="isEditable" v-if="isEditable"
......
...@@ -25,7 +25,7 @@ export default { ...@@ -25,7 +25,7 @@ export default {
</script> </script>
<template> <template>
<div class="block gl-display-flex gl-justify-content-space-between"> <div class="block gl-display-flex gl-justify-content-space-between gl-border-b-gray-100!">
<span class="issuable-header-text hide-collapsed"> <span class="issuable-header-text hide-collapsed">
{{ __('To Do') }} {{ __('To Do') }}
</span> </span>
......
...@@ -30,6 +30,10 @@ export default { ...@@ -30,6 +30,10 @@ export default {
required: false, required: false,
default: true, default: true,
}, },
sidebarCollapsed: {
type: Boolean,
required: false,
},
}, },
data() { data() {
return { return {
...@@ -61,21 +65,29 @@ export default { ...@@ -61,21 +65,29 @@ export default {
</script> </script>
<template> <template>
<div class="block alert-status"> <div
<div ref="status" class="sidebar-collapsed-icon" @click="$emit('toggle-sidebar')"> class="alert-status gl-py-5 gl-w-70p"
<gl-icon name="status" :size="14" /> :class="{ 'gl-border-b-1 gl-border-b-solid gl-border-b-gray-100': !sidebarCollapsed }"
<gl-loading-icon v-if="isUpdating" /> style="width: 70%"
</div> >
<gl-tooltip :target="() => $refs.status" boundary="viewport" placement="left"> <template v-if="sidebarCollapsed">
<gl-sprintf :message="s__('AlertManagement|Alert status: %{status}')"> <div ref="status" class="gl-ml-6" data-testid="status-icon" @click="$emit('toggle-sidebar')">
<template #status> <gl-icon name="status" />
{{ alert.status.toLowerCase() }} <gl-loading-icon v-if="isUpdating" />
</template> </div>
</gl-sprintf> <gl-tooltip :target="() => $refs.status" boundary="viewport" placement="left">
</gl-tooltip> <gl-sprintf :message="s__('AlertManagement|Alert status: %{status}')">
<template #status>
{{ alert.status.toLowerCase() }}
</template>
</gl-sprintf>
</gl-tooltip>
</template>
<div class="hide-collapsed"> <div v-else>
<p class="title gl-display-flex justify-content-between"> <p
class="gl-text-gray-900 gl-mb-2 gl-line-height-20 gl-display-flex gl-justify-content-space-between"
>
{{ s__('AlertManagement|Status') }} {{ s__('AlertManagement|Status') }}
<a <a
v-if="isEditable" v-if="isEditable"
......
...@@ -134,7 +134,12 @@ export default { ...@@ -134,7 +134,12 @@ export default {
</script> </script>
<template> <template>
<div :class="{ 'block todo': sidebarCollapsed, 'gl-ml-auto': !sidebarCollapsed }"> <div
:class="{
'block todo': sidebarCollapsed,
'gl-ml-auto': !sidebarCollapsed,
}"
>
<todo <todo
data-testid="alert-todo-button" data-testid="alert-todo-button"
:collapsed="sidebarCollapsed" :collapsed="sidebarCollapsed"
......
---
title: Refactor alert details sidebar CSS
merge_request: 60960
author:
type: other
import { GlDropdownItem } from '@gitlab/ui'; import { GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import axios from 'axios'; import axios from 'axios';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import SidebarAssignee from '~/vue_shared/alert_details/components/sidebar/sidebar_assignee.vue'; import SidebarAssignee from '~/vue_shared/alert_details/components/sidebar/sidebar_assignee.vue';
import SidebarAssignees from '~/vue_shared/alert_details/components/sidebar/sidebar_assignees.vue'; import SidebarAssignees from '~/vue_shared/alert_details/components/sidebar/sidebar_assignees.vue';
import AlertSetAssignees from '~/vue_shared/alert_details/graphql/mutations/alert_set_assignees.mutation.graphql'; import AlertSetAssignees from '~/vue_shared/alert_details/graphql/mutations/alert_set_assignees.mutation.graphql';
...@@ -13,6 +13,29 @@ describe('Alert Details Sidebar Assignees', () => { ...@@ -13,6 +13,29 @@ describe('Alert Details Sidebar Assignees', () => {
let wrapper; let wrapper;
let mock; let mock;
const mockPath = '/-/autocomplete/users.json';
const mockUsers = [
{
avatar_url:
'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
id: 1,
name: 'User 1',
username: 'root',
},
{
avatar_url:
'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
id: 2,
name: 'User 2',
username: 'not-root',
},
];
const findAssigned = () => wrapper.findByTestId('assigned-users');
const findDropdown = () => wrapper.findComponent(GlDropdownItem);
const findSidebarIcon = () => wrapper.findByTestId('assignees-icon');
const findUnassigned = () => wrapper.findByTestId('unassigned-users');
function mountComponent({ function mountComponent({
data, data,
users = [], users = [],
...@@ -21,7 +44,7 @@ describe('Alert Details Sidebar Assignees', () => { ...@@ -21,7 +44,7 @@ describe('Alert Details Sidebar Assignees', () => {
loading = false, loading = false,
stubs = {}, stubs = {},
} = {}) { } = {}) {
wrapper = shallowMount(SidebarAssignees, { wrapper = shallowMountExtended(SidebarAssignees, {
data() { data() {
return { return {
users, users,
...@@ -56,10 +79,7 @@ describe('Alert Details Sidebar Assignees', () => { ...@@ -56,10 +79,7 @@ describe('Alert Details Sidebar Assignees', () => {
mock.restore(); mock.restore();
}); });
const findAssigned = () => wrapper.find('[data-testid="assigned-users"]'); describe('sidebar expanded', () => {
const findUnassigned = () => wrapper.find('[data-testid="unassigned-users"]');
describe('updating the alert status', () => {
const mockUpdatedMutationResult = { const mockUpdatedMutationResult = {
data: { data: {
alertSetAssignees: { alertSetAssignees: {
...@@ -73,30 +93,13 @@ describe('Alert Details Sidebar Assignees', () => { ...@@ -73,30 +93,13 @@ describe('Alert Details Sidebar Assignees', () => {
beforeEach(() => { beforeEach(() => {
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
const path = '/-/autocomplete/users.json';
const users = [
{
avatar_url:
'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
id: 1,
name: 'User 1',
username: 'root',
},
{
avatar_url:
'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
id: 2,
name: 'User 2',
username: 'not-root',
},
];
mock.onGet(path).replyOnce(200, users); mock.onGet(mockPath).replyOnce(200, mockUsers);
mountComponent({ mountComponent({
data: { alert: mockAlert }, data: { alert: mockAlert },
sidebarCollapsed: false, sidebarCollapsed: false,
loading: false, loading: false,
users, users: mockUsers,
stubs: { stubs: {
SidebarAssignee, SidebarAssignee,
}, },
...@@ -106,7 +109,11 @@ describe('Alert Details Sidebar Assignees', () => { ...@@ -106,7 +109,11 @@ describe('Alert Details Sidebar Assignees', () => {
it('renders a unassigned option', async () => { it('renders a unassigned option', async () => {
wrapper.setData({ isDropdownSearching: false }); wrapper.setData({ isDropdownSearching: false });
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
expect(wrapper.find(GlDropdownItem).text()).toBe('Unassigned'); expect(findDropdown().text()).toBe('Unassigned');
});
it('does not display the collapsed sidebar icon', () => {
expect(findSidebarIcon().exists()).toBe(false);
}); });
it('calls `$apollo.mutate` with `AlertSetAssignees` mutation and variables containing `iid`, `assigneeUsernames`, & `projectPath`', async () => { it('calls `$apollo.mutate` with `AlertSetAssignees` mutation and variables containing `iid`, `assigneeUsernames`, & `projectPath`', async () => {
...@@ -170,4 +177,28 @@ describe('Alert Details Sidebar Assignees', () => { ...@@ -170,4 +177,28 @@ describe('Alert Details Sidebar Assignees', () => {
expect(findAssigned().find('.dropdown-menu-user-username').text()).toBe('@root'); expect(findAssigned().find('.dropdown-menu-user-username').text()).toBe('@root');
}); });
}); });
describe('sidebar collapsed', () => {
beforeEach(() => {
mock = new MockAdapter(axios);
mock.onGet(mockPath).replyOnce(200, mockUsers);
mountComponent({
data: { alert: mockAlert },
loading: false,
users: mockUsers,
stubs: {
SidebarAssignee,
},
});
});
it('does not display the status dropdown', () => {
expect(findDropdown().exists()).toBe(false);
});
it('does display the collapsed sidebar icon', () => {
expect(findSidebarIcon().exists()).toBe(true);
});
});
}); });
import { GlDropdown, GlDropdownItem, GlLoadingIcon } from '@gitlab/ui'; import { GlDropdown, GlDropdownItem, GlLoadingIcon } from '@gitlab/ui';
import { mount } from '@vue/test-utils'; import { mountExtended } from 'helpers/vue_test_utils_helper';
import updateAlertStatusMutation from '~/graphql_shared/mutations/alert_status_update.mutation.graphql'; import updateAlertStatusMutation from '~/graphql_shared/mutations/alert_status_update.mutation.graphql';
import AlertStatus from '~/vue_shared/alert_details/components/alert_status.vue'; import AlertStatus from '~/vue_shared/alert_details/components/alert_status.vue';
import AlertSidebarStatus from '~/vue_shared/alert_details/components/sidebar/sidebar_status.vue'; import AlertSidebarStatus from '~/vue_shared/alert_details/components/sidebar/sidebar_status.vue';
...@@ -13,9 +13,10 @@ describe('Alert Details Sidebar Status', () => { ...@@ -13,9 +13,10 @@ describe('Alert Details Sidebar Status', () => {
const findStatusDropdown = () => wrapper.find(GlDropdown); const findStatusDropdown = () => wrapper.find(GlDropdown);
const findStatusDropdownItem = () => wrapper.find(GlDropdownItem); const findStatusDropdownItem = () => wrapper.find(GlDropdownItem);
const findStatusLoadingIcon = () => wrapper.find(GlLoadingIcon); const findStatusLoadingIcon = () => wrapper.find(GlLoadingIcon);
const findStatusDropdownHeader = () => wrapper.find('[data-testid="dropdown-header"]'); const findStatusDropdownHeader = () => wrapper.findByTestId('dropdown-header');
const findAlertStatus = () => wrapper.findComponent(AlertStatus); const findAlertStatus = () => wrapper.findComponent(AlertStatus);
const findStatus = () => wrapper.find('[data-testid="status"]'); const findStatus = () => wrapper.findByTestId('status');
const findSidebarIcon = () => wrapper.findByTestId('status-icon');
function mountComponent({ function mountComponent({
data, data,
...@@ -24,7 +25,7 @@ describe('Alert Details Sidebar Status', () => { ...@@ -24,7 +25,7 @@ describe('Alert Details Sidebar Status', () => {
stubs = {}, stubs = {},
provide = {}, provide = {},
} = {}) { } = {}) {
wrapper = mount(AlertSidebarStatus, { wrapper = mountExtended(AlertSidebarStatus, {
propsData: { propsData: {
alert: { ...mockAlert }, alert: { ...mockAlert },
...data, ...data,
...@@ -52,7 +53,7 @@ describe('Alert Details Sidebar Status', () => { ...@@ -52,7 +53,7 @@ describe('Alert Details Sidebar Status', () => {
} }
}); });
describe('Alert Sidebar Dropdown Status', () => { describe('sidebar expanded', () => {
beforeEach(() => { beforeEach(() => {
mountComponent({ mountComponent({
data: { alert: mockAlert }, data: { alert: mockAlert },
...@@ -69,6 +70,10 @@ describe('Alert Details Sidebar Status', () => { ...@@ -69,6 +70,10 @@ describe('Alert Details Sidebar Status', () => {
expect(findStatusDropdownHeader().exists()).toBe(true); expect(findStatusDropdownHeader().exists()).toBe(true);
}); });
it('does not display the collapsed sidebar icon', () => {
expect(findSidebarIcon().exists()).toBe(false);
});
describe('updating the alert status', () => { describe('updating the alert status', () => {
const mockUpdatedMutationResult = { const mockUpdatedMutationResult = {
data: { data: {
...@@ -109,22 +114,40 @@ describe('Alert Details Sidebar Status', () => { ...@@ -109,22 +114,40 @@ describe('Alert Details Sidebar Status', () => {
expect(findStatusLoadingIcon().exists()).toBe(false); expect(findStatusLoadingIcon().exists()).toBe(false);
expect(findStatus().text()).toBe('Triggered'); expect(findStatus().text()).toBe('Triggered');
}); });
it('renders default translated statuses', () => {
mountComponent({ sidebarCollapsed: false });
expect(findAlertStatus().props('statuses')).toBe(PAGE_CONFIG.OPERATIONS.STATUSES);
expect(findStatus().text()).toBe('Triggered');
});
it('renders translated statuses', () => {
const status = 'TEST';
const statuses = { [status]: 'Test' };
mountComponent({
data: { alert: { ...mockAlert, status } },
provide: { statuses },
sidebarCollapsed: false,
});
expect(findAlertStatus().props('statuses')).toBe(statuses);
expect(findStatus().text()).toBe(statuses.TEST);
});
}); });
}); });
describe('Statuses', () => { describe('sidebar collapsed', () => {
it('renders default translated statuses', () => { beforeEach(() => {
mountComponent({}); mountComponent({
expect(findAlertStatus().props('statuses')).toBe(PAGE_CONFIG.OPERATIONS.STATUSES); data: { alert: mockAlert },
expect(findStatus().text()).toBe('Triggered'); loading: false,
});
});
it('does not display the status dropdown', () => {
expect(findStatusDropdown().exists()).toBe(false);
}); });
it('renders translated statuses', () => { it('does display the collapsed sidebar icon', () => {
const status = 'TEST'; expect(findSidebarIcon().exists()).toBe(true);
const statuses = { [status]: 'Test' };
mountComponent({ data: { alert: { ...mockAlert, status } }, provide: { statuses } });
expect(findAlertStatus().props('statuses')).toBe(statuses);
expect(findStatus().text()).toBe(statuses.TEST);
}); });
}); });
}); });
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