Browse Source

fix(CalendarEvents): remove archive from options, implement expiring period as a capability and add an option to reset conversation to normal one without object attached.

Signed-off-by: Dorra Jaouad <dorra.jaoued7@gmail.com>
pull/15035/head
Dorra Jaouad 6 months ago
committed by backportbot[bot]
parent
commit
ad734806f2
  1. 22
      src/components/MessagesList/MessagesGroup/Message/MessagePart/MessageBody.vue
  2. 97
      src/components/UIShared/ConversationActionsShortcut.vue
  3. 11
      src/services/conversationsService.ts
  4. 12
      src/store/conversationsStore.js

22
src/components/MessagesList/MessagesGroup/Message/MessagePart/MessageBody.vue

@ -26,8 +26,9 @@
<!-- Additional controls -->
<CallButton v-if="showJoinCallButton" />
<CalendarEventConversationActions v-else-if="showEventConversationActions"
<ConversationActionsShortcut v-else-if="showConversationActionsShortcut"
:token="message.token"
:object-type="conversation.objectType"
:is-highlighted="isLastMessage" />
<Poll v-else-if="showResultsButton"
:token="message.token"
@ -147,12 +148,13 @@ import NcRichText from '@nextcloud/vue/components/NcRichText'
import Poll from './Poll.vue'
import Quote from '../../../../Quote.vue'
import CalendarEventConversationActions from '../../../../TopBar/CalendarEventConversationActions.vue'
import CallButton from '../../../../TopBar/CallButton.vue'
import ConversationActionsShortcut from '../../../../UIShared/ConversationActionsShortcut.vue'
import { useIsInCall } from '../../../../../composables/useIsInCall.js'
import { useMessageInfo } from '../../../../../composables/useMessageInfo.js'
import { CONVERSATION } from '../../../../../constants.ts'
import { hasTalkFeature } from '../../../../../services/CapabilitiesManager.ts'
import { EventBus } from '../../../../../services/EventBus.ts'
import { usePollsStore } from '../../../../../stores/polls.ts'
import { parseSpecialSymbols, parseMentions } from '../../../../../utils/textParse.ts'
@ -162,6 +164,7 @@ const regex = emojiRegex()
// Regular expressions to check for task lists in message text like: - [ ], * [ ], + [ ],- [x], - [X]
const checkboxRegexp = /^\s*[-+*]\s.*\[[\sxX]\]/
const checkboxCheckedRegexp = /^\s*[-+*]\s.*\[[xX]\]/
const supportUnbindConversation = hasTalkFeature('local', 'unbind-conversation')
export default {
name: 'MessageBody',
@ -172,7 +175,7 @@ export default {
NcRichText,
Poll,
Quote,
CalendarEventConversationActions,
ConversationActionsShortcut,
// Icons
AlertCircleIcon,
IconBellOff,
@ -274,10 +277,15 @@ export default {
return this.$store.getters.conversation(this.message.token)
},
showEventConversationActions() {
return !this.isInCall && !this.isSidebar && this.$store.getters.isModeratorOrUser
&& this.conversation.objectType === CONVERSATION.OBJECT_TYPE.EVENT
&& !this.conversation.isArchived
hasRetentionPeriod() {
return this.conversation.objectType === CONVERSATION.OBJECT_TYPE.EVENT
|| this.conversation.objectType === CONVERSATION.OBJECT_TYPE.PHONE_TEMPORARY
},
showConversationActionsShortcut() {
return supportUnbindConversation
&& !this.isInCall && !this.isSidebar && this.$store.getters.isModeratorOrUser
&& this.hasRetentionPeriod
&& this.isCallEndedMessage
&& this.message.id > this.lastCallStartedMessageId
},

97
src/components/TopBar/CalendarEventConversationActions.vue → src/components/UIShared/ConversationActionsShortcut.vue

@ -4,36 +4,60 @@
-->
<script setup lang="ts">
import { computed, ref } from 'vue'
import { computed } from 'vue'
import { isNavigationFailure, NavigationFailureType } from 'vue-router'
import { useRouter, useRoute } from 'vue-router/composables'
import IconArchive from 'vue-material-design-icons/Archive.vue'
import IconCheckUnderline from 'vue-material-design-icons/CheckUnderline.vue'
import IconDelete from 'vue-material-design-icons/Delete.vue'
import { showError } from '@nextcloud/dialogs'
import { t } from '@nextcloud/l10n'
import { t, getLanguage } from '@nextcloud/l10n'
import NcButton from '@nextcloud/vue/components/NcButton'
import NcDialog from '@nextcloud/vue/components/NcDialog'
import { spawnDialog } from '@nextcloud/vue/functions/dialog'
import ConfirmDialog from '../../components/UIShared/ConfirmDialog.vue'
import { useStore } from '../../composables/useStore.js'
import { hasTalkFeature } from '../../services/CapabilitiesManager.ts'
import { CONVERSATION } from '../../constants.ts'
import { hasTalkFeature, getTalkConfig } from '../../services/CapabilitiesManager.ts'
const supportsArchive = hasTalkFeature('local', 'archived-conversations-v2')
const retentionEventPeriod = getTalkConfig('local', 'conversations', 'retention-event')
const retentionPhonePeriod = getTalkConfig('local', 'conversations', 'retention-phone')
const props = defineProps<{
token: string,
objectType: string,
isHighlighted: boolean,
}>()
const store = useStore()
const router = useRouter()
const route = useRoute()
const showDialog = ref(false)
const isModerator = computed(() => store.getters.isModerator)
const expirationDuration = computed(() => {
if (props.objectType === CONVERSATION.OBJECT_TYPE.EVENT) {
return retentionEventPeriod
} else if (props.objectType === CONVERSATION.OBJECT_TYPE.PHONE_TEMPORARY) {
return retentionPhonePeriod
}
return 0
})
const descriptionLabel = computed(() => {
if (expirationDuration.value === 0) {
return t('spreed', 'Would you like to delete this conversation?')
}
const expirationDurationFormatted = new Intl.RelativeTimeFormat(getLanguage(), { numeric: 'always' }).format(
expirationDuration.value, 'days'
)
return t('spreed', 'This conversation will be automatically deleted for everyone {expirationDurationFormatted} of no activity.', { expirationDurationFormatted })
})
/**
* Delete conversation
*/
@ -51,47 +75,58 @@ async function deleteEventConversation() {
}
/**
* Archive conversation
* Unbind conversation from object
*/
async function resetObjectConversation() {
await store.dispatch('unbindConversationFromObject', { token: props.token })
}
/**
* Show confirmation dialog
*/
async function archiveEventConversation() {
await store.dispatch('toggleArchive', { token: props.token, isArchived: false })
async function showConfirmationDialog() {
spawnDialog(ConfirmDialog, {
name: t('spreed', 'Delete conversation'),
message: t('spreed', 'Are you sure you want to delete this conversation?'),
buttons: [
{
label: t('spreed', 'No'),
type: 'tertiary',
},
{
label: t('spreed', 'Yes'),
type: 'error',
callback: () => {
deleteEventConversation()
},
}
],
})
}
</script>
<template>
<div class="conversation-actions"
:class="{ 'conversation-actions--highlighted': props.isHighlighted }">
<p>{{ t('spreed', 'Meeting conversations are archived after 7 days of no activity.') }}</p>
<p>{{ descriptionLabel }}</p>
<div class="conversation-actions__buttons">
<NcButton v-if="supportsArchive"
type="primary"
@click="archiveEventConversation">
<template #icon>
<IconArchive />
</template>
{{ t('spreed', 'Archive now') }}
</NcButton>
<NcButton v-if="isModerator"
type="error"
@click="showDialog = true">
@click="showConfirmationDialog">
<template #icon>
<IconDelete />
</template>
{{ t('spreed', 'Delete now') }}
</NcButton>
<NcButton v-if="supportsArchive"
type="secondary"
@click="resetObjectConversation">
<template #icon>
<IconCheckUnderline />
</template>
{{ t('spreed', 'Keep') }}
</NcButton>
</div>
<NcDialog :open.sync="showDialog"
:name="t('spreed', 'Delete conversation')"
:message="t('spreed', 'Are you sure you want to delete this conversation?')">
<template #actions>
<NcButton type="tertiary" @click="showDialog = false">
{{ t('spreed', 'No') }}
</NcButton>
<NcButton type="error" @click="deleteEventConversation">
{{ t('spreed', 'Yes') }}
</NcButton>
</template>
</NcDialog>
</div>
</template>

11
src/services/conversationsService.ts

@ -7,7 +7,6 @@ import axios from '@nextcloud/axios'
import { generateOcsUrl } from '@nextcloud/router'
import { hasTalkFeature } from './CapabilitiesManager.ts'
import { ATTENDEE, CONVERSATION } from '../constants.ts'
import type {
getAllConversationsParams,
getAllConversationsResponse,
@ -19,6 +18,7 @@ import type {
createConversationResponse,
legacyCreateConversationParams,
deleteConversationResponse,
unbindConversationFromObjectResponse,
setConversationNameParams,
setConversationNameResponse,
setConversationPasswordParams,
@ -167,6 +167,14 @@ async function deleteConversation(token: string): deleteConversationResponse {
return axios.delete(generateOcsUrl('apps/spreed/api/v4/room/{token}', { token }))
}
/**
* Detach a conversation from an object and it becomes a "normal" conversation.
* @param token The token of the conversation to be deleted.
*/
async function unbindConversationFromObject(token: string): unbindConversationFromObjectResponse {
return axios.delete(generateOcsUrl('apps/spreed/api/v4/room/{token}/object', { token }))
}
/**
* Add a conversation to the favorites
* @param token The token of the conversation to be favorites
@ -351,6 +359,7 @@ export {
createLegacyConversation,
createConversation,
deleteConversation,
unbindConversationFromObject,
addToFavorites,
removeFromFavorites,
archiveConversation,

12
src/store/conversationsStore.js

@ -42,6 +42,7 @@ import {
setConversationName,
setConversationDescription,
deleteConversation,
unbindConversationFromObject,
setNotificationLevel,
setNotificationCalls,
setConversationPermissions,
@ -1231,6 +1232,17 @@ const actions = {
showError(t('spreed', 'Could not delete the conversation picture'))
}
},
async unbindConversationFromObject(context, { token }) {
try {
const response = await unbindConversationFromObject(token)
const conversation = response.data.ocs.data
context.commit('addConversation', conversation)
} catch (error) {
console.error('Error while unbinding conversation from object: ', error)
showError(t('spreed', 'Could not remove the automatic expiration'))
}
}
}
export default { state, mutations, getters, actions }
Loading…
Cancel
Save