From f28493b11f1d50c8bc9e1247da5349add5f99dbf Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Tue, 17 Oct 2023 12:29:21 +0200 Subject: [PATCH] feat(NcListItemIcon): Allow to highlight search queries using the email notation Like `J. Doe ` Signed-off-by: Ferdinand Thiessen --- .../NcListItemIcon/NcListItemIcon.vue | 16 ++- .../NcListItemIcon/list-item-icon.spec.ts | 104 ++++++++++++++++++ 2 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 tests/unit/components/NcListItemIcon/list-item-icon.spec.ts diff --git a/src/components/NcListItemIcon/NcListItemIcon.vue b/src/components/NcListItemIcon/NcListItemIcon.vue index 091c152ec5..2fdd69013d 100644 --- a/src/components/NcListItemIcon/NcListItemIcon.vue +++ b/src/components/NcListItemIcon/NcListItemIcon.vue @@ -139,11 +139,11 @@ It might be used for list rendering or within the multiselect for example
+ :search="searchParts[0]" /> + :search="searchParts[1]" /> {{ userStatus.icon }} {{ userStatus.message }} @@ -314,6 +314,18 @@ export default { '--margin': this.margin + 'px', } }, + + /** + * Seperates the search property into two parts, the first one is the search part on the name, the second on the subname. + * @return {[string, string]} + */ + searchParts() { + // Match the email notation like "Jane " with the email address as matching group + const EMAIL_NOTATION = /^([^<]*)<([^>]+)>?$/ + + const match = this.search.match(EMAIL_NOTATION) + return this.isNoUser || !match ? [this.search, this.search] : [match[1].trim(), match[2]] + }, }, beforeMount() { diff --git a/tests/unit/components/NcListItemIcon/list-item-icon.spec.ts b/tests/unit/components/NcListItemIcon/list-item-icon.spec.ts new file mode 100644 index 0000000000..7e3f8710b7 --- /dev/null +++ b/tests/unit/components/NcListItemIcon/list-item-icon.spec.ts @@ -0,0 +1,104 @@ +/** + * @copyright Copyright (c) 2023 Ferdinand Thiessen + * + * @author Ferdinand Thiessen + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +import { shallowMount } from '@vue/test-utils' +import NcListItemIcon from '../../../../src/components/NcListItemIcon/NcListItemIcon.vue' + +describe('NcListItemIcon', () => { + it('highlights the search query', async () => { + const wrapper = shallowMount(NcListItemIcon, { + propsData: { + name: 'J. Doe', + subname: 'privacy@example.com', + search: 'doe', + }, + }) + + const highlights = wrapper.findAllComponents({ name: 'NcHighlight' }) + expect(highlights).toHaveLength(2) + expect(highlights.at(0).props('text')).toBe('J. Doe') + expect(highlights.at(0).props('search')).toBe('doe') + expect(highlights.at(1).props('text')).toBe('privacy@example.com') + expect(highlights.at(1).props('search')).toBe('doe') + }) + + it('highlights the email notation query', async () => { + const wrapper = shallowMount(NcListItemIcon, { + propsData: { + name: 'J. Doe', + subname: 'privacy@example.com', + search: 'Manager ', + }, + }) + + const highlights = wrapper.findAllComponents({ name: 'NcHighlight' }) + expect(highlights).toHaveLength(2) + expect(highlights.at(0).props('search')).toBe('Manager') + expect(highlights.at(1).props('search')).toBe('privacy@example.com') + }) + + it('highlights the email notation query even if only partly typed', async () => { + const wrapper = shallowMount(NcListItemIcon, { + propsData: { + name: 'J. Doe', + subname: 'privacy@example.com', + search: 'Manager { + const wrapper = shallowMount(NcListItemIcon, { + propsData: { + name: 'J. Doe', + subname: 'privacy@example.com', + search: 'Doe <', + }, + }) + + const highlights = wrapper.findAllComponents({ name: 'NcHighlight' }) + expect(highlights).toHaveLength(2) + expect(highlights.at(0).props('search')).toBe('Doe <') + expect(highlights.at(1).props('search')).toBe('Doe <') + }) + + it('does not highlight the email notation query when no user', async () => { + const wrapper = shallowMount(NcListItemIcon, { + propsData: { + name: 'J. Doe', + subname: 'privacy@example.com', + search: 'Doe ', + isNoUser: true, + }, + }) + + const highlights = wrapper.findAllComponents({ name: 'NcHighlight' }) + expect(highlights).toHaveLength(2) + expect(highlights.at(0).props('search')).toBe('Doe ') + expect(highlights.at(1).props('search')).toBe('Doe ') + }) +})