mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-13 19:58:09 +00:00
TSK-852 List perform individual requests (#2765)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
parent
892e7b1dbc
commit
f0bbd4d443
@ -1,19 +1,17 @@
|
||||
<script lang="ts">
|
||||
import contact, { Employee, EmployeeAccount, getName } from '@hcengineering/contact'
|
||||
import core, { IdMap, Ref, Space, toIdMap } from '@hcengineering/core'
|
||||
import core, { IdMap, Ref, Space } from '@hcengineering/core'
|
||||
import { ActionIcon, Button, IconClose, Label } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import presentation from '../plugin'
|
||||
import { createQuery, getClient } from '../utils'
|
||||
import { getClient } from '../utils'
|
||||
import UsersPopup from './UsersPopup.svelte'
|
||||
|
||||
export let value: Space
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
const query = createQuery()
|
||||
|
||||
let employees: IdMap<Employee> = new Map()
|
||||
query.query(contact.class.Employee, {}, (res) => (employees = toIdMap(res)))
|
||||
const employees: IdMap<Employee> = new Map()
|
||||
|
||||
let membersToAdd: EmployeeAccount[] = []
|
||||
let channelMembers: Ref<Employee>[] = []
|
||||
|
@ -18,6 +18,7 @@
|
||||
import type { Comment } from '@hcengineering/chunter'
|
||||
import chunter from '@hcengineering/chunter'
|
||||
import contact, { Employee, EmployeeAccount, getName } from '@hcengineering/contact'
|
||||
import { employeeByIdStore } from '@hcengineering/contact-resources'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { Avatar, getClient, MessageViewer } from '@hcengineering/presentation'
|
||||
import { Icon, ShowMore, TimeSince } from '@hcengineering/ui'
|
||||
@ -35,7 +36,7 @@
|
||||
async function getEmployee (value: Comment): Promise<Employee | undefined> {
|
||||
const acc = await client.findOne(contact.class.EmployeeAccount, { _id: value.modifiedBy as Ref<EmployeeAccount> })
|
||||
if (acc !== undefined) {
|
||||
const emp = await client.findOne(contact.class.Employee, { _id: acc.employee })
|
||||
const emp = $employeeByIdStore.get(acc.employee)
|
||||
return emp
|
||||
}
|
||||
}
|
||||
|
@ -16,12 +16,12 @@
|
||||
import { Attachment } from '@hcengineering/attachment'
|
||||
import { AttachmentList, AttachmentRefInput } from '@hcengineering/attachment-resources'
|
||||
import type { ChunterMessage, Message, Reaction } from '@hcengineering/chunter'
|
||||
import contact, { Employee, EmployeeAccount } from '@hcengineering/contact'
|
||||
import { EmployeePresenter } from '@hcengineering/contact-resources'
|
||||
import { EmployeeAccount } from '@hcengineering/contact'
|
||||
import { employeeByIdStore, EmployeePresenter } from '@hcengineering/contact-resources'
|
||||
import { getCurrentAccount, Ref, WithLookup } from '@hcengineering/core'
|
||||
import { NotificationClientImpl } from '@hcengineering/notification-resources'
|
||||
import { getResource } from '@hcengineering/platform'
|
||||
import { Avatar, createQuery, getClient, MessageViewer } from '@hcengineering/presentation'
|
||||
import { Avatar, getClient, MessageViewer } from '@hcengineering/presentation'
|
||||
import { EmojiPopup } from '@hcengineering/text-editor'
|
||||
import ui, { ActionIcon, Button, IconMoreH, Label, showPopup, tooltip } from '@hcengineering/ui'
|
||||
import { Action } from '@hcengineering/view'
|
||||
@ -46,16 +46,8 @@
|
||||
|
||||
let refInput: AttachmentRefInput
|
||||
|
||||
let employee: Employee | undefined
|
||||
const employeeQuery = createQuery()
|
||||
$: employeeQuery.query(
|
||||
contact.class.Employee,
|
||||
{
|
||||
_id: (message.$lookup?.createBy as EmployeeAccount)?.employee
|
||||
},
|
||||
(res) => ([employee] = res)
|
||||
)
|
||||
|
||||
$: empRef = (message.$lookup?.createBy as EmployeeAccount)?.employee
|
||||
$: employee = empRef !== undefined ? $employeeByIdStore.get(empRef) : undefined
|
||||
$: attachments = (message.$lookup?.attachments ?? []) as Attachment[]
|
||||
|
||||
const client = getClient()
|
||||
|
@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import chunter, { ChunterMessage } from '@hcengineering/chunter'
|
||||
import contact, { Employee, EmployeeAccount, getName } from '@hcengineering/contact'
|
||||
import { employeeByIdStore } from '@hcengineering/contact-resources'
|
||||
import { IdMap, Ref, Space, toIdMap } from '@hcengineering/core'
|
||||
import { Avatar, createQuery, MessageViewer } from '@hcengineering/presentation'
|
||||
import { IconClose } from '@hcengineering/ui'
|
||||
@ -34,11 +35,6 @@
|
||||
|
||||
employeeAccoutsQuery.query(contact.class.EmployeeAccount, {}, (res) => (employeeAcounts = toIdMap(res)))
|
||||
|
||||
const employeeQuery = createQuery()
|
||||
let employees: IdMap<Employee> = new Map()
|
||||
|
||||
employeeQuery.query(contact.class.Employee, {}, (res) => (employees = toIdMap(res)))
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
function getEmployee (
|
||||
@ -55,7 +51,7 @@
|
||||
|
||||
<div class="antiPopup vScroll popup">
|
||||
{#each pinnedMessages as message}
|
||||
{@const employee = getEmployee(message, employeeAcounts, employees)}
|
||||
{@const employee = getEmployee(message, employeeAcounts, $employeeByIdStore)}
|
||||
<div class="message">
|
||||
<div class="header">
|
||||
<div class="avatar">
|
||||
|
@ -1,20 +1,17 @@
|
||||
<script lang="ts">
|
||||
import contact, { Employee, EmployeeAccount, getName } from '@hcengineering/contact'
|
||||
import { employeeByIdStore } from '@hcengineering/contact-resources'
|
||||
import { Account, IdMap, Ref, toIdMap } from '@hcengineering/core'
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
|
||||
export let reactionAccounts: Ref<Account>[]
|
||||
let accounts: IdMap<EmployeeAccount> = new Map()
|
||||
let employees: IdMap<Employee> = new Map()
|
||||
|
||||
const query = createQuery()
|
||||
const empQ = createQuery()
|
||||
$: query.query(contact.class.EmployeeAccount, {}, (res) => {
|
||||
accounts = toIdMap(res)
|
||||
})
|
||||
|
||||
empQ.query(contact.class.Employee, {}, (res) => (employees = toIdMap(res)))
|
||||
|
||||
function getAccName (acc: Ref<Account>, accounts: IdMap<EmployeeAccount>, employees: IdMap<Employee>): string {
|
||||
const account = accounts.get(acc as Ref<EmployeeAccount>)
|
||||
if (account !== undefined) {
|
||||
@ -27,6 +24,6 @@
|
||||
|
||||
{#each reactionAccounts as acc}
|
||||
<div>
|
||||
{getAccName(acc, accounts, employees)}
|
||||
{getAccName(acc, accounts, $employeeByIdStore)}
|
||||
</div>
|
||||
{/each}
|
||||
|
@ -14,9 +14,10 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Message } from '@hcengineering/chunter'
|
||||
import contact, { Employee } from '@hcengineering/contact'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { Avatar, createQuery } from '@hcengineering/presentation'
|
||||
import { Employee } from '@hcengineering/contact'
|
||||
import { employeeByIdStore } from '@hcengineering/contact-resources'
|
||||
import { IdMap, Ref } from '@hcengineering/core'
|
||||
import { Avatar } from '@hcengineering/presentation'
|
||||
import { Label, TimeSince } from '@hcengineering/ui'
|
||||
import chunter from '../plugin'
|
||||
|
||||
@ -27,23 +28,17 @@
|
||||
const shown: number = 4
|
||||
let showReplies: Employee[] = []
|
||||
|
||||
const query = createQuery()
|
||||
$: updateQuery(employees, $employeeByIdStore)
|
||||
|
||||
$: updateQuery(employees)
|
||||
|
||||
function updateQuery (employees: Set<Ref<Employee>>) {
|
||||
query.query(
|
||||
contact.class.Employee,
|
||||
{
|
||||
_id: { $in: Array.from(employees) }
|
||||
},
|
||||
(res) => {
|
||||
showReplies = res
|
||||
},
|
||||
{
|
||||
limit: shown
|
||||
function updateQuery (employees: Set<Ref<Employee>>, map: IdMap<Employee>) {
|
||||
showReplies = []
|
||||
for (const employee of employees) {
|
||||
const emp = map.get(employee)
|
||||
if (emp !== undefined) {
|
||||
showReplies.push(emp)
|
||||
}
|
||||
)
|
||||
}
|
||||
showReplies = showReplies
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -2,7 +2,8 @@
|
||||
import attachment, { Attachment } from '@hcengineering/attachment'
|
||||
import AttachmentPreview from '@hcengineering/attachment-resources/src/components/AttachmentPreview.svelte'
|
||||
import { ChunterMessage } from '@hcengineering/chunter'
|
||||
import contact, { Employee, EmployeeAccount, getName as getContactName } from '@hcengineering/contact'
|
||||
import contact, { EmployeeAccount, getName as getContactName } from '@hcengineering/contact'
|
||||
import { employeeByIdStore } from '@hcengineering/contact-resources'
|
||||
import core, { IdMap, Ref, toIdMap, WithLookup } from '@hcengineering/core'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { Label, Scroller } from '@hcengineering/ui'
|
||||
@ -17,17 +18,14 @@
|
||||
let savedAttachmentsIds: Ref<Attachment>[] = []
|
||||
let savedAttachments: WithLookup<Attachment>[] = []
|
||||
let accounts: IdMap<EmployeeAccount> = new Map()
|
||||
let employees: IdMap<Employee> = new Map()
|
||||
|
||||
const messagesQuery = createQuery()
|
||||
const attachmentsQuery = createQuery()
|
||||
const savedMessagesQuery = createQuery()
|
||||
const savedAttachmentsQuery = createQuery()
|
||||
const accQ = createQuery()
|
||||
const empQ = createQuery()
|
||||
|
||||
accQ.query(contact.class.EmployeeAccount, {}, (res) => (accounts = toIdMap(res)))
|
||||
empQ.query(contact.class.Employee, {}, (res) => (employees = toIdMap(res)))
|
||||
|
||||
savedMessagesQuery.query(chunter.class.SavedMessages, {}, (res) => {
|
||||
savedMessagesIds = res.map((r) => r.attachedTo)
|
||||
@ -83,7 +81,7 @@
|
||||
function getName (a: Attachment): string | undefined {
|
||||
const acc = accounts.get(a.modifiedBy as Ref<EmployeeAccount>)
|
||||
if (acc !== undefined) {
|
||||
const emp = employees.get(acc?.employee)
|
||||
const emp = $employeeByIdStore.get(acc?.employee)
|
||||
if (emp !== undefined) {
|
||||
return getContactName(emp)
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
import { AttachmentRefInput } from '@hcengineering/attachment-resources'
|
||||
import type { ChunterSpace, Message, ThreadMessage } from '@hcengineering/chunter'
|
||||
import contact, { Employee, EmployeeAccount, getName } from '@hcengineering/contact'
|
||||
import { employeeByIdStore } from '@hcengineering/contact-resources'
|
||||
import core, {
|
||||
FindOptions,
|
||||
generateId,
|
||||
@ -24,7 +25,6 @@
|
||||
IdMap,
|
||||
Ref,
|
||||
SortingOrder,
|
||||
toIdMap,
|
||||
TxFactory
|
||||
} from '@hcengineering/core'
|
||||
import { NotificationClientImpl } from '@hcengineering/notification-resources'
|
||||
@ -102,11 +102,6 @@
|
||||
)
|
||||
}
|
||||
|
||||
let employees: IdMap<Employee> = new Map()
|
||||
const employeeQuery = createQuery()
|
||||
|
||||
employeeQuery.query(contact.class.Employee, {}, (res) => (employees = toIdMap(res)))
|
||||
|
||||
async function getParticipants (
|
||||
comments: ThreadMessage[],
|
||||
parent: Message | undefined,
|
||||
@ -176,7 +171,7 @@
|
||||
<DmPresenter value={channel} />
|
||||
{/if}
|
||||
{/await}
|
||||
{#await getParticipants(comments, parent, employees) then participants}
|
||||
{#await getParticipants(comments, parent, $employeeByIdStore) then participants}
|
||||
{participants.join(', ')}
|
||||
<Label label={chunter.string.AndYou} params={{ participants: participants.length }} />
|
||||
{/await}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { chunterId, ChunterMessage, Comment, ThreadMessage } from '@hcengineering/chunter'
|
||||
import contact, { EmployeeAccount, getName } from '@hcengineering/contact'
|
||||
import { employeeByIdStore } from '@hcengineering/contact-resources'
|
||||
import { Class, Client, Doc, getCurrentAccount, Obj, Ref, Space, Timestamp } from '@hcengineering/core'
|
||||
import { Asset } from '@hcengineering/platform'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
@ -48,11 +49,16 @@ export async function getDmName (client: Client, dm: Space): Promise<string> {
|
||||
employeeAccounts = employeeAccounts.filter((p) => p._id !== myAccId)
|
||||
}
|
||||
|
||||
const emloyees = await client.findAll(contact.class.Employee, {
|
||||
_id: { $in: employeeAccounts.map((p) => p.employee) }
|
||||
})
|
||||
const map = get(employeeByIdStore)
|
||||
const names: string[] = []
|
||||
|
||||
const name = emloyees.map((a) => getName(a)).join(', ')
|
||||
for (const acc of employeeAccounts) {
|
||||
const employee = map.get(acc.employee)
|
||||
if (employee !== undefined) {
|
||||
names.push(getName(employee))
|
||||
}
|
||||
}
|
||||
const name = names.join(', ')
|
||||
|
||||
return name
|
||||
}
|
||||
|
@ -14,28 +14,23 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Employee, EmployeeAccount, getName } from '@hcengineering/contact'
|
||||
import { EmployeeAccount, getName } from '@hcengineering/contact'
|
||||
import { Account } from '@hcengineering/core'
|
||||
import { getEmbeddedLabel } from '@hcengineering/platform'
|
||||
import { Avatar, createQuery } from '@hcengineering/presentation'
|
||||
import { Avatar } from '@hcengineering/presentation'
|
||||
import { showPopup, tooltip } from '@hcengineering/ui'
|
||||
import { EditDoc } from '@hcengineering/view-resources'
|
||||
import contact from '../plugin'
|
||||
import { employeeByIdStore } from '../utils'
|
||||
|
||||
export let value: Account
|
||||
|
||||
let employee: Employee | undefined
|
||||
$: employee = $employeeByIdStore.get((value as EmployeeAccount).employee)
|
||||
|
||||
async function onClick () {
|
||||
if (employee !== undefined) {
|
||||
showPopup(EditDoc, { _id: employee._id, _class: employee._class }, 'content')
|
||||
}
|
||||
}
|
||||
const query = createQuery()
|
||||
|
||||
$: if (value && value._class === contact.class.EmployeeAccount) {
|
||||
query.query(contact.class.Employee, { _id: (value as EmployeeAccount).employee }, (r) => ([employee] = r))
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if value}
|
||||
|
@ -1,11 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { Employee, EmployeeAccount, getName, Status } from '@hcengineering/contact'
|
||||
import { getCurrentAccount, Ref, WithLookup } from '@hcengineering/core'
|
||||
import { getCurrentAccount, Ref } from '@hcengineering/core'
|
||||
import { Avatar, createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { Button, Label, resizeObserver, showPopup } from '@hcengineering/ui'
|
||||
import { DocNavLink } from '@hcengineering/view-resources'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import contact from '../plugin'
|
||||
import { employeeByIdStore } from '../utils'
|
||||
import EmployeeSetStatusPopup from './EmployeeSetStatusPopup.svelte'
|
||||
import EmployeeStatusPresenter from './EmployeeStatusPresenter.svelte'
|
||||
import Edit from './icons/Edit.svelte'
|
||||
@ -16,14 +17,10 @@
|
||||
const me = (getCurrentAccount() as EmployeeAccount).employee
|
||||
$: editable = employeeId === me
|
||||
|
||||
const employeeQuery = createQuery()
|
||||
$: status = employee?.$lookup?.statuses?.[0]
|
||||
let employee: WithLookup<Employee> | undefined
|
||||
employeeQuery.query(contact.class.Employee, { _id: employeeId }, (res) => (employee = res[0]), {
|
||||
lookup: {
|
||||
_id: { statuses: contact.class.Status }
|
||||
}
|
||||
})
|
||||
const statusesQuery = createQuery()
|
||||
let status: Status | undefined = undefined
|
||||
$: employee = $employeeByIdStore.get(employeeId)
|
||||
statusesQuery.query(contact.class.Status, { attachedTo: employeeId }, (res) => (status = res[0]))
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { Employee } from '@hcengineering/contact'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { AssigneeBox, createQuery } from '@hcengineering/presentation'
|
||||
import { AssigneeBox } from '@hcengineering/presentation'
|
||||
import { ButtonKind } from '@hcengineering/ui'
|
||||
import { PersonLabelTooltip } from '..'
|
||||
import contact from '../plugin'
|
||||
import { employeeByIdStore } from '../utils'
|
||||
import EmployeePresenter from './EmployeePresenter.svelte'
|
||||
|
||||
export let value: Ref<Employee> | null | undefined
|
||||
@ -12,9 +13,7 @@
|
||||
export let tooltipLabels: PersonLabelTooltip | undefined = undefined
|
||||
export let onChange: ((value: Ref<Employee>) => void) | undefined = undefined
|
||||
|
||||
let employee: Employee | undefined
|
||||
const query = createQuery()
|
||||
$: value && query.query(contact.class.Employee, { _id: value }, (res) => ([employee] = res), { limit: 1 })
|
||||
$: employee = value ? $employeeByIdStore.get(value) : undefined
|
||||
|
||||
function getValue (
|
||||
employee: Employee | undefined,
|
||||
|
@ -70,6 +70,7 @@ import {
|
||||
resolveLocation
|
||||
} from './utils'
|
||||
|
||||
export { employeeByIdStore, employeesStore } from './utils'
|
||||
export {
|
||||
Channels,
|
||||
ChannelsEditor,
|
||||
|
@ -23,12 +23,13 @@ import {
|
||||
formatName,
|
||||
getName
|
||||
} from '@hcengineering/contact'
|
||||
import { Doc, getCurrentAccount, ObjQueryType, Ref, Timestamp, toIdMap } from '@hcengineering/core'
|
||||
import { Doc, getCurrentAccount, IdMap, ObjQueryType, Ref, Timestamp, toIdMap } from '@hcengineering/core'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { TemplateDataProvider } from '@hcengineering/templates'
|
||||
import { getPanelURI, Location } from '@hcengineering/ui'
|
||||
import view, { Filter } from '@hcengineering/view'
|
||||
import { FilterQuery } from '@hcengineering/view-resources'
|
||||
import { get, writable } from 'svelte/store'
|
||||
import contact from './plugin'
|
||||
|
||||
const client = getClient()
|
||||
@ -53,36 +54,28 @@ export function formatDate (dueDateMs: Timestamp): string {
|
||||
}
|
||||
|
||||
export async function employeeSort (value: Array<Ref<Employee>>): Promise<Array<Ref<Employee>>> {
|
||||
return await new Promise((resolve) => {
|
||||
const query = createQuery(true)
|
||||
query.query(contact.class.Employee, { _id: { $in: value } }, (res) => {
|
||||
const employees = toIdMap(res)
|
||||
value.sort((a, b) => {
|
||||
const employeeId1 = a as Ref<Employee> | null | undefined
|
||||
const employeeId2 = b as Ref<Employee> | null | undefined
|
||||
return value.sort((a, b) => {
|
||||
const employeeId1 = a as Ref<Employee> | null | undefined
|
||||
const employeeId2 = b as Ref<Employee> | null | undefined
|
||||
|
||||
if (employeeId1 == null && employeeId2 != null) {
|
||||
return 1
|
||||
}
|
||||
if (employeeId1 == null && employeeId2 != null) {
|
||||
return 1
|
||||
}
|
||||
|
||||
if (employeeId1 != null && employeeId2 == null) {
|
||||
return -1
|
||||
}
|
||||
if (employeeId1 != null && employeeId2 == null) {
|
||||
return -1
|
||||
}
|
||||
|
||||
if (employeeId1 != null && employeeId2 != null) {
|
||||
const employee1 = employees.get(employeeId1)
|
||||
const employee2 = employees.get(employeeId2)
|
||||
const name1 = employee1 != null ? getName(employee1) : ''
|
||||
const name2 = employee2 != null ? getName(employee2) : ''
|
||||
if (employeeId1 != null && employeeId2 != null) {
|
||||
const employee1 = get(employeeByIdStore).get(employeeId1)
|
||||
const employee2 = get(employeeByIdStore).get(employeeId2)
|
||||
const name1 = employee1 != null ? getName(employee1) : ''
|
||||
const name2 = employee2 != null ? getName(employee2) : ''
|
||||
|
||||
return name1.localeCompare(name2)
|
||||
}
|
||||
return name1.localeCompare(name2)
|
||||
}
|
||||
|
||||
return 0
|
||||
})
|
||||
resolve(value)
|
||||
query.unsubscribe()
|
||||
})
|
||||
return 0
|
||||
})
|
||||
}
|
||||
|
||||
@ -208,3 +201,11 @@ async function generateLocation (loc: Location, shortLink: string): Promise<Loca
|
||||
fragment: getPanelURI(view.component.EditDoc, doc._id, doc._class, 'content')
|
||||
}
|
||||
}
|
||||
|
||||
export const employeeByIdStore = writable<IdMap<Employee>>(new Map())
|
||||
export const employeesStore = writable<Employee[]>([])
|
||||
const query = createQuery(true)
|
||||
query.query(contact.class.Employee, {}, (res) => {
|
||||
employeesStore.set(res)
|
||||
employeeByIdStore.set(toIdMap(res))
|
||||
})
|
||||
|
@ -1,5 +1,6 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2023 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
@ -13,27 +14,12 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import MD5 from 'crypto-js/md5'
|
||||
|
||||
import {
|
||||
Account,
|
||||
AttachedData,
|
||||
AttachedDoc,
|
||||
Class,
|
||||
Client,
|
||||
Data,
|
||||
Doc,
|
||||
FindResult,
|
||||
Ref,
|
||||
Space,
|
||||
Timestamp,
|
||||
UXObject
|
||||
} from '@hcengineering/core'
|
||||
import { Account, AttachedDoc, Class, Doc, Ref, Space, Timestamp, UXObject } from '@hcengineering/core'
|
||||
import type { Asset, Plugin, Resource } from '@hcengineering/platform'
|
||||
import { IntlString, plugin } from '@hcengineering/platform'
|
||||
import { TemplateField, TemplateFieldCategory } from '@hcengineering/templates'
|
||||
import type { AnyComponent, IconSize } from '@hcengineering/ui'
|
||||
import { FilterMode, ViewAction, Viewlet } from '@hcengineering/view'
|
||||
import { TemplateFieldCategory, TemplateField } from '@hcengineering/templates'
|
||||
|
||||
/**
|
||||
* @public
|
||||
@ -164,57 +150,6 @@ export interface ContactsTab extends Doc {
|
||||
index: number
|
||||
}
|
||||
|
||||
const SEP = ','
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function combineName (first: string, last: string): string {
|
||||
return last + SEP + first
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function getFirstName (name: string): string {
|
||||
return name !== undefined ? name.substring(name.indexOf(SEP) + 1) : ''
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function getLastName (name: string): string {
|
||||
return name !== undefined ? name.substring(0, name.indexOf(SEP)) : ''
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function formatName (name: string): string {
|
||||
return getLastName(name) + ' ' + getFirstName(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function getName (value: Contact): string {
|
||||
if (isEmployee(value)) {
|
||||
return value.displayName ?? formatName(value.name)
|
||||
}
|
||||
if (isPerson(value)) {
|
||||
return formatName(value.name)
|
||||
}
|
||||
return value.name
|
||||
}
|
||||
|
||||
function isEmployee (value: Contact): value is Employee {
|
||||
return value._class === contactPlugin.class.Employee
|
||||
}
|
||||
|
||||
function isPerson (value: Contact): value is Person {
|
||||
return value._class === contactPlugin.class.Person
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
@ -223,7 +158,7 @@ export const contactId = 'contact' as Plugin
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
const contactPlugin = plugin(contactId, {
|
||||
export const contactPlugin = plugin(contactId, {
|
||||
class: {
|
||||
AvatarProvider: '' as Ref<Class<AvatarProvider>>,
|
||||
ChannelProvider: '' as Ref<Class<ChannelProvider>>,
|
||||
@ -329,188 +264,5 @@ const contactPlugin = plugin(contactId, {
|
||||
})
|
||||
|
||||
export default contactPlugin
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function findContacts (
|
||||
client: Client,
|
||||
_class: Ref<Class<Doc>>,
|
||||
person: Data<Contact>,
|
||||
channels: AttachedData<Channel>[]
|
||||
): Promise<{ contacts: Contact[], channels: AttachedData<Channel>[] }> {
|
||||
if (channels.length === 0 && person.name.length === 0) {
|
||||
return { contacts: [], channels: [] }
|
||||
}
|
||||
// Take only first part of first name for match.
|
||||
const values = channels.map((it) => it.value)
|
||||
|
||||
// Same name persons
|
||||
|
||||
const potentialChannels = await client.findAll(
|
||||
contactPlugin.class.Channel,
|
||||
{ value: { $in: values } },
|
||||
{ limit: 1000 }
|
||||
)
|
||||
let potentialContactIds = Array.from(new Set(potentialChannels.map((it) => it.attachedTo as Ref<Contact>)).values())
|
||||
|
||||
if (potentialContactIds.length === 0) {
|
||||
if (client.getHierarchy().isDerived(_class, contactPlugin.class.Person)) {
|
||||
const firstName = getFirstName(person.name).split(' ').shift() ?? ''
|
||||
const lastName = getLastName(person.name)
|
||||
// try match using just first/last name
|
||||
potentialContactIds = (
|
||||
await client.findAll(
|
||||
contactPlugin.class.Contact,
|
||||
{ name: { $like: `${lastName}%${firstName}%` } },
|
||||
{ limit: 100 }
|
||||
)
|
||||
).map((it) => it._id)
|
||||
if (potentialContactIds.length === 0) {
|
||||
return { contacts: [], channels: [] }
|
||||
}
|
||||
} else if (client.getHierarchy().isDerived(_class, contactPlugin.class.Organization)) {
|
||||
// try match using just first/last name
|
||||
potentialContactIds = (
|
||||
await client.findAll(contactPlugin.class.Contact, { name: { $like: `${person.name}` } }, { limit: 100 })
|
||||
).map((it) => it._id)
|
||||
if (potentialContactIds.length === 0) {
|
||||
return { contacts: [], channels: [] }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const potentialPersons: FindResult<Contact> = await client.findAll(
|
||||
contactPlugin.class.Contact,
|
||||
{ _id: { $in: potentialContactIds } },
|
||||
{
|
||||
lookup: {
|
||||
_id: {
|
||||
channels: contactPlugin.class.Channel
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const result: Contact[] = []
|
||||
const resChannels: AttachedData<Channel>[] = []
|
||||
for (const c of potentialPersons) {
|
||||
let matches = 0
|
||||
if (c.name === person.name) {
|
||||
matches++
|
||||
}
|
||||
for (const ch of (c.$lookup?.channels as Channel[]) ?? []) {
|
||||
for (const chc of channels) {
|
||||
if (chc.provider === ch.provider && chc.value === ch.value.trim()) {
|
||||
// We have matched value
|
||||
resChannels.push(chc)
|
||||
matches += 2
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (matches > 0) {
|
||||
result.push(c)
|
||||
}
|
||||
}
|
||||
return { contacts: result, channels: resChannels }
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function findPerson (
|
||||
client: Client,
|
||||
person: Data<Person>,
|
||||
channels: AttachedData<Channel>[]
|
||||
): Promise<Person[]> {
|
||||
const result = await findContacts(client, contactPlugin.class.Person, person, channels)
|
||||
return result.contacts as Person[]
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type GravatarPlaceholderType =
|
||||
| '404'
|
||||
| 'mp'
|
||||
| 'identicon'
|
||||
| 'monsterid'
|
||||
| 'wavatar'
|
||||
| 'retro'
|
||||
| 'robohash'
|
||||
| 'blank'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function buildGravatarId (email: string): string {
|
||||
return MD5(email.trim().toLowerCase()).toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function getGravatarUrl (
|
||||
gravatarId: string,
|
||||
size: IconSize = 'full',
|
||||
placeholder: GravatarPlaceholderType = 'identicon'
|
||||
): string {
|
||||
let width = 64
|
||||
switch (size) {
|
||||
case 'inline':
|
||||
case 'tiny':
|
||||
case 'x-small':
|
||||
case 'small':
|
||||
case 'medium':
|
||||
width = 64
|
||||
break
|
||||
case 'large':
|
||||
width = 256
|
||||
break
|
||||
case 'x-large':
|
||||
width = 512
|
||||
break
|
||||
}
|
||||
return `https://gravatar.com/avatar/${gravatarId}?s=${width}&d=${placeholder}`
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function checkHasGravatar (gravatarId: string, fetch?: typeof window.fetch): Promise<boolean> {
|
||||
try {
|
||||
return (await (fetch ?? window.fetch)(getGravatarUrl(gravatarId, 'full', '404'))).ok
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const AVATAR_COLORS = [
|
||||
'#4674ca', // blue
|
||||
'#315cac', // blue_dark
|
||||
'#57be8c', // green
|
||||
'#3fa372', // green_dark
|
||||
'#f9a66d', // yellow_orange
|
||||
'#ec5e44', // red
|
||||
'#e63717', // red_dark
|
||||
'#f868bc', // pink
|
||||
'#6c5fc7', // purple
|
||||
'#4e3fb4', // purple_dark
|
||||
'#57b1be', // teal
|
||||
'#847a8c' // gray
|
||||
]
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function getAvatarColorForId (id: string): string {
|
||||
let hash = 0
|
||||
|
||||
for (let i = 0; i < id.length; i++) {
|
||||
hash += id.charCodeAt(i)
|
||||
}
|
||||
|
||||
return AVATAR_COLORS[hash % AVATAR_COLORS.length]
|
||||
}
|
||||
export * from './types'
|
||||
export * from './utils'
|
||||
|
45
plugins/contact/src/types.ts
Normal file
45
plugins/contact/src/types.ts
Normal file
@ -0,0 +1,45 @@
|
||||
//
|
||||
// Copyright © 2023 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type GravatarPlaceholderType =
|
||||
| '404'
|
||||
| 'mp'
|
||||
| 'identicon'
|
||||
| 'monsterid'
|
||||
| 'wavatar'
|
||||
| 'retro'
|
||||
| 'robohash'
|
||||
| 'blank'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export const AVATAR_COLORS = [
|
||||
'#4674ca', // blue
|
||||
'#315cac', // blue_dark
|
||||
'#57be8c', // green
|
||||
'#3fa372', // green_dark
|
||||
'#f9a66d', // yellow_orange
|
||||
'#ec5e44', // red
|
||||
'#e63717', // red_dark
|
||||
'#f868bc', // pink
|
||||
'#6c5fc7', // purple
|
||||
'#4e3fb4', // purple_dark
|
||||
'#57b1be', // teal
|
||||
'#847a8c' // gray
|
||||
]
|
228
plugins/contact/src/utils.ts
Normal file
228
plugins/contact/src/utils.ts
Normal file
@ -0,0 +1,228 @@
|
||||
//
|
||||
// Copyright © 2023 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { AttachedData, Class, Client, Data, Doc, FindResult, Ref } from '@hcengineering/core'
|
||||
import { IconSize } from '@hcengineering/ui'
|
||||
import { MD5 } from 'crypto-js'
|
||||
import { Channel, Contact, contactPlugin, Employee, Person } from '.'
|
||||
import { AVATAR_COLORS, GravatarPlaceholderType } from './types'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function getAvatarColorForId (id: string): string {
|
||||
let hash = 0
|
||||
|
||||
for (let i = 0; i < id.length; i++) {
|
||||
hash += id.charCodeAt(i)
|
||||
}
|
||||
|
||||
return AVATAR_COLORS[hash % AVATAR_COLORS.length]
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function buildGravatarId (email: string): string {
|
||||
return MD5(email.trim().toLowerCase()).toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function getGravatarUrl (
|
||||
gravatarId: string,
|
||||
size: IconSize = 'full',
|
||||
placeholder: GravatarPlaceholderType = 'identicon'
|
||||
): string {
|
||||
let width = 64
|
||||
switch (size) {
|
||||
case 'inline':
|
||||
case 'tiny':
|
||||
case 'x-small':
|
||||
case 'small':
|
||||
case 'medium':
|
||||
width = 64
|
||||
break
|
||||
case 'large':
|
||||
width = 256
|
||||
break
|
||||
case 'x-large':
|
||||
width = 512
|
||||
break
|
||||
}
|
||||
return `https://gravatar.com/avatar/${gravatarId}?s=${width}&d=${placeholder}`
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function checkHasGravatar (gravatarId: string, fetch?: typeof window.fetch): Promise<boolean> {
|
||||
try {
|
||||
return (await (fetch ?? window.fetch)(getGravatarUrl(gravatarId, 'full', '404'))).ok
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function findContacts (
|
||||
client: Client,
|
||||
_class: Ref<Class<Doc>>,
|
||||
person: Data<Contact>,
|
||||
channels: AttachedData<Channel>[]
|
||||
): Promise<{ contacts: Contact[], channels: AttachedData<Channel>[] }> {
|
||||
if (channels.length === 0 && person.name.length === 0) {
|
||||
return { contacts: [], channels: [] }
|
||||
}
|
||||
// Take only first part of first name for match.
|
||||
const values = channels.map((it) => it.value)
|
||||
|
||||
// Same name persons
|
||||
|
||||
const potentialChannels = await client.findAll(
|
||||
contactPlugin.class.Channel,
|
||||
{ value: { $in: values } },
|
||||
{ limit: 1000 }
|
||||
)
|
||||
let potentialContactIds = Array.from(new Set(potentialChannels.map((it) => it.attachedTo as Ref<Contact>)).values())
|
||||
|
||||
if (potentialContactIds.length === 0) {
|
||||
if (client.getHierarchy().isDerived(_class, contactPlugin.class.Person)) {
|
||||
const firstName = getFirstName(person.name).split(' ').shift() ?? ''
|
||||
const lastName = getLastName(person.name)
|
||||
// try match using just first/last name
|
||||
potentialContactIds = (
|
||||
await client.findAll(
|
||||
contactPlugin.class.Contact,
|
||||
{ name: { $like: `${lastName}%${firstName}%` } },
|
||||
{ limit: 100 }
|
||||
)
|
||||
).map((it) => it._id)
|
||||
if (potentialContactIds.length === 0) {
|
||||
return { contacts: [], channels: [] }
|
||||
}
|
||||
} else if (client.getHierarchy().isDerived(_class, contactPlugin.class.Organization)) {
|
||||
// try match using just first/last name
|
||||
potentialContactIds = (
|
||||
await client.findAll(contactPlugin.class.Contact, { name: { $like: `${person.name}` } }, { limit: 100 })
|
||||
).map((it) => it._id)
|
||||
if (potentialContactIds.length === 0) {
|
||||
return { contacts: [], channels: [] }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const potentialPersons: FindResult<Contact> = await client.findAll(
|
||||
contactPlugin.class.Contact,
|
||||
{ _id: { $in: potentialContactIds } },
|
||||
{
|
||||
lookup: {
|
||||
_id: {
|
||||
channels: contactPlugin.class.Channel
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const result: Contact[] = []
|
||||
const resChannels: AttachedData<Channel>[] = []
|
||||
for (const c of potentialPersons) {
|
||||
let matches = 0
|
||||
if (c.name === person.name) {
|
||||
matches++
|
||||
}
|
||||
for (const ch of (c.$lookup?.channels as Channel[]) ?? []) {
|
||||
for (const chc of channels) {
|
||||
if (chc.provider === ch.provider && chc.value === ch.value.trim()) {
|
||||
// We have matched value
|
||||
resChannels.push(chc)
|
||||
matches += 2
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (matches > 0) {
|
||||
result.push(c)
|
||||
}
|
||||
}
|
||||
return { contacts: result, channels: resChannels }
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function findPerson (
|
||||
client: Client,
|
||||
person: Data<Person>,
|
||||
channels: AttachedData<Channel>[]
|
||||
): Promise<Person[]> {
|
||||
const result = await findContacts(client, contactPlugin.class.Person, person, channels)
|
||||
return result.contacts as Person[]
|
||||
}
|
||||
|
||||
const SEP = ','
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function combineName (first: string, last: string): string {
|
||||
return last + SEP + first
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function getFirstName (name: string): string {
|
||||
return name !== undefined ? name.substring(name.indexOf(SEP) + 1) : ''
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function getLastName (name: string): string {
|
||||
return name !== undefined ? name.substring(0, name.indexOf(SEP)) : ''
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function formatName (name: string): string {
|
||||
return getLastName(name) + ' ' + getFirstName(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function getName (value: Contact): string {
|
||||
if (isEmployee(value)) {
|
||||
return value.displayName ?? formatName(value.name)
|
||||
}
|
||||
if (isPerson(value)) {
|
||||
return formatName(value.name)
|
||||
}
|
||||
return value.name
|
||||
}
|
||||
|
||||
function isEmployee (value: Contact): value is Employee {
|
||||
return value._class === contactPlugin.class.Employee
|
||||
}
|
||||
|
||||
function isPerson (value: Contact): value is Person {
|
||||
return value._class === contactPlugin.class.Person
|
||||
}
|
@ -21,6 +21,7 @@
|
||||
EmployeeAccount,
|
||||
getName as getContactName
|
||||
} from '@hcengineering/contact'
|
||||
import { employeeByIdStore } from '@hcengineering/contact-resources'
|
||||
import { IdMap, Ref, SortingOrder, toIdMap } from '@hcengineering/core'
|
||||
import { Message, SharedMessage } from '@hcengineering/gmail'
|
||||
import { NotificationClientImpl } from '@hcengineering/notification-resources'
|
||||
@ -40,16 +41,13 @@
|
||||
|
||||
let messages: Message[] = []
|
||||
let accounts: IdMap<EmployeeAccount> = new Map()
|
||||
let employees: IdMap<Employee> = new Map()
|
||||
let selected: Set<Ref<SharedMessage>> = new Set<Ref<SharedMessage>>()
|
||||
let selectable = false
|
||||
|
||||
const messagesQuery = createQuery()
|
||||
const accountsQuery = createQuery()
|
||||
const employeesQuery = createQuery()
|
||||
|
||||
accountsQuery.query(contact.class.EmployeeAccount, {}, (res) => (accounts = toIdMap(res)))
|
||||
employeesQuery.query(contact.class.Employee, {}, (res) => (employees = toIdMap(res)))
|
||||
|
||||
const notificationClient = NotificationClientImpl.getClient()
|
||||
|
||||
@ -78,7 +76,7 @@
|
||||
object._class,
|
||||
'gmailSharedMessages',
|
||||
{
|
||||
messages: convertMessages(selectedMessages, accounts, employees)
|
||||
messages: convertMessages(selectedMessages, accounts, $employeeByIdStore)
|
||||
}
|
||||
)
|
||||
await notificationClient.updateLastView(channel._id, channel._class, undefined, true)
|
||||
@ -168,7 +166,12 @@
|
||||
<Scroller>
|
||||
<div class="popupPanel-body__main-content py-4 clear-mins flex-no-shrink">
|
||||
{#if messages && messages.length > 0}
|
||||
<Messages messages={convertMessages(messages, accounts, employees)} {selectable} bind:selected on:select />
|
||||
<Messages
|
||||
messages={convertMessages(messages, accounts, $employeeByIdStore)}
|
||||
{selectable}
|
||||
bind:selected
|
||||
on:select
|
||||
/>
|
||||
<div class="clear-mins h-4 flex-no-shrink" />
|
||||
{:else}
|
||||
<div class="flex-col-center justify-center h-full">
|
||||
|
@ -13,7 +13,8 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import contact, { Employee, EmployeeAccount, getName } from '@hcengineering/contact'
|
||||
import contact, { EmployeeAccount, getName } from '@hcengineering/contact'
|
||||
import { employeeByIdStore } from '@hcengineering/contact-resources'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
import { Request } from '@hcengineering/request'
|
||||
@ -26,7 +27,7 @@
|
||||
export let value: Request
|
||||
|
||||
let account: EmployeeAccount | undefined
|
||||
let employee: Employee | undefined
|
||||
$: employee = account && $employeeByIdStore.get(account.employee)
|
||||
|
||||
const query = createQuery()
|
||||
|
||||
@ -38,18 +39,6 @@
|
||||
},
|
||||
{ limit: 1 }
|
||||
)
|
||||
|
||||
const employeeQuery = createQuery()
|
||||
|
||||
$: account &&
|
||||
employeeQuery.query(
|
||||
contact.class.Employee,
|
||||
{ _id: account.employee },
|
||||
(res) => {
|
||||
;[employee] = res
|
||||
},
|
||||
{ limit: 1 }
|
||||
)
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
|
@ -13,9 +13,9 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import contact, { Employee, EmployeeAccount, formatName } from '@hcengineering/contact'
|
||||
import { EmployeePresenter } from '@hcengineering/contact-resources'
|
||||
import { AccountRole, getCurrentAccount, IdMap, SortingOrder, toIdMap } from '@hcengineering/core'
|
||||
import contact, { EmployeeAccount, formatName } from '@hcengineering/contact'
|
||||
import { employeeByIdStore, EmployeePresenter } from '@hcengineering/contact-resources'
|
||||
import { AccountRole, getCurrentAccount, SortingOrder } from '@hcengineering/core'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { DropdownIntlItem, DropdownLabelsIntl, Icon, Label } from '@hcengineering/ui'
|
||||
import setting from '../plugin'
|
||||
@ -23,7 +23,6 @@
|
||||
const client = getClient()
|
||||
|
||||
const query = createQuery()
|
||||
const employeeQuery = createQuery()
|
||||
|
||||
const currentRole = getCurrentAccount().role
|
||||
|
||||
@ -35,7 +34,6 @@
|
||||
|
||||
let accounts: EmployeeAccount[] = []
|
||||
$: owners = accounts.filter((p) => p.role === AccountRole.Owner)
|
||||
let employees: IdMap<Employee> = new Map()
|
||||
|
||||
query.query(
|
||||
contact.class.EmployeeAccount,
|
||||
@ -48,10 +46,6 @@
|
||||
}
|
||||
)
|
||||
|
||||
employeeQuery.query(contact.class.Employee, {}, (res) => {
|
||||
employees = toIdMap(res)
|
||||
})
|
||||
|
||||
async function change (account: EmployeeAccount, value: AccountRole): Promise<void> {
|
||||
await client.update(account, {
|
||||
role: value
|
||||
@ -67,7 +61,7 @@
|
||||
<div class="ac-body columns">
|
||||
<div class="ac-column max">
|
||||
{#each accounts as account (account._id)}
|
||||
{@const employee = employees.get(account.employee)}
|
||||
{@const employee = $employeeByIdStore.get(account.employee)}
|
||||
<div class="flex-between">
|
||||
{#if employee}
|
||||
<EmployeePresenter value={employee} isInteractive={false} />
|
||||
|
@ -13,41 +13,25 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { AttributeEditor, createQuery, EditableAvatar, getClient } from '@hcengineering/presentation'
|
||||
import { AttributeEditor, EditableAvatar, getClient } from '@hcengineering/presentation'
|
||||
|
||||
import setting from '../plugin'
|
||||
import { EditBox, Icon, Label, createFocusManager, FocusHandler, Button, showPopup } from '@hcengineering/ui'
|
||||
import contact, { Employee, EmployeeAccount, getFirstName, getLastName } from '@hcengineering/contact'
|
||||
import contact, { EmployeeAccount, getFirstName, getLastName } from '@hcengineering/contact'
|
||||
import { ChannelsEditor, employeeByIdStore } from '@hcengineering/contact-resources'
|
||||
import contactRes from '@hcengineering/contact-resources/src/plugin'
|
||||
import { getCurrentAccount } from '@hcengineering/core'
|
||||
import { changeName, leaveWorkspace } from '@hcengineering/login-resources'
|
||||
import { ChannelsEditor } from '@hcengineering/contact-resources'
|
||||
import MessageBox from '@hcengineering/presentation/src/components/MessageBox.svelte'
|
||||
import { Button, createFocusManager, EditBox, FocusHandler, Icon, Label, showPopup } from '@hcengineering/ui'
|
||||
import setting from '../plugin'
|
||||
const client = getClient()
|
||||
|
||||
let avatarEditor: EditableAvatar
|
||||
|
||||
let employee: Employee | undefined
|
||||
let firstName: string
|
||||
let lastName: string
|
||||
let displayName: string = ''
|
||||
const employeeQ = createQuery()
|
||||
|
||||
const account = getCurrentAccount() as EmployeeAccount
|
||||
|
||||
employeeQ.query(
|
||||
contact.class.Employee,
|
||||
{
|
||||
_id: account.employee
|
||||
},
|
||||
(res) => {
|
||||
employee = res[0]
|
||||
firstName = getFirstName(employee.name)
|
||||
lastName = getLastName(employee.name)
|
||||
displayName = employee.displayName ?? ''
|
||||
},
|
||||
{ limit: 1 }
|
||||
)
|
||||
const employee = $employeeByIdStore.get(account.employee)
|
||||
let firstName: string = employee ? getFirstName(employee.name) : ''
|
||||
let lastName: string = employee ? getLastName(employee.name) : ''
|
||||
let displayName = employee?.displayName ?? ''
|
||||
|
||||
async function onAvatarDone (e: any) {
|
||||
if (employee === undefined) return
|
||||
|
@ -1,8 +1,10 @@
|
||||
import contact, { EmployeeAccount, getName } from '@hcengineering/contact'
|
||||
import { employeeByIdStore } from '@hcengineering/contact-resources'
|
||||
import { Class, Doc, Hierarchy, Ref } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import setting from '@hcengineering/setting'
|
||||
import { TemplateDataProvider } from '@hcengineering/templates'
|
||||
import { get } from 'svelte/store'
|
||||
|
||||
function isEditable (hierarchy: Hierarchy, p: Class<Doc>): boolean {
|
||||
let ancestors = [p._id]
|
||||
@ -63,9 +65,7 @@ export async function getOwnerName (provider: TemplateDataProvider): Promise<str
|
||||
_id: value.modifiedBy as Ref<EmployeeAccount>
|
||||
})
|
||||
if (employeeAccount !== undefined) {
|
||||
const employee = await client.findOne(contact.class.Employee, {
|
||||
_id: employeeAccount.employee
|
||||
})
|
||||
const employee = get(employeeByIdStore).get(employeeAccount.employee)
|
||||
return employee != null ? getName(employee) : undefined
|
||||
}
|
||||
}
|
||||
|
@ -13,11 +13,12 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import contact, { Employee, EmployeeAccount, formatName } from '@hcengineering/contact'
|
||||
import { EmployeeAccount, formatName } from '@hcengineering/contact'
|
||||
import { employeeByIdStore } from '@hcengineering/contact-resources'
|
||||
import { getCurrentAccount } from '@hcengineering/core'
|
||||
import login, { loginId } from '@hcengineering/login'
|
||||
import { setMetadata } from '@hcengineering/platform'
|
||||
import { Avatar, createQuery } from '@hcengineering/presentation'
|
||||
import { Avatar } from '@hcengineering/presentation'
|
||||
import setting, { settingId, SettingsCategory } from '@hcengineering/setting'
|
||||
import {
|
||||
closePopup,
|
||||
@ -35,19 +36,7 @@
|
||||
}
|
||||
|
||||
const account = getCurrentAccount() as EmployeeAccount
|
||||
let employee: Employee | undefined
|
||||
const employeeQ = createQuery()
|
||||
|
||||
employeeQ.query(
|
||||
contact.class.Employee,
|
||||
{
|
||||
_id: account.employee
|
||||
},
|
||||
(res) => {
|
||||
employee = res[0]
|
||||
},
|
||||
{ limit: 1 }
|
||||
)
|
||||
$: employee = $employeeByIdStore.get(account.employee)
|
||||
|
||||
function selectCategory (sp: SettingsCategory): void {
|
||||
closePopup()
|
||||
|
@ -14,6 +14,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import contact, { Employee } from '@hcengineering/contact'
|
||||
import { employeeByIdStore, employeesStore } from '@hcengineering/contact-resources'
|
||||
import { Class, Doc, DocumentQuery, generateId, IdMap, Lookup, Ref, toIdMap, WithLookup } from '@hcengineering/core'
|
||||
import { Kanban, TypeState } from '@hcengineering/kanban'
|
||||
import notification from '@hcengineering/notification'
|
||||
@ -21,13 +22,13 @@
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import tags from '@hcengineering/tags'
|
||||
import {
|
||||
Component as ComponentType,
|
||||
Issue,
|
||||
IssuesGrouping,
|
||||
IssuesOrdering,
|
||||
IssueStatus,
|
||||
Component as ComponentType,
|
||||
Sprint,
|
||||
Project
|
||||
Project,
|
||||
Sprint
|
||||
} from '@hcengineering/tracker'
|
||||
import {
|
||||
Button,
|
||||
@ -54,8 +55,8 @@
|
||||
import { onMount } from 'svelte'
|
||||
import tracker from '../../plugin'
|
||||
import { issuesGroupBySorting, mapKanbanCategories } from '../../utils'
|
||||
import CreateIssue from '../CreateIssue.svelte'
|
||||
import ComponentEditor from '../components/ComponentEditor.svelte'
|
||||
import CreateIssue from '../CreateIssue.svelte'
|
||||
import AssigneePresenter from './AssigneePresenter.svelte'
|
||||
import SubIssuesSelector from './edit/SubIssuesSelector.svelte'
|
||||
import IssuePresenter from './IssuePresenter.svelte'
|
||||
@ -137,8 +138,7 @@
|
||||
const lookupIssue: Lookup<Issue> = {
|
||||
status: tracker.class.IssueStatus,
|
||||
component: tracker.class.Component,
|
||||
sprint: tracker.class.Sprint,
|
||||
assignee: contact.class.Employee
|
||||
sprint: tracker.class.Sprint
|
||||
}
|
||||
$: issuesQuery.query(
|
||||
tracker.class.Issue,
|
||||
@ -152,12 +152,6 @@
|
||||
}
|
||||
)
|
||||
|
||||
const assigneeQuery = createQuery()
|
||||
let assignee: Employee[] = []
|
||||
$: assigneeQuery.query(contact.class.Employee, {}, (result) => {
|
||||
assignee = result
|
||||
})
|
||||
|
||||
const statusesQuery = createQuery()
|
||||
let statuses: WithLookup<IssueStatus>[] = []
|
||||
let statusesMap: IdMap<IssueStatus> = new Map()
|
||||
@ -212,7 +206,7 @@
|
||||
statuses,
|
||||
components,
|
||||
sprints,
|
||||
assignee
|
||||
$employeesStore
|
||||
)
|
||||
|
||||
function update () {
|
||||
@ -225,7 +219,7 @@
|
||||
statuses,
|
||||
components,
|
||||
sprints,
|
||||
assignee
|
||||
$employeesStore
|
||||
)
|
||||
}
|
||||
|
||||
@ -354,7 +348,7 @@
|
||||
</div>
|
||||
<div class="abs-rt-content">
|
||||
<AssigneePresenter
|
||||
value={issue.$lookup?.assignee}
|
||||
value={issue.assignee ? $employeeByIdStore.get(issue.assignee) : null}
|
||||
defaultClass={contact.class.Employee}
|
||||
object={issue}
|
||||
isEditable={true}
|
||||
|
@ -13,8 +13,8 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import contact, { Employee, EmployeeAccount } from '@hcengineering/contact'
|
||||
import { EmployeePresenter } from '@hcengineering/contact-resources'
|
||||
import contact, { EmployeeAccount } from '@hcengineering/contact'
|
||||
import { employeeByIdStore, EmployeePresenter } from '@hcengineering/contact-resources'
|
||||
import core, { ClassifierKind, Doc, Mixin, Ref, WithLookup } from '@hcengineering/core'
|
||||
import { AttributeBarEditor, createQuery, getClient, KeyedAttribute } from '@hcengineering/presentation'
|
||||
|
||||
@ -78,10 +78,9 @@
|
||||
$: updateKeys(['title', 'description', 'priority', 'status', 'number', 'assignee', 'component', 'dueDate', 'sprint'])
|
||||
|
||||
const employeeAccountQuery = createQuery()
|
||||
const employeeQuery = createQuery()
|
||||
|
||||
let account: EmployeeAccount | undefined
|
||||
let employee: Employee | undefined
|
||||
$: employee = account && $employeeByIdStore.get(account.employee)
|
||||
|
||||
$: employeeAccountQuery.query(
|
||||
contact.class.EmployeeAccount,
|
||||
@ -91,16 +90,6 @@
|
||||
},
|
||||
{ limit: 1 }
|
||||
)
|
||||
|
||||
$: account &&
|
||||
employeeQuery.query(
|
||||
contact.class.Employee,
|
||||
{ _id: account.employee },
|
||||
(res) => {
|
||||
;[employee] = res
|
||||
},
|
||||
{ limit: 1 }
|
||||
)
|
||||
</script>
|
||||
|
||||
<div class="content">
|
||||
|
Loading…
Reference in New Issue
Block a user