Disable push notifications button for desktop (#10839)

Signed-off-by: Artem Savchenko <armisav@gmail.com>
This commit is contained in:
Artyom Savchenko
2026-05-19 21:16:50 +05:00
committed by GitHub
parent e94a1ef4df
commit 22f6aff97a
4 changed files with 106 additions and 1 deletions
+3 -1
View File
@@ -13,7 +13,9 @@
"build:watch": "compile ui",
"_phase:build": "compile ui",
"_phase:format": "format src",
"_phase:validate": "compile validate"
"_phase:validate": "compile validate",
"test": "jest --passWithNoTests --silent",
"_phase:test": "jest --passWithNoTests --silent"
},
"devDependencies": {
"@hcengineering/platform-rig": "workspace:^0.7.21",
@@ -0,0 +1,70 @@
//
// Copyright © 2026 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 { isDesktopClient } from './desktop'
describe('isDesktopClient', () => {
const globalAny = globalThis as any
const originalWindow = globalAny.window
afterEach(() => {
if (originalWindow === undefined) {
delete globalAny.window
} else {
globalAny.window = originalWindow
}
})
it('returns false in a regular https browser context', () => {
globalAny.window = {
location: { protocol: 'https:' }
}
expect(isDesktopClient()).toBe(false)
})
it('returns false when window is undefined (SSR / node)', () => {
delete globalAny.window
expect(isDesktopClient()).toBe(false)
})
it('returns true when the Electron IPC bridge is exposed on window', () => {
// The desktop preload script exposes the IPC bridge as `window.electron`
// (see desktop/src/ui/typesUtils.ts).
globalAny.window = {
electron: { sendNotification: jest.fn() },
// protocol is still https here — bridge alone must be enough
location: { protocol: 'https:' }
}
expect(isDesktopClient()).toBe(true)
})
it('returns true when the page is loaded from file:// (matches the failing scope in the bug report)', () => {
// The reported error showed scope `file:///workbench/n3-…` and script
// `file:///serviceWorker.js`. The file: protocol alone should disable
// push registration even if the bridge isn't visible yet.
globalAny.window = {
location: { protocol: 'file:' }
}
expect(isDesktopClient()).toBe(true)
})
it('treats a null electron property as not-a-bridge', () => {
globalAny.window = {
electron: null,
location: { protocol: 'https:' }
}
expect(isDesktopClient()).toBe(false)
})
})
@@ -0,0 +1,23 @@
//
// Copyright © 2025 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.
//
/**
* Detects whether the renderer is running inside the desktop (Electron) client.
*/
export function isDesktopClient (): boolean {
if (typeof window === 'undefined') return false
if ((window as any).electron != null) return true
return window.location?.protocol === 'file:'
}
@@ -66,6 +66,7 @@ import { getObjectLinkId, parseLinkId } from '@hcengineering/view-resources'
import type { LocationData } from '@hcengineering/workbench'
import { get, writable } from 'svelte/store'
import { isDesktopClient } from './desktop'
import { InboxNotificationsClientImpl } from './inboxNotificationsClient'
import { type InboxData, type InboxNotificationsFilter } from './types'
@@ -689,6 +690,10 @@ export const pushAllowed = writable<boolean>(false)
export async function checkPermission (value: boolean): Promise<boolean> {
if (!value) return true
if (isDesktopClient()) {
pushAllowed.set(false)
return false
}
if ('serviceWorker' in navigator && 'PushManager' in window) {
try {
const loc = getCurrentLocation()
@@ -725,6 +730,7 @@ function addWorkerListener (): void {
}
export function pushAvailable (): boolean {
if (isDesktopClient()) return false
const publicKey = getMetadata(notification.metadata.PushPublicKey)
return (
'serviceWorker' in navigator &&
@@ -736,6 +742,10 @@ export function pushAvailable (): boolean {
}
export async function subscribePush (): Promise<boolean> {
if (isDesktopClient()) {
pushAllowed.set(false)
return false
}
const client = getClient()
const publicKey = getMetadata(notification.metadata.PushPublicKey)
if ('serviceWorker' in navigator && 'PushManager' in window && publicKey !== undefined) {