Add desktop pushes for new inbox (#9414)

* Add desktop pushes for new inbox

Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>

* fix auto-merge

Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>

---------

Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
Kristina
2025-07-01 12:57:53 +07:00
committed by GitHub
parent 3c0275a365
commit 6142d2d86e
8 changed files with 78 additions and 24 deletions
+1
View File
@@ -258,6 +258,7 @@
"electron-updater": "^6.3.4",
"livekit-client": "^2.13.3",
"@hcengineering/server-backup": "^0.6.0",
"@hcengineering/communication-types": "^0.1.0",
"ws": "^8.18.2"
},
"productName": "Huly Desktop",
+1 -1
View File
@@ -267,7 +267,7 @@ ipcMain.on('send-notification', (event, notificationParams: NotificationParams)
notification.on('click', () => {
mainWindow?.show()
mainWindow?.webContents.send('handle-notification-navigation')
mainWindow?.webContents.send('handle-notification-navigation', notificationParams.application)
})
notification.show()
+2 -2
View File
@@ -66,11 +66,11 @@ window.addEventListener('DOMContentLoaded', () => {
navigate(parseLocation(urlObject))
})
ipcMain.handleNotificationNavigation(() => {
ipcMain.handleNotificationNavigation((application) => {
// For now navigate only to Inbox
const frontUrl = getMetadata(presentation.metadata.FrontUrl) ?? window.location.origin
const location = getCurrentResolvedLocation()
const urlString = `${frontUrl}/${workbenchId}/${location.path[1]}/${notificationId}`
const urlString = `${frontUrl}/${workbenchId}/${location.path[1]}/${application ?? notificationId}`
const urlObject = new URL(urlString)
navigate(parseLocation(urlObject))
})
+59 -14
View File
@@ -1,13 +1,21 @@
import { getPersonByPersonId, formatName } from '@hcengineering/contact'
import { Ref, TxOperations } from '@hcengineering/core'
import notification, { DocNotifyContext, CommonInboxNotification, ActivityInboxNotification, InboxNotification } from '@hcengineering/notification'
import { IntlString, addEventListener, translate } from '@hcengineering/platform'
import { formatName, getPersonByPersonId } from '@hcengineering/contact'
import { Ref, SortingOrder, TxOperations } from '@hcengineering/core'
import notification, {
notificationId,
ActivityInboxNotification,
CommonInboxNotification,
DocNotifyContext,
InboxNotification
} from '@hcengineering/notification'
import { addEventListener, getMetadata, IntlString, translate } from '@hcengineering/platform'
import { createNotificationsQuery, getClient } from '@hcengineering/presentation'
import { location } from '@hcengineering/ui'
import workbench, { workbenchId } from '@hcengineering/workbench'
import desktopPreferences, { defaultNotificationPreference } from '@hcengineering/desktop-preferences'
import { activePreferences } from '@hcengineering/desktop-preferences-resources'
import { InboxNotificationsClientImpl, getDisplayInboxData } from '@hcengineering/notification-resources'
import { getDisplayInboxData, InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
import { inboxId } from '@hcengineering/inbox'
import communication from '@hcengineering/communication'
import { IPCMainExposed } from './types'
@@ -123,17 +131,49 @@ export function configureNotifications (): void {
const inboxClient = InboxNotificationsClientImpl.getClient()
const notificationsQuery = createNotificationsQuery(true)
notificationsQuery.query({ read: false, limit: 1000 }, res => {
newUnreadNotifications = res.getResult().length
const isCommunicationEnabled = getMetadata(communication.metadata.Enabled) ?? false
if (preferences.showUnreadCounter) {
electronAPI.setBadge(prevUnViewdNotificationsCount + newUnreadNotifications)
}
if (isCommunicationEnabled) {
notificationsQuery.query({ read: false, limit: 1000 }, res => {
newUnreadNotifications = res.getResult().length
if (preferences.bounceAppIcon) {
electronAPI.dockBounce()
}
})
if (preferences.showUnreadCounter) {
electronAPI.setBadge(prevUnViewdNotificationsCount + newUnreadNotifications)
}
if (preferences.bounceAppIcon) {
electronAPI.dockBounce()
}
})
}
function startNotificationQuery (): void {
if (!isCommunicationEnabled) return
notificationsQuery.query({
read: false,
limit: 1,
strict: true,
order: SortingOrder.Descending,
created: {
greaterOrEqual: new Date()
}
}, (res) => {
if (!preferences.showNotifications) return
const notification = res.getResult()[0]
if (notification !== undefined) {
electronAPI.sendNotification({
silent: !preferences.playSound,
application: inboxId,
title: notification.content.title,
body: `${notification.content.senderName}: ${notification.content.shortText}`
})
}
})
}
if (preferences.showNotifications) {
startNotificationQuery()
}
async function handleNotifications (notificationsByContext: Map<Ref<DocNotifyContext>, InboxNotification[]>): Promise<void> {
const inboxData = await getDisplayInboxData(notificationsByContext)
@@ -174,6 +214,7 @@ export function configureNotifications (): void {
electronAPI.sendNotification({
silent: !preferences.playSound,
application: notificationId,
...notificationData
})
}
@@ -195,6 +236,10 @@ export function configureNotifications (): void {
if (!preferences.showUnreadCounter && newPreferences.showUnreadCounter) {
electronAPI.setBadge(prevUnViewdNotificationsCount + newUnreadNotifications)
}
if (newPreferences.showNotifications && !preferences.showNotifications) {
startNotificationQuery()
}
preferences = newPreferences
})
})
+2 -2
View File
@@ -121,8 +121,8 @@ const expose: IPCMainExposed = {
},
handleNotificationNavigation: (callback) => {
ipcRenderer.on('handle-notification-navigation', (event) => {
callback()
ipcRenderer.on('handle-notification-navigation', (event, application) => {
callback(application)
})
},
+3 -1
View File
@@ -1,4 +1,5 @@
import { ScreenSource } from '@hcengineering/love'
import { Plugin } from '@hcengineering/platform'
/**
* @public
@@ -75,6 +76,7 @@ export interface NotificationParams {
title: string
body: string
silent: boolean
application: Plugin
}
/**
@@ -87,7 +89,7 @@ export interface IPCMainExposed {
branding: () => Promise<Branding>
on: (event: string, op: (channel: any, args: any[]) => void) => void
handleDeepLink: (callback: (url: string) => void) => void
handleNotificationNavigation: (callback: () => void) => void
handleNotificationNavigation: (callback: (application: Plugin) => void) => void
handleUpdateDownloadProgress: (callback: (progress: number) => void) => void
setFrontCookie: (host: string, name: string, value: string) => Promise<void>
dockBounce: () => void
@@ -40,6 +40,7 @@
$: _message = $threadCreateMessageStore ?? message
let title = getDefaultTitle(message)
let selectedType: Ref<MasterTag> | undefined
let inProgress = false
function getDefaultTitle (message: Message): string {
const markup = toMarkup(message.content)
@@ -50,8 +51,13 @@
async function attachCard (): Promise<void> {
if (selectedType === undefined || title.trim() === '') return
await attachCardToMessage(_message, card, title, selectedType)
dispatch('close')
try {
inProgress = true
await attachCardToMessage(_message, card, title, selectedType)
dispatch('close')
} finally {
inProgress = false
}
}
function filterClasses (): [DropdownIntlItem, DropdownIntlItem[]][] {
@@ -129,7 +135,7 @@
/>
</div>
<svelte:fragment slot="footer">
{#if _message.thread != null}
{#if _message.thread != null && !inProgress}
<div class="footer-error">
<Label label={communication.string.MessageAlreadyHasCardAttached} />
</div>