diff options
author | DorraJaouad <dorra.jaoued7@gmail.com> | 2023-07-07 12:27:53 +0200 |
---|---|---|
committer | Maksim Sukharev <antreesy.web@gmail.com> | 2023-08-03 08:28:06 +0200 |
commit | de304d1e3971e248bb6ed7705f9bfa320bdc4055 (patch) | |
tree | 22069486965cb1277731ee418cc84c4144f08116 | |
parent | db952ee33d672335942d83edf483b194ab4f6680 (diff) |
Add open conv list dialog
Signed-off-by: DorraJaouad <dorra.jaoued7@gmail.com>
Improve the open conv list component and fix tests
Signed-off-by: DorraJaouad <dorra.jaoued7@gmail.com>
-rw-r--r-- | src/components/LeftSidebar/LeftSidebar.spec.js | 10 | ||||
-rw-r--r-- | src/components/LeftSidebar/LeftSidebar.vue | 65 | ||||
-rw-r--r-- | src/components/LeftSidebar/NewGroupConversation/NewGroupConversation.vue | 14 | ||||
-rw-r--r-- | src/components/LeftSidebar/OpenConversationsList/OpenConversationsList.vue | 82 | ||||
-rw-r--r-- | src/views/RoomSelector.spec.js | 15 | ||||
-rw-r--r-- | src/views/RoomSelector.vue | 57 |
6 files changed, 197 insertions, 46 deletions
diff --git a/src/components/LeftSidebar/LeftSidebar.spec.js b/src/components/LeftSidebar/LeftSidebar.spec.js index ea73f4faa..ace133521 100644 --- a/src/components/LeftSidebar/LeftSidebar.spec.js +++ b/src/components/LeftSidebar/LeftSidebar.spec.js @@ -13,7 +13,7 @@ import router from '../../__mocks__/router.js' import { searchPossibleConversations, searchListedConversations } from '../../services/conversationsService.js' import { EventBus } from '../../services/EventBus.js' import storeConfig from '../../store/storeConfig.js' -import { findNcListItems } from '../../test-helpers.js' +import { findNcListItems, findNcActionButton } from '../../test-helpers.js' jest.mock('@nextcloud/initial-state', () => ({ loadState: jest.fn(), @@ -709,16 +709,16 @@ describe('LeftSidebar.vue', () => { loadStateSettings.start_conversations = true const wrapper = mountComponent() - const buttonEl = wrapper.findComponent({ name: 'NewGroupConversation' }) - expect(buttonEl.exists()).toBeTruthy() + const newConversationbutton = findNcActionButton(wrapper, 'Create a new conversation') + expect(newConversationbutton.exists()).toBeTruthy() }) test('does not show new conversation button if user cannot start conversations', () => { loadStateSettings.start_conversations = false const wrapper = mountComponent() - const buttonEl = wrapper.findComponent({ name: 'NewGroupConversation' }) - expect(buttonEl.exists()).toBeFalsy() + const newConversationbutton = findNcActionButton(wrapper, 'Create a new conversation') + expect(newConversationbutton.exists()).toBeFalsy() }) }) diff --git a/src/components/LeftSidebar/LeftSidebar.vue b/src/components/LeftSidebar/LeftSidebar.vue index 1d1b67a2c..3f10a2660 100644 --- a/src/components/LeftSidebar/LeftSidebar.vue +++ b/src/components/LeftSidebar/LeftSidebar.vue @@ -35,8 +35,8 @@ @keydown.enter.native="handleEnter" @abort-search="abortSearch" /> - <!-- Options --> - <div class="options" + <!-- Filters --> + <div class="filters" :class="{'hidden-visually': isFocused}"> <NcActions class="filter-actions" :primary="isFiltered !== null"> @@ -75,10 +75,36 @@ </NcActions> </div> - <!-- New Conversation --> - <NewGroupConversation v-if="canStartConversations" - ref="newGroupConversation" - class="new-conversation__button" /> + <!-- Actions --> + <div class="actions"> + <NcActions class="conversations-actions"> + <template #icon> + <DotsVertical :size="20" /> + </template> + <NcActionButton close-after-click + @click="showModalListConversations"> + <template #icon> + <List :size="20" /> + </template> + {{ t('spreed','Join open conversations') }} + </NcActionButton> + + <NcActionButton v-if="canStartConversations" + close-after-click + @click="showModalNewConversation"> + <template #icon> + <Plus :size="20" /> + </template> + {{ t('spreed','Create a new conversation') }} + </NcActionButton> + </NcActions> + </div> + + <!-- All open conversations list --> + <OpenConversationsList ref="openConversationsList" /> + + <!-- New Conversation dialog--> + <NewGroupConversation ref="newGroupConversation" /> </div> <template #list> @@ -96,7 +122,7 @@ <LoadingPlaceholder type="conversations" /> </template> <Hint v-else-if="noMatchFound" - :hint="t('spreed', 'No matches')" /> + :hint="t('spreed', 'No matches found')" /> <template v-if="isSearching"> <template v-if="!listedConversationsLoading && searchResultsListedConversations.length > 0"> <NcAppNavigationCaption :title="t('spreed', 'Open conversations')" /> @@ -182,9 +208,12 @@ import debounce from 'debounce' import AtIcon from 'vue-material-design-icons/At.vue' +import DotsVertical from 'vue-material-design-icons/DotsVertical.vue' import FilterIcon from 'vue-material-design-icons/Filter.vue' import FilterRemoveIcon from 'vue-material-design-icons/FilterRemove.vue' +import List from 'vue-material-design-icons/FormatListBulleted.vue' import MessageBadge from 'vue-material-design-icons/MessageBadge.vue' +import Plus from 'vue-material-design-icons/Plus.vue' import { showError } from '@nextcloud/dialogs' import { emit } from '@nextcloud/event-bus' @@ -203,6 +232,7 @@ import Hint from '../Hint.vue' import LoadingPlaceholder from '../LoadingPlaceholder.vue' import Conversation from './ConversationsList/Conversation.vue' import NewGroupConversation from './NewGroupConversation/NewGroupConversation.vue' +import OpenConversationsList from './OpenConversationsList/OpenConversationsList.vue' import SearchBox from './SearchBox/SearchBox.vue' import { CONVERSATION } from '../../constants.js' @@ -225,6 +255,7 @@ export default { Hint, SearchBox, NewGroupConversation, + OpenConversationsList, Conversation, LoadingPlaceholder, NcListItem, @@ -235,6 +266,9 @@ export default { MessageBadge, FilterIcon, FilterRemoveIcon, + Plus, + List, + DotsVertical, }, mixins: [ @@ -383,6 +417,15 @@ export default { getFocusableList() { return this.$el.querySelectorAll('li.acli_wrapper .acli') }, + + showModalNewConversation() { + this.$refs.newGroupConversation.showModal() + }, + + showModalListConversations() { + this.$refs.openConversationsList.showModal() + }, + setIsFocused(event) { if (event.relatedTarget?.className.includes('input-field__clear-button') || this.searchText !== '') { return @@ -757,19 +800,19 @@ export default { } -.options{ +.filters { position: absolute; right : 52px; // New conversation button's width display: flex; height: var(--default-clickable-area); } -.new-conversation__button{ +.actions { position: absolute; - right: 1px; + right: 5px; } -.filter-actions__button--active{ +.filter-actions__button--active { background-color: var(--color-primary-element-light); border-radius: 6px; :deep(.action-button__longtext){ diff --git a/src/components/LeftSidebar/NewGroupConversation/NewGroupConversation.vue b/src/components/LeftSidebar/NewGroupConversation/NewGroupConversation.vue index 3a5a02958..c6e93eb4d 100644 --- a/src/components/LeftSidebar/NewGroupConversation/NewGroupConversation.vue +++ b/src/components/LeftSidebar/NewGroupConversation/NewGroupConversation.vue @@ -21,15 +21,6 @@ <template> <div class="wrapper"> - <NcButton type="tertiary" - class="toggle" - :aria-label="t('spreed', 'Create a new group conversation')" - :title="t('spreed', 'Create a new group conversation')" - @click="showModal"> - <template #icon> - <Plus :size="20" /> - </template> - </NcButton> <!-- New group form --> <NcModal v-if="modal" :container="container" @@ -169,8 +160,6 @@ <script> -import Plus from 'vue-material-design-icons/Plus.vue' - import { getCapabilities } from '@nextcloud/capabilities' import { showError } from '@nextcloud/dialogs' @@ -218,7 +207,6 @@ export default { NcModal, NcPasswordField, NcTextField, - Plus, SetContacts, }, @@ -305,7 +293,7 @@ export default { }) }, }, - expose: ['showModalForItem'], + expose: ['showModalForItem','showModal'], methods: { showModal() { diff --git a/src/components/LeftSidebar/OpenConversationsList/OpenConversationsList.vue b/src/components/LeftSidebar/OpenConversationsList/OpenConversationsList.vue new file mode 100644 index 000000000..e9b68a9bb --- /dev/null +++ b/src/components/LeftSidebar/OpenConversationsList/OpenConversationsList.vue @@ -0,0 +1,82 @@ +<!-- + - @copyright Copyright (c) 2023 + - + - @license GNU AGPL version 3 or any later version + - + - 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 <http://www.gnu.org/licenses/>. +--> + +<template> + <RoomSelector v-if="modal" + :container="container" + list-open-conversations + show-postable-only + :dialog-title="dialogTitle" + @close="closeModal" + @select="openConversation" /> +</template> + +<script> + +import RoomSelector from '../../../views/RoomSelector.vue' + +export default { + + name: 'OpenConversationsList', + + components: { + RoomSelector, + }, + + data() { + return { + modal: false, + } + }, + + computed: { + container() { + return this.$store.getters.getMainContainerSelector() + }, + + dialogTitle() { + return t('spreed', 'Open conversations') + }, + + }, + + methods: { + showModal() { + this.modal = true + }, + + closeModal() { + this.modal = false + }, + + openConversation(token) { + this.$router.push({ + name: 'conversation', + params: { + token: `${token}`, + }, + }).catch(err => console.debug(`Error while pushing the new conversation's route: ${err}`)) + + this.closeModal() + }, + }, + +} + +</script> diff --git a/src/views/RoomSelector.spec.js b/src/views/RoomSelector.spec.js index e1124d445..3524fc9a0 100644 --- a/src/views/RoomSelector.spec.js +++ b/src/views/RoomSelector.spec.js @@ -1,4 +1,5 @@ import { shallowMount } from '@vue/test-utils' +import flushPromises from 'flush-promises' import axios from '@nextcloud/axios' import { generateOcsUrl } from '@nextcloud/router' @@ -85,10 +86,12 @@ describe('RoomSelector.vue', () => { const wrapper = shallowMount(RoomSelector) expect(axios.get).toHaveBeenCalledWith( - generateOcsUrl('/apps/spreed/api/v4/room') + generateOcsUrl('/apps/spreed/api/v4/room'), + { params: { includeStatus: true } } ) // need to wait for re-render, otherwise the list is not rendered yet + await flushPromises() await wrapper.vm.$nextTick() const list = wrapper.findAll('li') @@ -103,12 +106,13 @@ describe('RoomSelector.vue', () => { showPostableOnly: true, }, }) - expect(axios.get).toHaveBeenCalledWith( - generateOcsUrl('/apps/spreed/api/v4/room') + generateOcsUrl('/apps/spreed/api/v4/room'), + { params: { includeStatus: true } } ) // need to wait for re-render, otherwise the list is not rendered yet + await flushPromises() await wrapper.vm.$nextTick() const list = wrapper.findAll('li') @@ -120,9 +124,10 @@ describe('RoomSelector.vue', () => { const wrapper = shallowMount(RoomSelector) expect(axios.get).toHaveBeenCalledWith( - generateOcsUrl('/apps/spreed/api/v4/room') + generateOcsUrl('/apps/spreed/api/v4/room'), + { params: { includeStatus: true } } ) - + await flushPromises() await wrapper.vm.$nextTick() const eventHandler = jest.fn() diff --git a/src/views/RoomSelector.vue b/src/views/RoomSelector.vue index c392ebf6f..b1ab2cbbb 100644 --- a/src/views/RoomSelector.vue +++ b/src/views/RoomSelector.vue @@ -53,8 +53,13 @@ <span>{{ room.displayName }}</span> </li> </ul> - <div v-else-if="!loading"> - {{ t('spreed', 'No conversations found') }} + <div v-else-if="!loading" class="no-match-message"> + <h2 class="no-match-title"> + {{ noMatchFoundTitle }} + </h2> + <p v-if="noMatchFoundSubtitle" class="subtitle"> + {{ noMatchFoundSubtitle }} + </p> </div> </div> <div id="modal-buttons"> @@ -73,9 +78,6 @@ <script> import Magnify from 'vue-material-design-icons/Magnify.vue' -import axios from '@nextcloud/axios' -import { generateOcsUrl } from '@nextcloud/router' - import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' import NcModal from '@nextcloud/vue/dist/Components/NcModal.js' import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js' @@ -83,6 +85,7 @@ import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js' import ConversationIcon from '../components/ConversationIcon.vue' import { CONVERSATION } from '../constants.js' +import { searchListedConversations, fetchConversations } from '../services/conversationsService.js' export default { name: 'RoomSelector', @@ -108,6 +111,7 @@ export default { type: String, default: '', }, + /** * Whether to only show conversations to which * the user can post messages. @@ -116,6 +120,11 @@ export default { type: Boolean, default: false, }, + + listOpenConversations: { + type: Boolean, + default: false, + }, }, emits: ['close', 'select'], data() { @@ -142,20 +151,34 @@ export default { return roomsTemp.filter(room => room.displayName.toLowerCase().includes(this.searchText.toLowerCase())) } }, + + noMatchFoundTitle() { + return this.listOpenConversations + ? t('spreed', 'No open conversations found') + : t('spreed', 'No conversations found') + }, + + noMatchFoundSubtitle() { + return this.listOpenConversations + ? t('spreed', 'Either there are no open conversations or you joined all of them.') + : t('spreed', 'Check spelling or use complete words.') + }, }, - beforeMount() { - this.fetchRooms() + async beforeMount() { + await this.fetchRooms() const $store = OCA.Talk?.instance?.$store if ($store) { this.currentRoom = $store.getters.getToken() } }, methods: { - fetchRooms() { - axios.get(generateOcsUrl('/apps/spreed/api/v4/room')).then((response) => { - this.rooms = response.data.ocs.data.sort(this.sortConversations) - this.loading = false - }) + async fetchRooms() { + const response = this.listOpenConversations + ? await searchListedConversations({ searchText: '' }, {}) + : await fetchConversations({}) + + this.rooms = response.data.ocs.data.sort(this.sortConversations) + this.loading = false }, sortConversations(conversation1, conversation2) { if (conversation1.isFavorite !== conversation2.isFavorite) { @@ -221,6 +244,16 @@ export default { height: 100%; } +.no-match-message{ + padding: 40px 0; + text-align: center; + +} + +.no-match-title{ + font-weight: normal; +} + li { padding: 6px; border: 1px solid transparent; |