chore: collapse conversation sidebar sections (folders, teams, inboxes and labels) - CW-7059 (#14509)
## Description Added ability to collapse conversation sidebar sections (folders, teams, inboxes and labels) Fixes #CW-7059 ## Type of change Please delete options that are not relevant. - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality not to work as expected) - [ ] This change requires a documentation update ## How Has This Been Tested? Tested locally. Added specs. Attaching the loom for them same. https://github.com/user-attachments/assets/40d613e7-6c82-4078-abf4-79739a00f718 ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [ ] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules --------- Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Co-authored-by: iamsivin <iamsivin@gmail.com>
This commit is contained in:
co-authored by
Sivin Varghese
iamsivin
parent
27404b4a27
commit
274e92e0e4
@@ -0,0 +1,172 @@
|
||||
import { mount } from '@vue/test-utils';
|
||||
import { ref } from 'vue';
|
||||
import SidebarSubGroup from '../SidebarSubGroup.vue';
|
||||
import { LOCAL_STORAGE_KEYS } from 'dashboard/constants/localStorage';
|
||||
import { provideSidebarContext } from '../provider';
|
||||
|
||||
vi.mock('dashboard/composables/store', () => ({
|
||||
useMapGetter: () => ref(1),
|
||||
}));
|
||||
|
||||
vi.mock('dashboard/composables/usePolicy', () => ({
|
||||
usePolicy: () => ({
|
||||
shouldShow: () => true,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('vue-router', () => ({
|
||||
useRouter: () => ({
|
||||
resolve: () => ({ path: '/' }),
|
||||
getRoutes: () => [],
|
||||
}),
|
||||
}));
|
||||
|
||||
const children = [
|
||||
{
|
||||
name: 'Sales-1',
|
||||
label: 'Sales',
|
||||
to: { name: 'team_conversations' },
|
||||
},
|
||||
];
|
||||
|
||||
const mountSubGroup = props => {
|
||||
return mount(
|
||||
{
|
||||
components: { SidebarSubGroup },
|
||||
setup() {
|
||||
provideSidebarContext({});
|
||||
},
|
||||
template: '<SidebarSubGroup v-bind="$attrs" />',
|
||||
},
|
||||
{
|
||||
attrs: {
|
||||
name: 'Conversation:Teams',
|
||||
label: 'Teams',
|
||||
icon: 'i-lucide-users',
|
||||
children,
|
||||
isExpanded: true,
|
||||
collapsible: true,
|
||||
...props,
|
||||
},
|
||||
global: {
|
||||
stubs: {
|
||||
SidebarGroupLeaf: {
|
||||
props: {
|
||||
label: { type: String, required: true },
|
||||
hideTreeLine: { type: Boolean, default: false },
|
||||
thinTreeLine: { type: Boolean, default: false },
|
||||
},
|
||||
template:
|
||||
'<li class="sidebar-leaf" :data-hide-tree-line="String(hideTreeLine)" :data-thin-tree-line="String(thinTreeLine)">{{ label }}</li>',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
describe('SidebarSubGroup', () => {
|
||||
let localStorageStore;
|
||||
|
||||
beforeEach(() => {
|
||||
localStorageStore = {};
|
||||
Object.defineProperty(window, 'localStorage', {
|
||||
value: {
|
||||
getItem: key => localStorageStore[key] || null,
|
||||
setItem: (key, value) => {
|
||||
localStorageStore[key] = String(value);
|
||||
},
|
||||
removeItem: key => {
|
||||
delete localStorageStore[key];
|
||||
},
|
||||
clear: () => {
|
||||
localStorageStore = {};
|
||||
},
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
window.localStorage.clear();
|
||||
});
|
||||
|
||||
it('keeps collapsible sections expanded by default', () => {
|
||||
const wrapper = mountSubGroup();
|
||||
|
||||
expect(wrapper.find('button').attributes('aria-expanded')).toBe('true');
|
||||
expect(wrapper.find('.sidebar-leaf').isVisible()).toBe(true);
|
||||
});
|
||||
|
||||
it('renders the tree line on the separator, positioned relative to it', () => {
|
||||
const wrapper = mountSubGroup({ showTreeLine: true });
|
||||
const button = wrapper.find('button');
|
||||
|
||||
expect(button.classes()).toContain('relative');
|
||||
expect(button.classes()).toContain('before:bg-n-slate-4');
|
||||
expect(button.classes()).toContain('before:-bottom-1');
|
||||
});
|
||||
|
||||
it('renders the end curve on the last separator', () => {
|
||||
const wrapper = mountSubGroup({ showTreeLine: true, endTreeLine: true });
|
||||
const button = wrapper.find('button');
|
||||
|
||||
expect(button.classes()).toContain('before:h-3');
|
||||
expect(button.classes()).toContain('after:border-b-2');
|
||||
});
|
||||
|
||||
it('draws nested item tree lines via the leaf connectors', () => {
|
||||
const wrapper = mountSubGroup({ showTreeLine: true });
|
||||
|
||||
expect(
|
||||
wrapper.find('.sidebar-leaf').attributes('data-hide-tree-line')
|
||||
).toBe('false');
|
||||
});
|
||||
|
||||
it('marks nested item connectors as thin', () => {
|
||||
const wrapper = mountSubGroup({ showTreeLine: true });
|
||||
|
||||
expect(
|
||||
wrapper.find('.sidebar-leaf').attributes('data-thin-tree-line')
|
||||
).toBe('true');
|
||||
});
|
||||
|
||||
it('minimizes the section and stores it by account and section name', async () => {
|
||||
const wrapper = mountSubGroup();
|
||||
|
||||
await wrapper.find('button').trigger('click');
|
||||
|
||||
const storedSections = JSON.parse(
|
||||
window.localStorage.getItem(LOCAL_STORAGE_KEYS.SIDEBAR_MINIMIZED_SECTIONS)
|
||||
);
|
||||
expect(wrapper.find('button').attributes('aria-expanded')).toBe('false');
|
||||
expect(wrapper.find('.sidebar-leaf').isVisible()).toBe(false);
|
||||
expect(storedSections).toEqual({ '1:Conversation:Teams': true });
|
||||
});
|
||||
|
||||
it('uses the stored minimized state when mounted again', () => {
|
||||
window.localStorage.setItem(
|
||||
LOCAL_STORAGE_KEYS.SIDEBAR_MINIMIZED_SECTIONS,
|
||||
JSON.stringify({ '1:Conversation:Teams': true })
|
||||
);
|
||||
|
||||
const wrapper = mountSubGroup();
|
||||
|
||||
expect(wrapper.find('button').attributes('aria-expanded')).toBe('false');
|
||||
expect(wrapper.find('.sidebar-leaf').isVisible()).toBe(false);
|
||||
});
|
||||
|
||||
it('expands a stored minimized section when one of its children is active', () => {
|
||||
window.localStorage.setItem(
|
||||
LOCAL_STORAGE_KEYS.SIDEBAR_MINIMIZED_SECTIONS,
|
||||
JSON.stringify({ '1:Conversation:Teams': true })
|
||||
);
|
||||
|
||||
const wrapper = mountSubGroup({ activeChild: children[0] });
|
||||
|
||||
const storedSections = JSON.parse(
|
||||
window.localStorage.getItem(LOCAL_STORAGE_KEYS.SIDEBAR_MINIMIZED_SECTIONS)
|
||||
);
|
||||
expect(wrapper.find('button').attributes('aria-expanded')).toBe('true');
|
||||
expect(wrapper.find('.sidebar-leaf').isVisible()).toBe(true);
|
||||
expect(storedSections).toEqual({});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user