Skip to content

Commit

Permalink
Chunter: pin messages (#1396)
Browse files Browse the repository at this point in the history
Signed-off-by: budaeva <irina.budaeva@xored.com>
  • Loading branch information
budaeva authored Apr 14, 2022
1 parent da45faf commit b6156fa
Show file tree
Hide file tree
Showing 14 changed files with 261 additions and 12 deletions.
3 changes: 3 additions & 0 deletions models/chunter/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ export class TChannel extends TSpace implements Channel {
@Prop(TypeTimestamp(), chunter.string.LastMessage)
lastMessage?: Timestamp

@Prop(ArrOf(TypeRef(chunter.class.ChunterMessage)), chunter.string.PinnedMessages)
pinned?: Ref<ChunterMessage>[]

@Prop(TypeString(), chunter.string.Topic)
@Index(IndexKind.FullText)
topic?: string
Expand Down
3 changes: 2 additions & 1 deletion models/chunter/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ export default mergeIds(chunterId, chunter, {
CreateBy: '' as IntlString,
Create: '' as IntlString,
MarkUnread: '' as IntlString,
LastMessage: '' as IntlString
LastMessage: '' as IntlString,
PinnedMessages: '' as IntlString
},
viewlet: {
Chat: '' as Ref<ViewletDescriptor>
Expand Down
3 changes: 3 additions & 0 deletions plugins/chunter-assets/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
"MarkUnread": "Mark unread",
"GetNewReplies": "Get notified about new replies",
"TurnOffReplies": "Turn off notifications for replies",
"PinMessage": "Pin message",
"UnpinMessage": "Unpin message",
"Pinned": "Pinned:",
"EditMessage": "Edit message",
"DeleteMessage": "Delete message"
}
Expand Down
3 changes: 3 additions & 0 deletions plugins/chunter-assets/lang/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
"MarkUnread": "Отметить как непрочитанное",
"GetNewReplies": "Получать уведомления о новых ответах",
"TurnOffReplies": "Выключить уведомления об ответах",
"PinMessage": "Закрепить сообщение",
"UnpinMessage": "Открепить сообщение",
"Pinned": "Закреплено:",
"EditMessage": "Редактировать сообщение",
"DeleteMessage": "Удалить сообщение"
}
Expand Down
6 changes: 4 additions & 2 deletions plugins/chunter-resources/src/components/Channel.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
-->
<script lang="ts">
import attachment from '@anticrm/attachment'
import type { Message } from '@anticrm/chunter'
import type { ChunterMessage, Message } from '@anticrm/chunter'
import contact, { Employee } from '@anticrm/contact'
import core, { Doc, Ref, Space, WithLookup } from '@anticrm/core'
import { NotificationClientImpl } from '@anticrm/notification-resources'
Expand All @@ -23,7 +23,9 @@
import chunter from '../plugin'
import ChannelSeparator from './ChannelSeparator.svelte'
import MessageComponent from './Message.svelte'
export let space: Ref<Space> | undefined
export let pinnedIds: Ref<ChunterMessage>[]
let div: HTMLDivElement | undefined
let autoscroll: boolean = false
Expand Down Expand Up @@ -111,7 +113,7 @@
{#if newMessagesPos === i}
<ChannelSeparator title={chunter.string.New} line reverse isNew />
{/if}
<MessageComponent {message} {employees} on:openThread />
<MessageComponent {message} {employees} on:openThread isPinned={pinnedIds.includes(message._id)} />
{/each}
{/if}
</div>
Expand Down
18 changes: 16 additions & 2 deletions plugins/chunter-resources/src/components/ChannelView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@
-->
<script lang="ts">
import { AttachmentRefInput } from '@anticrm/attachment-resources'
import { Message } from '@anticrm/chunter'
import { ChunterMessage, Message } from '@anticrm/chunter'
import { generateId, getCurrentAccount, Ref, Space, TxFactory } from '@anticrm/core'
import { NotificationClientImpl } from '@anticrm/notification-resources'
import { getClient } from '@anticrm/presentation'
import { createQuery, getClient } from '@anticrm/presentation'
import { getCurrentLocation, navigate } from '@anticrm/ui'
import { createBacklinks } from '../backlinks'
import chunter from '../plugin'
import Channel from './Channel.svelte'
import PinnedMessages from './PinnedMessages.svelte'
export let space: Ref<Space>
Expand Down Expand Up @@ -63,13 +64,26 @@
loc.path[3] = _id
navigate(loc)
}
const pinnedQuery = createQuery()
let pinnedIds: Ref<ChunterMessage>[] = []
pinnedQuery.query(
chunter.class.Channel,
{ _id: space },
(res) => {
pinnedIds = res[0]?.pinned ?? []
},
{ limit: 1 }
)
</script>

<PinnedMessages {space} {pinnedIds} />
<Channel
{space}
on:openThread={(e) => {
openThread(e.detail)
}}
{pinnedIds}
/>
<div class="reference">
<AttachmentRefInput {space} {_class} objectId={_id} on:message={onMessage} />
Expand Down
22 changes: 21 additions & 1 deletion plugins/chunter-resources/src/components/Message.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import { Action } from '@anticrm/view'
import { getActions } from '@anticrm/view-resources'
import { createEventDispatcher } from 'svelte'
import { UnpinMessage } from '../index';
import chunter from '../plugin'
import { getTime } from '../utils'
// import Share from './icons/Share.svelte'
Expand All @@ -37,6 +38,7 @@
export let message: WithLookup<Message>
export let employees: Map<Ref<Employee>, Employee>
export let thread: boolean = false
export let isPinned: boolean = false
$: employee = getEmployee(message)
$: attachments = (message.$lookup?.attachments ?? []) as Attachment[]
Expand All @@ -59,6 +61,16 @@
action: chunter.actionImpl.SubscribeMessage
} as Action)
$: pinActions = isPinned
? ({
label: chunter.string.UnpinMessage,
action: chunter.actionImpl.UnpinMessage
} as Action)
: ({
label: chunter.string.PinMessage,
action: chunter.actionImpl.PinMessage
} as Action)
$: isEditing = false;
const editAction = {
Expand All @@ -68,12 +80,20 @@
const deleteAction = {
label: chunter.string.DeleteMessage,
action: async () => await client.remove(message)
action: async () => {
(await client.findAll(chunter.class.ThreadMessage, {attachedTo: message._id})).forEach(c => {
UnpinMessage(c)
})
UnpinMessage(message)
await client.remove(message)
}
}
const showMenu = async (ev: Event): Promise<void> => {
const actions = await getActions(client, message, chunter.class.Message)
actions.push(subscribeAction)
actions.push(pinActions)
showPopup(
Menu,
{
Expand Down
29 changes: 29 additions & 0 deletions plugins/chunter-resources/src/components/PinnedMessages.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<script lang="ts">
import { ChunterMessage } from '@anticrm/chunter'
import { Ref, Space } from '@anticrm/core'
import { Label, showPopup } from '@anticrm/ui'
import PinnedMessagesPopup from './PinnedMessagesPopup.svelte'
import chunter from '../plugin'
export let space: Ref<Space>
export let pinnedIds: Ref<ChunterMessage>[]
function showMessages (ev: MouseEvent & { currentTarget: EventTarget & HTMLDivElement }) {
showPopup(PinnedMessagesPopup, { space }, ev.target)
}
</script>

{#if pinnedIds.length > 0}
<div class="bottom-divider over-underline pt-2 pb-2 container">
<div on:click={(ev) => showMessages(ev)}>
<Label label={chunter.string.Pinned} />
{pinnedIds.length}
</div>
</div>
{/if}

<style lang="scss">
.container {
padding-left: 2.5rem;
}
</style>
116 changes: 116 additions & 0 deletions plugins/chunter-resources/src/components/PinnedMessagesPopup.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<script lang="ts">
import chunter, { ChunterMessage } from '@anticrm/chunter'
import contact, { Employee, EmployeeAccount, formatName } from '@anticrm/contact'
import { Ref, Space } from '@anticrm/core'
import { Avatar, createQuery, getClient, MessageViewer } from '@anticrm/presentation'
import { IconClose } from '@anticrm/ui'
import { createEventDispatcher } from 'svelte'
import { UnpinMessage } from '../index'
import { getTime } from '../utils'
export let space: Ref<Space>
const pinnedQuery = createQuery()
let pinnedIds: Ref<ChunterMessage>[] = []
pinnedQuery.query(
chunter.class.Channel,
{ _id: space },
(res) => {
pinnedIds = res[0]?.pinned ?? []
},
{ limit: 1 }
)
const messagesQuery = createQuery()
let pinnedMessages: ChunterMessage[] = []
$: pinnedIds &&
messagesQuery.query(chunter.class.ChunterMessage, { _id: { $in: pinnedIds } }, (res) => {
pinnedMessages = res
})
const employeeAccoutsQuery = createQuery()
let employeeAcounts: EmployeeAccount[]
employeeAccoutsQuery.query(contact.class.EmployeeAccount, {}, (res) => (employeeAcounts = res))
const client = getClient()
const dispatch = createEventDispatcher()
async function getAvatar (_id?: Ref<Employee>): Promise<string | undefined | null> {
if (_id === undefined) return (await client.findOne(contact.class.Employee, { _id }))?.avatar
}
function getEmployee (message: ChunterMessage): EmployeeAccount | undefined {
return employeeAcounts?.find((e) => e._id === message.createBy)
}
</script>

<div class="antiPopup vScroll popup">
{#each pinnedMessages as message}
<div class="message">
<div class="header">
{#await getEmployee(message) then employeeAccount}
{#await getAvatar(employeeAccount?.employee) then avatar}
<div class="avatar">
<Avatar size={'medium'} {avatar} />
</div>
{/await}
<span class="name">
{formatName(employeeAccount?.name ?? '')}
</span>
{/await}
<div
class="cross"
on:click={async () => {
if (pinnedIds.length === 1)
dispatch('close')
UnpinMessage(message)
}}
>
<IconClose size="small" />
</div>
</div>
<MessageViewer message={message.content} />
<span class="time">{getTime(message.createOn)}</span>
</div>
{/each}
</div>

<style lang="scss">
.popup {
padding: 1.25rem 1.25rem 1.25rem;
max-height: 20rem;
color: var(--theme-caption-color);
}
.message {
padding: 0.75rem 1rem 0.75rem;
margin-bottom: 1rem;
box-shadow: inherit;
border-radius: inherit;
}
.header {
display: flex;
flex-direction: row;
align-items: center;
.name {
font-weight: 500;
margin-left: 1rem;
flex-grow: 2;
}
.cross {
opacity: 0.4;
cursor: pointer;
&:hover {
opacity: 1;
}
}
}
.time {
font-size: 0.75rem;
}
</style>
18 changes: 17 additions & 1 deletion plugins/chunter-resources/src/components/ThreadComment.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import { ActionIcon, IconMoreH, Menu, showPopup } from '@anticrm/ui'
import { Action } from '@anticrm/view'
import { getActions } from '@anticrm/view-resources'
import { UnpinMessage } from '../index';
import chunter from '../plugin'
import { getTime } from '../utils'
// import Share from './icons/Share.svelte'
Expand All @@ -33,6 +34,7 @@
export let message: WithLookup<ThreadMessage>
export let employees: Map<Ref<Employee>, Employee>
export let isPinned: boolean = false
$: attachments = (message.$lookup?.attachments ?? []) as Attachment[]
Expand All @@ -53,6 +55,16 @@
action: chunter.actionImpl.SubscribeComment
} as Action)
$: pinActions = isPinned
? ({
label: chunter.string.UnpinMessage,
action: chunter.actionImpl.UnpinMessage
} as Action)
: ({
label: chunter.string.PinMessage,
action: chunter.actionImpl.PinMessage
} as Action)
$: isEditing = false;
const editAction = {
Expand All @@ -62,12 +74,16 @@
const deleteAction = {
label: chunter.string.DeleteMessage,
action: async () => await client.removeDoc(message._class, message.space, message._id)
action: async () => {
await client.removeDoc(message._class, message.space, message._id)
UnpinMessage(message)
}
}
const showMenu = async (ev: Event): Promise<void> => {
const actions = await getActions(client, message, chunter.class.ThreadMessage)
actions.push(subscribeAction)
actions.push(pinActions)
showPopup(
Menu,
{
Expand Down
Loading

0 comments on commit b6156fa

Please sign in to comment.