mirror of
https://github.com/hcengineering/platform.git
synced 2025-01-03 08:57:14 +03:00
Add employee action to start conversation (#6687)
Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
parent
e72766a6b2
commit
0763624688
@ -19,6 +19,7 @@ import notification, { notificationActionTemplates } from '@hcengineering/model-
|
||||
import activity from '@hcengineering/activity'
|
||||
import workbench from '@hcengineering/model-workbench'
|
||||
import core from '@hcengineering/model-core'
|
||||
import contact from '@hcengineering/contact'
|
||||
|
||||
import chunter from './plugin'
|
||||
|
||||
@ -43,6 +44,18 @@ export function defineActions (builder: Builder): void {
|
||||
chunter.category.Chunter
|
||||
)
|
||||
|
||||
createAction(builder, {
|
||||
action: chunter.actionImpl.StartConversation,
|
||||
label: chunter.string.StartConversation,
|
||||
icon: chunter.icon.Thread,
|
||||
input: 'focus',
|
||||
category: chunter.category.Chunter,
|
||||
target: contact.mixin.Employee,
|
||||
context: {
|
||||
mode: 'context',
|
||||
group: 'associate'
|
||||
}
|
||||
})
|
||||
defineMessageActions(builder)
|
||||
defineChannelActions(builder)
|
||||
}
|
||||
|
@ -53,7 +53,8 @@ export default mergeIds(chunterId, chunter, {
|
||||
ReplyToThread: '' as ViewAction,
|
||||
OpenInSidebar: '' as ViewAction,
|
||||
TranslateMessage: '' as ViewAction,
|
||||
ShowOriginalMessage: '' as ViewAction
|
||||
ShowOriginalMessage: '' as ViewAction,
|
||||
StartConversation: '' as ViewAction
|
||||
},
|
||||
category: {
|
||||
Chunter: '' as Ref<ActionCategory>
|
||||
|
@ -148,6 +148,8 @@
|
||||
}
|
||||
|
||||
.icon {
|
||||
writing-mode: initial;
|
||||
text-orientation: initial;
|
||||
&.vertical {
|
||||
transform: rotate(90deg);
|
||||
text-orientation: upright;
|
||||
|
@ -126,6 +126,7 @@
|
||||
"TranslateMessage": "Translate message",
|
||||
"Translate": "Translate",
|
||||
"ShowOriginal": "Show original",
|
||||
"Translating": "Translating..."
|
||||
"Translating": "Translating...",
|
||||
"StartConversation": "Start conversation"
|
||||
}
|
||||
}
|
@ -126,6 +126,7 @@
|
||||
"TranslateMessage": "Traducir mensaje",
|
||||
"Translate": "Traducir",
|
||||
"ShowOriginal": "Mostrar original",
|
||||
"Translating": "Traduciendo..."
|
||||
"Translating": "Traduciendo...",
|
||||
"StartConversation": "Iniciar conversación"
|
||||
}
|
||||
}
|
@ -126,6 +126,7 @@
|
||||
"TranslateMessage": "Traduire le message",
|
||||
"Translate": "Traduire",
|
||||
"ShowOriginal": "Afficher l'original",
|
||||
"Translating": "Traduction en cours..."
|
||||
"Translating": "Traduction en cours...",
|
||||
"StartConversation": "Démarrer la conversation"
|
||||
}
|
||||
}
|
@ -126,6 +126,7 @@
|
||||
"TranslateMessage": "Traduzir mensagem",
|
||||
"Translate": "Traduzir",
|
||||
"ShowOriginal": "Mostrar original",
|
||||
"Translating": "A traduzir..."
|
||||
"Translating": "A traduzir...",
|
||||
"StartConversation": "Iniciar conversa"
|
||||
}
|
||||
}
|
@ -126,6 +126,7 @@
|
||||
"TranslateMessage": "Перевести сообщение",
|
||||
"Translate": "Перевести",
|
||||
"ShowOriginal": "Показать оригинал",
|
||||
"Translating": "Перевод..."
|
||||
"Translating": "Перевод...",
|
||||
"StartConversation": "Начать диалог"
|
||||
}
|
||||
}
|
@ -126,6 +126,7 @@
|
||||
"TranslateMessage": "翻译消息",
|
||||
"Translate": "翻译",
|
||||
"ShowOriginal": "显示原文",
|
||||
"Translating": "翻译中..."
|
||||
"Translating": "翻译中...",
|
||||
"StartConversation": "开始对话"
|
||||
}
|
||||
}
|
||||
|
@ -14,24 +14,20 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
|
||||
import { DirectMessage } from '@hcengineering/chunter'
|
||||
import contact, { Employee, Person, PersonAccount } from '@hcengineering/contact'
|
||||
import core, { getCurrentAccount, Ref } from '@hcengineering/core'
|
||||
import { personIdByAccountId, SelectUsersPopup } from '@hcengineering/contact-resources'
|
||||
import notification from '@hcengineering/notification'
|
||||
import contact, { Employee, PersonAccount } from '@hcengineering/contact'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { SelectUsersPopup } from '@hcengineering/contact-resources'
|
||||
import presentation, { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { Modal, showPopup } from '@hcengineering/ui'
|
||||
|
||||
import chunter from '../../../plugin'
|
||||
import { buildDmName } from '../../../utils'
|
||||
import { buildDmName, createDirect } from '../../../utils'
|
||||
import ChannelMembers from '../../ChannelMembers.svelte'
|
||||
import { openChannel } from '../../../navigation'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
const myAcc = getCurrentAccount() as PersonAccount
|
||||
const query = createQuery()
|
||||
|
||||
let employeeIds: Ref<Employee>[] = []
|
||||
@ -51,74 +47,12 @@
|
||||
}
|
||||
|
||||
async function createDirectMessage (): Promise<void> {
|
||||
const employeeAccounts = await client.findAll(contact.class.PersonAccount, { person: { $in: employeeIds } })
|
||||
const accIds = [myAcc._id, ...employeeAccounts.filter(({ _id }) => _id !== myAcc._id).map(({ _id }) => _id)].sort()
|
||||
const dmId = await createDirect(employeeIds)
|
||||
|
||||
const existingDms = await client.findAll(chunter.class.DirectMessage, {})
|
||||
const newDirectPersons = Array.from(new Set([...employeeIds, myAcc.person])).sort()
|
||||
|
||||
let direct: DirectMessage | undefined
|
||||
|
||||
for (const dm of existingDms) {
|
||||
const existDirectPersons = Array.from(
|
||||
new Set(dm.members.map((id) => $personIdByAccountId.get(id as Ref<PersonAccount>)))
|
||||
)
|
||||
.filter((person): person is Ref<Person> => person !== undefined)
|
||||
.sort()
|
||||
if (deepEqual(existDirectPersons, newDirectPersons)) {
|
||||
direct = dm
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const existingMembers = direct?.members
|
||||
const missingAccounts = existingMembers !== undefined ? accIds.filter((id) => !existingMembers.includes(id)) : []
|
||||
|
||||
if (direct !== undefined && missingAccounts.length > 0) {
|
||||
await client.updateDoc(chunter.class.DirectMessage, direct.space, direct._id, {
|
||||
$push: { members: { $each: missingAccounts, $position: 0 } }
|
||||
})
|
||||
}
|
||||
|
||||
const dmId =
|
||||
direct?._id ??
|
||||
(await client.createDoc(chunter.class.DirectMessage, core.space.Space, {
|
||||
name: '',
|
||||
description: '',
|
||||
private: true,
|
||||
archived: false,
|
||||
members: accIds
|
||||
}))
|
||||
|
||||
const context = await client.findOne(notification.class.DocNotifyContext, {
|
||||
user: myAcc._id,
|
||||
objectId: dmId,
|
||||
objectClass: chunter.class.DirectMessage
|
||||
})
|
||||
|
||||
if (context !== undefined) {
|
||||
if (context.hidden) {
|
||||
await client.updateDoc(context._class, context.space, context._id, { hidden: false })
|
||||
}
|
||||
|
||||
dispatch('close')
|
||||
if (dmId !== undefined) {
|
||||
openChannel(dmId, chunter.class.DirectMessage)
|
||||
return
|
||||
dispatch('close')
|
||||
}
|
||||
|
||||
const space = await client.findOne(contact.class.PersonSpace, { person: myAcc.person }, { projection: { _id: 1 } })
|
||||
if (!space) return
|
||||
await client.createDoc(notification.class.DocNotifyContext, space._id, {
|
||||
user: myAcc._id,
|
||||
objectId: dmId,
|
||||
objectClass: chunter.class.DirectMessage,
|
||||
objectSpace: core.space.Space,
|
||||
hidden: false,
|
||||
isPinned: false
|
||||
})
|
||||
|
||||
openChannel(dmId, chunter.class.DirectMessage)
|
||||
dispatch('close')
|
||||
}
|
||||
|
||||
function handleCancel (): void {
|
||||
|
@ -78,7 +78,8 @@ import {
|
||||
removeChannelAction,
|
||||
translateMessage,
|
||||
showOriginalMessage,
|
||||
canTranslateMessage
|
||||
canTranslateMessage,
|
||||
startConversationAction
|
||||
} from './utils'
|
||||
|
||||
export { default as ChatMessageInput } from './components/chat-message/ChatMessageInput.svelte'
|
||||
@ -213,6 +214,7 @@ export default async (): Promise<Resources> => ({
|
||||
ReplyToThread: replyToThread,
|
||||
OpenInSidebar: openChannelInSidebarAction,
|
||||
TranslateMessage: translateMessage,
|
||||
ShowOriginalMessage: showOriginalMessage
|
||||
ShowOriginalMessage: showOriginalMessage,
|
||||
StartConversation: startConversationAction
|
||||
}
|
||||
})
|
||||
|
@ -22,7 +22,7 @@ import activity, {
|
||||
import { isReactionMessage } from '@hcengineering/activity-resources'
|
||||
import { type Channel, type ChatMessage, type DirectMessage, type ThreadMessage } from '@hcengineering/chunter'
|
||||
import contact, { getName, type Employee, type Person, type PersonAccount } from '@hcengineering/contact'
|
||||
import { PersonIcon, employeeByIdStore } from '@hcengineering/contact-resources'
|
||||
import { PersonIcon, employeeByIdStore, personIdByAccountId } from '@hcengineering/contact-resources'
|
||||
import core, {
|
||||
getCurrentAccount,
|
||||
type Account,
|
||||
@ -35,7 +35,7 @@ import core, {
|
||||
type Timestamp,
|
||||
type WithLookup
|
||||
} from '@hcengineering/core'
|
||||
import { type DocNotifyContext, type InboxNotification } from '@hcengineering/notification'
|
||||
import notification, { type DocNotifyContext, type InboxNotification } from '@hcengineering/notification'
|
||||
import {
|
||||
InboxNotificationsClientImpl,
|
||||
isActivityNotification,
|
||||
@ -48,10 +48,11 @@ import { classIcon, getDocLinkTitle, getDocTitle } from '@hcengineering/view-res
|
||||
import { get, writable, type Unsubscriber } from 'svelte/store'
|
||||
import aiBot from '@hcengineering/ai-bot'
|
||||
import { translate as aiTranslate } from '@hcengineering/ai-bot-resources'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
|
||||
import ChannelIcon from './components/ChannelIcon.svelte'
|
||||
import DirectIcon from './components/DirectIcon.svelte'
|
||||
import { resetChunterLocIfEqual } from './navigation'
|
||||
import { openChannelInSidebar, resetChunterLocIfEqual } from './navigation'
|
||||
import chunter from './plugin'
|
||||
import { shownTranslatedMessagesStore, translatedMessagesStore, translatingMessagesStore } from './stores'
|
||||
|
||||
@ -560,3 +561,90 @@ export async function canTranslateMessage (): Promise<boolean> {
|
||||
const url = getMetadata(aiBot.metadata.EndpointURL) ?? ''
|
||||
return url !== ''
|
||||
}
|
||||
|
||||
export async function startConversationAction (docs?: Employee | Employee[]): Promise<void> {
|
||||
if (docs === undefined) return
|
||||
const employees = Array.isArray(docs) ? docs : [docs]
|
||||
const employeeIds = employees.map(({ _id }) => _id)
|
||||
|
||||
const dm = await createDirect(employeeIds)
|
||||
|
||||
if (dm !== undefined) {
|
||||
await openChannelInSidebar(dm, chunter.class.DirectMessage, undefined, undefined, true)
|
||||
}
|
||||
}
|
||||
|
||||
export async function createDirect (employeeIds: Array<Ref<Employee>>): Promise<Ref<DirectMessage>> {
|
||||
const client = getClient()
|
||||
const me = getCurrentAccount()
|
||||
|
||||
const employeeAccounts = await client.findAll(contact.class.PersonAccount, { person: { $in: employeeIds } })
|
||||
const accIds = [me._id, ...employeeAccounts.filter(({ _id }) => _id !== me._id).map(({ _id }) => _id)].sort()
|
||||
|
||||
const existingDms = await client.findAll(chunter.class.DirectMessage, {})
|
||||
const newDirectPersons = Array.from(new Set([...employeeIds, me.person] as Array<Ref<Person>>)).sort()
|
||||
|
||||
let direct: DirectMessage | undefined
|
||||
|
||||
for (const dm of existingDms) {
|
||||
const existDirectPersons = Array.from(
|
||||
new Set(dm.members.map((id) => get(personIdByAccountId).get(id as Ref<PersonAccount>)))
|
||||
)
|
||||
.filter((person): person is Ref<Person> => person !== undefined)
|
||||
.sort()
|
||||
if (deepEqual(existDirectPersons, newDirectPersons)) {
|
||||
direct = dm
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const existingMembers = direct?.members
|
||||
const missingAccounts = existingMembers !== undefined ? accIds.filter((id) => !existingMembers.includes(id)) : []
|
||||
|
||||
if (direct !== undefined && missingAccounts.length > 0) {
|
||||
await client.updateDoc(chunter.class.DirectMessage, direct.space, direct._id, {
|
||||
$push: { members: { $each: missingAccounts, $position: 0 } }
|
||||
})
|
||||
}
|
||||
|
||||
const dmId =
|
||||
direct?._id ??
|
||||
(await client.createDoc(chunter.class.DirectMessage, core.space.Space, {
|
||||
name: '',
|
||||
description: '',
|
||||
private: true,
|
||||
archived: false,
|
||||
members: accIds
|
||||
}))
|
||||
|
||||
const context = await client.findOne(notification.class.DocNotifyContext, {
|
||||
user: me._id,
|
||||
objectId: dmId,
|
||||
objectClass: chunter.class.DirectMessage
|
||||
})
|
||||
|
||||
if (context !== undefined) {
|
||||
if (context.hidden) {
|
||||
await client.updateDoc(context._class, context.space, context._id, { hidden: false })
|
||||
}
|
||||
|
||||
return dmId
|
||||
}
|
||||
|
||||
const space = await client.findOne(
|
||||
contact.class.PersonSpace,
|
||||
{ person: me.person as Ref<Person> },
|
||||
{ projection: { _id: 1 } }
|
||||
)
|
||||
if (space == null) return dmId
|
||||
await client.createDoc(notification.class.DocNotifyContext, space._id, {
|
||||
user: me._id,
|
||||
objectId: dmId,
|
||||
objectClass: chunter.class.DirectMessage,
|
||||
objectSpace: core.space.Space,
|
||||
hidden: false,
|
||||
isPinned: false
|
||||
})
|
||||
|
||||
return dmId
|
||||
}
|
||||
|
@ -208,7 +208,8 @@ export default plugin(chunterId, {
|
||||
TranslateMessage: '' as IntlString,
|
||||
Translate: '' as IntlString,
|
||||
ShowOriginal: '' as IntlString,
|
||||
Translating: '' as IntlString
|
||||
Translating: '' as IntlString,
|
||||
StartConversation: '' as IntlString
|
||||
},
|
||||
ids: {
|
||||
DMNotification: '' as Ref<NotificationType>,
|
||||
|
@ -23,4 +23,4 @@
|
||||
export let selected: Ref<Widget> | undefined = undefined
|
||||
</script>
|
||||
|
||||
<WidgetsBar {widgets} {preferences} {selected} />
|
||||
<WidgetsBar {widgets} {preferences} {selected} roundBorder />
|
||||
|
@ -24,6 +24,7 @@
|
||||
export let widgets: Widget[] = []
|
||||
export let preferences: WidgetPreference[] = []
|
||||
export let selected: Ref<Widget> | undefined = undefined
|
||||
export let roundBorder = false
|
||||
|
||||
function handleAddWidget (): void {
|
||||
showPopup(AddWidgetsPopup, { widgets })
|
||||
@ -48,7 +49,7 @@
|
||||
.filter((widget): widget is Widget => widget !== undefined && widget.type === WidgetType.Configurable)
|
||||
</script>
|
||||
|
||||
<div class="root">
|
||||
<div class="root" class:roundBorder>
|
||||
<div class="block">
|
||||
{#each fixedWidgets as widget}
|
||||
<WidgetPresenter
|
||||
@ -103,6 +104,10 @@
|
||||
max-width: 3.5rem;
|
||||
border-top: 1px solid var(--theme-divider-color);
|
||||
overflow-y: auto;
|
||||
|
||||
&.roundBorder {
|
||||
border-top-left-radius: var(--small-focus-BorderRadius);
|
||||
}
|
||||
}
|
||||
|
||||
.block {
|
||||
|
Loading…
Reference in New Issue
Block a user