UBER-816: Fix mentions (#3641)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2023-08-30 12:27:59 +07:00 committed by GitHub
parent 5098a8d85e
commit 93fd82a797
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 42 additions and 55 deletions

View File

@ -17,7 +17,7 @@
"About": "About",
"Members": "Members",
"NoMembers": "No members",
"MentionedIn": "mentioned this ",
"MentionedIn": "mentioned you in ",
"ContactInfo": "Contact Info",
"Content": "Content",
"Comment": "Comment",

View File

@ -17,7 +17,7 @@
"About": "Информация",
"Members": "Участники",
"NoMembers": "Нет участников",
"MentionedIn": "упомянул(а) ",
"MentionedIn": "упомянул(а) вас в",
"ContactInfo": "Контактная информация",
"Content": "Содержимое",
"Comment": "Комментарий",

View File

@ -16,25 +16,20 @@
<script lang="ts">
import { AttachmentDocList } from '@hcengineering/attachment-resources'
import type { Comment } from '@hcengineering/chunter'
import chunter from '@hcengineering/chunter'
import { Person, PersonAccount, getName } from '@hcengineering/contact'
import { Avatar, personByIdStore, personAccountByIdStore } from '@hcengineering/contact-resources'
import { Doc, IdMap, Ref } from '@hcengineering/core'
import { MessageViewer, createQuery, getClient } from '@hcengineering/presentation'
import { Icon, Label, ShowMore, TimeSince } from '@hcengineering/ui'
import { AttributeModel } from '@hcengineering/view'
import { LinkPresenter, getObjectPresenter } from '@hcengineering/view-resources'
import { Avatar, personAccountByIdStore, personByIdStore } from '@hcengineering/contact-resources'
import { IdMap, Ref } from '@hcengineering/core'
import { MessageViewer, getClient } from '@hcengineering/presentation'
import { ShowMore, TimeSince } from '@hcengineering/ui'
import { LinkPresenter, ObjectPresenter } from '@hcengineering/view-resources'
export let value: Comment
export let inline: boolean = false
export let disabled = false
export let inbox: boolean = false
const client = getClient()
const cutId = (str: string): string => {
return str.slice(0, 4) + '...' + str.slice(-4)
}
async function getEmployee (
value: Comment,
employees: IdMap<Person>,
@ -49,17 +44,6 @@
$: links = getLinks(value.message)
let presenter: AttributeModel | undefined
getObjectPresenter(client, value.attachedToClass, { key: '' }).then((p) => {
presenter = p
})
let doc: Doc | undefined = undefined
const docQuery = createQuery()
$: docQuery.query(value.attachedToClass, { _id: value.attachedTo }, (res) => {
;[doc] = res
})
function getLinks (content: string): HTMLLinkElement[] {
const parser = new DOMParser()
const parent = parser.parseFromString(content, 'text/html').firstChild?.childNodes[1] as HTMLElement
@ -82,18 +66,10 @@
{#if inline}
<div class="flex-presenter inline-presenter">
{#if presenter && doc}
<span class="labels-row" style:text-transform={'lowercase'}><Label label={chunter.string.MessageOn} /></span>
&nbsp;
<div class="icon">
<Icon icon={chunter.icon.Thread} size={'small'} />
</div>
&nbsp;
<svelte:component this={presenter.presenter} value={doc} {inline} {disabled} />
{#if !inbox}
<ObjectPresenter _class={value.attachedToClass} objectId={value.attachedTo} />
{:else}
<Label label={chunter.string.Message} />
&nbsp;
<span class="content-dark-color">#{cutId(value._id.toString())}</span>
<MessageViewer message={value.message} />
{/if}
</div>
{:else}

View File

@ -16,10 +16,8 @@
import type { Backlink } from '@hcengineering/chunter'
import type { Doc } from '@hcengineering/core'
import { createQuery, getClient } from '@hcengineering/presentation'
import { Label } from '@hcengineering/ui'
import { AttributeModel } from '@hcengineering/view'
import { getObjectPresenter } from '@hcengineering/view-resources'
import chunter from '../../plugin'
export let value: Backlink
@ -49,7 +47,6 @@
{#if presenter}
<span class="labels-row">
<span style:text-transform={'lowercase'}><Label label={chunter.string.In} /></span>
<svelte:component this={presenter.presenter} value={doc} inline disabled />
</span>
{/if}

View File

@ -14,8 +14,9 @@
-->
<script lang="ts">
import contact, { Employee } from '@hcengineering/contact'
import type { Class, DocumentQuery, Ref, Doc } from '@hcengineering/core'
import type { Class, Doc, DocumentQuery, Ref } from '@hcengineering/core'
import type { IntlString } from '@hcengineering/platform'
import { getClient } from '@hcengineering/presentation'
import type { ButtonKind, ButtonSize, TooltipAlignment } from '@hcengineering/ui'
import { Button, Label, showPopup } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
@ -25,7 +26,6 @@
import UserInfo from './UserInfo.svelte'
import UsersPopup from './UsersPopup.svelte'
import Members from './icons/Members.svelte'
import { getClient } from '@hcengineering/presentation'
export let items: Ref<Employee>[] = []
export let _class: Ref<Class<Employee>> = contact.mixin.Employee
@ -40,8 +40,16 @@
export let emptyLabel = plugin.string.Members
export let readonly: boolean = false
let persons: Employee[] = items.map((p) => $employeeByIdStore.get(p)).filter((p) => p !== undefined) as Employee[]
$: persons = items.map((p) => $employeeByIdStore.get(p)).filter((p) => p !== undefined) as Employee[]
function filter (items: Ref<Employee>[]): Ref<Employee>[] {
return items.filter((it, idx, arr) => arr.indexOf(it) === idx)
}
let persons: Employee[] = filter(items)
.map((p) => $employeeByIdStore.get(p))
.filter((p) => p !== undefined) as Employee[]
$: persons = filter(items)
.map((p) => $employeeByIdStore.get(p))
.filter((p) => p !== undefined) as Employee[]
const dispatch = createEventDispatcher()
const client = getClient()
@ -55,7 +63,7 @@
docQuery,
multiSelect: true,
allowDeselect: false,
selectedUsers: items,
selectedUsers: filter(items),
filter: (it: Doc) => {
const h = client.getHierarchy()
if (h.hasMixin(it, contact.mixin.Employee)) {
@ -68,7 +76,7 @@
undefined,
(result) => {
if (result != null) {
items = result
items = filter(result)
dispatch('update', items)
}
}

View File

@ -96,7 +96,7 @@
>
<div class="flex-row-center flex-no-shrink mr-8">
{#if presenter}
<svelte:component this={presenter} value={doc} inline accent disabled />
<svelte:component this={presenter} value={doc} inline accent disabled inbox />
{/if}
{#if newTxes > 0 && !selected}
<div class="counter float">{newTxes}</div>

View File

@ -111,7 +111,7 @@
</div>
<div class="clear-mins flex-no-shrink mt-4">
{#if presenter}
<svelte:component this={presenter} value={doc} inline disabled />
<svelte:component this={presenter} value={doc} inline disabled inbox />
{/if}
</div>
<div class="flex-between flex-baseline mt-3">

View File

@ -15,7 +15,7 @@
//
import chunter, { Backlink } from '@hcengineering/chunter'
import contact, { Employee, PersonAccount, formatName } from '@hcengineering/contact'
import contact, { Employee, Person, PersonAccount, formatName } from '@hcengineering/contact'
import core, {
Account,
AnyAttribute,
@ -68,7 +68,7 @@ export async function OnBacklinkCreate (tx: Tx, control: TriggerControl): Promis
const ptx = tx as TxCollectionCUD<Doc, Backlink>
let res: Tx[] = []
if (!checkTx(ptx, hierarchy)) return []
if (!(await checkTx(ptx, hierarchy, control))) return []
const receiver = await getPersonAccount(ptx.objectId as Ref<Employee>, control)
if (receiver === undefined) return []
@ -79,7 +79,7 @@ export async function OnBacklinkCreate (tx: Tx, control: TriggerControl): Promis
const doc = await getBacklinkDoc(backlink, control)
if (doc !== undefined) {
const collab = hierarchy.as(doc, notification.mixin.Collaborators)
if (!collab.collaborators.includes(receiver._id)) {
if (collab.collaborators === undefined || !collab.collaborators.includes(receiver._id)) {
const collabTx = control.txFactory.createTxMixin(
doc._id,
doc._class,
@ -98,18 +98,24 @@ export async function OnBacklinkCreate (tx: Tx, control: TriggerControl): Promis
return res
}
function checkTx (ptx: TxCollectionCUD<Doc, Backlink>, hierarchy: Hierarchy): boolean {
async function checkTx (
ptx: TxCollectionCUD<Doc, Backlink>,
hierarchy: Hierarchy,
control: TriggerControl
): Promise<boolean> {
if (ptx._class !== core.class.TxCollectionCUD) {
return false
}
if (
ptx.tx._class !== core.class.TxCreateDoc ||
!hierarchy.isDerived(ptx.tx.objectClass, chunter.class.Backlink) ||
!hierarchy.isDerived(ptx.objectClass, contact.mixin.Employee)
) {
if (ptx.tx._class !== core.class.TxCreateDoc || !hierarchy.isDerived(ptx.tx.objectClass, chunter.class.Backlink)) {
return false
}
if (ptx.objectClass === contact.class.Person) {
// We need to check if person is employee.
const [person] = await control.findAll(contact.class.Person, { _id: ptx.objectId as Ref<Person> })
return person !== undefined ? hierarchy.hasMixin(person, contact.mixin.Employee) : false
}
return true
}