From b8fbcc695e0e868120528f346695115fe440dc6f Mon Sep 17 00:00:00 2001 From: Denis Bykhov <bykhov.denis@gmail.com> Date: Fri, 6 Oct 2023 16:29:25 +0600 Subject: [PATCH] UBER-1000 (#3801) Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> --- plugins/contact-assets/lang/en.json | 2 - plugins/contact-assets/lang/ru.json | 2 - plugins/contact-resources/src/assignee.ts | 35 ++------ .../src/components/AssigneeBox.svelte | 11 +-- .../src/components/AssigneePopup.svelte | 86 +++++++++--------- plugins/contact-resources/src/plugin.ts | 2 - plugins/notification-resources/src/utils.ts | 3 +- plugins/tracker-assets/lang/en.json | 1 + plugins/tracker-assets/lang/ru.json | 1 + .../components/issues/AssigneeEditor.svelte | 87 ++++++++++--------- plugins/tracker-resources/src/plugin.ts | 3 +- plugins/tracker-resources/src/utils.ts | 64 ++++++++------ plugins/view-resources/src/actions.ts | 38 ++++---- .../src/components/Workbench.svelte | 17 +--- 14 files changed, 169 insertions(+), 183 deletions(-) diff --git a/plugins/contact-assets/lang/en.json b/plugins/contact-assets/lang/en.json index 8185683a40..1eb262a5f6 100644 --- a/plugins/contact-assets/lang/en.json +++ b/plugins/contact-assets/lang/en.json @@ -90,8 +90,6 @@ "AddMembersHeader": "Add members to {value}:", "Assigned": "Assigned", "Unassigned": "Unassigned", - "CategoryPreviousAssigned": "Previously assigned", - "CategoryComponentLead": "Component lead", "CategoryCurrentUser": "Current user", "CategoryOther": "Other", "NumberMembers": "{count, plural, =0 {no members} =1 {1 member} other {# members}}", diff --git a/plugins/contact-assets/lang/ru.json b/plugins/contact-assets/lang/ru.json index 2b1332923c..630ac97851 100644 --- a/plugins/contact-assets/lang/ru.json +++ b/plugins/contact-assets/lang/ru.json @@ -92,8 +92,6 @@ "Assigned": "Назначен", "Unassigned": "Не назначен", "CategoryCurrentUser": "Текущий пользователь", - "CategoryPreviousAssigned": "Ранее назначенные", - "CategoryComponentLead": "Ответственный за компонент", "CategoryOther": "Прочие", "Position": "Должность", "ConfigLabel": "Контакты", diff --git a/plugins/contact-resources/src/assignee.ts b/plugins/contact-resources/src/assignee.ts index 7eefb560db..cd245c96da 100644 --- a/plugins/contact-resources/src/assignee.ts +++ b/plugins/contact-resources/src/assignee.ts @@ -1,36 +1,11 @@ +import { Person } from '@hcengineering/contact' +import { Ref } from '@hcengineering/core' import { IntlString } from '@hcengineering/platform' -import contact from './plugin' /** * @public */ -export type AssigneeCategory = 'CurrentUser' | 'Assigned' | 'PreviouslyAssigned' | 'ComponentLead' | 'Members' | 'Other' - -const assigneeCategoryTitleMap: Record<AssigneeCategory, IntlString> = Object.freeze({ - CurrentUser: contact.string.CategoryCurrentUser, - Assigned: contact.string.Assigned, - PreviouslyAssigned: contact.string.CategoryPreviousAssigned, - ComponentLead: contact.string.CategoryComponentLead, - Members: contact.string.Members, - Other: contact.string.CategoryOther -}) - -/** - * @public - */ -export const assigneeCategoryOrder: AssigneeCategory[] = [ - 'CurrentUser', - 'Assigned', - 'PreviouslyAssigned', - 'ComponentLead', - 'Members', - 'Other' -] - -/** - * @public - */ -export function getCategoryTitle (category: AssigneeCategory | undefined): IntlString { - const cat: AssigneeCategory = category ?? 'Other' - return assigneeCategoryTitleMap[cat] +export interface AssigneeCategory { + label: IntlString + func: (val: Array<Ref<Person>>) => Promise<Array<Ref<Person>>> } diff --git a/plugins/contact-resources/src/components/AssigneeBox.svelte b/plugins/contact-resources/src/components/AssigneeBox.svelte index d77b08374b..172c40db3a 100644 --- a/plugins/contact-resources/src/components/AssigneeBox.svelte +++ b/plugins/contact-resources/src/components/AssigneeBox.svelte @@ -39,6 +39,7 @@ import EmployeePresenter from './EmployeePresenter.svelte' import UserInfo from './UserInfo.svelte' import IconPerson from './icons/Person.svelte' + import { AssigneeCategory } from '../assignee' export let _class: Ref<Class<Employee>> = contact.mixin.Employee export let excluded: Ref<Contact>[] | undefined = undefined @@ -49,9 +50,7 @@ export let label: IntlString export let placeholder: IntlString = presentation.string.Search export let value: Ref<Person> | null | undefined - export let prevAssigned: Ref<Person>[] | undefined = [] - export let componentLead: Ref<Employee> | undefined = undefined - export let members: Ref<Employee>[] | undefined = [] + export let categories: AssigneeCategory[] | undefined = undefined export let allowDeselect = true export let titleDeselect: IntlString | undefined = undefined export let readonly = false @@ -87,7 +86,7 @@ const mgr = getFocusManager() - const _click = (ev: MouseEvent): void => { + function _click (ev: MouseEvent): void { if (!readonly) { ev.preventDefault() ev.stopPropagation() @@ -98,9 +97,7 @@ _class, options, docQuery, - prevAssigned, - componentLead, - members, + categories, ignoreUsers: excluded ?? [], icon, selected: value, diff --git a/plugins/contact-resources/src/components/AssigneePopup.svelte b/plugins/contact-resources/src/components/AssigneePopup.svelte index 549eb7a933..d22679ffa0 100644 --- a/plugins/contact-resources/src/components/AssigneePopup.svelte +++ b/plugins/contact-resources/src/components/AssigneePopup.svelte @@ -13,34 +13,33 @@ // limitations under the License. --> <script lang="ts"> - import contact, { Contact, PersonAccount, Person, Employee } from '@hcengineering/contact' - import { DocumentQuery, FindOptions, getCurrentAccount, Ref } from '@hcengineering/core' + import { Contact, Person, PersonAccount } from '@hcengineering/contact' + import { DocumentQuery, FindOptions, Ref, getCurrentAccount } from '@hcengineering/core' import type { Asset, IntlString } from '@hcengineering/platform' + import presentation, { createQuery } from '@hcengineering/presentation' import { - createFocusManager, + AnySvelteComponent, EditWithIcon, FocusHandler, Icon, IconCheck, IconSearch, - deviceOptionsStore, - ListView, - resizeObserver, - AnySvelteComponent, Label, + ListView, + createFocusManager, + deviceOptionsStore, + resizeObserver, tooltip } from '@hcengineering/ui' - import presentation, { createQuery } from '@hcengineering/presentation' import { createEventDispatcher } from 'svelte' - import { AssigneeCategory, assigneeCategoryOrder, getCategoryTitle } from '../assignee' + import { AssigneeCategory } from '../assignee' + import contact from '../plugin' import UserInfo from './UserInfo.svelte' export let options: FindOptions<Contact> | undefined = undefined export let selected: Ref<Person> | undefined export let docQuery: DocumentQuery<Contact> | undefined = undefined - export let prevAssigned: Ref<Employee>[] | undefined = [] - export let componentLead: Ref<Employee> | undefined = undefined - export let members: Ref<Employee>[] | undefined = [] + export let categories: AssigneeCategory[] | undefined = undefined export let allowDeselect = true export let titleDeselect: IntlString | undefined export let placeholder: IntlString = presentation.string.Search @@ -49,16 +48,15 @@ export let shadows: boolean = true export let width: 'medium' | 'large' | 'full' = 'medium' export let searchField: string = 'name' - export let showCategories: boolean = true export let icon: Asset | AnySvelteComponent | undefined = undefined - const currentEmployee = (getCurrentAccount() as PersonAccount).person + $: showCategories = categories !== undefined && categories.length > 0 let search: string = '' let objects: Contact[] = [] let contacts: Contact[] = [] - let categorizedPersons: Map<Ref<Person>, AssigneeCategory> + const categorizedPersons: Map<Ref<Person>, AssigneeCategory> = new Map() const dispatch = createEventDispatcher() const query = createQuery() @@ -79,29 +77,40 @@ { ...(options ?? {}), limit: 200, sort: { name: 1 } } ) - $: updateCategories(objects, currentEmployee, prevAssigned, componentLead, members) + $: updateCategories(objects, categories) - function updateCategories ( - objects: Contact[], - currentEmployee: Ref<Person>, - prevAssigned: Ref<Person>[] | undefined, - componentLead: Ref<Person> | undefined, - members: Ref<Person>[] | undefined - ) { - const persons = new Map<Ref<Person>, AssigneeCategory>(objects.map((t) => [t._id, 'Other'])) - if (componentLead) { - persons.set(componentLead, 'ComponentLead') + const currentUserCategory: AssigneeCategory = { + label: contact.string.CategoryCurrentUser, + func: async () => { + const account = getCurrentAccount() as PersonAccount + return [account.person] } - members?.forEach((p) => persons.set(p, 'Members')) - prevAssigned?.forEach((p) => persons.set(p, 'PreviouslyAssigned')) - if (selected) { - persons.set(selected, 'Assigned') - } - persons.set(currentEmployee, 'CurrentUser') + } - categorizedPersons = new Map<Ref<Person>, AssigneeCategory>( - [...persons].sort((a, b) => assigneeCategoryOrder.indexOf(a[1]) - assigneeCategoryOrder.indexOf(b[1])) - ) + const assigned: AssigneeCategory = { + label: contact.string.Assigned, + func: async () => { + return selected ? [selected] : [] + } + } + + const otherCategory: AssigneeCategory = { + label: contact.string.CategoryOther, + func: async (val: Ref<Contact>[]) => { + return val + } + } + + async function updateCategories (objects: Contact[], categories: AssigneeCategory[] | undefined) { + const refs = objects.map((e) => e._id) + + for (const category of [currentUserCategory, assigned, ...(categories ?? []), otherCategory]) { + const res = await category.func(refs) + for (const contact of res) { + if (categorizedPersons.has(contact)) continue + categorizedPersons.set(contact, category) + } + } contacts = [] categorizedPersons.forEach((p, k) => { const c = objects.find((e) => e._id === k) @@ -176,15 +185,12 @@ {@const obj = toAny(contacts[item])} {@const category = categorizedPersons.get(obj._id)} <!-- {@const cl = hierarchy.getClass(contacts[item]._class)} --> - {#if item === 0 || (item > 0 && categorizedPersons.get(toAny(contacts[item - 1])._id) !== categorizedPersons.get(obj._id))} + {#if category !== undefined && (item === 0 || (item > 0 && categorizedPersons.get(toAny(contacts[item - 1])._id) !== categorizedPersons.get(obj._id)))} <!--Category for first item--> {#if item > 0}<div class="menu-separator" />{/if} <div class="menu-group__header flex-row-center category-box"> - <!-- {#if cl.icon} - <div class="clear-mins mr-2"><Icon icon={cl.icon} size={'small'} /></div> - {/if} --> <span class="overflow-label"> - <Label label={getCategoryTitle(category)} /> + <Label label={category.label} /> </span> </div> {/if} diff --git a/plugins/contact-resources/src/plugin.ts b/plugins/contact-resources/src/plugin.ts index 5c11f93c55..95ad496eaf 100644 --- a/plugins/contact-resources/src/plugin.ts +++ b/plugins/contact-resources/src/plugin.ts @@ -74,8 +74,6 @@ export default mergeIds(contactId, contact, { Assigned: '' as IntlString, Unassigned: '' as IntlString, CategoryCurrentUser: '' as IntlString, - CategoryPreviousAssigned: '' as IntlString, - CategoryComponentLead: '' as IntlString, CategoryOther: '' as IntlString, DeleteEmployee: '' as IntlString, DeleteEmployeeDescr: '' as IntlString, diff --git a/plugins/notification-resources/src/utils.ts b/plugins/notification-resources/src/utils.ts index 77b35d96a9..ca14a909c6 100644 --- a/plugins/notification-resources/src/utils.ts +++ b/plugins/notification-resources/src/utils.ts @@ -47,8 +47,9 @@ export class NotificationClientImpl implements NotificationClient { ) } - static createClient (): void { + static createClient (): NotificationClientImpl { NotificationClientImpl._instance = new NotificationClientImpl() + return NotificationClientImpl._instance } static getClient (): NotificationClientImpl { diff --git a/plugins/tracker-assets/lang/en.json b/plugins/tracker-assets/lang/en.json index 2ebba7db4d..24c8d98239 100644 --- a/plugins/tracker-assets/lang/en.json +++ b/plugins/tracker-assets/lang/en.json @@ -282,6 +282,7 @@ "IssueNotificationChanged": "{senderName} changed {property}", "IssueNotificationChangedProperty": "{senderName} changed {property} to \"{newValue}\"", "IssueNotificationMessage": "{senderName}: {message}", + "PreviousAssigned": "Previously assigned", "IssueAssigneedToYou": "Assigned to you" }, "status": {} diff --git a/plugins/tracker-assets/lang/ru.json b/plugins/tracker-assets/lang/ru.json index 92fd268755..34b29185e6 100644 --- a/plugins/tracker-assets/lang/ru.json +++ b/plugins/tracker-assets/lang/ru.json @@ -282,6 +282,7 @@ "IssueNotificationChanged": "{senderName} изменил {property}", "IssueNotificationChangedProperty": "{senderName} изменил {property} на \"{newValue}\"", "IssueNotificationMessage": "{senderName}: {message}", + "PreviousAssigned": "Ранее назначенные", "IssueAssigneedToYou": "Назначено вам" }, "status": {} diff --git a/plugins/tracker-resources/src/components/issues/AssigneeEditor.svelte b/plugins/tracker-resources/src/components/issues/AssigneeEditor.svelte index 5282145fe0..7a609915b6 100644 --- a/plugins/tracker-resources/src/components/issues/AssigneeEditor.svelte +++ b/plugins/tracker-resources/src/components/issues/AssigneeEditor.svelte @@ -13,15 +13,17 @@ // limitations under the License. --> <script lang="ts"> - import { Employee, PersonAccount, Person } from '@hcengineering/contact' + import { Employee, Person, PersonAccount } from '@hcengineering/contact' import { AssigneeBox, personAccountByIdStore } from '@hcengineering/contact-resources' + import { AssigneeCategory } from '@hcengineering/contact-resources/src/assignee' import { Doc, DocumentQuery, Ref } from '@hcengineering/core' - import { createQuery, getClient } from '@hcengineering/presentation' - import { Issue, Project } from '@hcengineering/tracker' + import { getClient } from '@hcengineering/presentation' + import { Issue } from '@hcengineering/tracker' import { ButtonKind, ButtonSize, IconSize, TooltipAlignment } from '@hcengineering/ui' import { createEventDispatcher } from 'svelte' import tracker from '../../plugin' import { getPreviousAssignees } from '../../utils' + import { get } from 'svelte/store' type Object = (Doc | {}) & Pick<Issue, 'space' | 'component' | 'assignee'> @@ -38,37 +40,8 @@ const client = getClient() const dispatch = createEventDispatcher() - const projectQuery = createQuery() - let project: Project | undefined - let prevAssigned: Ref<Person>[] = [] - let componentLead: Ref<Employee> | undefined = undefined - let members: Ref<Employee>[] = [] - let docQuery: DocumentQuery<Employee> = {} - - $: '_class' in object && - getPreviousAssignees(object._id).then((res) => { - prevAssigned = res - }) - - async function updateComponentMembers (project: Project, issue: Object) { - if (issue.component) { - const component = await client.findOne(tracker.class.Component, { _id: issue.component }) - componentLead = component?.lead || undefined - } else { - componentLead = undefined - } - if (project !== undefined) { - const accounts = project.members - .map((p) => $personAccountByIdStore.get(p as Ref<PersonAccount>)) - .filter((p) => p !== undefined) as PersonAccount[] - members = accounts.map((p) => p.person as Ref<Employee>) - } else { - members = [] - } - - docQuery = project?.private ? { _id: { $in: members } } : { active: true } - } + const docQuery: DocumentQuery<Employee> = { active: true } const handleAssigneeChanged = async (newAssignee: Ref<Person> | undefined) => { if (newAssignee === undefined || object.assignee === newAssignee) { @@ -82,9 +55,47 @@ } } - $: projectQuery.query(tracker.class.Project, { _id: object.space }, (res) => ([project] = res)) - $: project && updateComponentMembers(project, object) - $: docQuery = project?.private ? { _id: { $in: members } } : {} + let categories: AssigneeCategory[] = [] + + function getCategories (object: Object): void { + categories = [] + if ('_class' in object) { + const _id = object._id + categories.push({ + label: tracker.string.PreviousAssigned, + func: async () => await getPreviousAssignees(_id) + }) + } + categories.push({ + label: tracker.string.ComponentLead, + func: async () => { + if (!object.component) { + return [] + } + const component = await client.findOne(tracker.class.Component, { _id: object.component }) + return component?.lead ? [component.lead] : [] + } + }) + categories.push({ + label: tracker.string.Members, + func: async () => { + if (!object.space) { + return [] + } + const project = await client.findOne(tracker.class.Project, { _id: object.space }) + if (project === undefined) { + return [] + } + const store = get(personAccountByIdStore) + const accounts = project.members + .map((p) => store.get(p as Ref<PersonAccount>)) + .filter((p) => p !== undefined) as PersonAccount[] + return accounts.map((p) => p.person as Ref<Employee>) + } + }) + } + + $: getCategories(object) </script> {#if object} @@ -94,9 +105,7 @@ label={tracker.string.Assignee} placeholder={tracker.string.Assignee} value={object.assignee} - {prevAssigned} - {componentLead} - {members} + {categories} titleDeselect={tracker.string.Unassigned} {size} {kind} diff --git a/plugins/tracker-resources/src/plugin.ts b/plugins/tracker-resources/src/plugin.ts index fcbea42014..d4a6a51bbb 100644 --- a/plugins/tracker-resources/src/plugin.ts +++ b/plugins/tracker-resources/src/plugin.ts @@ -300,7 +300,8 @@ export default mergeIds(trackerId, tracker, { NoStatusFound: '' as IntlString, CreateMissingStatus: '' as IntlString, - UnsetParent: '' as IntlString + UnsetParent: '' as IntlString, + PreviousAssigned: '' as IntlString }, component: { NopeComponent: '' as AnyComponent, diff --git a/plugins/tracker-resources/src/utils.ts b/plugins/tracker-resources/src/utils.ts index 53528e8c9f..8b7ef0c1cb 100644 --- a/plugins/tracker-resources/src/utils.ts +++ b/plugins/tracker-resources/src/utils.ts @@ -13,7 +13,7 @@ // limitations under the License. // -import { Employee } from '@hcengineering/contact' +import { Contact } from '@hcengineering/contact' import core, { ApplyOperations, AttachedData, @@ -29,23 +29,24 @@ import core, { Space, Status, StatusCategory, - toIdMap, TxCollectionCUD, + TxCreateDoc, TxOperations, TxResult, - TxUpdateDoc + TxUpdateDoc, + toIdMap } from '@hcengineering/core' import { Asset, IntlString } from '@hcengineering/platform' -import { createQuery } from '@hcengineering/presentation' +import { createQuery, getClient } from '@hcengineering/presentation' import { calcRank } from '@hcengineering/task' import { Component, Issue, IssuePriority, + IssueStatus, IssuesDateModificationPeriod, IssuesGrouping, IssuesOrdering, - IssueStatus, Milestone, MilestoneStatus, Project, @@ -54,18 +55,18 @@ import { import { AnyComponent, AnySvelteComponent, + MILLISECONDS_IN_WEEK, + PaletteColorIndexes, areDatesEqual, getMillisecondsInMonth, - isWeekend, - MILLISECONDS_IN_WEEK, - PaletteColorIndexes + isWeekend } from '@hcengineering/ui' import { KeyFilter, ViewletDescriptor } from '@hcengineering/view' import { CategoryQuery, - groupBy, ListSelectionProvider, SelectDirection, + groupBy, statusStore } from '@hcengineering/view-resources' import { get } from 'svelte/store' @@ -497,24 +498,33 @@ export function subIssueListProvider (subIssues: Issue[], target: Ref<Issue>): v } } -export async function getPreviousAssignees (objectId: Ref<Doc>): Promise<Array<Ref<Employee>>> { - return await new Promise((resolve) => { - const query = createQuery(true) - query.query( - core.class.Tx, - { - 'tx.objectId': objectId, - 'tx.operations.assignee': { $exists: true } - }, - (res) => { - const prevAssignee = res - .map((t) => ((t as TxCollectionCUD<Doc, Issue>).tx as TxUpdateDoc<Issue>).operations.assignee) - .filter((p) => !(p == null)) as Array<Ref<Employee>> - resolve(prevAssignee) - query.unsubscribe() - } - ) - }) +export async function getPreviousAssignees (objectId: Ref<Doc> | undefined): Promise<Array<Ref<Contact>>> { + if (objectId === undefined) { + return [] + } + const client = getClient() + const createTx = ( + await client.findAll<TxCollectionCUD<Issue, Issue>>(core.class.TxCollectionCUD, { + 'tx.objectId': objectId, + 'tx._class': core.class.TxCreateDoc + }) + )[0] + const updateTxes = await client.findAll<TxCollectionCUD<Issue, Issue>>( + core.class.TxCollectionCUD, + { 'tx.objectId': objectId, 'tx._class': core.class.TxUpdateDoc, 'tx.operations.assignee': { $exists: true } }, + { sort: { modifiedOn: -1 } } + ) + const set: Set<Ref<Contact>> = new Set() + const createAssignee = (createTx.tx as TxCreateDoc<Issue>).attributes.assignee + for (const tx of updateTxes) { + const assignee = (tx.tx as TxUpdateDoc<Issue>).operations.assignee + if (assignee == null) continue + set.add(assignee) + } + if (createAssignee != null) { + set.add(createAssignee) + } + return Array.from(set) } async function updateIssuesOnMove ( diff --git a/plugins/view-resources/src/actions.ts b/plugins/view-resources/src/actions.ts index 17225e651e..d950cd6ba1 100644 --- a/plugins/view-resources/src/actions.ts +++ b/plugins/view-resources/src/actions.ts @@ -56,14 +56,31 @@ export async function getActions ( derived: Ref<Class<Doc>> = core.class.Doc, mode: ViewContextType = 'context' ): Promise<Action[]> { - const actions: Action[] = await client.findAll(view.class.Action, { + let actions: Action[] = await client.findAll(view.class.Action, { 'context.mode': mode }) const categories: Partial<Record<ActionGroup | 'top', number>> = { top: 1, tools: 50, other: 100, remove: 200 } - let filteredActions: Action[] = [] + if (Array.isArray(doc)) { + for (const d of doc) { + actions = filterActions(client, d, actions, derived) + } + } else { + actions = filterActions(client, doc, actions, derived) + } + const inputVal: ViewActionInput[] = ['none'] + if (!Array.isArray(doc) || doc.length === 1) { + inputVal.push('focus') + inputVal.push('any') + } + if (Array.isArray(doc) && doc.length > 0) { + inputVal.push('selection') + inputVal.push('any') + } + actions = actions.filter((it) => inputVal.includes(it.input)) + const filteredActions: Action[] = [] for (const action of actions) { if (action.visibilityTester == null) { filteredActions.push(action) @@ -75,23 +92,6 @@ export async function getActions ( } } } - if (Array.isArray(doc)) { - for (const d of doc) { - filteredActions = filterActions(client, d, filteredActions, derived) - } - } else { - filteredActions = filterActions(client, doc, filteredActions, derived) - } - const inputVal: ViewActionInput[] = ['none'] - if (!Array.isArray(doc) || doc.length === 1) { - inputVal.push('focus') - inputVal.push('any') - } - if (Array.isArray(doc) && doc.length > 0) { - inputVal.push('selection') - inputVal.push('any') - } - filteredActions = filteredActions.filter((it) => inputVal.includes(it.input)) filteredActions.sort((a, b) => { const aTarget = categories[a.context.group ?? 'top'] ?? 0 const bTarget = categories[b.context.group ?? 'top'] ?? 0 diff --git a/plugins/workbench-resources/src/components/Workbench.svelte b/plugins/workbench-resources/src/components/Workbench.svelte index d717500141..043d81ed44 100644 --- a/plugins/workbench-resources/src/components/Workbench.svelte +++ b/plugins/workbench-resources/src/components/Workbench.svelte @@ -102,7 +102,6 @@ const excludedApps = getMetadata(workbench.metadata.ExcludedApplications) ?? [] const client = getClient() - NotificationClientImpl.createClient() let apps: Application[] | Promise<Application[]> = client .findAll(workbench.class.Application, { hidden: false, _id: { $nin: excludedApps } }) @@ -162,18 +161,10 @@ ) let hasNotification = false - const notificationQuery = createQuery() - - notificationQuery.query( - notification.class.DocUpdates, - { - user: accountId, - hidden: false - }, - (res) => { - hasNotification = res.some((p) => p.txes.some((p) => p.isNew)) - } - ) + const noficicationClient = NotificationClientImpl.getClient() + noficicationClient.docUpdates.subscribe((res) => { + hasNotification = res.some((p) => !p.hidden && p.txes.some((p) => p.isNew)) + }) const workspaceId = $location.path[1]