mirror of
https://github.com/nextcloud/spreed.git
synced 2025-07-21 10:37:10 +00:00
Merge pull request #15419 from nextcloud/fix/vue3/right-sidebar-shared-items
fix: expand ts migration and fix infinite loading bug of shared items tab in 1-1 conversation
This commit is contained in:
@ -80,7 +80,7 @@ import { useViewer } from '../../../../../composables/useViewer.js'
|
||||
import { SHARED_ITEM } from '../../../../../constants.ts'
|
||||
import { getTalkConfig } from '../../../../../services/CapabilitiesManager.ts'
|
||||
import { useActorStore } from '../../../../../stores/actor.ts'
|
||||
import { useSharedItemsStore } from '../../../../../stores/sharedItems.js'
|
||||
import { useSharedItemsStore } from '../../../../../stores/sharedItems.ts'
|
||||
|
||||
const PREVIEW_TYPE = {
|
||||
TEMPORARY: 0,
|
||||
|
@ -301,8 +301,8 @@ export default {
|
||||
|| this.conversation.participantType === PARTICIPANT.TYPE.MODERATOR
|
||||
},
|
||||
|
||||
isModeratorOrUser() {
|
||||
return this.$store.getters.isModeratorOrUser
|
||||
isGuestModerator() {
|
||||
return this.conversation?.participantType === PARTICIPANT.TYPE.GUEST_MODERATOR
|
||||
},
|
||||
|
||||
isInLobby() {
|
||||
@ -339,7 +339,7 @@ export default {
|
||||
},
|
||||
|
||||
showParticipantsTab() {
|
||||
return (this.getUserId || this.isModeratorOrUser) && (!this.isOneToOne || this.isInCall) && !this.isNoteToSelf
|
||||
return (this.getUserId || this.isGuestModerator) && (!this.isOneToOne || this.isInCall) && !this.isNoteToSelf
|
||||
},
|
||||
|
||||
showSharedItemsTab() {
|
||||
@ -461,7 +461,7 @@ export default {
|
||||
immediate: true,
|
||||
},
|
||||
|
||||
isModeratorOrUser(newValue) {
|
||||
isGuestModerator(newValue) {
|
||||
if (newValue && !this.isInCall) {
|
||||
// Switch active tab to participants list if guest was promoted to moderators
|
||||
this.activeTab = 'participants'
|
||||
|
@ -5,23 +5,20 @@
|
||||
|
||||
<template>
|
||||
<div class="shared-items" :class="{ 'shared-items__list': hasListLayout }">
|
||||
<template v-for="item in itemsToDisplay">
|
||||
<div v-if="isLocation" :key="item.id" class="shared-items__location">
|
||||
<template v-for="item in itemsToDisplay" :key="item.id">
|
||||
<div v-if="isLocation" class="shared-items__location">
|
||||
<Location wide v-bind="item.messageParameters.object" />
|
||||
</div>
|
||||
|
||||
<DeckCard v-else-if="isDeckCard"
|
||||
:key="item.id"
|
||||
wide
|
||||
v-bind="item.messageParameters.object" />
|
||||
|
||||
<Poll v-else-if="isPoll"
|
||||
:key="item.id"
|
||||
:token="token"
|
||||
v-bind="item.messageParameters.object" />
|
||||
|
||||
<div v-else-if="isOther"
|
||||
:key="item.id"
|
||||
class="shared-items__other">
|
||||
<a v-if="item.messageParameters.object?.link"
|
||||
:href="item.messageParameters.object.link"
|
||||
@ -34,7 +31,6 @@
|
||||
</div>
|
||||
|
||||
<FilePreview v-else
|
||||
:key="item.id"
|
||||
:token="token"
|
||||
:small-preview="!isMedia"
|
||||
:row-layout="!isMedia"
|
||||
|
@ -38,8 +38,8 @@ import NcButton from '@nextcloud/vue/components/NcButton'
|
||||
import NcModal from '@nextcloud/vue/components/NcModal'
|
||||
import SharedItems from './SharedItems.vue'
|
||||
import { useId } from '../../../composables/useId.ts'
|
||||
import { useSharedItemsStore } from '../../../stores/sharedItems.js'
|
||||
import { sharedItemsOrder, sharedItemTitle } from './sharedItemsConstants.js'
|
||||
import { useSharedItemsStore } from '../../../stores/sharedItems.ts'
|
||||
import { sharedItemsOrder, sharedItemTitle } from './sharedItemsConstants.ts'
|
||||
|
||||
export default {
|
||||
name: 'SharedItemsBrowser',
|
||||
|
@ -3,9 +3,103 @@
|
||||
- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-->
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type {
|
||||
Conversation,
|
||||
SharedItems as ShareItemsType,
|
||||
} from '../../../types/index.ts'
|
||||
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import NcAppNavigationCaption from '@nextcloud/vue/components/NcAppNavigationCaption'
|
||||
import NcButton from '@nextcloud/vue/components/NcButton'
|
||||
import NcCollectionList from '@nextcloud/vue/components/NcCollectionList'
|
||||
import NcEmptyContent from '@nextcloud/vue/components/NcEmptyContent'
|
||||
import NcRelatedResourcesPanel from '@nextcloud/vue/components/NcRelatedResourcesPanel'
|
||||
import DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'
|
||||
import FolderMultipleImage from 'vue-material-design-icons/FolderMultipleImage.vue'
|
||||
import IconPoll from 'vue-material-design-icons/Poll.vue'
|
||||
import LoadingComponent from '../../LoadingComponent.vue'
|
||||
import SharedItems from './SharedItems.vue'
|
||||
import SharedItemsBrowser from './SharedItemsBrowser.vue'
|
||||
import { useGetToken } from '../../../composables/useGetToken.ts'
|
||||
import { CONVERSATION } from '../../../constants.ts'
|
||||
import { hasTalkFeature } from '../../../services/CapabilitiesManager.ts'
|
||||
import { EventBus } from '../../../services/EventBus.ts'
|
||||
import { useActorStore } from '../../../stores/actor.ts'
|
||||
import { useSharedItemsStore } from '../../../stores/sharedItems.ts'
|
||||
import { useSidebarStore } from '../../../stores/sidebar.ts'
|
||||
import {
|
||||
sharedItemButtonTitle,
|
||||
sharedItemsOrder,
|
||||
sharedItemsWithPreviewLimit,
|
||||
sharedItemTitle,
|
||||
} from './sharedItemsConstants.ts'
|
||||
|
||||
const props = defineProps<{
|
||||
active: boolean
|
||||
}>()
|
||||
const token = useGetToken()
|
||||
const showSharedItemsBrowser = ref(false)
|
||||
const browserActiveTab = ref('')
|
||||
const projectsEnabled = loadState('core', 'projects_enabled', false)
|
||||
const hasRelatedResources = ref(false)
|
||||
|
||||
const store = useStore()
|
||||
const sharedItemsStore = useSharedItemsStore()
|
||||
const sidebarStore = useSidebarStore()
|
||||
const actorStore = useActorStore()
|
||||
|
||||
const conversation = computed<Conversation>(() => store.getters.conversation(token.value))
|
||||
const canCreatePollDrafts = computed(() => {
|
||||
return hasTalkFeature(token.value, 'talk-polls-drafts') && store.getters.isModerator
|
||||
&& [CONVERSATION.TYPE.GROUP, CONVERSATION.TYPE.PUBLIC].includes(conversation.value.type)
|
||||
})
|
||||
const sharedItems = computed(() => sharedItemsStore.sharedItems(token.value))
|
||||
const hasSharedItems = computed(() => Object.keys(sharedItems.value).length > 0)
|
||||
|
||||
watch([token, () => props.active, () => sidebarStore.show], ([token, isActive, isOpen]) => {
|
||||
if (token && isActive && isOpen) {
|
||||
sharedItemsStore.getSharedItemsOverview(token)
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
/**
|
||||
* Check if there are more items of a specific type than the limit allows.
|
||||
*/
|
||||
function hasMore(type: string, items: ShareItemsType) {
|
||||
return Object.values(items).length > limit(type)
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the SharedItemsBrowser dialog for a specific type of shared items.
|
||||
*/
|
||||
function showMore(type: string) {
|
||||
browserActiveTab.value = type
|
||||
showSharedItemsBrowser.value = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the limit for the number of items displayed based on the type.
|
||||
*/
|
||||
function limit(type: string) {
|
||||
return sharedItemsWithPreviewLimit.includes(type) ? 2 : 6
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the Poll Drafts browser dialog.
|
||||
*/
|
||||
function openPollDraftHandler() {
|
||||
EventBus.emit('poll-drafts-open', { token: token.value })
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="shared-items-tab">
|
||||
<LoadingComponent v-if="loading" class="shared-items-tab__loading" />
|
||||
<LoadingComponent v-if="!sharedItemsStore.overviewLoaded[token]" class="shared-items-tab__loading" />
|
||||
|
||||
<template v-else>
|
||||
<NcButton v-if="canCreatePollDrafts"
|
||||
@ -17,8 +111,8 @@
|
||||
{{ t('spreed', 'Browse poll drafts') }}
|
||||
</NcButton>
|
||||
<!-- Shared items grouped by type -->
|
||||
<template v-for="type in sharedItemsOrder">
|
||||
<div v-if="sharedItems[type]" :key="type">
|
||||
<template v-for="type in sharedItemsOrder" :key="type">
|
||||
<div v-if="sharedItems[type]">
|
||||
<NcAppNavigationCaption :name="sharedItemTitle[type] || sharedItemTitle.default" />
|
||||
<SharedItems :type="type"
|
||||
:token="token"
|
||||
@ -42,12 +136,12 @@
|
||||
<NcRelatedResourcesPanel class="related-resources"
|
||||
provider-id="talk"
|
||||
:item-id="conversation.token"
|
||||
@has-resources="value => hasRelatedResources = value" />
|
||||
@has-resources="(value: boolean) => hasRelatedResources = value" />
|
||||
|
||||
<!-- Shared from "Projects" app -->
|
||||
<template v-if="projectsEnabled">
|
||||
<NcAppNavigationCaption :name="t('spreed', 'Projects')" />
|
||||
<NcCollectionList v-if="getUserId && token"
|
||||
<NcCollectionList v-if="actorStore.userId && token"
|
||||
:id="token"
|
||||
type="room"
|
||||
:name="conversation.displayName"
|
||||
@ -73,149 +167,6 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import NcAppNavigationCaption from '@nextcloud/vue/components/NcAppNavigationCaption'
|
||||
import NcButton from '@nextcloud/vue/components/NcButton'
|
||||
import NcCollectionList from '@nextcloud/vue/components/NcCollectionList'
|
||||
import NcEmptyContent from '@nextcloud/vue/components/NcEmptyContent'
|
||||
import NcRelatedResourcesPanel from '@nextcloud/vue/components/NcRelatedResourcesPanel'
|
||||
import DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'
|
||||
import FolderMultipleImage from 'vue-material-design-icons/FolderMultipleImage.vue'
|
||||
import IconPoll from 'vue-material-design-icons/Poll.vue'
|
||||
import LoadingComponent from '../../LoadingComponent.vue'
|
||||
import SharedItems from './SharedItems.vue'
|
||||
import SharedItemsBrowser from './SharedItemsBrowser.vue'
|
||||
import { useGetToken } from '../../../composables/useGetToken.ts'
|
||||
import { CONVERSATION } from '../../../constants.ts'
|
||||
import { hasTalkFeature } from '../../../services/CapabilitiesManager.ts'
|
||||
import { EventBus } from '../../../services/EventBus.ts'
|
||||
import { useActorStore } from '../../../stores/actor.ts'
|
||||
import { useSharedItemsStore } from '../../../stores/sharedItems.js'
|
||||
import { useSidebarStore } from '../../../stores/sidebar.ts'
|
||||
import {
|
||||
sharedItemButtonTitle,
|
||||
sharedItemsOrder,
|
||||
sharedItemsWithPreviewLimit,
|
||||
sharedItemTitle,
|
||||
} from './sharedItemsConstants.js'
|
||||
|
||||
export default {
|
||||
|
||||
name: 'SharedItemsTab',
|
||||
|
||||
components: {
|
||||
DotsHorizontal,
|
||||
FolderMultipleImage,
|
||||
IconPoll,
|
||||
LoadingComponent,
|
||||
NcAppNavigationCaption,
|
||||
NcButton,
|
||||
NcCollectionList,
|
||||
NcEmptyContent,
|
||||
NcRelatedResourcesPanel,
|
||||
SharedItems,
|
||||
SharedItemsBrowser,
|
||||
},
|
||||
|
||||
props: {
|
||||
active: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
setup() {
|
||||
return {
|
||||
actorStore: useActorStore(),
|
||||
sharedItemsStore: useSharedItemsStore(),
|
||||
sidebarStore: useSidebarStore(),
|
||||
sharedItemButtonTitle,
|
||||
sharedItemTitle,
|
||||
sharedItemsOrder,
|
||||
sharedItemsWithPreviewLimit,
|
||||
token: useGetToken(),
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
showSharedItemsBrowser: false,
|
||||
browserActiveTab: '',
|
||||
projectsEnabled: loadState('core', 'projects_enabled', false),
|
||||
hasRelatedResources: false,
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
getUserId() {
|
||||
return this.actorStore.userId
|
||||
},
|
||||
|
||||
conversation() {
|
||||
return this.$store.getters.conversation(this.token)
|
||||
},
|
||||
|
||||
canCreatePollDrafts() {
|
||||
return hasTalkFeature(this.token, 'talk-polls-drafts') && this.$store.getters.isModerator
|
||||
&& [CONVERSATION.TYPE.GROUP, CONVERSATION.TYPE.PUBLIC].includes(this.conversation.type)
|
||||
},
|
||||
|
||||
loading() {
|
||||
return !this.sharedItemsStore.overviewLoaded[this.token]
|
||||
},
|
||||
|
||||
sharedItems() {
|
||||
return this.sharedItemsStore.sharedItems(this.token)
|
||||
},
|
||||
|
||||
hasSharedItems() {
|
||||
return Object.keys(this.sharedItems).length > 0
|
||||
},
|
||||
|
||||
isSidebarOpen() {
|
||||
return this.sidebarStore.show
|
||||
},
|
||||
|
||||
sharedItemsIdentifier() {
|
||||
return this.token + ':' + this.active + ':' + this.isSidebarOpen
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
sharedItemsIdentifier: {
|
||||
immediate: true,
|
||||
handler() {
|
||||
if (this.token && this.active && this.isSidebarOpen) {
|
||||
this.sharedItemsStore.getSharedItemsOverview(this.token)
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
t,
|
||||
hasMore(type, items) {
|
||||
return Object.values(items).length > this.limit(type)
|
||||
},
|
||||
|
||||
showMore(type) {
|
||||
this.browserActiveTab = type
|
||||
this.showSharedItemsBrowser = true
|
||||
},
|
||||
|
||||
limit(type) {
|
||||
return this.sharedItemsWithPreviewLimit.includes(type) ? 2 : 6
|
||||
},
|
||||
|
||||
openPollDraftHandler() {
|
||||
EventBus.emit('poll-drafts-open', { token: this.token })
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.more {
|
||||
margin-top: 8px;
|
||||
|
@ -13,9 +13,9 @@ export const sharedItemsOrder = [SHARED_ITEM.TYPES.MEDIA,
|
||||
SHARED_ITEM.TYPES.AUDIO,
|
||||
SHARED_ITEM.TYPES.LOCATION,
|
||||
SHARED_ITEM.TYPES.DECK_CARD,
|
||||
SHARED_ITEM.TYPES.OTHER]
|
||||
SHARED_ITEM.TYPES.OTHER] as const
|
||||
|
||||
export const sharedItemsWithPreviewLimit = [SHARED_ITEM.TYPES.DECK_CARD, SHARED_ITEM.TYPES.LOCATION, SHARED_ITEM.TYPES.POLL]
|
||||
export const sharedItemsWithPreviewLimit = [SHARED_ITEM.TYPES.DECK_CARD, SHARED_ITEM.TYPES.LOCATION, SHARED_ITEM.TYPES.POLL] as const
|
||||
|
||||
export const sharedItemTitle = {
|
||||
[SHARED_ITEM.TYPES.MEDIA]: t('spreed', 'Media'),
|
||||
@ -28,7 +28,7 @@ export const sharedItemTitle = {
|
||||
[SHARED_ITEM.TYPES.AUDIO]: t('spreed', 'Audio'),
|
||||
[SHARED_ITEM.TYPES.OTHER]: t('spreed', 'Other'),
|
||||
default: t('spreed', 'Other'),
|
||||
}
|
||||
} as const
|
||||
|
||||
export const sharedItemButtonTitle = {
|
||||
[SHARED_ITEM.TYPES.MEDIA]: t('spreed', 'Show all media'),
|
||||
@ -41,4 +41,4 @@ export const sharedItemButtonTitle = {
|
||||
[SHARED_ITEM.TYPES.AUDIO]: t('spreed', 'Show all audio'),
|
||||
[SHARED_ITEM.TYPES.OTHER]: t('spreed', 'Show all other'),
|
||||
default: t('spreed', 'Show all other'),
|
||||
}
|
||||
} as const
|
@ -3,12 +3,19 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type {
|
||||
getSharedItemsOverviewParams,
|
||||
getSharedItemsOverviewResponse,
|
||||
getSharedItemsParams,
|
||||
getSharedItemsResponse,
|
||||
} from '../types/index.ts'
|
||||
|
||||
import axios from '@nextcloud/axios'
|
||||
import { generateOcsUrl } from '@nextcloud/router'
|
||||
|
||||
// Returns the last n shared items for each category and for a given conversation
|
||||
// (n = limit)
|
||||
const getSharedItemsOverview = async function(token, limit) {
|
||||
const getSharedItemsOverview = async function({ token, limit }: { token: string } & getSharedItemsOverviewParams): getSharedItemsOverviewResponse {
|
||||
return axios.get(generateOcsUrl('apps/spreed/api/v1/chat/{token}/share/overview', {
|
||||
token,
|
||||
}), {
|
||||
@ -20,7 +27,7 @@ const getSharedItemsOverview = async function(token, limit) {
|
||||
|
||||
// Returns the last 200 (or limit) shared items, given a conversation and the type
|
||||
// of shared item
|
||||
const getSharedItems = async function(token, objectType, lastKnownMessageId, limit) {
|
||||
const getSharedItems = async function({ token, objectType, lastKnownMessageId, limit }: { token: string } & getSharedItemsParams): getSharedItemsResponse {
|
||||
return axios.get(generateOcsUrl('apps/spreed/api/v1/chat/{token}/share', {
|
||||
token,
|
||||
}), {
|
@ -70,7 +70,7 @@ import { useFederationStore } from '../stores/federation.ts'
|
||||
import { useGroupwareStore } from '../stores/groupware.ts'
|
||||
import pinia from '../stores/pinia.ts'
|
||||
import { useReactionsStore } from '../stores/reactions.js'
|
||||
import { useSharedItemsStore } from '../stores/sharedItems.js'
|
||||
import { useSharedItemsStore } from '../stores/sharedItems.ts'
|
||||
import { useTalkHashStore } from '../stores/talkHash.js'
|
||||
import { useTokenStore } from '../stores/token.ts'
|
||||
import { convertToUnix } from '../utils/formattedTime.ts'
|
||||
|
@ -29,7 +29,7 @@ import { useCallViewStore } from '../stores/callView.ts'
|
||||
import { useGuestNameStore } from '../stores/guestName.js'
|
||||
import { usePollsStore } from '../stores/polls.ts'
|
||||
import { useReactionsStore } from '../stores/reactions.js'
|
||||
import { useSharedItemsStore } from '../stores/sharedItems.js'
|
||||
import { useSharedItemsStore } from '../stores/sharedItems.ts'
|
||||
import CancelableRequest from '../utils/cancelableRequest.js'
|
||||
import { debugTimer } from '../utils/debugTimer.ts'
|
||||
import { convertToUnix } from '../utils/formattedTime.ts'
|
||||
|
@ -3,11 +3,11 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { sharedItemsOrder } from '../../components/RightSidebar/SharedItems/sharedItemsConstants.js'
|
||||
import { sharedItemsOrder } from '../../components/RightSidebar/SharedItems/sharedItemsConstants.ts'
|
||||
import { SHARED_ITEM } from '../../constants.ts'
|
||||
import { getSharedItems, getSharedItemsOverview } from '../../services/sharedItemsService.js'
|
||||
import { getSharedItems, getSharedItemsOverview } from '../../services/sharedItemsService.ts'
|
||||
import { generateOCSErrorResponse, generateOCSResponse } from '../../test-helpers.js'
|
||||
import { useSharedItemsStore } from '../sharedItems.js'
|
||||
import { useSharedItemsStore } from '../sharedItems.ts'
|
||||
|
||||
jest.mock('../../services/sharedItemsService', () => ({
|
||||
getSharedItems: jest.fn(),
|
||||
@ -123,7 +123,7 @@ describe('sharedItemsStore', () => {
|
||||
await sharedItemsStore.getSharedItemsOverview(token)
|
||||
|
||||
// Assert
|
||||
expect(getSharedItemsOverview).toHaveBeenCalledWith(token, limitOverview)
|
||||
expect(getSharedItemsOverview).toHaveBeenCalledWith({ token, limit: limitOverview })
|
||||
expect(sharedItemsStore.sharedItems(token)).toEqual(result)
|
||||
})
|
||||
|
||||
@ -147,7 +147,12 @@ describe('sharedItemsStore', () => {
|
||||
await sharedItemsStore.getSharedItems(token, SHARED_ITEM.TYPES.MEDIA)
|
||||
|
||||
// Assert
|
||||
expect(getSharedItems).toHaveBeenCalledWith(token, SHARED_ITEM.TYPES.MEDIA, 100, limitGeneral)
|
||||
expect(getSharedItems).toHaveBeenCalledWith({
|
||||
token,
|
||||
objectType: SHARED_ITEM.TYPES.MEDIA,
|
||||
lastKnownMessageId: 100,
|
||||
limit: limitGeneral,
|
||||
})
|
||||
expect(sharedItemsStore.sharedItems(token)).toEqual(result)
|
||||
})
|
||||
|
||||
@ -163,7 +168,12 @@ describe('sharedItemsStore', () => {
|
||||
const output = await sharedItemsStore.getSharedItems(token, SHARED_ITEM.TYPES.MEDIA)
|
||||
|
||||
// Assert
|
||||
expect(getSharedItems).toHaveBeenCalledWith(token, SHARED_ITEM.TYPES.MEDIA, 100, limitGeneral)
|
||||
expect(getSharedItems).toHaveBeenCalledWith({
|
||||
token,
|
||||
objectType: SHARED_ITEM.TYPES.MEDIA,
|
||||
lastKnownMessageId: 100,
|
||||
limit: limitGeneral,
|
||||
})
|
||||
expect(output).toEqual({ hasMoreItems: false, messages: [] })
|
||||
expect(sharedItemsStore.sharedItems(token)).toEqual(result)
|
||||
})
|
||||
|
@ -3,31 +3,24 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type {
|
||||
ChatMessage,
|
||||
SharedItems,
|
||||
SharedItemsOverview,
|
||||
} from '../types/index.ts'
|
||||
|
||||
import { defineStore } from 'pinia'
|
||||
import { getSharedItems, getSharedItemsOverview } from '../services/sharedItemsService.js'
|
||||
import { getSharedItems, getSharedItemsOverview } from '../services/sharedItemsService.ts'
|
||||
import { getItemTypeFromMessage } from '../utils/getItemTypeFromMessage.ts'
|
||||
|
||||
/**
|
||||
* @typedef {'media'|'file'|'voice'|'audio'|'location'|'deckcard'|'other'} Type
|
||||
* @typedef {string} Token
|
||||
*/
|
||||
type SharedItemType = keyof SharedItemsOverview
|
||||
|
||||
/**
|
||||
* @typedef {object} Message
|
||||
* @property {string} token - conversation token
|
||||
* @property {number} id - message id
|
||||
*/
|
||||
type SharedItemsPoolType = Record<string, Record<SharedItemType, Record<number, SharedItems[keyof SharedItems]>>>
|
||||
|
||||
/**
|
||||
* @typedef {object} Messages
|
||||
* @property {{[key: number]: Message}} messages - messages with shared items for this conversation
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {object} State
|
||||
* @property {{[key: Token]: {[key: Type]: Messages}}} sharedItemsPool - The shared items pool.
|
||||
* @property {{[key: Token]: boolean}} overviewLoaded - The overview loaded state.
|
||||
*/
|
||||
type State = {
|
||||
sharedItemsPool: SharedItemsPoolType
|
||||
overviewLoaded: Record<string, boolean>
|
||||
}
|
||||
|
||||
/**
|
||||
* Store for shared items shown in RightSidebar
|
||||
@ -36,13 +29,13 @@ import { getItemTypeFromMessage } from '../utils/getItemTypeFromMessage.ts'
|
||||
* @param {State} options.state store state structure
|
||||
*/
|
||||
export const useSharedItemsStore = defineStore('sharedItems', {
|
||||
state: () => ({
|
||||
state: (): State => ({
|
||||
sharedItemsPool: {},
|
||||
overviewLoaded: {},
|
||||
}),
|
||||
|
||||
getters: {
|
||||
sharedItems: (state) => (token) => {
|
||||
sharedItems: (state) => (token: string) => {
|
||||
if (!state.sharedItemsPool[token]) {
|
||||
state.sharedItemsPool[token] = {}
|
||||
}
|
||||
@ -52,7 +45,7 @@ export const useSharedItemsStore = defineStore('sharedItems', {
|
||||
},
|
||||
|
||||
actions: {
|
||||
checkForExistence(token, type) {
|
||||
checkForExistence(token: string, type: SharedItemType) {
|
||||
if (token && !this.sharedItemsPool[token]) {
|
||||
this.sharedItemsPool[token] = {}
|
||||
}
|
||||
@ -62,10 +55,10 @@ export const useSharedItemsStore = defineStore('sharedItems', {
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Token} token conversation token
|
||||
* @param {{[key: Type]: Message[]}} data server response
|
||||
* @param token conversation token
|
||||
* @param data server response
|
||||
*/
|
||||
addSharedItemsFromOverview(token, data) {
|
||||
addSharedItemsFromOverview(token: string, data: SharedItemsOverview) {
|
||||
for (const type of Object.keys(data)) {
|
||||
if (Object.keys(data[type]).length) {
|
||||
this.checkForExistence(token, type)
|
||||
@ -81,10 +74,10 @@ export const useSharedItemsStore = defineStore('sharedItems', {
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Token} token conversation token
|
||||
* @param {Message} message message with shared items
|
||||
* @param token conversation token
|
||||
* @param message message with shared items
|
||||
*/
|
||||
addSharedItemFromMessage(token, message) {
|
||||
addSharedItemFromMessage(token: string, message: ChatMessage) {
|
||||
const type = getItemTypeFromMessage(message)
|
||||
this.checkForExistence(token, type)
|
||||
|
||||
@ -94,10 +87,10 @@ export const useSharedItemsStore = defineStore('sharedItems', {
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Token} token conversation token
|
||||
* @param {string} messageId id of message to be deleted
|
||||
* @param token conversation token
|
||||
* @param messageId id of message to be deleted
|
||||
*/
|
||||
deleteSharedItemFromMessage(token, messageId) {
|
||||
deleteSharedItemFromMessage(token: string, messageId: number) {
|
||||
if (!this.sharedItemsPool[token]) {
|
||||
return
|
||||
}
|
||||
@ -117,7 +110,7 @@ export const useSharedItemsStore = defineStore('sharedItems', {
|
||||
* @param {Type} type type of shared item
|
||||
* @param {Message[]} messages message with shared items
|
||||
*/
|
||||
addSharedItemsFromMessages(token, type, messages) {
|
||||
addSharedItemsFromMessages(token: string, type: string, messages: SharedItems[keyof SharedItems][]) {
|
||||
this.checkForExistence(token, type)
|
||||
|
||||
messages.forEach((message) => {
|
||||
@ -128,11 +121,11 @@ export const useSharedItemsStore = defineStore('sharedItems', {
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Token} token conversation token
|
||||
* @param {string} messageId starting message id to purge shared items from older messages
|
||||
* @param token conversation token
|
||||
* @param messageId starting message id to purge shared items from older messages
|
||||
* If messageId is not provided, all shared items in this conversation will be deleted.
|
||||
*/
|
||||
purgeSharedItemsStore(token, messageId = null) {
|
||||
purgeSharedItemsStore(token: string, messageId: number | null = null) {
|
||||
if (!this.sharedItemsPool[token]) {
|
||||
return
|
||||
}
|
||||
@ -141,7 +134,7 @@ export const useSharedItemsStore = defineStore('sharedItems', {
|
||||
for (const type of Object.keys(this.sharedItemsPool[token])) {
|
||||
for (const id of Object.keys(this.sharedItemsPool[token][type])) {
|
||||
if (+id < +messageId) {
|
||||
delete this.sharedItemsPool[token][type][id]
|
||||
delete this.sharedItemsPool[token][type][+id]
|
||||
}
|
||||
}
|
||||
if (Object.keys(this.sharedItemsPool[token][type]).length === 0) {
|
||||
@ -157,10 +150,10 @@ export const useSharedItemsStore = defineStore('sharedItems', {
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Token} token conversation token
|
||||
* @param {Type} type type of shared item
|
||||
* @param token conversation token
|
||||
* @param type type of shared item
|
||||
*/
|
||||
async getSharedItems(token, type) {
|
||||
async getSharedItems(token: string, type: string) {
|
||||
// function is called from Message or SharedItemsBrowser, poll should not be empty at the moment
|
||||
if (!this.sharedItemsPool[token] || !this.sharedItemsPool[token][type]) {
|
||||
console.error(`Missing shared items poll of type '${type}' in conversation ${token}`)
|
||||
@ -168,9 +161,9 @@ export const useSharedItemsStore = defineStore('sharedItems', {
|
||||
}
|
||||
|
||||
const limit = 20
|
||||
const lastKnownMessageId = Math.min.apply(Math, Object.keys(this.sharedItemsPool[token][type]))
|
||||
const lastKnownMessageId = Math.min(...Object.keys(this.sharedItemsPool[token][type]).map(Number))
|
||||
try {
|
||||
const response = await getSharedItems(token, type, lastKnownMessageId, limit)
|
||||
const response = await getSharedItems({ token, objectType: type, lastKnownMessageId, limit })
|
||||
const messages = Object.values(response.data.ocs.data)
|
||||
if (messages.length) {
|
||||
this.addSharedItemsFromMessages(token, type, messages)
|
||||
@ -185,13 +178,13 @@ export const useSharedItemsStore = defineStore('sharedItems', {
|
||||
/**
|
||||
* @param {Token} token conversation token
|
||||
*/
|
||||
async getSharedItemsOverview(token) {
|
||||
async getSharedItemsOverview(token: string) {
|
||||
if (this.overviewLoaded[token]) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await getSharedItemsOverview(token, 7)
|
||||
const response = await getSharedItemsOverview({ token, limit: 7 })
|
||||
this.addSharedItemsFromOverview(token, response.data.ocs.data)
|
||||
} catch (error) {
|
||||
console.error(error)
|
@ -348,6 +348,14 @@ export type deletePollDraftResponse = ApiResponse<operations['poll-close-poll'][
|
||||
|
||||
export type requiredPollParams = Omit<createPollParams, 'draft'>
|
||||
|
||||
// Shared items
|
||||
export type getSharedItemsOverviewParams = operations['chat-get-objects-shared-in-room-overview']['parameters']['query']
|
||||
export type getSharedItemsOverviewResponse = ApiResponse<operations['chat-get-objects-shared-in-room-overview']['responses'][200]['content']['application/json']>
|
||||
export type SharedItemsOverview = operations['chat-get-objects-shared-in-room-overview']['responses'][200]['content']['application/json']['ocs']['data']
|
||||
export type getSharedItemsParams = operations['chat-get-objects-shared-in-room']['parameters']['query']
|
||||
export type getSharedItemsResponse = ApiResponse<operations['chat-get-objects-shared-in-room']['responses'][200]['content']['application/json']>
|
||||
export type SharedItems = operations['chat-get-objects-shared-in-room']['responses'][200]['content']['application/json']['ocs']['data']
|
||||
|
||||
// Mentions
|
||||
export type ChatMention = components['schemas']['ChatMentionSuggestion']
|
||||
export type getMentionsParams = operations['chat-mentions']['parameters']['query']
|
||||
|
Reference in New Issue
Block a user