mirror of
https://github.com/hcengineering/platform.git
synced 2025-06-09 09:20:54 +00:00
Add remove message action
Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
parent
26f01bb27d
commit
06747dc3c2
@ -167,6 +167,19 @@ class Client {
|
||||
await this.sendEvent(event)
|
||||
}
|
||||
|
||||
async removeMessage (card: CardID, message: MessageID, messageCreated: Date): Promise<void> {
|
||||
const event: CreatePatchEvent = {
|
||||
type: MessageRequestEventType.CreatePatch,
|
||||
patchType: PatchType.remove,
|
||||
card,
|
||||
message,
|
||||
messageCreated,
|
||||
data: { },
|
||||
creator: this.getSocialId()
|
||||
}
|
||||
await this.sendEvent(event)
|
||||
}
|
||||
|
||||
async createReaction (card: CardID, message: MessageID, messageCreated: Date, reaction: string): Promise<void> {
|
||||
const event: CreateReactionEvent = {
|
||||
type: MessageRequestEventType.CreateReaction,
|
||||
|
@ -28,6 +28,10 @@
|
||||
"Yesterday": "Včera",
|
||||
"YesterdayAt": "Včera v {time}",
|
||||
"AndMore": "a {count} dalších",
|
||||
"IsTyping": "{count, plural, =1 {píše} other {píší}}"
|
||||
"IsTyping": "{count, plural, =1 {píše} other {píší}}",
|
||||
"Loading": "Načítání...",
|
||||
"MessageIn": "Zpráva #{title}",
|
||||
"ThreadWasDeleted": "Tato vlákno byla smazána.",
|
||||
"MessageWasRemoved": "Tato zpráva byla odstraněna."
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,10 @@
|
||||
"Yesterday": "Gestern",
|
||||
"YesterdayAt": "Gestern um {time}",
|
||||
"AndMore": "und {count} weitere",
|
||||
"IsTyping": "{count, plural, =1 {schreibt} other {schreiben}}"
|
||||
"IsTyping": "{count, plural, =1 {schreibt} other {schreiben}}",
|
||||
"Loading": "Laden...",
|
||||
"MessageIn": "Nachricht #{title}",
|
||||
"ThreadWasDeleted": "Dieser Thread wurde gelöscht.",
|
||||
"MessageWasRemoved": "Diese Nachricht wurde entfernt."
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,8 @@
|
||||
"AndMore": "and {count} more",
|
||||
"IsTyping": "{count, plural, =1 {is typing} other {are typing}}...",
|
||||
"Loading": "Loading...",
|
||||
"MessageIn": "Message #{title}"
|
||||
"MessageIn": "Message #{title}",
|
||||
"ThreadWasRemoved": "This thread was removed.",
|
||||
"MessageWasRemoved": "This message was removed."
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,10 @@
|
||||
"Yesterday": "Ayer",
|
||||
"YesterdayAt": "Ayer a las {time}",
|
||||
"AndMore": "y {count} más",
|
||||
"IsTyping": "{count, plural, =1 {está escribiendo} other {están escribiendo}}"
|
||||
"IsTyping": "{count, plural, =1 {está escribiendo} other {están escribiendo}}",
|
||||
"Loading": "Cargando...",
|
||||
"MessageIn": "Mensaje #{title}",
|
||||
"ThreadWasDeleted": "Este hilo fue eliminado.",
|
||||
"MessageWasRemoved": "Este mensaje fue eliminado."
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,10 @@
|
||||
"Yesterday": "Hier",
|
||||
"YesterdayAt": "Hier à {time}",
|
||||
"AndMore": "et {count} autres",
|
||||
"IsTyping": "{count, plural, =1 {est en train d'écrire} other {écrivent}}"
|
||||
"IsTyping": "{count, plural, =1 {est en train d'écrire} other {écrivent}}",
|
||||
"Loading": "Chargement...",
|
||||
"MessageIn": "Message #{title}",
|
||||
"ThreadWasDeleted": "Ce fil de discussion a été supprimé.",
|
||||
"MessageWasRemoved": "Ce message a été supprimé."
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,10 @@
|
||||
"Yesterday": "Ieri",
|
||||
"YesterdayAt": "Ieri alle {time}",
|
||||
"AndMore": "e {count} altri",
|
||||
"IsTyping": "{count, plural, =1 {sta scrivendo} other {stanno scrivendo}}"
|
||||
"IsTyping": "{count, plural, =1 {sta scrivendo} other {stanno scrivendo}}",
|
||||
"Loading": "Caricamento...",
|
||||
"MessageIn": "Messaggio #{title}",
|
||||
"ThreadWasDeleted": "Questo thread è stato eliminato.",
|
||||
"MessageWasRemoved": "Questo messaggio è stato rimosso."
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,10 @@
|
||||
"Yesterday": "昨日",
|
||||
"YesterdayAt": "昨日・{time}",
|
||||
"AndMore": "および{count}件の他",
|
||||
"IsTyping": "{count, plural, =1 {入力中} other {入力中}}"
|
||||
"IsTyping": "{count, plural, =1 {入力中} other {入力中}}",
|
||||
"Loading": "読み込み中...",
|
||||
"MessageIn": "メッセージ #{title}",
|
||||
"ThreadWasDeleted": "このスレッドは削除されました。",
|
||||
"MessageWasRemoved": "このメッセージは削除されました。"
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,10 @@
|
||||
"Yesterday": "Ontem",
|
||||
"YesterdayAt": "Ontem às {time}",
|
||||
"AndMore": "e mais {count}",
|
||||
"IsTyping": "{count, plural, =1 {está digitando} other {estão digitando}}"
|
||||
"IsTyping": "{count, plural, =1 {está digitando} other {estão digitando}}",
|
||||
"Loading": "Carregando...",
|
||||
"MessageIn": "Mensagem #{title}",
|
||||
"ThreadWasDeleted": "Este thread foi excluído.",
|
||||
"MessageWasRemoved": "Este mensagem foi removida."
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,10 @@
|
||||
"Yesterday": "Вчера",
|
||||
"YesterdayAt": "Вчера в {time}",
|
||||
"AndMore": "и еще {count}",
|
||||
"IsTyping": "{count, plural, =1 {печатает} other {печатают}}..."
|
||||
"IsTyping": "{count, plural, =1 {печатает} other {печатают}}...",
|
||||
"Loading": "Загрузка...",
|
||||
"MessageIn": "Сообщение #{title}",
|
||||
"ThreadWasDeleted": "Этот поток был удален.",
|
||||
"MessageWasRemoved": "Это сообщение было удалено."
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,10 @@
|
||||
"Yesterday": "昨天",
|
||||
"YesterdayAt": "昨天 于 {time}",
|
||||
"AndMore": "和其他 {count} 条",
|
||||
"IsTyping": "{count, plural, =1 {正在输入} other {正在输入}}"
|
||||
"IsTyping": "{count, plural, =1 {正在输入} other {正在输入}}",
|
||||
"Loading": "加载中...",
|
||||
"MessageIn": "消息 #{title}",
|
||||
"ThreadWasDeleted": "此线程已被删除。",
|
||||
"MessageWasRemoved": "此消息已被删除。"
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { showPopup, ButtonIcon } from '@hcengineering/ui'
|
||||
import ui, { showPopup, ButtonIcon, IconDelete } from '@hcengineering/ui'
|
||||
import { Message } from '@hcengineering/communication-types'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import emojiPlugin from '@hcengineering/emoji'
|
||||
@ -30,6 +30,7 @@
|
||||
export let canReply: boolean = true
|
||||
export let canReact: boolean = true
|
||||
export let isOpened: boolean = false
|
||||
export let canRemove: boolean = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@ -89,6 +90,18 @@
|
||||
})
|
||||
}
|
||||
|
||||
if (canRemove) {
|
||||
actions.push({
|
||||
id: 'remove',
|
||||
label: ui.string.Remove,
|
||||
icon: IconDelete,
|
||||
order: 999,
|
||||
action: () => {
|
||||
dispatch('remove')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return actions.sort((a, b) => a.order - b.order)
|
||||
}
|
||||
|
||||
|
@ -17,11 +17,13 @@
|
||||
import { MessageViewer as MarkupMessageViewer } from '@hcengineering/presentation'
|
||||
import { Message, MessageType } from '@hcengineering/communication-types'
|
||||
import { Card } from '@hcengineering/card'
|
||||
import { Label } from '@hcengineering/ui'
|
||||
|
||||
import ActivityMessageViewer from './ActivityMessageViewer.svelte'
|
||||
import { toMarkup } from '../../utils'
|
||||
import { isActivityMessage } from '../../activity'
|
||||
import ThreadMessageViewer from './ThreadMessageViewer.svelte'
|
||||
import uiNext from '../../plugin'
|
||||
|
||||
export let card: Card
|
||||
export let message: Message
|
||||
@ -29,10 +31,20 @@
|
||||
|
||||
{#if message.type === MessageType.Thread || message.thread != null}
|
||||
<ThreadMessageViewer {message} thread={message.thread} />
|
||||
{:else if message.type === MessageType.Message}
|
||||
<MarkupMessageViewer message={toMarkup(message.content)} />
|
||||
{:else if isActivityMessage(message)}
|
||||
<ActivityMessageViewer {message} {card} />
|
||||
{:else}
|
||||
<MarkupMessageViewer message={toMarkup(message.content)} />
|
||||
{#if message.removed}
|
||||
<span class="overflow-label removed-label">
|
||||
<Label label={uiNext.string.MessageWasRemoved} />
|
||||
</span>
|
||||
{:else}
|
||||
<MarkupMessageViewer message={toMarkup(message.content)} />
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.removed-label {
|
||||
color: var(--theme-text-placeholder-color);
|
||||
}
|
||||
</style>
|
||||
|
@ -15,10 +15,10 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { getPersonBySocialId, Person } from '@hcengineering/contact'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { getClient, getCommunicationClient } from '@hcengineering/presentation'
|
||||
import { Card } from '@hcengineering/card'
|
||||
import { getCurrentAccount } from '@hcengineering/core'
|
||||
import { getEventPositionElement, showPopup, Action as MenuAction } from '@hcengineering/ui'
|
||||
import ui, { getEventPositionElement, showPopup, Action as MenuAction, IconDelete } from '@hcengineering/ui'
|
||||
import { personByPersonIdStore } from '@hcengineering/contact-resources'
|
||||
import type { SocialID } from '@hcengineering/communication-types'
|
||||
import { Message, MessageType } from '@hcengineering/communication-types'
|
||||
@ -42,11 +42,14 @@
|
||||
export let hideAvatar: boolean = false
|
||||
|
||||
const client = getClient()
|
||||
const communicationClient = getCommunicationClient()
|
||||
const me = getCurrentAccount()
|
||||
|
||||
let isEditing = false
|
||||
let isDeleted = false
|
||||
let author: Person | undefined
|
||||
|
||||
$:isDeleted = message.removed || (message.type === MessageType.Thread && message.thread == null)
|
||||
$: void updateAuthor(message.creator)
|
||||
|
||||
function canEdit (): boolean {
|
||||
@ -57,6 +60,13 @@
|
||||
return me.socialIds.includes(message.creator)
|
||||
}
|
||||
|
||||
function canRemove (): boolean {
|
||||
if (!editable) return false
|
||||
if (message.type !== MessageType.Message) return false
|
||||
|
||||
return me.socialIds.includes(message.creator)
|
||||
}
|
||||
|
||||
function canReply (): boolean {
|
||||
return message.type === MessageType.Message || message.type === MessageType.Thread
|
||||
}
|
||||
@ -74,6 +84,12 @@
|
||||
isEditing = true
|
||||
}
|
||||
|
||||
async function handleRemove (): Promise<void> {
|
||||
if (!canRemove()) return
|
||||
message.removed = true
|
||||
await communicationClient.removeMessage(message.card, message.id, message.created)
|
||||
}
|
||||
|
||||
function isInside (x: number, y: number, rect: DOMRect): boolean {
|
||||
return x >= rect.left && y >= rect.top && x <= rect.right && y <= rect.bottom
|
||||
}
|
||||
@ -147,6 +163,14 @@
|
||||
})
|
||||
}
|
||||
|
||||
if (canRemove()) {
|
||||
actions.push({
|
||||
label: ui.string.Remove,
|
||||
icon: IconDelete,
|
||||
action: handleRemove
|
||||
})
|
||||
}
|
||||
|
||||
showPopup(Menu, { actions }, getEventPositionElement(event), () => {})
|
||||
}
|
||||
}
|
||||
@ -161,19 +185,21 @@
|
||||
<div
|
||||
class="message"
|
||||
id={`${message.id}`}
|
||||
on:contextmenu={editable && !isEditing ? handleContextMenu : undefined}
|
||||
on:contextmenu={editable && !isEditing && !isDeleted ? handleContextMenu : undefined}
|
||||
class:active={isActionsOpened && !isEditing}
|
||||
class:noHover={!editable}
|
||||
style:padding
|
||||
>
|
||||
{#if !isEditing && editable}
|
||||
{#if !isEditing && editable && !isDeleted}
|
||||
<div class="message__actions" class:opened={isActionsOpened}>
|
||||
<MessageActionsPanel
|
||||
{message}
|
||||
editable={canEdit()}
|
||||
canReply={canReply()}
|
||||
canRemove={canRemove()}
|
||||
bind:isOpened={isActionsOpened}
|
||||
on:edit={handleEdit}
|
||||
on:remove={handleRemove}
|
||||
on:reply={() => {
|
||||
void replyToThread(message, card)
|
||||
}}
|
||||
@ -181,7 +207,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if isThread || message.type === MessageType.Activity}
|
||||
{#if isThread || message.type === MessageType.Activity || message.removed}
|
||||
<OneRowMessageBody {message} {card} {author} {replies} {hideAvatar} />
|
||||
{:else}
|
||||
<MessageBody {message} {card} {author} bind:isEditing {compact} {replies} {hideAvatar} />
|
||||
|
@ -47,7 +47,8 @@
|
||||
<div class="messages-group__messages">
|
||||
{#each messages as message, index (message.id)}
|
||||
{@const previousMessage = messages[index - 1]}
|
||||
{@const compact =
|
||||
{@const compact = !message.removed &&
|
||||
!previousMessage?.removed &&
|
||||
previousMessage !== undefined &&
|
||||
previousMessage.creator === message.creator &&
|
||||
previousMessage.type === message.type &&
|
||||
|
@ -37,7 +37,7 @@
|
||||
}
|
||||
|
||||
let isDeleted = false
|
||||
$:isDeleted = message.type === MessageType.Thread && message.thread == null
|
||||
$:isDeleted = (message.type === MessageType.Thread && message.thread == null) || message.removed
|
||||
</script>
|
||||
|
||||
<div class="message__body">
|
||||
|
@ -19,7 +19,8 @@
|
||||
import cardPlugin, { Card } from '@hcengineering/card'
|
||||
import { ObjectPresenter } from '@hcengineering/view-resources'
|
||||
import { Label } from '@hcengineering/ui'
|
||||
import {Class, type Ref} from '@hcengineering/core'
|
||||
import { Class, type Ref } from '@hcengineering/core'
|
||||
import uiNext from '../../plugin'
|
||||
|
||||
export let message: Message
|
||||
export let thread: Thread | undefined
|
||||
@ -59,7 +60,9 @@
|
||||
<div class="thread-view">
|
||||
{#if label && !isDeleted}
|
||||
<div class="thread-type">
|
||||
<span class="overflow-label">
|
||||
<Label {label} />
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
{#if threadCard}
|
||||
@ -72,7 +75,7 @@
|
||||
/>
|
||||
{:else if isDeleted}
|
||||
<div class="deletedText">
|
||||
This thread was deleted.
|
||||
<Label label={uiNext.string.ThreadWasRemoved} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -49,7 +49,9 @@ export const uiNext = plugin(uiNextId, {
|
||||
AndMore: '' as IntlString,
|
||||
IsTyping: '' as IntlString,
|
||||
Loading: '' as IntlString,
|
||||
MessageIn: '' as IntlString
|
||||
MessageIn: '' as IntlString,
|
||||
ThreadWasRemoved: '' as IntlString,
|
||||
MessageWasRemoved: '' as IntlString
|
||||
}
|
||||
})
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user