mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-22 11:42:30 +03:00
UBER-816: Fix mentions (#3641)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
5098a8d85e
commit
93fd82a797
@ -17,7 +17,7 @@
|
|||||||
"About": "About",
|
"About": "About",
|
||||||
"Members": "Members",
|
"Members": "Members",
|
||||||
"NoMembers": "No members",
|
"NoMembers": "No members",
|
||||||
"MentionedIn": "mentioned this ",
|
"MentionedIn": "mentioned you in ",
|
||||||
"ContactInfo": "Contact Info",
|
"ContactInfo": "Contact Info",
|
||||||
"Content": "Content",
|
"Content": "Content",
|
||||||
"Comment": "Comment",
|
"Comment": "Comment",
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
"About": "Информация",
|
"About": "Информация",
|
||||||
"Members": "Участники",
|
"Members": "Участники",
|
||||||
"NoMembers": "Нет участников",
|
"NoMembers": "Нет участников",
|
||||||
"MentionedIn": "упомянул(а) ",
|
"MentionedIn": "упомянул(а) вас в",
|
||||||
"ContactInfo": "Контактная информация",
|
"ContactInfo": "Контактная информация",
|
||||||
"Content": "Содержимое",
|
"Content": "Содержимое",
|
||||||
"Comment": "Комментарий",
|
"Comment": "Комментарий",
|
||||||
|
@ -16,25 +16,20 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { AttachmentDocList } from '@hcengineering/attachment-resources'
|
import { AttachmentDocList } from '@hcengineering/attachment-resources'
|
||||||
import type { Comment } from '@hcengineering/chunter'
|
import type { Comment } from '@hcengineering/chunter'
|
||||||
import chunter from '@hcengineering/chunter'
|
|
||||||
import { Person, PersonAccount, getName } from '@hcengineering/contact'
|
import { Person, PersonAccount, getName } from '@hcengineering/contact'
|
||||||
import { Avatar, personByIdStore, personAccountByIdStore } from '@hcengineering/contact-resources'
|
import { Avatar, personAccountByIdStore, personByIdStore } from '@hcengineering/contact-resources'
|
||||||
import { Doc, IdMap, Ref } from '@hcengineering/core'
|
import { IdMap, Ref } from '@hcengineering/core'
|
||||||
import { MessageViewer, createQuery, getClient } from '@hcengineering/presentation'
|
import { MessageViewer, getClient } from '@hcengineering/presentation'
|
||||||
import { Icon, Label, ShowMore, TimeSince } from '@hcengineering/ui'
|
import { ShowMore, TimeSince } from '@hcengineering/ui'
|
||||||
import { AttributeModel } from '@hcengineering/view'
|
import { LinkPresenter, ObjectPresenter } from '@hcengineering/view-resources'
|
||||||
import { LinkPresenter, getObjectPresenter } from '@hcengineering/view-resources'
|
|
||||||
|
|
||||||
export let value: Comment
|
export let value: Comment
|
||||||
export let inline: boolean = false
|
export let inline: boolean = false
|
||||||
export let disabled = false
|
export let disabled = false
|
||||||
|
export let inbox: boolean = false
|
||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
|
||||||
const cutId = (str: string): string => {
|
|
||||||
return str.slice(0, 4) + '...' + str.slice(-4)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getEmployee (
|
async function getEmployee (
|
||||||
value: Comment,
|
value: Comment,
|
||||||
employees: IdMap<Person>,
|
employees: IdMap<Person>,
|
||||||
@ -49,17 +44,6 @@
|
|||||||
|
|
||||||
$: links = getLinks(value.message)
|
$: 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[] {
|
function getLinks (content: string): HTMLLinkElement[] {
|
||||||
const parser = new DOMParser()
|
const parser = new DOMParser()
|
||||||
const parent = parser.parseFromString(content, 'text/html').firstChild?.childNodes[1] as HTMLElement
|
const parent = parser.parseFromString(content, 'text/html').firstChild?.childNodes[1] as HTMLElement
|
||||||
@ -82,18 +66,10 @@
|
|||||||
|
|
||||||
{#if inline}
|
{#if inline}
|
||||||
<div class="flex-presenter inline-presenter">
|
<div class="flex-presenter inline-presenter">
|
||||||
{#if presenter && doc}
|
{#if !inbox}
|
||||||
<span class="labels-row" style:text-transform={'lowercase'}><Label label={chunter.string.MessageOn} /></span>
|
<ObjectPresenter _class={value.attachedToClass} objectId={value.attachedTo} />
|
||||||
|
|
||||||
<div class="icon">
|
|
||||||
<Icon icon={chunter.icon.Thread} size={'small'} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<svelte:component this={presenter.presenter} value={doc} {inline} {disabled} />
|
|
||||||
{:else}
|
{:else}
|
||||||
<Label label={chunter.string.Message} />
|
<MessageViewer message={value.message} />
|
||||||
|
|
||||||
<span class="content-dark-color">#{cutId(value._id.toString())}</span>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
|
@ -16,10 +16,8 @@
|
|||||||
import type { Backlink } from '@hcengineering/chunter'
|
import type { Backlink } from '@hcengineering/chunter'
|
||||||
import type { Doc } from '@hcengineering/core'
|
import type { Doc } from '@hcengineering/core'
|
||||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||||
import { Label } from '@hcengineering/ui'
|
|
||||||
import { AttributeModel } from '@hcengineering/view'
|
import { AttributeModel } from '@hcengineering/view'
|
||||||
import { getObjectPresenter } from '@hcengineering/view-resources'
|
import { getObjectPresenter } from '@hcengineering/view-resources'
|
||||||
import chunter from '../../plugin'
|
|
||||||
|
|
||||||
export let value: Backlink
|
export let value: Backlink
|
||||||
|
|
||||||
@ -49,7 +47,6 @@
|
|||||||
|
|
||||||
{#if presenter}
|
{#if presenter}
|
||||||
<span class="labels-row">
|
<span class="labels-row">
|
||||||
<span style:text-transform={'lowercase'}><Label label={chunter.string.In} /></span>
|
|
||||||
<svelte:component this={presenter.presenter} value={doc} inline disabled />
|
<svelte:component this={presenter.presenter} value={doc} inline disabled />
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -14,8 +14,9 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import contact, { Employee } from '@hcengineering/contact'
|
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 type { IntlString } from '@hcengineering/platform'
|
||||||
|
import { getClient } from '@hcengineering/presentation'
|
||||||
import type { ButtonKind, ButtonSize, TooltipAlignment } from '@hcengineering/ui'
|
import type { ButtonKind, ButtonSize, TooltipAlignment } from '@hcengineering/ui'
|
||||||
import { Button, Label, showPopup } from '@hcengineering/ui'
|
import { Button, Label, showPopup } from '@hcengineering/ui'
|
||||||
import { createEventDispatcher } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
@ -25,7 +26,6 @@
|
|||||||
import UserInfo from './UserInfo.svelte'
|
import UserInfo from './UserInfo.svelte'
|
||||||
import UsersPopup from './UsersPopup.svelte'
|
import UsersPopup from './UsersPopup.svelte'
|
||||||
import Members from './icons/Members.svelte'
|
import Members from './icons/Members.svelte'
|
||||||
import { getClient } from '@hcengineering/presentation'
|
|
||||||
|
|
||||||
export let items: Ref<Employee>[] = []
|
export let items: Ref<Employee>[] = []
|
||||||
export let _class: Ref<Class<Employee>> = contact.mixin.Employee
|
export let _class: Ref<Class<Employee>> = contact.mixin.Employee
|
||||||
@ -40,8 +40,16 @@
|
|||||||
export let emptyLabel = plugin.string.Members
|
export let emptyLabel = plugin.string.Members
|
||||||
export let readonly: boolean = false
|
export let readonly: boolean = false
|
||||||
|
|
||||||
let persons: Employee[] = items.map((p) => $employeeByIdStore.get(p)).filter((p) => p !== undefined) as Employee[]
|
function filter (items: Ref<Employee>[]): Ref<Employee>[] {
|
||||||
$: persons = items.map((p) => $employeeByIdStore.get(p)).filter((p) => p !== undefined) as 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 dispatch = createEventDispatcher()
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
@ -55,7 +63,7 @@
|
|||||||
docQuery,
|
docQuery,
|
||||||
multiSelect: true,
|
multiSelect: true,
|
||||||
allowDeselect: false,
|
allowDeselect: false,
|
||||||
selectedUsers: items,
|
selectedUsers: filter(items),
|
||||||
filter: (it: Doc) => {
|
filter: (it: Doc) => {
|
||||||
const h = client.getHierarchy()
|
const h = client.getHierarchy()
|
||||||
if (h.hasMixin(it, contact.mixin.Employee)) {
|
if (h.hasMixin(it, contact.mixin.Employee)) {
|
||||||
@ -68,7 +76,7 @@
|
|||||||
undefined,
|
undefined,
|
||||||
(result) => {
|
(result) => {
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
items = result
|
items = filter(result)
|
||||||
dispatch('update', items)
|
dispatch('update', items)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@
|
|||||||
>
|
>
|
||||||
<div class="flex-row-center flex-no-shrink mr-8">
|
<div class="flex-row-center flex-no-shrink mr-8">
|
||||||
{#if presenter}
|
{#if presenter}
|
||||||
<svelte:component this={presenter} value={doc} inline accent disabled />
|
<svelte:component this={presenter} value={doc} inline accent disabled inbox />
|
||||||
{/if}
|
{/if}
|
||||||
{#if newTxes > 0 && !selected}
|
{#if newTxes > 0 && !selected}
|
||||||
<div class="counter float">{newTxes}</div>
|
<div class="counter float">{newTxes}</div>
|
||||||
|
@ -111,7 +111,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="clear-mins flex-no-shrink mt-4">
|
<div class="clear-mins flex-no-shrink mt-4">
|
||||||
{#if presenter}
|
{#if presenter}
|
||||||
<svelte:component this={presenter} value={doc} inline disabled />
|
<svelte:component this={presenter} value={doc} inline disabled inbox />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-between flex-baseline mt-3">
|
<div class="flex-between flex-baseline mt-3">
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import chunter, { Backlink } from '@hcengineering/chunter'
|
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, {
|
import core, {
|
||||||
Account,
|
Account,
|
||||||
AnyAttribute,
|
AnyAttribute,
|
||||||
@ -68,7 +68,7 @@ export async function OnBacklinkCreate (tx: Tx, control: TriggerControl): Promis
|
|||||||
const ptx = tx as TxCollectionCUD<Doc, Backlink>
|
const ptx = tx as TxCollectionCUD<Doc, Backlink>
|
||||||
let res: Tx[] = []
|
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)
|
const receiver = await getPersonAccount(ptx.objectId as Ref<Employee>, control)
|
||||||
if (receiver === undefined) return []
|
if (receiver === undefined) return []
|
||||||
@ -79,7 +79,7 @@ export async function OnBacklinkCreate (tx: Tx, control: TriggerControl): Promis
|
|||||||
const doc = await getBacklinkDoc(backlink, control)
|
const doc = await getBacklinkDoc(backlink, control)
|
||||||
if (doc !== undefined) {
|
if (doc !== undefined) {
|
||||||
const collab = hierarchy.as(doc, notification.mixin.Collaborators)
|
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(
|
const collabTx = control.txFactory.createTxMixin(
|
||||||
doc._id,
|
doc._id,
|
||||||
doc._class,
|
doc._class,
|
||||||
@ -98,18 +98,24 @@ export async function OnBacklinkCreate (tx: Tx, control: TriggerControl): Promis
|
|||||||
return res
|
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) {
|
if (ptx._class !== core.class.TxCollectionCUD) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (ptx.tx._class !== core.class.TxCreateDoc || !hierarchy.isDerived(ptx.tx.objectClass, chunter.class.Backlink)) {
|
||||||
ptx.tx._class !== core.class.TxCreateDoc ||
|
|
||||||
!hierarchy.isDerived(ptx.tx.objectClass, chunter.class.Backlink) ||
|
|
||||||
!hierarchy.isDerived(ptx.objectClass, contact.mixin.Employee)
|
|
||||||
) {
|
|
||||||
return false
|
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
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user